{"id":30,"date":"2009-07-14T01:31:44","date_gmt":"2009-07-14T01:31:44","guid":{"rendered":"http:\/\/www.northatlantawebdesign.com\/?p=30"},"modified":"2009-07-27T10:10:05","modified_gmt":"2009-07-27T14:10:05","slug":"getting-the-com-object-from-hwnd-using-accessibleobjectfromwindow-in-microsoft-word-2007","status":"publish","type":"post","link":"https:\/\/www.northatlantawebdesign.com\/index.php\/2009\/07\/14\/getting-the-com-object-from-hwnd-using-accessibleobjectfromwindow-in-microsoft-word-2007\/","title":{"rendered":"Getting the COM object from HWND using AccessibleObjectFromWindow in Microsoft Word 2007"},"content":{"rendered":"<p>After spending some time on this over the past few days, and sorting through the spotty documentation provided by Microsoft on Accessibility, I was able to get a handle on the <a type=\"amzn\">COM<\/a> object in <a type=\"amzn\">Microsoft Word 2007<\/a>.\u00a0 It turns out to be pretty simple, and is actually in the documentation <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd317978(VS.85).aspx\">they provide here<\/a>, but they don&#8217;t make it clear as day.\u00a0 I intend to do that here.<\/p>\n<p><!--more--><\/p>\n<p>First we obtain the hwnd of the Microsoft Word Process:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/The main window in Microsoft Word has a class name of OpusApp\r\nHWND wordWindow = FindWindow(L&quot;OpusApp&quot;, NULL);\r\n<\/pre>\n<p>We can then traverse the child windows until we find the one with classname _WwG:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/Use the EnumChildWindows function to iterate through all child windows until we find _WwG\r\nEnumChildWindows(wordWindow, (WNDENUMPROC) EnumChildProc, (LPARAM)1);\r\n<\/pre>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstatic BOOL EnumChildProc(HWND hwnd, LPARAM)\r\n{\r\n     WCHAR szClassName&#x5B;64];\r\n     if(GetClassNameW(hwnd, szClassName, 64))\r\n     {\r\n          if(_wcsicmp(szClassName, L&quot;_WwG&quot;) == 0)\r\n          {\r\n               \/\/Get AccessibleObject\r\n               Word::Window* pWindow = NULL;\r\n               HRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, __uuidof(Word::Window), (void**)&amp;pWindow);\r\n               if(hr == S_OK)\r\n               {\r\n                    \/\/Word object is now in pWindow pointer, from this you can obtain the document or application\r\n                    Word::_Document* pDoc = NULL;\r\n                    pWindow-&gt;get_Document(&amp;pDoc);\r\n               }\r\n               return false;     \/\/ Stops enumerating through children\r\n          }\r\n     }\r\n\t return true;\r\n}\r\n<\/pre>\n<p>Next we obtain our Word::Window object through AccessibleObjectFromWindow:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nWord::Window* pWindow = NULL;\r\nHRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, __uuidof(Word::Window), (void**)&amp;pWindow);\r\n<\/pre>\n<p>That&#8217;s it!\u00a0 We now have our Word::Window COM Object.\u00a0 From this object we can obtain the Word::Application and Word::Document objects, allowing us full interaction with the active document.\u00a0 So with just a few lines of code, we now have access to automate a word 2007 document.<\/p>\n<p>Full source code:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;windows.h&gt;\r\n#include &lt;oleacc.h&gt;\r\n#include &quot;msword.h&quot;\r\n\r\nstatic BOOL EnumChildProc(HWND hwnd, LPARAM)\r\n{\r\n\tWCHAR szClassName&#x5B;64];\r\n\tif(GetClassNameW(hwnd, szClassName, 64))\r\n\t{\r\n\t\tif(_wcsicmp(szClassName, L&quot;_WwG&quot;) == 0)\r\n\t\t{\r\n\t\t\t\/\/Get AccessibleObject\r\n\t\t\tWord::Window* pWindow = NULL;\r\n\t\t\tHRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, __uuidof(Word::Window), (void**)&amp;pWindow);\r\n\t\t\tif(hr == S_OK)\r\n\t\t\t{\r\n\t\t\t\t\/\/Word object is now in pWindow pointer, from this you can obtain the document or application\r\n\t\t\t\tWord::_Document* pDoc = NULL;\r\n\t\t\t\tpWindow-&gt;get_Document(&amp;pDoc);\r\n\t\t\t}\r\n\t\t\treturn false;     \/\/ Stops enumerating through children\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\nint main( int argc, CHAR* argv&#x5B;])\r\n{\r\n\t\/\/The main window in Microsoft Word has a class name of OpusApp\r\n\tHWND wordWindow = FindWindow(L&quot;OpusApp&quot;, NULL);\r\n\r\n\t\/\/Use the EnumChildWindows function to iterate through all child windows until we find _WwG\r\n\tEnumChildWindows(wordWindow, (WNDENUMPROC) EnumChildProc, (LPARAM)1);\r\n\r\n\treturn 0;\r\n}\r\n<\/pre>\n<p>The logic to find the correct window can be changed for multiple instances of Word.\u00a0 Also, you must have the Word type library imported to use the Word COM API.\u00a0 We&#8217;ll leave those two for another topic on another date.  Check back later in the week for a follow up post on how to access Microsoft Excel 2007 in the same manner.<\/p>\n<p>Useful Links for this post:<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd317978%28VS.85%29.aspx\">AccessibleObjectFromWindow Documentation<\/a><\/li>\n<li><a title=\"Using Visual C++ to Automate Office\" href=\"http:\/\/support.microsoft.com\/kb\/238972\">Using Visual C++ to Automate Office<\/a><\/li>\n<li><a title=\"EnumChildWindows Documentation\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms633494%28VS.85%29.aspx\">EnumChildWindows Documentation<\/a><\/li>\n<\/ul>\n<p>Key phrases: Accessing Word 2007 COM object using AccessibleObjectFromWindow, Automating Word 2007 with Microsoft Active Accessibility MSAA<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After spending some time on this over the past few days, and sorting through the spotty documentation provided by Microsoft on Accessibility, I was able to get a handle on the COM object in Microsoft Word 2007.\u00a0 It turns out to be pretty simple, and is actually in the documentation they provide here, but they [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7,10],"tags":[22,21,15,71,72],"class_list":["post-30","post","type-post","status-publish","format-standard","hentry","category-accessibility","category-microsoft-office-2007","category-microsoft-word-2007","tag-accessibleobjectfromwindow","tag-com","tag-microsoft-active-accessibility","tag-microsoft-office-2007","tag-microsoft-word-2007"],"_links":{"self":[{"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/posts\/30","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/comments?post=30"}],"version-history":[{"count":34,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/posts\/30\/revisions"}],"predecessor-version":[{"id":134,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/posts\/30\/revisions\/134"}],"wp:attachment":[{"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/media?parent=30"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/categories?post=30"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.northatlantawebdesign.com\/index.php\/wp-json\/wp\/v2\/tags?post=30"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}