【VBA×WindowsAPI】ScreenToClient関数の使い方
ScreenToClient関数
ScreenToClient関数はスクリーン基準の座標をウィンドウのクライアント領域基準の座標に変換するための関数です。クライアント領域とはタイトルバーや境界線などを除いたウィンドウのメイン描画部分のことです。VBAのUserformでコントロールを配置する際に使うLeft/Topプロパティはこのクライアント領域基準の座標となっています。
クライアント領域基準の座標はその領域の左上の地点を基準(原点)に、ウィンドウの水平方向をX軸、ウィンドウの垂直方向をY軸として2次元平面上の座標(x,y)で表すことができます。このとき座標の基準をスクリーンの左上とすることでスクリーン基準の座標(x’,y’)として表すこともできます。
ScreenToClient関数はこのスクリーン基準の座標(x’,y’)をクライアント領域基準の座標(x,y)に変換するための関数です。このとき変換する座標の単位はピクセル(px)となります。UserFormで使用するLeft/Topプロパティは単位がポイント(pt)のため、UserFormのコントロールの座標を使う場合は事前に単位変換しておく必要があります。
ScreenToClient関数とは反対にクライアント領域基準の座標をスクリーン基準の座標に変換するためのClientToScreen関数という関数も存在します。状況によって使い分けることが可能です。
使用方法
ScreenToClient関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
Declare PtrSafe Function ScreenToClient Lib “user32” _
(ByVal hWnd As LongPtr, lpPoint As POINTAPI) As Long
Declare Function ScreenToClient Lib “user32” _
(ByVal hwnd As Long, lpPoint As POINTAPI) As Long
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。
1 2 3 4 5 |
#If VBA7 Then Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hWnd As LongPtr, lpPoint As POINTAPI) As Long #Else Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long #End If |
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。
・Public Declare PtrSafe Function~ :モジュール外で呼び出し有効
引数に使われている「POINTAPI」は下記のように構造体として定義しておく必要があります。
座標を扱う関数で利用されることが多く、ある地点のx座標、y座標を格納するための構造体です。
1 2 3 4 |
Type POINTAPI x As Long y As Long End Type |
構文
ScreenToClient関数の構文は下記のように書きます。
lRet = ScreenToClient(hWnd, lpPoint)
引数
hWnd (64bit:LongPtr型 / 32bit:Long型)
座標変換の基準となるクライアント領域を持つウィンドウのハンドルを入力します。
スクリーン座標がこのウィンドウのクライアント領域の座標に変換されます。
ウィンドウハンドルはFindWindow関数、FindWindowEx関数、GetActiveWindow関数などの関数で取得が可能です。ウィンドウハンドルは環境によって型が変化するので注意が必要です。
lpPoint (POINTAPI型)
スクリーン座標が入ったPOINTAPI構造体を入力します。
事前に定義しているPOINTAPI構造体を使うことで下記のように、xとyに値を入れることが可能です。
1 2 3 |
Dim tCoord As POINTAPI tCoord.x = 250 tCoord.y = 100 |
たとえば上記の処理の後にこの「tCoord」を引数として入力すると、スクリーン座標での「x=250」と「y=100」が、もう一方の引数hWndが示すウィンドウのクライアント領域基準の座標に変換され「tCoord」の中身を更新してくれます。(ByRefで入力しているため in/out を兼ねている)
戻り値
lRet (Long型)
戻り値は関数が成功した場合は「0以外」です。
失敗した場合は「0」が返されます。
サンプルコード
以下はScreenToClient関数とFindWindow関数を使って、スクリーン上の点座標(250,100)をメモ帳ウィンドウ上(クライアント領域)の座標に変換するサンプルコードです。
メモ帳を開いた状態で下記コードを実行すると、スクリーン座標の値をメモ帳ウィンドウ上での座標値に変換し、その値をイミディエイトウィンドウに出力することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hWnd As LongPtr, lpPoint As POINTAPI) As Long Type POINTAPI x As Long y As Long End Type Sub main() Dim hWnd As LongPtr Dim tCoord As POINTAPI Dim lRet As Long 'メモ帳のウィンドウハンドルを取得 hWnd = FindWindow("notepad", vbNullString) tCoord.x = 250 'スクリーン基準 x座標 tCoord.y = 100 'スクリーン基準 y座標 '座標変換(スクリーン基準→クライアント領域基準) lRet = ScreenToClient(hWnd, tCoord) Debug.Print tCoord.x 'クライアント領域基準 x座標 Debug.Print tCoord.y 'クライアント領域基準 y座標 End Sub |
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:ScreenToClient 関数 (winuser.h) – Win32 apps