• ベストアンサー

他のアプリケーションの操作について

こんにちは。 現在、WindowsXP、Visual Studio2005(以下VS)にて既存のアプリケーションの操作を行うツールを作成しようとしています。 Findwindow関数で親のハンドルをとり、EnumChildWindow関数でコントロールのハンドルを取得しましたが、操作したいボタンの情報が取れません。 参考にさせていただいたコードは以下です。 http://blog.goo.ne.jp/masaki_goo_2006/e/cea1b601e33fb7a344ecba2ee972efe4 VS付属spy++の調査も同様の結果で、そのボタンの情報が出てきませんでした。 コントロールの情報がとれないという事はあるのでしょうか? ちなみにボタンはtoolbarの上にありtoolbarの情報は取れています。 情報が取れない場合、操作は出来ないということでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

 こんにちは。ツールボタンのどの情報を取りたいのでしょうか。  SendMessage() TB_???のメッセージで情報を受け取る際、構造体等のポインタを必要とするものが多数ありますが、他プロセスのウィンドウハンドルに向かって此方側のポインタを渡してみた所で、向こう側からしてみれば「寝耳に水」も良い所です。  プロセス間共有メモリを仲介して、データをやり取りする事になります。どちらにしろ、そんな簡単な事ではありません。  以下ではVirtualAllocEx()を使用していますが、windows xpで上手くいくかはわかりません(windows 2000sp4の上では上手くいっています)。  参考資料程度に。 #include<tchar.h> #include<windows.h> #include<commctrl.h> #include<stdio.h> typedef struct ProcessMemory { DWORD dwProcessID; DWORD dwThreadID; HANDLE hProcess; union { LPVOID pVoid; LPBYTE pByte; LPARAM lParam; }; } PROCESSMEMORY, *LPPROCESSMEMORY; static BOOL OpenProcessMemory(LPPROCESSMEMORY p, HWND hWndOutProcess, DWORD dwSize) { p->dwThreadID = ::GetWindowThreadProcessId(hWndOutProcess, &p->dwProcessID); if(!p->dwThreadID || !p->dwProcessID) return FALSE; p->hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, p->dwProcessID); if(!p->hProcess) return FALSE; p->pVoid = ::VirtualAllocEx(p->hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); return p->pVoid != NULL; } static BOOL CloseProcessMemory(LPPROCESSMEMORY p) { if(!p->hProcess) return FALSE; ::VirtualFreeEx(p->hProcess, p->pVoid, 0, MEM_RELEASE); ::CloseHandle(p->hProcess); ::ZeroMemory(p, sizeof(PROCESSMEMORY)); return TRUE; } static DWORD WriteProcessMemory(LPPROCESSMEMORY p, DWORD dwByteOfOffset, const void* pIn, DWORD dwSizeOfIn) { DWORD dwLen = 0; ::WriteProcessMemory(p->hProcess, &p->pByte[dwByteOfOffset], pIn, dwSizeOfIn, &dwLen); return dwLen; } static DWORD ReadProcessMemory(const LPPROCESSMEMORY p, DWORD dwByteOfOffset, void* pOut, DWORD dwSizeOfOut) { DWORD dwLen = 0; ::ReadProcessMemory(p->hProcess, &p->pByte[dwByteOfOffset], pOut, dwSizeOfOut, &dwLen); return dwLen; } int main() { //見つかっているものとする HWND hWndOutProcess = ::FindWindow(_T("Afx:400000:b:10011:6:7042d"), NULL); HWND hWndCtlBar = ::FindWindowEx(hWndOutProcess, NULL, _T("AfxControlBar42d"), NULL); HWND hWndToolBar = ::FindWindowEx(hWndCtlBar, NULL, TOOLBARCLASSNAME, NULL); //他プロセスのメインウィンドウ PROCESSMEMORY pm = {0}; ::OpenProcessMemory(&pm, hWndOutProcess, sizeof(TBBUTTON)); //他プロセスのツールバーの数を取る const int count = ::SendMessage(hWndToolBar, TB_BUTTONCOUNT, 0, 0); for(int i = 0; i < count; ++i) { //受け皿 TBBUTTON tbb = {0}; //プロセス間共有メモリをゼロで初期化 ::WriteProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON)); //他プロセスのツールボタンメッセージ→プロセス間共有メモリ ::SendMessage(hWndToolBar, TB_GETBUTTON, i, pm.lParam); //プロセス間共有メモリ→受け皿 ::ReadProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON)); //取りあえず表示 ::printf("[ボタン番号 : %d][ボタン状態 : %d][ボタンスタイル : %d][ボタンID : %d][ビットマップ番号 : %d]\n", i, tbb.fsState, tbb.fsStyle, tbb.idCommand, tbb.iBitmap); } ::CloseProcessMemory(&pm); return 0; }

itouke77
質問者

お礼

具体的な例ありがとうございます。 とても参考になります。 >ツールボタンのどの情報を取りたいのでしょうか。 やりたいことはそれぞれのボタンを押すことです。 その為のツールバー上のボタンのハンドル?をどのようにとればよいかわかりませんでした。 なかなか難しい内容で時間がかかるかもしれませんが いただいた情報を頼りになんとか確認してみたいと思います。

すると、全ての回答が全文表示されます。

その他の回答 (3)

回答No.4

 こんにちは。御礼頂きました。  すっかり見落としていました。プログラムからツールボタンを操作するのが目的でした。  此れに関して回答すると、WM_COMMANDをツールバーの親ウィンドウに送るか、WM_LBUTTONDOWN/WM_LBUTTONUPにツールボタンの座標を指定してクリックされた事にすれば出来ます。 //メモリの割り当て PROCESSMEMORY pm = {0}; ::OpenProcessMemory(&pm, hWndOutProcess, sizeof(TBBUTTON)); //受け皿 TBBUTTON tbb = {0}; //必要があれば此処でhWndOutProcessを最前面に持ってくる //プロセス間共有メモリをゼロで初期化 ::WriteProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON)); //2番目のツールボタンの情報を取る ::SendMessage(hWndToolBar, TB_GETBUTTON, 1, pm.lParam); //プロセス間共有メモリ→受け皿 ::ReadProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON)); //ツールバーの親ウィンドウにWM_COMMANDを送る ::SendMessage(hWndCtlBar/*ツールバーの親ウィンドウを指定*/, WM_COMMAND, tbb.idCommand, (LPARAM)hWndToolBar); //メモリを閉じる ::CloseProcessMemory(&pm);  又は、 //メモリの割り当て PROCESSMEMORY pm = {0}; ::OpenProcessMemory(&pm, hWndOutProcess, sizeof(RECT)); //受け皿 RECT rc = {0}; //必要があれば此処でhWndOutProcessを最前面に持ってくる //プロセス間共有メモリをゼロで初期化 ::WriteProcessMemory(&pm, 0, &rc, sizeof(RECT)); //2番目のツールボタンの矩形領域を取る ::SendMessage(hWndToolBar, TB_GETITEMRECT, 1, pm.lParam); //プロセス間共有メモリ→受け皿 ::ReadProcessMemory(&pm, 0, &rc, sizeof(RECT)); //ツールバーのボタン上でマウスの左ボタンが押された事にする ::SendMessage(hWndToolBar, WM_LBUTTONDOWN, 0, MAKELONG(rc.left + 2, rc.top + 2)); //ツールバーのボタン上でマウスの左ボタンが離された事にする ::SendMessage(hWndToolBar, WM_LBUTTONUP, 0, MAKELONG(rc.left + 2, rc.top + 2)); //メモリを閉じる ::CloseProcessMemory(&pm);  と言った具合です(当方のPC上では両方とも動きます)。

itouke77
質問者

お礼

動作確認のため返信遅れました。 申し訳ありません。 ほぼいただいたコード通りで無事に押すことが出来ました。 ありがとうございます。とても助かりました。    ただ、ボタンが8個しかないのに、"TB_BUTTONCOUNT"で取得した数は19を示しています。 (この数の違いは何を示しているのかは後ほど知らべたいと思います。) 押せるボタンは8個ですのでどの番号がどのボタンを示しているのか、総当りで探した次第です。 しかし調べてみたところTB_ISBUTTONCHECKEDなどの他のメッセージを使えばこの辺の特定がうまく出来そうなので組み込んでみたいと思います。

すると、全ての回答が全文表示されます。
  • titokani
  • ベストアンサー率19% (341/1726)
回答No.2
itouke77
質問者

お礼

ありがとうございます。 調べてみます。

すると、全ての回答が全文表示されます。
  • titokani
  • ベストアンサー率19% (341/1726)
回答No.1

ツールバーのボタンはボタンのようでボタンではありません。あくまでツールバーの一部です。 なので、情報を取得するには、ツールバーのメッセージを使うとよいでしょう。

itouke77
質問者

お礼

ありがとうございます。 ボタン(のようなもの)が10個くらいついているのですが どのボタンかを特定するのはどうすればいいのでしょうか? 一つは位置情報かなと考えているのですが。

すると、全ての回答が全文表示されます。