まとめ
- UI Automationでボタンのクリックまで出来る
- 最初のハンドラを取得するところもUI Automationで出来る
前提・実現したいこと
VC++でUI Automationを使いボタンコントロールをクリックする処理を行いたい。
自作のアプリケーションから他のアプリケーションを操作する処理を実現するために
まずWindows7に標準で搭載されている電卓アプリを操作しようとしています。
以前の質問でボタンのテキストが空になっていることが判明し、そのボタンを判別する手段としてUI Autmationを教えていただきました。
なんとかボタンの特定までは行き着けそうなのですが、特定したボタンをクリックする事が出来ずにいます。
今のところは
UI Automationで目的のNameを持つWindowを探す ↓ 見つかればHWNDを取得する ↓ SendMessageでBM_CLICKを送出することでボタンを押す ```という流れで実現できるかなと思いながらコードを作っています。 よろしくお願いいたします。 ### 該当のソースコード 2018 0126 動いた 過去のソースは編集履歴を参照してください ```c++ void CUIAutoDlg::UseUIAutomation() { // COM初期化 if( CoInitialize(NULL) != S_OK){ MessageBox(_T("CoInitialize stuck!")); return; } // IUIAutmation初期化 IUIAutomation *autoMaster; if (HRESULT h = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&autoMaster)) != S_OK) { MessageBox(_T("CoCreateInstance stuck!")); return; } // TreeWalker初期化 IUIAutomationTreeWalker *treeWalker; autoMaster->get_ContentViewWalker(&treeWalker); // 電卓のIUIAutomationElement取得 IUIAutomationElement *autElm = NULL; HWND h = ::FindWindow(_T("CalcFrame"), _T("電卓")); if(autoMaster->ElementFromHandle(h, &autElm)){ MessageBox(_T("ElementFromHandle stuck!")); return; } autElm->SetFocus(); // 1のボタンを探してくる IUIAutomationElement *clickElement = NULL; if (GetUIAutomationElementFromChildrenByName(autoMaster, treeWalker, autElm, L"1", clickElement) != S_OK) { MessageBox(_T("control not found!")); return; } // 押す IUnknown *btn; clickElement->GetCurrentPattern(UIA_InvokePatternId, &btn); ((IUIAutomationInvokePattern *)btn)->Invoke(); btn->Release(); autElm->Release(); treeWalker->Release(); autoMaster->Release(); CoUninitialize();} BOOL CUIAutoDlg::GetUIAutomationElementFromChildrenByName(IUIAutomation *autoMaster, IUIAutomationTreeWalker *treeWalker, IUIAutomationElement *uiaElement, const BSTR windowName, IUIAutomationElement *& distElement) { IUIAutomationElement *childElm = NULL; // 子コントロールからさがす if (treeWalker->GetFirstChildElement(uiaElement, &childElm) != S_OK) { return S_FALSE; // 子がない } IUIAutomationElement *nextChildElm = NULL; UIA_HWND hwnd = NULL; while (childElm) { BSTR tempWindowName; childElm->get_CurrentName(&tempWindowName); if (_tcscmp( tempWindowName, windowName) == 0) { // Nameが一致するコントロールを見つけた SysFreeString(tempWindowName); // 用済み distElement = childElm; return S_OK; //hwnd; // UIA_HWNDはHWNDじゃない! } SysFreeString(tempWindowName); // 用済み // 孫以下のウィドウは再起で処理 if (GetUIAutomationElementFromChildrenByName(autoMaster, treeWalker, childElm, windowName, distElement) == S_OK) return S_OK; treeWalker->GetNextSiblingElement(childElm, &nextChildElm); childElm->Release(); // 用済み childElm = nextChildElm; } return S_FALSE; // nameの該当するコントロールが無い }
一応、GetHWNDByName
の戻り値をNULLにして一旦動かしてみてはいます。
試したこと
UIA_HWND
からHWND
への変換方法を探してみましたが見つけられませんでした。
HWND
を取得する方法を探してみましたが見つけられませんでした・・・。
IUIAutmationElement
クラスがメッセージ投げてくれるのではなどと思って調べてみましたがそれっぽい関数が見つけられませんでした
補足情報(FW/ツールのバージョンなど)
- Windows7/64bit SP1
- VisualStudio2015SP
- VC++/MFC
- UI Automation
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/26 05:54