{"id":4863,"date":"2013-03-25T07:00:00","date_gmt":"2013-03-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/03\/25\/using-accessibility-to-monitor-windows-as-they-come-and-go\/"},"modified":"2013-03-25T07:00:00","modified_gmt":"2013-03-25T07:00:00","slug":"using-accessibility-to-monitor-windows-as-they-come-and-go","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130325-00\/?p=4863","title":{"rendered":"Using accessibility to monitor windows as they come and go"},"content":{"rendered":"<p>Today&#8217;s Little Program monitors windows as they come and go.\nWhen people contemplate doing this,\nthey come up with ideas like installing a\n<CODE>WH_CBT<\/CODE> hook\nor a\n<CODE>WH_SHELL<\/CODE> hook,\nbut one of the major problems with those types of hooks\nis that they are injected hooks.\nInjection is bad for a number of reasons.\n<\/P>\n<UL>\n<LI>It forces the hook to be in a DLL so it can be injected.\n<LI>Hook activities need to be marshaled back to the main program.\n<LI>Your DLL will capture events only in processes of the same bitness,\n    because\n    <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/10\/20\/9006720.aspx\">\n    you cannot load a 32-bit DLL into a 64-bit process or vice versa<\/A>.\n<LI>You can inject into an elevated process only if your process\n    is also elevated.\n    If your process is non-elevated, then you will not capture\n    events for windows belonging to elevated processes.\n<\/UL>\n<P>\nThis is where accessibility comes in handy,\nbecause accessibility lets you specify whether you want your\nhook to be an injected or non-injected one.\nAnd if you&#8217;re non-injected, then the programming model is much simpler\nbecause everything happens in your process\n(indeed, on a single thread).\n<\/P>\n<P>\nTake\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nthe scratch program<\/A>\nand make the following changes:\n<\/P>\n<PRE>\n#include &lt;strsafe.h&gt;<\/p>\n<p>BOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n <FONT COLOR=\"blue\">g_hwndChild = CreateWindow(TEXT(&#8220;listbox&#8221;), NULL,\n     LBS_HASSTRINGS | WS_CHILD | WS_VISIBLE | WS_VSCROLL,\n     0, 0, 0, 0, hwnd, NULL, g_hinst, 0);\n if (!g_hwndChild) return FALSE;<\/FONT>\n return TRUE;\n}<\/p>\n<p><FONT COLOR=\"blue\">void CALLBACK WinEventProc(\n    HWINEVENTHOOK hWinEventHook,\n    DWORD event,\n    HWND hwnd,\n    LONG idObject,\n    LONG idChild,\n    DWORD dwEventThread,\n    DWORD dwmsEventTime\n)\n{\n if (hwnd &amp;&amp;\n     idObject == OBJID_WINDOW &amp;&amp;\n     idChild == CHILDID_SELF)\n {\n  PCTSTR pszAction = NULL;\n  TCHAR szBuf[80];\n  switch (event) {\n  case EVENT_OBJECT_CREATE:\n   pszAction = TEXT(&#8220;created&#8221;);\n   break;\n  case EVENT_OBJECT_DESTROY:\n   pszAction = TEXT(&#8220;destroyed&#8221;);\n   break;\n  }\n  if (pszAction) {\n   TCHAR szClass[80];\n   TCHAR szName[80];\n   szClass[0] = TEXT(&#8216;\\0&#8217;);\n   szName[0] = TEXT(&#8216;\\0&#8217;);\n   if (IsWindow(hwnd)) {\n    GetClassName(hwnd, szClass, ARRAYSIZE(szClass));\n    GetWindowText(hwnd, szName, ARRAYSIZE(szName));\n   }\n   TCHAR szBuf[80];\n   StringCchPrintf(szBuf, ARRAYSIZE(szBuf),\n                   TEXT(&#8220;%p %s \\&#8221;%s\\&#8221; (%s)&#8221;), hwnd, pszAction,\n                   szName, szClass);\n   ListBox_AddString(g_hwndChild, szBuf);\n  }\n }\n}<\/FONT><\/p>\n<p>int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,\n                   LPSTR lpCmdLine, int nShowCmd)\n{\n &#8230;\n  ShowWindow(hwnd, nShowCmd);<\/p>\n<p> <FONT COLOR=\"blue\">HWINEVENTHOOK hWinEventHook = SetWinEventHook(\n     EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY,\n     NULL, WinEventProc, 0, 0,\n     WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);<\/FONT><\/p>\n<p>  while (GetMessage(&amp;msg, NULL, 0, 0)) {\n   TranslateMessage(&amp;msg);\n   DispatchMessage(&amp;msg);\n  }<\/p>\n<p>  <FONT COLOR=\"blue\">if (hWinEventHook) UnhookWinEvent(hWinEventHook);<\/FONT>\n&#8230;\n}\n<\/PRE>\n<P>\nThis is a generalization of our earlier program which\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/10\/26\/10230020.aspx\">\nwaits for a specific window to be destroyed<\/A>,\nexcept that we now are watching <I>all<\/I> windows\nfor creation and destruction.\n<\/P>\n<P>\nWhen you run this program, you see that there is a lot of\nwindow activity,\nbut maybe you are interested only in windows when they are shown\nand hidden.\nNo problem, that&#8217;s a small change:\n<\/P>\n<PRE>\n  switch (event) {\n  <FONT COLOR=\"blue\">case EVENT_OBJECT_SHOW:\n   pszAction = TEXT(&#8220;shown&#8221;);\n   break;\n  case EVENT_OBJECT_HIDE:\n   pszAction = TEXT(&#8220;hidden&#8221;);\n   break;<\/FONT>\n  }\n&#8230;<\/p>\n<p> HWINEVENTHOOK hWinEventHook = SetWinEventHook(\n     <FONT COLOR=\"blue\">EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE<\/FONT>,\n     NULL, WinEventProc, 0, 0,\n     WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);\n<\/PRE>\n<P>\nNotice that these notifications are received for windows\nfrom both 32-bit and 64-bit processes,\nand that they are received even for windows belonging\nto elevated processes.\nYou can&#8217;t do that with an injected hook.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s Little Program monitors windows as they come and go. When people contemplate doing this, they come up with ideas like installing a WH_CBT hook or a WH_SHELL hook, but one of the major problems with those types of hooks is that they are injected hooks. Injection is bad for a number of reasons. It [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-4863","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s Little Program monitors windows as they come and go. When people contemplate doing this, they come up with ideas like installing a WH_CBT hook or a WH_SHELL hook, but one of the major problems with those types of hooks is that they are injected hooks. Injection is bad for a number of reasons. It [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=4863"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4863\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=4863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}