Showing posts with label context menu. Show all posts
Showing posts with label context menu. Show all posts

Monday, November 12, 2007

When IWebBrowser2::get_HWND returns E_FAIL

IWebBrowser2::get_HWND "gets the handle of the Microsoft Internet Explorer main window". As any COM method get_HWND returns a HRESULT value. According to MSDN, the method "returns S_OK if successful, or an error value otherwise".

It was hard for me to imagine how this method could fail but I still got an E_FAIL return value. This happened because the IWebBrowser2 object was not the top level browser. A web page containing frames/iframes is represented by a hierarchy of IHTMLWindow objects. Each window has an associated IHTMLDocument2 object exposed by IHTMLWindow2::get_document. An IHTMLWindow can be also converted to a IWebBrowser2 object. Here's my solution to get the main window handle starting from a non-top level browser object (this is a common scenario when adding your custom menu item in the IE context menu).

// IHTMLWindow2 to IWebBrowser2
CComQIPtr<IWebBrowser2> IHTMLWindow2ToIWebBrowser2(CComQIPtr<IHTMLWindow2> spHTMLWindow)
{
ATLASSERT(spHTMLWindow != NULL);

// Query for a service provider.
CComQIPtr<IWebBrowser2> spBrowser;
CComQIPtr<IServiceProvider> spServiceProvider = spHTMLWindow;

if (spServiceProvider != NULL)
{
// Ask the service provider for a IWebBrowser2 object.
spServiceProvider->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&spBrowser);
}

return spBrowser;
}

// IWebBrowser2 to IHTMLWindow2
CComQIPtr<IHTMLWindow2> IWebBrowserToIHTMLWindow(CComQIPtr<IWebBrowser2> spBrowser)
{
ATLASSERT(spBrowser != NULL);
CComQIPtr<IHTMLWindow2> spWindow;

// Get the document of the browser.
CComQIPtr<IDispatch> spDisp;
spBrowser->get_Document(&spDisp);

// Get the window of the document.
CComQIPtr<IHTMLDocument2> spDoc = spDisp;
if (spDoc != NULL)
{
spDoc->get_parentWindow(&spWindow);
}

return spWindow;
}


CComQIPtr<IWebBrowser2> TopBrowser(CComQIPtr<IWebBrowser2> spBrowser)
{
ATLASSERT(spBrowser != NULL);

// Retrieve IHTMLWindow2 from browser.
CComQIPtr<IHTMLWindow2> spHTMLWnd = IWebBrowserToIHTMLWindow(spBrowser);
if (spHTMLWnd != NULL)
{
// Find top window.
CComQIPtr<IHTMLWindow2> spTopWindow;
HRESULT hResult = spHTMLWnd->get_top(&spTopWindow);

if (SUCCEEDED(hResult) && (spTopWindow != NULL))
{
// Convert the browser object to window.

return IHTMLWindow2ToIWebBrowser2(spTopWindow);
}
}

return CComQIPtr<IWebBrowser2>();
}

This technique was successfully implemented and tested in My web automation library.

Sunday, October 28, 2007

Open TextRange selection as URL

On many forums, people post URLs as plain text and this forces me to:
  • select the text URL
  • ctrl+C to copy it in the clipboard
  • ctrl+T to open a new tab
  • paste the URL in the address bar of the newly created tab
  • press "Enter" key to start navigation

I found this whole process very annoying and it seems I have to go through this many times a day. Here's my attempt to automate it by creating an extension for "Internet Explorer" similar to Linkification extension (for "Fire Fox" browser). I called my extension: "Make Link".

How it works:

  • right click on text URL
  • choose "MakeLink: use clicked text as link" menu item (the URL is open in a new tab automatically)

or you can

  • fully select the URL text or only a part of it
  • right click on selected text
  • choose "MakeLink: use clicked text as link" menu item (text link is open in a new tab automatically)

DOWNLOADS:

Points of interests:

  • HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt registry key to add a item in the IE context menu
  • gain access to window object passed in external.menuArguments
  • document.selection property to get the selected TextRange
  • TextRange methods: moveStart, moveEnd, moveToPoint, select
  • The extension is entirely written in JScript (no BHO, no COM).

Known issues:

  • on some web pages with horizontal scroll simply right click a text URL won't work. You need to select a part of the URL and then right click it.