【VBA×WindowsAPI】ReleaseDC関数の使い方

ReleaseDC関数

ReleaseDC関数は取得したデバイスコンテキスト(以下DC)を解放するための関数です。
ウィンドウ内に線や図形を描画したり、指定ピクセルの色を取得したりといった"ウィンドウの描画"に関わる操作を行う際には、各ウィンドウがそれぞれ持っているDCにアクセスする必要があります。

DCにアクセスするためにはGetDC関数もしくはGetWindowDC関数を使用してDCへのハンドルを取得することで、それを引数として関連関数に渡すことで様々な描画に関する操作を行うことができます。(※DCについての説明はリンク先ページに記載しているので合わせて参照下さい)

このとき上記のようにDCを使った描画関係の処理を行った後は必ず明示的にDCを解放する必要があります。このDCの解放を行うための関数がReleaseDC関数です。

VBAでは基本的にコードがすべて終わると使用していたメモリ(変数など)は自動ですべて解放されますが、WindowsAPIであるこれら関数は"解放する"という処理を書かないとコードが終わってもメモリが解放されません。つまり、コードを実行するたびに無駄なメモリが蓄積していきメモリリークに陥ってしまうということです。

これについては「GetDC関数もしくはGetWindowDC関数を使ったら、その後にReleaseDC関数を必ず使わないといけない」という対の存在として認識しておけば問題ありません。

また、ReleaseDC関数はCreateDC関数により新たに生成したDCはReleaseDC関数で解放することが出来ません。こちらの場合はDeleteDC関数を使って解放(削除)する必要があります。

 

使用方法

ReleaseDC関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。

使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。

 icon-code  64bit  

Declare PtrSafe Function ReleaseDC Lib “User32" _
(ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long

icon-code  32bit  

Declare Function ReleaseDC Lib “user32" _
(ByVal hwnd As Long, ByVal hdc As Long) As Long

上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。

#If VBA7 Then
    Declare PtrSafe Function ReleaseDC Lib "User32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long
#Else
    Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
#End If

 
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。

Private Declare PtrSafe Function~ :モジュール内でのみ呼び出し有効
Public Declare PtrSafe Function~ :モジュール外で呼び出し有効

 
 

構文

ReleaseDC関数の構文は下記のように書きます。

icon-code ReleaseDC関数 

lRet = ReleaseDC(hwnd, hdc)

引数

 hwnd    (64bit:LongPtr型 / 32bit:Long型) 

解放するDCを持つウィンドウのハンドルを入力します。
基本的にはGetDC関数もしくはGetWindowDC関数の引数として入力したウィンドウのハンドルと同じものを入力します。GetDC/GetWindowDC関数の引数としてNULL値(0)を入力した場合は、同じくNULL値(0)を入力します
  

 hdc    (64bit:LongPtr型 / 32bit:Long型) 

解放するDCのハンドルを入力します。
基本的にはGetDC/GetWindowDC関数で取得したハンドルと同じものを入力します。

両引数とも開発環境によって型が変化するので注意が必要です。
 

戻り値

 lRet    (Long型) 

戻り値として"DCの解放が正常にできたか"が返ります。
DCが正常に解放できた場合は「1」が、解放できなかった場合は「0」が返ります。

 

サンプルコード

ReleaseDC関数は取得したDCを解放するだけの関数で、それだけでは特に何もできません。
よって「DCを取得するための関数」と「DCを使って何らかの描画関連処理を行うための関数」も合わせて利用するのが一般的です。たとえば「ある指定のウィンドウに対して何らかの描画関連の処理を行う」には基本的には下記コードのような流れが基本となります。

Declare PtrSafe Function GetDC Lib "User32" (ByVal hwnd As LongPtr) As LongPtr
Declare PtrSafe Function ReleaseDC Lib "User32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long
Declare PtrSafe Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

Sub main()

    Dim hwnd As LongPtr
    Dim hdc  As LongPtr
    Dim lRet As Long
    
    'ウィンドウ名からウィンドウハンドルを取得
    hwnd = FindWindow(vbNullString, "ウィンドウ名")
    
    '取得したウィンドウのデバイスコンテキストへのハンドルを取得
    hdc = GetDC(hwnd)
    
    '----------------------------------
    '
    '   ウィンドウに対する描画関連の処理
    '
    '----------------------------------
    
    'デバイスコンテキストを解放
    lRet = ReleaseDC(hwnd, hdc)

End Sub

 

 icon-share-square  VBA×WindowsAPIまとめページ

その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。

 icon-share-square  参考

Microsoft公式:ReleaseDC 関数 (winuser.h) – Win32 apps

2023年7月16日Excel,VBA,Windows API