【VBA×WindowsAPI】マウスカーソル位置にあるウィンドウのハンドルを取得する

WindowsAPIを使ってウィンドウの操作を行うとき、多くの場合はウィンドウハンドルを取得する必要があります。ウィンドウハンドルを取得するための関数は様々存在しますが、「指定のウィンドウ内にある特定の子ウィンドウのハンドルをパッと調べたい」という場合にそれを解決する関数は存在しません。ただいくつかの関数を組み合わせれば、このようなニーズに応えることができます。そこで、ここではマウスカーソルの下にあるウィンドウのハンドルを取得する方法を解説していきます。

カーソル位置にあるウィンドウのハンドルを取得

ウィンドウにはそれぞれを識別するためにウィンドウハンドルというものが割り当てられています。WindowsAPIではこのウィンドウハンドルを使うことで、指定のウィンドウに対して描画設定を変更したりウィンドウタイトルを取得したりと様々な操作を行うことが可能になっています。

VBAでウィンドウの操作を行う場合も基本的にはWindowsAPIを使う必要があるため、このウィンドウハンドルを取得する必要があります。WindowsAPIにはウィンドウのキャプションやクラス名から指定のウィンドウハンドルを取得するFindWindow関数や、現在アクティブなウィンドウのハンドルを取得するGetActiveWindow関数などウィンドウハンドルを取得するための関数がいくつも用意されているため状況や目的に合わせて使い分ける必要があります。

現在のカーソル位置にあるウィンドウのハンドルを取得するには下記のWindowsAPIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。

icon-check-square WindowFromPoint関数  :指定の座標にあるウィンドウのハンドルを取得する
icon-check-square GetCursorPos関数          :カーソル位置の座標を取得する(スクリーン座標基準)
icon-check-square CopyMemory関数         :指定のメモリ領域を別の領域にコピーする

「そもそもWindowsAPIって何?」という方はコチラ(メインページ)も併せて参照下さい。

サンプルコード

現在のカーソル位置にあるウィンドウのハンドルを取得するためのサンプルコードは下記の通りです。下記コードではGetWindowText関数GetClassName関数を使い、ウィンドウハンドルだけでなくウィンドウのタイトルとクラス名もあわせて取得し、イミディエイトウィンドウに出力しています。
注意点として下記コードはカーソルの動きを常に監視するためにDo~Loop関数で無限ループを発生させています。Doeventsを入れているので停止ボタンを押せばいつでも止められますが、ループを抜け出す処理は入れていないので実際にマクロに組み込む場合は何らかの終了条件の追加が必要です。

コード解説

icon-edit 現在のカーソル座標を取得

カーソル位置にあるウィンドウのハンドルを取得するにはまず、カーソルがスクリーンの”どの位置”に存在しているのか、つまりは座標を取得する必要があります。ここでいう座標とはスクリーンの左上を原点として横軸をX座標(右方向が+)、縦軸をY座標(下方向が+)としたスクリーン座標です。

Windows APIで2次元の座標を扱う場合は、X座標値とY座標値の2つの要素を持つPOINTAPI構造体を使うことが一般的です。この構造体はVBAには用意されていないのでTypeステートメントを使って下記のように記載し、ユーザー定義型として明示的に定義する必要があります。

icon-code POINTAPI構造体の定義 

Private Type POINTAPI

        x As Long

        y As Long

End Type

現在のカーソル位置の座標を取得するにはGetCursorPos関数を使い下記のように記載します。引数にユーザー定義型(As POINTAPI)で宣言された変数を入力することで、その変数(構造体)内に現在のカーソル位置のスクリーン座標を取得することができます。

icon-code GetCursorPos関数 

Call GetCursorPos(tPt)

 

icon-edit カーソル座標地点にあるウィンドウのハンドルを取得

現在のカーソル位置のスクリーン座標をPOINTAPI構造体に格納することが出来たら、WindowFromPoint関数を使ってその座標地点にあるウィンドウのハンドルを取得します。

icon-code WindowFromPoint関数 

hWnd = WindowFromPoint(llPtr)

Win64環境ではWindowFromPoint関数の引数にはPOINTAPI構造体をLongLong型に変換したものを入力する必要があります。このPOINTAPI構造体→LongLong型の変換はCopyMemory関数を使って行います。少し難しい内容ですが事前にLongLong型のメモリ領域を確保しておき、その領域にPOINTAPI構造体のメモリをコピーすることで型の変換を行うことができます。この方法はMicrosoft提供のWin32API_PtrSafe.txtにもそのまま記載されている手法です。

関連情報

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

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

icon-share-square 参考

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

Excel, VBA, Windows API

Posted by Lic