Но для Modern-приложений всё иначе. Давайте возьмём, к примеру, приложение «Погода» из стандартного набора Windows8. Допустим, мы открыли его в боковой панели и хотим как-то узнать из нашего обычного (Desktop) приложения, а какую же оно показывает температуру. Если посмотреть на окно «Погоды» с помощью Spy++ мы увидим родительское окно типа Windows.UI.Core.CoreWindow и вложенное в него окно Web Platform Embedding. А значит перед нами Modern-приложение написанное на HTML\Js и живущее внутри встроенного компонента браузера. То есть вышеописанные манипуляции с Windows-контролами не имеют смысла — их в этом окне попросту нет, поскольку всё его содержимое рендерится целиком.
Но давайте же всё-таки попробуем вытащить из него текущую температуру.
Начнём с того, что на MSDN, в его стиле, есть две статьи с противоположным содержанием — одна предостерегает нас от того, чтобы лазить руками в IE, встроенный в чужие компоненты, потому что это небезопасно и можно всё сломать («This function is designed for internal use by Active Accessibility and is documented for informational purposes only. Neither clients nor servers should call this function. Бла-бла-бла…»). А вторая говорит, что всё ок, можно, и даже даёт код, как это сделать. Первая нам не интереса, а вторая — KB 249232.
Правда, в ней есть ошибка — в вызове функции ObjectFromLresult
они пытаются взять неверный интерфейс и в итоге ничего не работает. Но это вообще стиль MSDN, надо привыкать.
Итак, в чём же суть нашей затеи?
- Находим окно верхнего уровня с заданным заголовком и классом («Weather» и «Windows.UI.Core.CoreWindow», соответственно).
- Перечисляем его «детей», находим окно класса «Internet Explorer_Server».
- Отправляем этому окну сообщение WM_HTML_GETOBJECT, получаем в ответ указатель, который с помощь функции
ObjectFromLresult
может быть преобразован к указателю на интерфейс IHTMLDocument2. - Имея IHTMLDocument2 мы уже можем делать с документом всё, что угодно — получить его контент, изменить, сэмулировать «клик», выполнить Javascript.
Я практически был уверен, что где-то в районе пунктов 3-4 на пути встанет механизм безопасности Windows, отделяющий Modern-приложения друг от друга и от десктопных, и уже был готов применять что-то из средств, описанных мною в прошлой статье. Но… Этого не понадобилось. Несмотря на то, что приложение «Погода» работает вроде бы в песочнице, вроде бы с Low Integrity — мы спокойно можем отправлять ему сообщения, получать указатель на IHTMLDocument2, обмениваться с ним данными. Никаких барьеров безопасности преодолевать не пришлось — их просто нет.
Итог:
#include "stdafx.h" #include <iostream> #include <sstream> #include <mshtml.h> #include <atlbase.h> #include <oleacc.h> #include "conio.h" using namespace std; BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam) { TCHAR buf[100]; ::GetClassName( hwnd, (LPTSTR)&buf, 100 ); if ( _tcscmp( buf, _T("Internet Explorer_Server") ) == 0 ) { *(HWND*)lParam = hwnd; return FALSE; } else return TRUE; }; void GetDocInterface(HWND hWnd) { CoInitialize( NULL ); // Explicitly load MSAA so we know if it's installed HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") ); if ( hInst != NULL ) { if ( hWnd != NULL ) { HWND hWndChild=NULL; // Get 1st document window ::EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild ); if ( hWndChild ) { CComPtr<IHTMLDocument2> spDoc; LRESULT lRes; UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") ); ::SendMessageTimeout( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes ); LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, "ObjectFromLresult" ); if ( pfObjectFromLresult != NULL ) { HRESULT hr; hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument2, 0, (void**)&spDoc ); if ( SUCCEEDED(hr) ) { BSTR bstrContent = NULL; IHTMLElement *p = 0; spDoc->get_body(&p); if (p) { p->get_innerHTML( &bstrContent ); std::wstring ws(bstrContent, SysStringLen(bstrContent)); std::string s(ws.begin(), ws.end()); cout << s; p->Release(); } } } } // else document not ready } // else Internet Explorer is not running ::FreeLibrary( hInst ); } // else Active Accessibility is not installed CoUninitialize(); } int _tmain(int argc, _TCHAR* argv[]) { wstring windowTitle, windowClass; wcout << "Please enter parent window title (you can find it by Spy++):" << endl; std::getline(std::wcin, windowTitle); wcout << "Please enter parent window class (you can find it by Spy++):" << endl; std::getline(std::wcin, windowClass); HWND hwnd = FindWindow(windowClass.c_str(), windowTitle.c_str()); wcout << "HWND is " << hwnd << endl; GetDocInterface(hwnd); _getch(); return 0; }
ссылка на оригинал статьи http://habrahabr.ru/post/206656/
Добавить комментарий