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
  1. Option Explicit  
  2.   
  3. Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _  
  4.     (ByVal lpClassName As StringByVal lpWindowName As StringAs Long  
  5.   
  6. Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _  
  7.     (ByVal hwndParent As LongByVal hwndChildAfter As Long, _  
  8.      ByVal lpszClass As StringByVal lpszWindow As StringAs Long  
  9.   
  10. Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _  
  11.     (ByVal hwnd As LongByVal msg As Long, _  
  12.      ByVal wParam As LongByVal lParam As LongAs Long  
  13.   
  14. Const BM_CLICK = &HF5  
  15.   
  16. Sub SampleCode()  
  17.     Dim hwnd(3) As Long  
  18.     hwnd(0) = FindWindow("SciCalc""電卓")  
  19.     hwnd(1) = FindWindowEx(hwnd(0), 0, "Button""9")  
  20.     hwnd(2) = FindWindowEx(hwnd(0), 0, "Button""*")  
  21.     hwnd(3) = FindWindowEx(hwnd(0), 0, "Button""=")  
  22.   
  23.     Dim Ret As Long  
  24.     Ret = SendMessage(hwnd(1), BM_CLICK, 0, 0)  
  25.     Ret = SendMessage(hwnd(2), BM_CLICK, 0, 0)  
  26.     Ret = SendMessage(hwnd(1), BM_CLICK, 0, 0)  
  27.     Ret = SendMessage(hwnd(3), BM_CLICK, 0, 0)  
  28. End Sub  
これで電卓のディスプレイには81と表示されているはずです。


今度は、この81と表示されている文字列を受け取ってみます。
使うメッセージはWM_GETTEXT/WM_GETTEXTLENGTH
  1. Option Explicit  
  2.   
  3. Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _  
  4.     (ByVal lpClassName As StringByVal lpWindowName As StringAs Long  
  5.   
  6. Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _  
  7.     (ByVal hwndParent As LongByVal hwndChildAfter As Long, _  
  8.      ByVal lpszClass As StringByVal lpszWindow As StringAs Long  
  9.   
  10. Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _  
  11.     (ByVal hWnd As LongByVal MSG As Long, _  
  12.      ByVal wParam As LongByVal lParam As LongAs Long  
  13.   
  14. Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" _  
  15.     (ByVal hWnd As LongByVal MSG As Long, _  
  16.      ByVal wParam As LongByVal lParam As StringAs Long  
  17.   
  18. Const BM_CLICK = &HF5  
  19. Const WM_GETTEXT = &HD  
  20. Const WM_GETTEXTLENGTH = &HE  
  21.   
  22. Sub SampleCode()  
  23.     Dim hWnd(3) As Long  
  24.     hWnd(0) = FindWindow("SciCalc""電卓")  
  25.     hWnd(1) = FindWindowEx(hWnd(0), 0, "Button""9")  
  26.     hWnd(2) = FindWindowEx(hWnd(0), 0, "Button""*")  
  27.     hWnd(3) = FindWindowEx(hWnd(0), 0, "Button""=")  
  28.   
  29.     Dim Ret As Long  
  30.     Ret = SendMessage(hWnd(1), BM_CLICK, 0, 0)  
  31.     Ret = SendMessage(hWnd(2), BM_CLICK, 0, 0)  
  32.     Ret = SendMessage(hWnd(1), BM_CLICK, 0, 0)  
  33.     Ret = SendMessage(hWnd(3), BM_CLICK, 0, 0)  
  34.       
  35.       
  36.     Dim hwnd2 As Long '表示部のハンドル取得  
  37.     hwnd2 = FindWindowEx(hWnd(0), 0, "Edit""")  
  38.       
  39.     Dim length As Long '表示部の文字列のバイト数を調べる  
  40.     length = SendMessage(hwnd2, WM_GETTEXTLENGTH, 0, 0)  
  41.       
  42.     Dim DisplayStr As String  
  43.     DisplayStr = String(length, vbNullChar)  
  44.     Ret = SendMessageStr(hwnd2, WM_GETTEXT, length + 1, DisplayStr)  
  45.       
  46.     Debug.Print Left(DisplayStr, Len(DisplayStr) - 1)  
  47. End Sub  
WM_GETTEXT/WM_GETTEXTLENGTHを追加しました。
ただ、WM_GETTEXTの第四引数は文字列を受取るので
SendMessageの引数と一致していません。
そこで、SendMessageStrという関数名の物を別に作り第四引数をStringにしています。
SendMessageじゃなくてSendMessageStrって何??
と、思ったかたは、「WindowsAPIについて」の■関数についてを参照してください。



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

  1. Option Explicit  
  2.   
  3. Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _  
  4.   (ByVal lpClassName As StringByVal lpWindowName As StringAs Long  
  5.   
  6. Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _  
  7.         (ByVal hwnd As LongByVal msg As Long, _  
  8.          ByVal wParam As LongByVal lParam As LongAs Long  
  9.   
  10. Const WM_CLOSE = &H10  
  11.   
  12. Sub SampleCode()  
  13.     Dim hwnd As Long, Ret As Long  
  14.     '操作したいウィンドウのハンドルを調べる  
  15.     hwnd = FindWindow("SciCalc""電卓")   
  16.       
  17.     '調べたハンドルに対し閉じるメッセージを送る  
  18.     Ret = SendMessage(hwnd, WM_CLOSE, 0, 0)   
  19. End Sub  


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

0 件のコメント: