【VBA×WindowsAPI】指定のウィンドウの実行ファイルパスを取得する
Windows APIでは各ウィンドウに設定されているウィンドウハンドルを使ってウィンドウ操作を行います。このウィンドウハンドルは基本的に特定のウィンドウを指定して取得するものです。つまり、どのアプリケーションのウィンドウなのかを分かったうえで使うのが普通です。ただ、ハンドルだけ手元にあってこれがどのアプリケーションのものなのか知りたいという状況に出くわすこともあります。
ここではWindows APIを使って指定のウィンドウハンドルから実行ファイルのフルパスを取得する方法を解説していきます。これにより、たとえばGetForegroundWindow関数で取得した最前面ウィンドウがどのアプリケーションのウィンドウかを判定することができるようになります。
ウィンドウハンドルから実行ファイルを特定
Windows APIを使うことで、指定ウィンドウ(=プロセス)に紐づく実行ファイルのフルパスを取得できます。流れはシンプルで下記の通りです。ウィンドウはアプリケーションの最上位のウィンドウである必要はなく、FindWindowEx関数などで取得した子ウィンドウのハンドルでも問題ありません。
② OpenProcessでプロセスIDの対象プロセスを開いてプロセスハンドルを取得
③ GetModuleFileNameExでメインモジュール(= 実行ファイル)のフルパスを取得
④ CloseHandleで後片付け
それぞれの関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。
GetWindowThreadProcessId関数 :指定ウィンドウを作成したプロセスの識別子を取得する
OpenProcess関数 :指定プロセスを操作するためのハンドルを取得する
CloseHandle関数 :取得したハンドルを閉じてリソースを解放す
GetModuleFileNameExA関数 :指定プロセスの実行ファイルのパスを取得する
サンプルコード
下記は指定のウィンドウハンドルから実行ファイルのパスを取得するサンプルコードです。
コード内ではExcelのハンドル(Application.hWnd)を入力しているためそのまま実行すると「EXCEL.EXE」のフルパスが取得できます(結果はイミディエイトウィンドウに出力)。他アプリを対象にしたい場合はFindWindow関数などで取得したウィンドウハンドルを使用してください。
Option Explicit
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As LongPtr, lpdwProcessId As Long) As Long
Private Declare PtrSafe Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function GetModuleFileNameExA Lib "psapi" (ByVal hProcess As LongPtr, ByVal hModule As LongPtr, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const PROCESS_VM_READ = &H10
Sub main()
Dim hWnd As LongPtr
Dim sPath As String
hWnd = Application.hWnd
sPath = GetAppPathFromHwnd(hWnd)
Debug.Print sPath
End Sub
Private Function GetAppPathFromHwnd(ByVal hWnd As LongPtr) As String
Dim lProcId As Long
Dim hProc As LongPtr
Dim sBuf As String * 260
Dim lLen As Long
'ウィンドウのプロセスIDを取得
Call GetWindowThreadProcessId(hWnd, lProcId)
If lProcId = 0 Then Exit Function
'プロセスを開く
hProc = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, lProcId)
If hProc <> 0 Then
lLen = GetModuleFileNameExA(hProc, 0, sBuf, Len(sBuf))
If lLen > 0 Then
GetAppPathFromHwnd = Left$(sBuf, lLen)
End If
Call CloseHandle(hProc)
End If
End Function
関連情報
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:GetWindowThreadProcessId 関数 (winuser.h) – Win32 apps
OpenProcess 関数 (processthreadsapi.h) – Win32 apps
CloseHandle 関数 (handleapi.h) – Win32 apps
GetModuleFileNameExA 関数 (psapi.h) – Win32 apps











