Translate

2009年12月16日水曜日

ほんとにめものめものめものめものめも

ちょいとwin32APiに初めて手を出すにあたりいろいろめもってみる。
正直さっぱりわからんw

やりたいことは、他のあぷりを操作したいってことで
ウィンドウのハンドルを取得してメッセージを投げて
ほげほげするってあたり。
ひとまず、vb.netを使ってみるよ!


まずは、操作したいアプリのハンドルを取得するために...
FindWindow 関数
指定された文字列と一致するクラス名とウィンドウ名を持つトップレベルウィンドウ( 親を持たないウィンドウ)のハンドルを返します。この関数は、子ウィンドウは探しません。検索では、大文字小文字は区別されません。

子ウィンドウを探すには、FindWindowEx 関数を使ってください。FindWindowEx 関数による検索は、指定した子ウィンドウから開始されます。

HWND FindWindow(
LPCTSTR lpClassName, // クラス名
LPCTSTR lpWindowName // ウィンドウ名
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc364634.aspx

この子を使う為に行うAPIの宣言は...
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer

ソース→http://www.winapi-database.com/Window/Change/FindWindow.html


じゃぁ、クラス名は?というと下記ソフトらへんを使うとクラス名が判明するっと。
・Winspector Spy(参考記事
・WinIDWinID

とか使って目的のウィンドウやオブジェクトにカーソルをあてるとすぐにクラス名がわかりますね。
あとは、ウィンドウの名前を指定してあげればおkと。

ウィンドウのハンドルがわかると今度はそこに所属してるオブジェクトのハンドルを取得して
データを送り込んだり読み込んだり、ボタンを押したりする為にウィンドウに所属している
子供のハンドルを取得するために下記関数を使うと。
FindWindowEx 関数
指定された文字列と一致するクラス名とウィンドウ名文字列を持つウィンドウのハンドルを返します。この関数は、子ウィンドウを検索します。この関数による検索は、指定された子ウィンドウの直後の子ウィンドウから開始されます。大文字小文字は区別されません。

HWND FindWindowEx(
HWND hwndParent, // 親ウィンドウのハンドル
HWND hwndChildAfter, // 子ウィンドウのハンドル
LPCTSTR lpszClass, // クラス名
LPCTSTR lpszWindow // ウィンドウ名
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc410853.aspx


この子を使う為に行うAPIの宣言は...
Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Integer

ソース→http://www.winapi-database.com/Window/Change/FindWindowEx.html
第1引数は、Findwindowで取得したハンドル
第2引数は、同じクラス名のオブジェクトがあった場合に、最初に見つかった
子ハンドルを渡してあげると次の同じ名前の子ハンドルをしることができると。
第3引数は、知りたいオブジェクトのクラス名を指定。
上に書いたソフトを使えばわかると。
第4引数は、ウィンドウ名だったり(vbのフォームに配置するオブジェクトのプロパティでいうとこの)キャプション名。

で、しれると。
あとは、SendMessageだったり、SendMesageStrとかだったり
非同期送信したければPostMessageをつかったりすると。
例としてSendMessage。

SendMessage 関数
1 つまたは複数のウィンドウへ、指定されたメッセージを送信します。この関数は、指定されたウィンドウのウィンドウプロシージャを呼び出し、そのウィンドウプロシージャがメッセージを処理し終わった後で、制御を返します。

メッセージを送信して即座に制御を返すには、SendMessageCallback または SendNotifyMessage 関数を使ってください。メッセージを 1 つのスレッドのメッセージキューにポストして即座に制御を返すには、PostMessage または PostThreadMessage 関数を使ってください。

LRESULT SendMessage(
HWND hWnd, // 送信先ウィンドウのハンドル
UINT Msg, // メッセージ
WPARAM wParam, // メッセージの最初のパラメータ
LPARAM lParam // メッセージの 2 番目のパラメータ
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc411022.aspx

第1引数は、FindWindowExで知った実際に操作したいウィンドウハンドルを指定
第2引数は、メッセージ。
ウィンドウメッセージとかで検索するとわさわさでてきたりする。
C系では、メッセージが定数として指定されているけどVB.net等では指定されてないので
自分で値を設定してから使うもんらしーよ。
例えば
Public Const WM_SETTEXT = &HC
Public Const WM_GETTEXT = &HD
Public Const WM_IME_CHAR = &H286
Public Const LB_GETTEXT = &H189
Public Const WM_GETTEXTLENGTH = &HE
Public Const LB_GETCOUNT = &H18B
Public Const BM_CLICK = &HF5
って感じにね。
メッセージは種類がやまほどあるんで、そのつど調べて設定して使うと。

第3引数と第4引数は、メッセージによって要求される引数が違うので必要に応じてわたしてあげると。


APIの宣言は、
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

ソース→http://www.winapi-database.com/Program/Message/SendMessage.html


ちなみに、SendMessageは、引数に数値をとるために文字列を使う場合はSendMessageStrを使うとよいらしー。
Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As System.Text.StringBuilder) As Integer



VB.netではlParamの引数にStringじゃなくてStringBUilderを使うらしい。

これをもとに大量加筆しました→自作あぷりからAPIで他のあぷりをいじるときのめも。