Sometimes you need from one program to get to the contents of another program. Well, for example, get some content out of it, or automate actions. In the case of classic Windows applications, this problem is solved very simply - we find the parent window through
FindWindow , then, knowing its HWND, we can list the child windows and controls on them. And then there is complete freedom - we can get the text written on these elements, change their size and position, send messages to emulate a mouse click or typing from the keyboard, even delete existing elements and create new ones.

But for Modern-applications everything is different. Let's take, for example, the Weather app from the standard Windows8 set. Suppose we opened it in the sidebar and want to somehow find out from our usual (Desktop) application, and what temperature it shows. If you look at the Weather window using Spy ++, you will see the parent window of the Windows.UI.Core.CoreWindow type and the Web Platform Embedding window attached to it. So we have a Modern-application written in HTML \ Js and living inside the embedded browser component. That is, the above-described manipulations with Windows controls do not make sense - they are simply not in this window, since all of its contents are rendered entirely.
But let's try to get the current temperature out of it.
')
Let's start with the fact that on MSDN, in its style, there are two articles with the opposite content - one warns us not to clap hands in IE, embedded in other components, because it is not safe and you can break everything (
“This function is designed If you’re referring to this function, you’ll not be able to call this function (blah blah bla ... blah bla bla bla ... And the second one says that everything is OK, it is possible, and even gives the code how to do it. The first is not of interest to us, and the second is
KB 249232 .
True, there is an error in it - in the function call
ObjectFromLresult
they are trying to take the wrong interface and in the end nothing works. But this is generally MSDN style, you have to get used to it.
So, what is the essence of our venture?
- Find the top-level window with the specified header and class ("Weather" and "Windows.UI.Core.CoreWindow", respectively).
- We list its “children”, we find the window of the class “Internet Explorer_Server”.
- We send a WM_HTML_GETOBJECT message to this window, we get a pointer in response, which can be converted to a pointer to the IHTMLDocument2 interface using the ObjectFromLresult function.
- Having IHTMLDocument2 we can already do anything with the document - get its content, change, simulate a “click”, execute Javascript.
I was almost sure that somewhere in the 3-4 points area, the Windows security mechanism that separates Modern-applications from each other and from the desktop will be on the way, and I was ready to use some of the tools I described in the
previous article . But ... It was not needed. Despite the fact that the Weather app seems to work in a sandbox, it seems to be with Low Integrity - we can safely send messages to it, get a pointer to IHTMLDocument2, exchange data with it. No security barriers had to be overcome - they simply did not exist.
Total:

Main code #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; }
All project on Github