You are viewing csharpcoder

   Journal    Friends    Archive    Profile    Memories
 

David Airapetyan on C# and .NET - Automating existing Internet Explorer instances in C#

Jun. 7th, 2007 11:35 am Automating existing Internet Explorer instances in C#

Microsoft Internet Explorer is a very rich platform with an extensive OM. It comes to no surprise that it has been chosen as a building block for many applications, including the Vista Sidebar and Microsoft Office InfoPath. I use IE whenever I have to process or display HTML (for example, for parsing out data from websites) as it saves me a lot of time by taking care of all the HTTP interaction and HTML parsing. But what if you wanted to access the Internet Explorer's OM for an existing application? The biggest scenario here is test automation but there are other scenarios as well (for example, enhancing the browsing experience by pre-populating fields – without the complexity of writing an IE toolbar).

The way one attached to an existing IE instance is by first locating the HWND for the window you are interested in and then by using Microsoft Active Accessibility to get to the actual IE instance.

To get to the IE HWND, we can use the EnumWindows()/EnumChildWindows() win32 methods. Here is an example that locates a specified top-level window and gets the IE HWND from it (assuming it's a first-level child):

static bool FindTopLevelWindow(IntPtr hWnd, ref IntPtr lParam)
{

  int textLength = GetWindowTextLength(hWnd) + 1;
  StringBuilder windowTextBuilder = new StringBuilder(textLength);
  GetWindowText(hWnd, windowTextBuilder, textLength);

  string windowName = windowTextBuilder.ToString();

   if (windowName.IndexOf(TopLevelWindowSubstring,
        StringComparison.CurrentCultureIgnoreCase) >= 0)
  {
    lParam = hWnd;

    return false;
  }

  return true;
}

static bool FindEmbeddedIEWindow(IntPtr hWnd, ref IntPtr lParam)
{

  StringBuilder classNameBuilder = new StringBuilder(MaxClassNameLength);
  GetClassName(hWnd, classNameBuilder, MaxClassNameLength);

  string className = classNameBuilder.ToString();

  if (className.Equals(IEWindowName, StringComparison.CurrentCulture))
  {
    lParam = hWnd;

    return false;
  }


  return true;
}

 
IntPtr topLevelWindow = IntPtr.Zero;
EnumWindows(FindTopLevelWindow, ref topLevelWindow);

if (topLevelWindow == IntPtr.Zero)
{

  return;
}

IntPtr ieWindow = IntPtr.Zero;

EnumChildWindows(topLevelWindow, FindEmbeddedIEWindow, ref ieWindow);

if (ieWindow == IntPtr.Zero)
{

  return;
}

Now that we have the IE HWND we can get to the underlying HTML document:

uint htmlGetObjectMessage = RegisterWindowMessage(WMHtmlGetObject);

UIntPtr sendMessageResult = UIntPtr.Zero;

SendMessageTimeout(ieWindow, htmlGetObjectMessage, UIntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out sendMessageResult);

if (sendMessageResult == UIntPtr.Zero)
{

  return;
}

//Get the object from sendMessageResult

System.Guid IID_IHTMLDocument = typeof(IHTMLDocument).GUID;

object documentObject = ObjectFromLresult(sendMessageResult, IID_IHTMLDocument,
                   IntPtr.Zero);

Finally, documentObject can be cast to any of the IHTMLDocumentx interfaces to access and manipulate the HTML DOM.

Note that it is also possible to get to the IE window itself (see reference #2). The IEDriver project (reference #3) comes with a handy set of methods to automate IE. It only automates top-level IE windows but it could be changed using the method described above to automate any embedded IE instance.

Here is a complete example where a console application finds the IE instance embedded in InfoPath and changes the background color of the BODY tag:

http://www.davidair.com/misc/ChangeHostedIEBackground.zip

References:

1. "How to get IHTMLDocument2 from a HWND", a Microsoft KB article written in C++: http://support.microsoft.com/kb/q249232/

2. "ObjectFromLresult Interop Question", an MSDN forum post on which the code in my post is based: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=301976&SiteID=1

3. "Automating Internet Explorer", a CodeProject article on how to automate IE where you attach to the top-level window: http://www.codeproject.com/csharp/AutomatingInternetExplore.asp

4. PInvoke.net, a one-place stop for all your P/Invoke needs: http://pinvoke.net/

Leave a commentPrevious Entry Share Next Entry