教えて!ExcelVBA!

ExcelVBAの基礎知識・書き方について紹介します。

【ExcelVBA API操作】起動したアプリケーションのプロセスハンドルを取得(OpenProcess)及び解放(CloseHandle)する方法を教えて!

f:id:m_kbou:20210520104210p:plain

起動したアプリケーションのプロセスハンドルを取得するWindowsAPI関数(OpenProcess)及び解放するWindowsAPI関数(CloseHandle)について紹介します。プロセスハンドルとは起動したアプリケーション毎に割り振られる番号と理解して下さい。具体的な例としては、メモ帳を開くとプロセスハンドルは「1」となり、もう一つメモ帳を開くと「2」となります。このプロセスハンドルが取得できれば起動したアプリケーションを番号で操作できる事になります。

 

 

構文

記述方法は以下の通りとなります。

(1)起動アプリケーションのプロセスハンドルを取得

(API定義)

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

----------------------------------------

(定数)

Public Const アクセス方法 = &H1F0FFF

----------------------------------------

 (VBA記述)

OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId)

[説明]:

起動したアプリケーションのプロセスハンドルを取得するAPI関数はOpenProcess関数となります。VBAから呼び出して使用する場合には、

---------------------------------

・定義

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

・定数

Public Const アクセス方法 = &H1F0FFF

---------------------------------

をプロシージャ外で宣言します。

引数であるdwDesiredAccessにはプロセスオブジェクトで認められるアクセス方法を指定し、bInheritHandleには取得したハンドルを継承するか否かを指定し、dwProcessIdには開くべきプロセスのプロセスIDを指定します。また、dwDesiredAccessについては定数で記述した「アクセス方法」をセットし、bInheritHandleについては固定値で「True」をセットします。OpenProcess関数を実行すると戻り値として「プロセスハンドル値」又は「Null」が返ります。「プロセスハンドル値」の場合は起動したアプリケーションのプロセスハンドル値取得に成功した状態となり、「Null」の場合は失敗した状態となります。

(2)起動アプリケーションのプロセスハンドルを解放

(API定義)

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

----------------------------------------

 (VBA記述)

CloseHandle(hObject)

[説明]:

起動したアプリケーションのプロセスハンドルを解放するAPI関数はCloseHandle関数となります。VBAから呼び出して使用する場合には、

---------------------------------

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

---------------------------------

をプロシージャ外で宣言します。

引数であるhObjectにはプロセスハンドル値を指定します。プロセスハンドル値は上記のOpenProcess関数で取得したプロセスハンドル値を指定します。CloseHandle関数を実行すると戻り値として「0以外」又は「0」が返ります。「0以外」の場合はプロセスハンドルの解放が成功した状態となり、「0」の場合は失敗した状態となります。

 

使い方

使用方法について説明します。 

[プログラミング例]:

'*------------------------------------------
'(プロセスハンドル取得API関数:OpenProcess)
Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Public Const アクセス方法 = &H1F0FFF

'*------------------------------------------
'(プロセスハンドル解放API関数:CloseHandle)
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'*------------------------------------------

Sub 起動したアプリケーションのプロセスハンドルを取得及び解放する()

  '↓処理①
  Dim 戻り値 As Long
  Dim プロセス As Long

  '↓処理②
  戻り値 = Shell("Notepad.exe", vbNormalFocus)

  '↓処理③
  プロセス = OpenProcess(アクセス方法, True, 戻り値)
  If (IsNull(プロセス) = True) Then
    MsgBox "取得に失敗しました。(ハンドル値:" & プロセス & ")"
    Exit Sub
  Else
    MsgBox "取得に成功しました。(ハンドル値:" & プロセス & ")"
  End If

  '↓処理④
  戻り値 = CloseHandle(プロセス)
  If (戻り値 = 0) Then
    MsgBox "解放に失敗しました。(戻り値:" & プロセス & ")"
  Else
    MsgBox "解放に成功しました。(戻り値:" & プロセス & ")"
  End If

End Sub

処理の流れは以下の通りとなります。

[処理①]:変数定義
戻り値とプロセス値を格納する変数定義となります。

[処理②]:Shell関数によるメモ帳の起動
Shell関数を使用してメモ帳を起動します。起動時の戻り値(プロセスID)は[処理①]で定義した変数:戻り値にセットします。

[処理③]:OpenProcessによるプロセスハンドルの取得
WindowsAPI関数であるOpenProcessを使用した起動アプリケーションのプロセスハンドル値を取得します。各引数には以下の内容をセットして処理を実行します。
・dwDesiredAccess・・・アクセス方法をセットします。
           ※定数で記述した「アクセス方法」をセットします。
・bInheritHandle・・・取得ハンドルの継承状況をセットします。
           ※「True」(固定値)をセットします。
・dwProcessId・・・開くべきプロセスのプロセスIDをセットします。
           ※今回はShell関数の戻り値をセットします。
実行すると戻り値として「Null」又は「取得したプロセスハンドル値」が返されます。「Null」の場合はプロセスハンドル値の取得に失敗した状態(MsgBoxで”取得に失敗しました。”を表示)となります。また、「Null以外」の場合は取得に成功した状態(MsgBoxで”取得に成功しました。”を表示)となります。

[処理④]:CloseHandleによるプロセスハンドルの解放
WindowsAPI関数であるCloseHandleを使用した[処理③]で取得したプロセスハンドル値を解放します。引数には以下の内容をセットして処理を実行します。
・hObject・・・OpenProcessで取得したプロセスハンドル値をセットします。
        ※今回は変数:プロセスをセットします。
実行すると戻り値として「0」又は「0以外」が返ります。「0」の場合はプロセスハンドルの解放に失敗した状態(MsgBoxで”解放に失敗しました。”を表示)となります。また、「0以外」の場合は解放に成功した状態(MsgBoxで”解放に成功しました。”を表示)となります。

f:id:m_kbou:20210521134444p:plain

※上記のプログラミング例は、VBE(VBA記述画面)に記述しないと実行ができません。VBEの開き方についてはこちらを参考にして下さい。

[実行例]:

①<実行>ボタンをクリックします。<実行>ボタンには上記のプログラミング例のプログラムが登録されています。(※ボタンの作り方やボタンにプログラムを割り当てるにはこちらを参考にして下さい。)

f:id:m_kbou:20210520104323p:plain

②メモ帳が開くので、メモ帳をアイコン化(最小化)します。

f:id:m_kbou:20210520104355p:plain

③メモ帳のプロセスハンドル値を取得する事ができたので、「取得に成功しました。(ハンドル値:5320)」がMsgBoxで表示されます。<OK>ボタンをクリックします。(※ハンドル値は状況により値が変わります。)

f:id:m_kbou:20210520104422p:plain

④メモ帳のプロセスハンドル値を解放する事ができたので、「解放に成功しました。(戻り値:1)」がMsgBoxで表示されます。<OK>ボタンをクリックします。

f:id:m_kbou:20210520104457p:plain

[サンプル]:

上記で説明したファイルをダウンロードできます。ご自由にお使い下さい。

drive.google.com

起動したアプリケーションのプロセスハンドルを取得及び解放する方法についての説明は以上です。

 

おわりに

今回はWindowsAPI関数による起動したアプリケーションのプロセスハンドルを取得及び解放する方法について説明しました。類似の内容にアプリケーション終了までプログラムの実行を待機する方法もあります。こちらも是非参考にして下さい。