Friday, July 10, 2009

A WebBrowser Implementation That Actually Raises Events!

A question that comes up rather frequently on the Forums is "Why doesn't the WebBrowser event ___________ ever get raised?" Typically, the blank is filled in with "MouseClick" and "KeyDown" and other input events. The reason for this is the fact that the WebBrowser control is an ActiveX-based control. Essentially, all of the events that would normally be raised by the control itself, are instead captured inside the document that resides within the control. In order to get the events to be raised at the control level, it's important to attach the event handlers to the document, and not the control. Unfortunately, the default implementation of WebBrowser doesn't expose the document's events at this level, so you're left with no way of tracking what's happening within the WebBrowser control, as far as input is concerned. Well, no more. Here's an implementation of WebBrowser, called ActiveWebBrowser, that can handle these events, and exposes them publicly at the WebBrowser level, without interfering with the existing events on the page.

This code will require you to reference the COM library called "Microsoft HTML Object Library" in your code, which should be available through the COM tab in the Add References dialog.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using mshtml;


namespace WindowsFormsApplication1
{
public class MSHtmlEventArgs : EventArgs
{
public MSHtmlEventArgs(mshtml.IHTMLEventObj obj)
{
EventObj = obj;
}

public mshtml.IHTMLEventObj EventObj { get; private set; }
}


public class ActiveWebBrowser : WebBrowser
{
private IConnectionPoint icp;
private int cookie = -1;

public event EventHandler<MSHtmlEventArgs> DocumentActivate;
public event EventHandler<MSHtmlEventArgs> DocumentAfterUpdate;
public event EventHandler<MSHtmlEventArgs> DocumentBeforeActivate;
public event EventHandler<MSHtmlEventArgs> DocumentBeforeDeactivate;
public event EventHandler<MSHtmlEventArgs> DocumentBeforeEditFocus;
public event EventHandler<MSHtmlEventArgs> DocumentBeforeUpdate;
public event EventHandler<MSHtmlEventArgs> DocumentCellChange;
public event EventHandler<MSHtmlEventArgs> DocumentClick;
public event EventHandler<MSHtmlEventArgs> DocumentContextMenu;
public event EventHandler<MSHtmlEventArgs> DocumentControlSelect;
public event EventHandler<MSHtmlEventArgs> DocumentDataAvailable;
public event EventHandler<MSHtmlEventArgs> DocumentDataSetChanged;
public event EventHandler<MSHtmlEventArgs> DocumentDataSetComplete;
public event EventHandler<MSHtmlEventArgs> DocumentDoubleClick;
public event EventHandler<MSHtmlEventArgs> DocumentDeactivate;
public event EventHandler<MSHtmlEventArgs> DocumentDragStart;
public event EventHandler<MSHtmlEventArgs> DocumentErrorUpdate;
public event EventHandler<MSHtmlEventArgs> DocumentFocusIn;
public event EventHandler<MSHtmlEventArgs> DocumentFocusOut;
public event EventHandler<MSHtmlEventArgs> DocumentHelp;
public event EventHandler<MSHtmlEventArgs> DocumentKeyDown;
public event EventHandler<MSHtmlEventArgs> DocumentKeyPress;
public event EventHandler<MSHtmlEventArgs> DocumentKeyUp;
public event EventHandler<MSHtmlEventArgs> DocumentMouseDown;
public event EventHandler<MSHtmlEventArgs> DocumentMouseMove;
public event EventHandler<MSHtmlEventArgs> DocumentMouseUp;
public event EventHandler<MSHtmlEventArgs> DocumentMouseOut;
public event EventHandler<MSHtmlEventArgs> DocumentMouseOver;
public event EventHandler<MSHtmlEventArgs> DocumentMouseWheel;
public event EventHandler<MSHtmlEventArgs> DocumentPropertyChange;
public event EventHandler<MSHtmlEventArgs> DocumentReadyStateChange;
public event EventHandler<MSHtmlEventArgs> DocumentRowEnter;
public event EventHandler<MSHtmlEventArgs> DocumentRowExit;
public event EventHandler<MSHtmlEventArgs> DocumentRowsDelete;
public event EventHandler<MSHtmlEventArgs> DocumentRowsInserted;
public event EventHandler<MSHtmlEventArgs> DocumentSelectionChange;
public event EventHandler<MSHtmlEventArgs> DocumentSelectStart;
public event EventHandler<MSHtmlEventArgs> DocumentStop;

protected override void OnDocumentCompleted(WebBrowserDocumentCompletedEventArgs e)
{
base.OnDocumentCompleted(e);

IConnectionPointContainer icpc;
icpc = (IConnectionPointContainer)this.Document.DomDocument;
Guid guid = typeof(HTMLDocumentEvents2).GUID;
icpc.FindConnectionPoint(ref guid, out icp);
icp.Advise(new HandleWebBrowserDHTMLEvents(this), out cookie);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (-1 != cookie) icp.Unadvise(cookie);
cookie = -1;
}
base.Dispose(disposing);
}

class HandleWebBrowserDHTMLEvents : mshtml.HTMLDocumentEvents2
{
private ActiveWebBrowser _webBrowser;

public HandleWebBrowserDHTMLEvents(ActiveWebBrowser webBrowser)
{
_webBrowser = webBrowser;
}

public void onactivate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentActivate != null)
_webBrowser.DocumentActivate(_webBrowser, new MSHtmlEventArgs(e));
}

public void onafterupdate(mshtml.IHTMLEventObj e) {
if (_webBrowser.DocumentAfterUpdate != null)
_webBrowser.DocumentAfterUpdate(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onbeforeactivate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentBeforeActivate != null)
_webBrowser.DocumentBeforeActivate(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public bool onbeforedeactivate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentBeforeDeactivate != null)
_webBrowser.DocumentBeforeDeactivate(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onbeforeeditfocus(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentBeforeEditFocus != null)
_webBrowser.DocumentBeforeEditFocus(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onbeforeupdate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentBeforeUpdate != null)
_webBrowser.DocumentBeforeUpdate(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void oncellchange(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentCellChange != null)
_webBrowser.DocumentCellChange(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onclick(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentClick != null)
_webBrowser.DocumentClick(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public bool oncontextmenu(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentContextMenu != null)
_webBrowser.DocumentContextMenu(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public bool oncontrolselect(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentControlSelect != null)
_webBrowser.DocumentControlSelect(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void ondataavailable(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDataAvailable != null)
_webBrowser.DocumentDataAvailable(_webBrowser, new MSHtmlEventArgs(e));
}

public void ondatasetchanged(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDataSetChanged != null)
_webBrowser.DocumentDataSetChanged(_webBrowser, new MSHtmlEventArgs(e));
}

public void ondatasetcomplete(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDataSetComplete != null)
_webBrowser.DocumentDataSetComplete(_webBrowser, new MSHtmlEventArgs(e));
}

public bool ondblclick(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDoubleClick != null)
_webBrowser.DocumentDoubleClick(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void ondeactivate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDeactivate != null)
_webBrowser.DocumentDeactivate(_webBrowser, new MSHtmlEventArgs(e));
}

public bool ondragstart(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentDragStart != null)
_webBrowser.DocumentDragStart(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public bool onerrorupdate(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentErrorUpdate != null)
_webBrowser.DocumentErrorUpdate(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onfocusin(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentFocusIn != null)
_webBrowser.DocumentFocusIn(_webBrowser, new MSHtmlEventArgs(e));
}

public void onfocusout(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentFocusOut != null)
_webBrowser.DocumentFocusOut(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onhelp(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentHelp != null)
_webBrowser.DocumentHelp(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onkeydown(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentKeyDown != null)
_webBrowser.DocumentKeyDown(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onkeypress(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentKeyPress != null)
_webBrowser.DocumentKeyPress(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onkeyup(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentKeyUp != null)
_webBrowser.DocumentKeyUp(_webBrowser, new MSHtmlEventArgs(e));
}

public void onmousedown(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseDown != null)
_webBrowser.DocumentMouseDown(_webBrowser, new MSHtmlEventArgs(e));
}

public void onmousemove(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseMove != null)
_webBrowser.DocumentMouseMove(_webBrowser, new MSHtmlEventArgs(e));
}

public void onmouseout(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseOut != null)
_webBrowser.DocumentMouseOut(_webBrowser, new MSHtmlEventArgs(e));
}

public void onmouseover(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseOver != null)
_webBrowser.DocumentMouseOver(_webBrowser, new MSHtmlEventArgs(e));
}

public void onmouseup(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseUp != null)
_webBrowser.DocumentMouseUp(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onmousewheel(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentMouseWheel != null)
_webBrowser.DocumentMouseWheel(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onpropertychange(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentPropertyChange != null)
_webBrowser.DocumentPropertyChange(_webBrowser, new MSHtmlEventArgs(e));
}

public void onreadystatechange(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentReadyStateChange != null)
_webBrowser.DocumentReadyStateChange(_webBrowser, new MSHtmlEventArgs(e));
}

public void onrowenter(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentRowEnter != null)
_webBrowser.DocumentRowEnter(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onrowexit(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentRowExit != null)
_webBrowser.DocumentRowExit(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public void onrowsdelete(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentRowsDelete != null)
_webBrowser.DocumentRowsDelete(_webBrowser, new MSHtmlEventArgs(e));
}

public void onrowsinserted(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentRowsInserted != null)
_webBrowser.DocumentRowsInserted(_webBrowser, new MSHtmlEventArgs(e));
}

public void onselectionchange(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentSelectionChange != null)
_webBrowser.DocumentSelectionChange(_webBrowser, new MSHtmlEventArgs(e));
}

public bool onselectstart(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentSelectStart != null)
_webBrowser.DocumentSelectStart(_webBrowser, new MSHtmlEventArgs(e));
return true;
}

public bool onstop(mshtml.IHTMLEventObj e)
{
if (_webBrowser.DocumentStop != null)
_webBrowser.DocumentStop(_webBrowser, new MSHtmlEventArgs(e));
return true;
}
}
}
}