【VBA×WindowsAPI】ClientToScreen関数の使い方
ClientToScreen関数
ClientToScreen関数はウィンドウのクライアント領域基準の座標をスクリーン基準の座標に変換するための関数です。クライアント領域とはタイトルバーや境界線などを除いたウィンドウのメイン描画部分のことです。VBAのUserformでコントロールを配置する際に使うLeft/Topプロパティはこのクライアント領域基準の座標となっています。
クライアント領域基準の座標はその領域の左上の地点を基準(原点)に、ウィンドウの水平方向をX軸、ウィンドウの垂直方向をY軸として2次元平面上の座標(x,y)で表すことができます。このとき座標の基準をスクリーンの左上とすることでスクリーン基準の座標(x’,y’)として表すこともできます。
ClientToScreen関数はこのクライアント領域基準の座標(x,y)をスクリーン基準の座標(x’,y’)に変換するための関数です。このとき変換する座標の単位はピクセル(px)となります。UserFormで使用するLeft/Topプロパティは単位がポイント(pt)のため、UserFormのコントロール等からスクリーン座標を取得する場合は事前に単位変換しておく必要があります。
ClientToScreen関数とは反対にスクリーン基準の座標をクライアント領域基準の座標に変換するためのScreenToClient関数という関数も存在します。状況によって使い分けることが可能です。
使用方法
ClientToScreen関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
Declare PtrSafe Function ClientToScreen Lib “user32” _
(ByVal hwnd As LongPtr, lpPoint As POINTAPI) As Long
Declare Function ClientToScreen Lib “user32” _
(ByVal hwnd As Long, lpPoint As POINTAPI) As Long
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。
1 2 3 4 5 |
#If VBA7 Then Declare PtrSafe Function ClientToScreen Lib "user32" (ByVal hwnd As LongPtr, lpPoint As POINTAPI) As Long #Else Declare Function ClientToScreen 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 |
構文
ClientToScreen関数の構文は下記のように書きます。
lRet = ClientToScreen(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」を引数として入力すると、もう一方の引数hWndが示すウィンドウのクライアント領域基準の座標である「x=250」と「y=100」が、スクリーン基準の座標に変換され「tCoord」の中身を更新してくれます。(ByRefで入力しているため in/out を兼ねている)
戻り値
lRet (Long型)
戻り値は関数が成功した場合は「0以外」です。
失敗した場合は「0」が返されます。
サンプルコード
以下はClientToScreen関数と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 ClientToScreen 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 = ClientToScreen(hWnd, tCoord) Debug.Print tCoord.x 'スクリーン基準 x座標 Debug.Print tCoord.y 'スクリーン基準 y座標 End Sub |
UserForm上のコントロールの位置(Top/Left/Width/Height)をスクリーン基準に変換する場合には単位をピクセル(px)に合わせるために下記のようなコードを書きます。
UserForm上の適当な位置に「Label1」というLebelコントロールを作成して、フォームのコードに下記コードを直接コピペしてください。その後、UserFormを起動するとLabel1の左上の点のスクリーン基準の座標がイミディエイトウィンドウに出力されます。スクリーン左上に持っていくとx,yがいずれも0に近づくことが確認できます。
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 28 29 30 31 32 33 34 35 36 |
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function ClientToScreen Lib "user32" (ByVal hWnd As LongPtr, lpPoint As POINTAPI) As Long Private Type POINTAPI x As Long y As Long End Type Dim hWnd As LongPtr Dim tCoord As POINTAPI Dim lRet As Long Private Sub UserForm_Initialize() 'メモ帳のウィンドウハンドルを取得 hWnd = FindWindow("ThunderDFrame", Me.Caption) End Sub Private Sub UserForm_Layout() tCoord.x = PointToPixel(Label1.Left) 'クライアント領域基準 x座標 tCoord.y = PointToPixel(Label1.Top) 'クライアント領域基準 y座標 '座標変換(クライアント領域→スクリーン基準) lRet = ClientToScreen(hWnd, tCoord) Debug.Print "x = " & tCoord.x 'スクリーン基準 x座標 Debug.Print "y = " & tCoord.y 'スクリーン基準 y座標 End Sub Private Function PointToPixel(dPt As Double) As Double Const DPI As Double = 96 PointToPixel = dPt / 72 * DPI End Function |
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:ClientToScreen 関数 (winuser.h) – Win32 apps