2012年8月5日日曜日

[ExcelVBA] SendMessage


■説明
メッセージをウィンドウへ送信する関数
この関数は、指定されたウィンドウのウィンドウプロシージャを呼出、その処理が終わった後で処理を返します。ボタンをクリックして新たなウィンドウを開きそのウィンドウを閉じない限り処理が前に進めないといったケースもあります。
このように同期してほしくない時は、PostMessage関数を使うことで解決できます。

■宣言
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal MSG As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
第一引数:メッセージを送りたいハンドルを指定
第ニ引数:メッセージの種類を指定
第三引数:メッセージの種類に応じて指定。
第四引数:メッセージの種類に応じて指定。
※第四引数は、メッセージの種類に応じて違う型の時もあります。
戻り値:メッセージの種類によってことなります。


■サンプルコード
電卓を使ってみます。
まずは、9 * 9 =の計算を行なってみます。
使うメッセージはBM_CLICK
Option Explicit

Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
    (ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
     ByVal lpszClass As String, ByVal lpszWindow As String) As Long

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
    (ByVal hwnd As Long, ByVal msg As Long, _
     ByVal wParam As Long, ByVal lParam As Long) As Long

Const BM_CLICK = &HF5

Sub SampleCode()
    Dim hwnd(3) As Long
    hwnd(0) = FindWindow("SciCalc", "電卓")
    hwnd(1) = FindWindowEx(hwnd(0), 0, "Button", "9")
    hwnd(2) = FindWindowEx(hwnd(0), 0, "Button", "*")
    hwnd(3) = FindWindowEx(hwnd(0), 0, "Button", "=")

    Dim Ret As Long
    Ret = SendMessage(hwnd(1), BM_CLICK, 0, 0)
    Ret = SendMessage(hwnd(2), BM_CLICK, 0, 0)
    Ret = SendMessage(hwnd(1), BM_CLICK, 0, 0)
    Ret = SendMessage(hwnd(3), BM_CLICK, 0, 0)
End Sub
これで電卓のディスプレイには81と表示されているはずです。


今度は、この81と表示されている文字列を受け取ってみます。
使うメッセージはWM_GETTEXT/WM_GETTEXTLENGTH
Option Explicit

Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
    (ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
     ByVal lpszClass As String, ByVal lpszWindow As String) As Long

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal MSG As Long, _
     ByVal wParam As Long, ByVal lParam As Long) As Long

Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal MSG As Long, _
     ByVal wParam As Long, ByVal lParam As String) As Long

Const BM_CLICK = &HF5
Const WM_GETTEXT = &HD
Const WM_GETTEXTLENGTH = &HE

Sub SampleCode()
    Dim hWnd(3) As Long
    hWnd(0) = FindWindow("SciCalc", "電卓")
    hWnd(1) = FindWindowEx(hWnd(0), 0, "Button", "9")
    hWnd(2) = FindWindowEx(hWnd(0), 0, "Button", "*")
    hWnd(3) = FindWindowEx(hWnd(0), 0, "Button", "=")

    Dim Ret As Long
    Ret = SendMessage(hWnd(1), BM_CLICK, 0, 0)
    Ret = SendMessage(hWnd(2), BM_CLICK, 0, 0)
    Ret = SendMessage(hWnd(1), BM_CLICK, 0, 0)
    Ret = SendMessage(hWnd(3), BM_CLICK, 0, 0)
    
    
    Dim hwnd2 As Long '表示部のハンドル取得
    hwnd2 = FindWindowEx(hWnd(0), 0, "Edit", "")
    
    Dim length As Long '表示部の文字列のバイト数を調べる
    length = SendMessage(hwnd2, WM_GETTEXTLENGTH, 0, 0)
    
    Dim DisplayStr As String
    DisplayStr = String(length, vbNullChar)
    Ret = SendMessageStr(hwnd2, WM_GETTEXT, length + 1, DisplayStr)
    
    Debug.Print Left(DisplayStr, Len(DisplayStr) - 1)
End Sub
WM_GETTEXT/WM_GETTEXTLENGTHを追加しました。
ただ、WM_GETTEXTの第四引数は文字列を受取るので
SendMessageの引数と一致していません。
そこで、SendMessageStrという関数名の物を別に作り第四引数をStringにしています。
SendMessageじゃなくてSendMessageStrって何??
と、思ったかたは、「WindowsAPIについて」の■関数についてを参照してください。



最後に電卓を閉じてしまいます。

Option Explicit

Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
        (ByVal hwnd As Long, ByVal msg As Long, _
         ByVal wParam As Long, ByVal lParam As Long) As Long

Const WM_CLOSE = &H10

Sub SampleCode()
    Dim hwnd As Long, Ret As Long
    '操作したいウィンドウのハンドルを調べる
    hwnd = FindWindow("SciCalc", "電卓") 
    
    '調べたハンドルに対し閉じるメッセージを送る
    Ret = SendMessage(hwnd, WM_CLOSE, 0, 0) 
End Sub


メッセージは数多くあるのでここでは紹介しきれないので
後は、探してみてためしてみてください。

0 件のコメント: