{"id":191,"date":"2007-10-06T21:42:37","date_gmt":"2007-10-06T21:42:37","guid":{"rendered":"http:\/\/dalelane.co.uk\/blog\/?p=191"},"modified":"2007-10-06T21:57:58","modified_gmt":"2007-10-06T21:57:58","slug":"getting-the-currently-selected-text-from-pocket-internet-explorer","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=191","title":{"rendered":"Getting the currently selected text from Pocket Internet Explorer"},"content":{"rendered":"<p><img decoding=\"async\" hspace=\"10\" vspace=\"5\" align=\"left\" src=\"post-images\/071006-google.gif\"\/>As part of my hack for <a href=\"http:\/\/www.mobilecamplondon.org\/\">mobileCampLondon<\/a>, I wanted to get the current selection from the web browser on my Windows Mobile phone. <\/p>\n<p>The plan was to add a new menu item to Pocket Internet Explorer that lets you search for the text you&#8217;ve selected in Google. So I needed to get the currently selected text in order to include it in a Google search page URL. I thought it&#8217;d be simple, but it turned out to be more of a hassle than I expected.<\/p>\n<p>My final approach is more of a hack than I&#8217;d have liked, so in this post, I&#8217;ll outline my unsuccessful approaches before showing what I finally ended up doing.<\/p>\n<p><!--more-->My handle to Pocket Internet Explorer (PIE) is represented by pWebBrowser &#8211; a <a target=\"_blank\" href=\"http:\/\/msdn2.microsoft.com\/EN-US\/library\/bb159694.aspx\">IWebBrowser2<\/a> object.<\/p>\n<p><strong>Attempt 1 &#8211; ExecWB<\/strong><\/p>\n<p>The most obvious approach was to use ExecWB to execute a copy command, and get the currently selected text from the clipboard. <\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">HRESULT hr = pWebBrowser->ExecWB(OLECMDID_COPY, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);<\/pre>\n<p>This didn&#8217;t work. <\/p>\n<p><code>hr<\/code> ends up containing <code>-2147221248<\/code> (&#8220;Trying to revoke a drop target that has not been registered&#8221;). <\/p>\n<p>A look at the <a href=\"http:\/\/msdn2.microsoft.com\/EN-US\/library\/bb159694.aspx\" target=\"_blank\" title=\"IWebBrowser2\">MSDN documentation for ExecWB<\/a> (<em>I do look at documentation occasionally&#8230; honest!<\/em>) says that: <\/p>\n<blockquote><p>This method is not supported for Windows Mobile Version 5.0 and later.<\/p><\/blockquote>\n<p>This doesn&#8217;t mean it&#8217;s not implemented (some commands seem to work &#8211; a little experimentation shows that using ExecWB to send <code>OLECMDID_SELECTALL<\/code>, for example, does select everything on the page as you&#8217;d expect). But it does apparently mean that I can&#8217;t moan that it won&#8217;t work. And <a href=\"http:\/\/support.microsoft.com\/kb\/251133\" target=\"_blank\">-2147417848 seems to mean that the OLECMDID value you&#8217;ve tried to use is not defined<\/a>. <\/p>\n<p>It was time to think of another way&#8230;<\/p>\n<p><strong>Attempt 2 &#8211; IHTMLDocument2<\/strong><\/p>\n<p>The next plan was to get a handle to the <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa752574.aspx\" target=\"_blank\">HTML document<\/a> being displayed by the web browser, and use the <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa752606.aspx\" target=\"_blank\"><code>selection<\/code><\/a> property to get the currently selected text. <\/p>\n<p>Easy? Erm&#8230; not so much.<\/p>\n<p>After much searching through the Windows Mobile SDK, I couldn&#8217;t find IHTMLDocument2 anywhere. But, I did find a mention of <code>IPIEHTMLDocument2<\/code> in an <code>idl<\/code> file in the SDK Include directory. (<em>Ugh. I don&#8217;t get the point of idl files&#8230; why do I have to build my own libraries? \ud83d\ude41 <\/em>)<\/p>\n<p>There were a few steps between me and getting a handle to a IPIEHTMLDocument2 object&#8230;<\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">C:\\\\Program Files\\\\Windows Mobile\\\\Windows Mobile 5.0 Pocket PC SDK\\\\Include\\\\Armv4i>midl \/D:UNDER_CE \/I . webvw.idl\r\nMicrosoft (R) 32b\/64b MIDL Compiler Version 6.00.0366\r\nCopyright (c) Microsoft Corporation 1991-2002. All rights reserved.\r\nProcessing .\\\\webvw.idl\r\nwebvw.idl\r\nProcessing .\\\\oaidl.idl\r\noaidl.idl\r\nProcessing .\\\\objidl.idl\r\nobjidl.idl\r\nProcessing .\\\\unknwn.idl\r\nunknwn.idl\r\nProcessing .\\\\wtypes.idl\r\nwtypes.idl\r\nProcessing .\\\\basetsd.h\r\nbasetsd.h\r\nProcessing .\\\\ocidl.idl\r\nocidl.idl\r\nProcessing .\\\\oleidl.idl\r\noleidl.idl\r\nProcessing .\\\\dispex.idl\r\ndispex.idl\r\nProcessing .\\\\servprov.idl\r\nservprov.idl\r\nProcessing .\\\\urlmon.idl\r\nurlmon.idl\r\nProcessing .\\\\msxml2.idl\r\nmsxml2.idl\r\nProcessing C:\\\\Program Files\\\\IDEs\\\\Visual Studio 2005\\\\VC\\\\PlatformSDK\\\\include\\\\oaidl.acf\r\noaidl.acf\r\nProcessing C:\\\\Program Files\\\\IDEs\\\\Visual Studio 2005\\\\VC\\\\PlatformSDK\\\\include\\\\ocidl.acf\r\nocidl.acf<\/pre>\n<p>This produces a <code>webvw.tlb<\/code> file, which I imported into my code using:<\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">#import \"C:\\\\\\\\Program Files\\\\\\\\Windows Mobile\\\\\\\\Windows Mobile 5.0 Pocket PC SDK\\\\\\\\Include\\\\\\\\Armv4i\\\\\\\\webvw.tlb\" <\/pre>\n<p>Then I added <code>wvuuid.lib<\/code> to the project dependencies in Visual Studio. <\/p>\n<p>On the plus side, this let me get a IPIEHTMLDocument2 object:<\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">IDispatch* pHtmlDocDispatch;\r\nIOleCommandTarget* pOleCommandTarget;\r\nWEBVIEWLib::IPIEHTMLDocument2*         pHTMLDocument2;\r\nWEBVIEWLib::IPIEHTMLWindow2*           pHTMLWindow; \r\n            IPIEHTMLElementCollection* pHTMLElementCollection;\r\n\r\nhr = pWebBrowser->get_Document(&pHtmlDocDispatch);\r\nCHR(hr);\r\n\r\nif (pHtmlDocDispatch != NULL)\r\n{\r\n    hr = pHtmlDocDispatch->QueryInterface(IID_IPIEHTMLDocument2, (void**)&pHTMLDocument2);\r\n    CHR(hr);\r\n\r\n    hr = pHTMLDocument2->get_parentWindow(&pHTMLWindow);\r\n    CHR(hr);\r\n\r\n    pHTMLDocument2->selection ... oh. bugger.\r\n}<\/pre>\n<p>On the down side&#8230; dammit. <code>IPIEHTMLDocument2<\/code> doesn&#8217;t have the <code>selection<\/code> property. So this was all for nothing. Damn. <\/p>\n<p><strong>Attempt 3 &#8211; DTM_COPYSELECTIONTONEWISTREAM<\/strong><\/p>\n<p>At this point, I was running out of ideas and turned to Google for inspiration. I came across the idea of using <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa931932.aspx\" target=\"_blank\">SendMessage<\/a>  to send <code>DTM_COPYSELECTIONTONEWISTREAM<\/code> to the web browser&#8217;s window.<\/p>\n<p>The code looks something like this:<\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">ULONG ulNumChars = 0;\r\nLPWSTR pSelectedText = NULL;\r\nLPSTREAM pStream = 0;\r\nDWORD rsd = 0;\r\nHGLOBAL hglbCopy;\r\nLPTSTR lptstrCopy; \r\nHWND hWndHTML;\r\n\r\nIOleWindow *pOleWindow;\r\nhr = pDataObj->QueryInterface(IID_IOleWindow, (void**)&pOleWindow);\r\nCHR(hr);\r\n\r\nhr = pOleWindow->GetWindow(&hWndHTML);\r\nCHR(hr);\r\n\r\nhr = SendMessage(hWndHTML, \r\n                 DTM_COPYSELECTIONTONEWISTREAM, \r\n                 (WPARAM)&rsd, \r\n                 (LPARAM)&pStream); \r\n                 CHR(hr);\r\n\r\nif(pStream)\r\n{\r\n    STATSTG stat = { 0 };\r\n    hr = pStream->Stat(&stat, STATFLAG_NONAME);\r\n    CHR(hr); \r\n\r\n    pSelectedText = (LPWSTR)LocalAlloc(LPTR,(ULONG)stat.cbSize.QuadPart + 4);\r\n\r\n    if (pSelectedText)\r\n    {\r\n        hr = pStream->Read(pSelectedText, \r\n                           (ULONG)stat.cbSize.QuadPart, \r\n                           &ulNumChars);\r\n        CHR(hr);\r\n\r\n        EmptyClipboard();\r\n        hglbCopy = GlobalAlloc(GMEM_MOVEABLE, ulNumChars+2);\r\n        if(hglbCopy != NULL)\r\n        {\r\n            lptstrCopy = (LPTSTR) GlobalLock(hglbCopy);\r\n            memcpy(lptstrCopy, pSelectedText, ulNumChars);\r\n            GlobalUnlock(hglbCopy);\r\n            SetClipboardData(CF_UNICODETEXT, hglbCopy);\r\n        }\r\n\r\n        LocalFree(pSelectedText);\r\n    }\r\n\r\n    pStream->Release ();\r\n}\r\n\r\nCloseClipboard();<\/pre>\n<p>Sounds good, and certainly looks the business.<\/p>\n<p>Except, it didn&#8217;t work. Or at least, in a weekend where I spent <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=190\">more time meeting people and joining in discussions than coding<\/a>, I didn&#8217;t get the bottom of what is wrong with it. Whatever I did, <code>pStream<\/code> stayed empty. \ud83d\ude41<\/p>\n<p><strong>Attempt 4 &#8211; Cheating<\/strong><\/p>\n<p>Okay, so at this point it was getting late on Sunday and I was still no nearer to solving what was supposed to a small aspect of the hacks I wanted to show people. So&#8230; I kinda cheated. \ud83d\ude42<\/p>\n<pre style=\"overflow-x: scroll; font-size: 1.2em; background-color: #eeeeee; border: 1px solid #666666; padding: 3px;\">keybd_event (VK_CONTROL, 0, 0,               0);\r\nkeybd_event (0x43,       0, 0,               0);\r\nSleep(1000);\r\nkeybd_event (0x43,       0, KEYEVENTF_KEYUP, 0);\r\nkeybd_event (VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);<\/pre>\n<p>I used <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa928103.aspx\" target=\"_blank\">keybd_event<\/a> to fake a Ctrl-C keystroke. I press Ctrl and C, wait for a bit, then release them, copying the selection to the clipboard. <\/p>\n<p>Urgh, Very hacky, but I guess that is in-keeping with the spirit of a <a href=\"http:\/\/www.mobilecamplondon.org\/?p=15\">hack challenge<\/a>!<\/p>\n<p>So there we go&#8230; if anyone knows a better way of doing this, or if anyone knows why I couldn&#8217;t get <code>DTM_COPYSELECTIONTONEWISTREAM<\/code> to work, I&#8217;d love to hear from you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As part of my hack for mobileCampLondon, I wanted to get the current selection from the web browser on my Windows Mobile phone. The plan was to add a new menu item to Pocket Internet Explorer that lets you search for the text you&#8217;ve selected in Google. So I needed to get the currently selected [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-191","post","type-post","status-publish","format-standard","hentry","category-code"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/191","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=191"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/191\/revisions"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=191"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=191"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=191"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}