How To Handle Custom URL Protocols with the Microsoft WebBrowser Control

Now that you know “How To Use the Microsoft WebBrowser Control to Render HTML from Memory” and “How To Navigate to an Anchor in the Microsoft WebBrowser Control when Rendering HTML from Memory“, it’s time to learn how to handle custom URL protocols to tailor the navigation inside the WebBrowser Control to fit your application. The following demonstrates a custom URL protocol called “app”:

<a href="app://">Test</a>

When you would put this link in a normal Internet Explorer window, clicking the link will generate an error because IE does not know how to handle the APP protocol. The name APP is chosen arbitrarily. You can use whatever you want. Handling these custom protocols in your C++ application is actually pretty simple and it doesn’t even involve any real COM coding like in the previous articles. The first thing you need to do is to add a handler for the BeforeNavigate2 handler. Open the resource editor and open your dialog with the WebBrowser control. Right click the WebBrowser control and select “Add Event Handler…”. Select “BeforeNavigate2” as message type, select the appropriate class and click “Add and Edit”. This handler will be called right before the WebBrowser control will navigate to a new page. To handle the custom protocol, implement the handler as follows:

void CMyDlg::BeforeNavigate2Explorer(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Flags,
    VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers, BOOL* Cancel)
    const wchar_t* cpszProtocolName = L"app";
    const wchar_t* cpszProtocolSeparator = L"://";

    // We only handle VT_BSTR.
    if (URL->vt != VT_BSTR)

    // Check the protocol of the URL
    CString str = URL->bstrVal;
    int iPos = str.Find(cpszProtocolSeparator);
    if (iPos == -1)    // Unable to figure out protocol

    // Extract protocol and check if it's our APP protocol
    CString strProtocol = str.Mid(0, iPos);
    if (strProtocol.CompareNoCase(cpszProtocolName))
        return;    // not our APP protocol

    // It's our APP protocol, so start processing it.
    // Start by preventing Internet Explorer from handling the protocol.
    *Cancel = TRUE;

    // Extract target URL
    CString strTarget = str.Mid(iPos+wcslen(cpszProtocolSeparator));

    // Now we are ready to process our protocol.
    // For this demo, I just render a new HTML page with the name
    // of the URL target without the protocol part of the string.
    CString strHTML;
    strHTML.Format(L"My APP protocol processing: \"%s\"", strTarget);

The flow is pretty straightforward. The URL protocol is extracted; if it’s not our protocol, we let Internet Explorer handle the URL for us. If it is our custom “APP” protocol, we first set Cancel to TRUE which will prevent Internet Explorer from handling this URL protocol. Once that is done, we are completely free to implement the handling of the “APP” protocol however we want. As demonstration I just write a new HTML document from memory which will just mention that we are processing an “APP” protocol URL and that will also display the target part of the URL.

You can quickly test the code with the following piece of HTML rendered from memory:

    L"<p><a href=\"app://FirstAppProtocolTestLink\">test 1</a></p>"
    L"<p><a href=\"APP://SecondAppProtocolTestLink.Withdots\">test 2</a></p>"

Run the application, click on the “test 1” or “test 2” link and see what happens.

That’s it for handling custom URL protocols in C++ 🙂


1 Comment so far »

  1. pp said,

    Wrote on December 21, 2010 @ 7:26 pm

    That’s all nice and well, but BeforeNavigate2 event fires only when control is loading an URL (or frame). So that means once per HTML page.

    Do you know any way how would you be able to filter these out (or custom handle) before the HTML has loaded?

    In other words – is there an event that would fire on each a href tag – in above example – twice – WHILE loading HTML.

    In particular I need it to filter out and cancel unwanted URL’s (like unwanted images, unwanted scripts etc.) but could be of course used for something like this as well. Any idea?

Comment RSS · TrackBack URI

Leave a Comment

Name: (Required)

E-mail: (Required)