Sunday, December 2, 2007

the internet explorer pop-up manager and your webbrowser control host

This is a re-posting of a post originally published on 2004-01-26. The original can be found here. This version has been updated to match what is currently reality.

Overview
With the introduction of Windows XP Service Pack 2, Internet Explorer 6 (and up) introduced a built-in pop-up window manager. If your program is going to host the webbrowser control, you may or may not want the pop-up blocker's functionality. This post will describe how to alter, override or enable the pop-up blocker's functionality for application.

Implement INewWindowManager
The basic Implement INewWindowManager. The webbrowser control will QueryInterface its site for this method. You should implement this in the same place you (would) implement IDocHostUIHandler.

When webbrowser control detects a new window is being requested, it will call the EvaluateNewWindow() method on the interface. Just about any method for opening a new window should trigger this call. What follows is boiler-plate for various scenarios:

I Do Not Want Any Pop-up Management
This is the easy case, since pop-up management is opt-in. Simply do nothing. The webbrowser control will query you for INWM. If the query fails, no pop-up management will occur. This decision was made so that applications that already exist would not have to change when Windows XP Service Pack 2 shipped.

I Want Exactly What Internet Explorer Does
This is easy too. Simply implement INWM::ENW() and return E_NOTIMPL. You will get all the same functionality, including checking against the user's white list and action according to the user's preferences.

CMyObject::EvaluateNewWindow(...)
{
return E_NOTIMPL;
}
When the webbrowser control sees the failure code, it will fall back to the default pop-up management.

I Want My Own Logic
Implement INWM::ENW() and use the parameters to decide whether or not to block the new window. Return S_FALSE to block the window and S_OK to allow it:

CMyObject::EvaluateNewWindow(...)
{
HRESULT hr = S_OK;
if (/* your logic here */)
{
hr = S_FALSE;
}
else if (/* more of your logic here */)
{
hr = S_FALSE;
}
// ... and so on ...

// Now update your UI.
switch(hr)
{
case S_OK:
OnPopupNotBlocked(...);
break;

case S_FALSE:
OnPopupBlocked(...);
break;
}

return hr;
}
Developer's Note
I will admit right now, this is the first public interface I ever designed. I was young and stupid and the Interface was not subject to a lot of review by people with more expertise. If I was doing it all over again, I would probably not have done it this way. But it works.

1 comment:

acolin said...

Hi! Is it possible to rely on the default implementation of the INewWindowManager implementation but also have access to the result of the default implementation? If the default implementation decides to block the new window, it would be nice to find that out.

If the answer to the above is NOT POSSIBLE, then could you describe the default implementation? It's clearly looking at time since last user action (there's a built-in max value?) and potentially has black/white lists for URLs, any other clever things it does (esp. to avoid false positives)?

My ultimate goal is to (1) not implement custom popup logic, and (2) get notified when popup is blocked.

Thank you in advance.