Windowハンドルの取得

Windowハンドルの取得

 Win32APIなどを用い、ウィンドウを指定して何らかの処理を行う場合、必ずウィンドウのハンドルが必要になります。ウィンドウハンドルとはコンピュータが各ウィンドウに割り振る管理番号で、これを指定することで、コンピュータに該当のウィンドウを認識させます。
 ここでは、様々な方法で各種のウィンドウハンドルを取得する、サンプルコードとメモを記載します。

ポイント

 ・Application.Hwndプロパティ
 ・GetActiveWindow関数(Win32API)
 ・GetDesktopWindow関数(Win32API)
 ・FindWindow関数(Win32API)
 ・FindWindowEx関数(Win32API)
 ・GetWindow関数(Win32API)


プロパティを用いたウィンドウハンドル取得のサンプルコード

Application.Hwndプロパティ

 Excelの最上位のウィンドウ ハンドルをLong型の値で返す。値の取得のみ可能。
 Excel2002で追加されたプロパティであるため、Excel2000以前では使用できない。

Sub Get_Hwnd_1()
    MsgBox Excel.Application.Hwnd
End Sub

Win32APIを用いたウィンドウハンドル取得のサンプルコード

 次からは、ハンドルを取得するためのWin32API関数である。幾つかの種類があるが、ここで共通していることが2つある。
 1つ目は各関数の宣言場所。宣言は「宣言セクション」(各モジュールの最上部)に記述する。
 2つ目は返り値。関数が成功するとハンドル番号、失敗すると「0」を返す。

64ビットOfficeへの対応
 Win32APIの使用時に気をつけることは、64ビット版のOfficeへの対応である。対応項目は幾つかあるが、特に重要な点が2つある。
 1つ目は、Declare の後に、Ptrsafe 属性を設定すること。2つ目は、分岐による関数宣言である。これは32ビット用の宣言と、64ビット用の宣言を記述し、分岐によりコンピュータに該当の宣言を認識させるものである。  その他、変数の型を変更するケースもあるが、ここでは割愛
 次は、分岐による関数宣言例である(宣言セクションに記述)。

#If VBA7 And Win64 Then
    Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr '64bit
    Dim myHwnd As LongPtr
#Else
    Declare Function GetActiveWindow Lib "user32" () As Long
    Dim myHwnd As Long
#End If

 パソコン環境によっては、上記コードの一部が赤く表示されることもあるが、動作に問題はなくコードは実行できる。

GetDesktopWindow関数

 デスクトップのウィンドウハンドルを取得

【宣言】

#If VBA7 And Win64 Then
    Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
    Dim myHwnd As LongPtr
#Else
    Declare Function GetDesktopWindow Lib "user32" () As Long
    Dim myHwnd As Long
#End If

【使用例】

Sub Get_Hwnd_2()
    MsgBox GetDesktopWindow()
End Sub

GetActiveWindow関数

 アクティブになっているウィンドウハンドルの取得

【宣言】

#If VBA7 And Win64 Then
    Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr '64bit
    Dim myHwnd As LongPtr
#Else
    Declare Function GetActiveWindow Lib "user32" () As Long
    Dim myHwnd As Long
#End If

【使用例】

Sub Get_Hwnd_3()
    MsgBox GetActiveWindow()
End Sub

FindWindow関数

 クラスやウィンドウの名前からウィンドウハンドルを取得

【宣言】

#If VBA7 And Win64 Then
    Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As LongPtr
    Dim myHwnd As LongPtr
#Else
    Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Dim myHwnd As Long
#End If

 lpClassName・・・クラス名
 lpWindowName・・・ウィンドウ名
 引数は省略不可。指定しない場合はvbNullStringで対応する。
 2つの引数を共にvbNullStringにした場合は、最前面のWindowのハンドルを取得する。



【使用例】

'代表的なアプリケーションのクラス名
'Excel「XLMAIN」 Word「OpusApp」 PowerPoint「PP10FrameClass」 Access「OMain」
'Visual Basic Editor「wndclass_desked_gsk」 Internet Explorer「IEFrame」
'メモ帳「Notepad」 ペイント「MSPaintApp」 電卓「SciCalc」 ワードパッド「WordPadClass」
'-------------------------------------------------------------------------------------------------------

Sub Get_Hwnd_4()
    MsgBox FindWindow("XLMAIN", vbNullString)
    MsgBox FindWindow(vbNullString, Application.Caption)
End Sub

FindWindowEx関数

 親ウィンドウを基準に、クラスやウィンドウの名前から子ウィンドウのハンドルを取得

【宣言】

#If VBA7 And Win64 Then
    Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
        ByVal hwndParent As LongPtr, _
        ByVal hwndChildAfter As LongPtr, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As LongPtr
    Dim myHwnd As LongPtr
#Else
    Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
        ByVal hwndParent As Long, _
        ByVal hwndChildAfter As Long, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Dim myHwnd As Long
#End If

【引数】
 hwndParent・・・親Windowのハンドル
 hwndChildAfter・・・検索を開始する子Windowのハンドル。「0」の場合、最初の子Windowから検索
 lpClassName・・・クラス名
 lpWindowName・・・ウィンドウ名

【使用例】

Sub Get_Hwnd_5()
    myHwnd = FindWindow("XLMAIN", vbNullString)
    If myHwnd = 0 Then Exit Sub
    'Excelのクライアント領域のウィンドウハンドル
    MsgBox FindWindowEx(myHwnd, 0, "XLDESK", vbNullString)
End Sub

GetWindow関数

 あるウィンドウを基準に、他の任意のウィンドウハンドルを取得する

【宣言】

#If VBA7 And Win64 Then
    Declare PtrSafe Function GetWindow Lib "user32" ( _
        ByVal hwnd As LongPtr, _
        ByVal wCmd As Long) As LongPtr
    Dim myHwnd As LongPtr
#Else
    Declare Function GetWindow Lib "user32" ( _
        ByVal hwnd As Long, _
        ByVal wCmd As Long) As Long
    Dim myHwnd As Long
#End If

'///GetWindowの定数///
Const GW_HWNDFIRST = 0  '基準となるWindowと同じ種類のうち最前面のWindow
Const GW_HWNDLAST = 1   '基準となるWindowと同じ種類のうち最背面のWindow
Const GW_HWNDNEXT = 2   '基準となるWindowの次のWindow
Const GW_HWNDPREV = 3   '基準となるWindowの前のWindow
Const GW_OWNER = 4      '基準となるWindowのオーナーWindow
Const GW_CHILD = 5      '基準となるWindowの子WindowのうちトップレベルのWindow

【引数】
 hwnd・・・基準となるウィンドウのハンドル
 wCmd・・・どのような検索コマンドを実行するかを指定。定数を使用。

【使用例】

Sub Get_Hwnd_6()
    myHwnd = FindWindow("XLMAIN", vbNullString)
    MsgBox GetWindow(myHwnd, GW_CHILD)
End Sub

全サンプルコード

 上記の全てを繋げ、比較を行うサンプルコード。

#If VBA7 And Win64 Then
    Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
    Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
    Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As LongPtr
    Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
        ByVal hwndParent As LongPtr, _
        ByVal hwndChildAfter As LongPtr, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As LongPtr
    Declare PtrSafe Function GetWindow Lib "user32" ( _
        ByVal hwnd As LongPtr, _
        ByVal wCmd As Long) As LongPtr
    Dim myHwnd As LongPtr
    Dim myCHwnd As LongPtr
#Else
    Declare Function GetActiveWindow Lib "user32" () As Long
    Declare Function GetDesktopWindow Lib "user32" () As Long
    Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
        ByVal hwndParent As Long, _
        ByVal hwndChildAfter As Long, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Declare Function GetWindow Lib "user32" ( _
        ByVal hwnd As Long, _
        ByVal wCmd As Long) As Long
    Dim myHwnd As Long
    Dim myCHwnd As Long
#End If

'///GetWindowの定数///
Const GW_HWNDFIRST = 0  '基準となるWindowと同じ種類のうち最前面のWindow
Const GW_HWNDLAST = 1   '基準となるWindowと同じ種類のうち最背面のWindow
Const GW_HWNDNEXT = 2   '基準となるWindowの次のWindow
Const GW_HWNDPREV = 3   '基準となるWindowの前のWindow
Const GW_OWNER = 4      '基準となるWindowのオーナーWindow
Const GW_CHILD = 5      '基準となるWindowの子WindowのうちトップレベルのWindow

'------------------------------------------------------------------------------
Sub Get_Hwnd()
    Dim strWndCap As String

    myHwnd = GetDesktopWindow()
    MsgBox "GetDesktopWindow:" & myHwnd

    myHwnd = Excel.Application.hwnd 'Excel2000以前では使用できない
    MsgBox "Application.Hwnd:" & myHwnd

    myHwnd = GetActiveWindow()
    MsgBox "GetActiveWindow:" & myHwnd

    myHwnd = FindWindow("XLMAIN", vbNullString)
    MsgBox "FindWindow(""XLMAIN"", vbNullString):" & myHwnd

    strWndCap = Application.Caption
    myHwnd = FindWindow(vbNullString, strWndCap)
    MsgBox "FindWindow(vbNullString, strWndCap):" & myHwnd

    myCHwnd = FindWindowEx(myHwnd, 0, "XLDESK", vbNullString) 'Excelのクライアント領域
    MsgBox "FindWindowEx:" & myCHwnd

    myHwnd = GetWindow(myHwnd, GW_CHILD)
    MsgBox "GetWindow(myHwnd, GW_CHILD):" & myHwnd
End Sub

Excel Tips for Teachers

Copyright (C) 2009- 坂江 保 All Rights Reserved.