WebOCs, popups, and the default browser

Applications which host the WebOC (Web Browser control) may choose to support popups and new windows by hooking the NewWindow3 event and returning in ppDisp a pointer to a new, hidden, non-navigated WebBrowser object or InternetExplorer object.  If such an interface is returned, the browser so provided will handle the new window navigation.

On the other hand, if WebOC hosts elect not to handle this event, then the request for a new window will result in the launching of a new Web Browser application/window.  The WebOC provides a flag which controls whether the browser window created is an Internet Explorer window, or that of the system's default browser (e.g. Safari, Opera, Chrome, Firefox, etc).  

In order to indicate the desired behavior, the WebOC host may call the Exec method, passing the IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW constant (defined in the Windows 7 SDK's msiehost.h as 0x5), and a boolean value indicating whether or not the system default browser should be launched to handle new windows.

Some C++ sample code demonstrating this API is as follows:

IOleCommandTarget *pCmdTarget;
hr = IUnknown_QueryService(_pBrowser, SID_STopFrameBrowser, IID_PPV_ARGS(&pCmdTarget));
if (SUCCEEDED(hr))
{
    VARIANT var = {0};
    var.vt = VT_BOOL;
// ***** Indicate preference here: FALSE=UseIE; TRUE=UseSysDefault ****

    var.boolVal = TRUE;
    hr = pCmdTarget->Exec(&CGID_InternetExplorer, IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW, 0, &var, NULL);

    pCmdTarget->Release();
}

For users of the .NET WebBrowser control, you can invoke set the boolean like so:

#region Open-Links-In-System-Default-Browser

    IntPtr pUnk = Marshal.GetIUnknownForObject(wbView.ActiveXInstance);
    IServiceProvider iSP = (IServiceProvider)wbView.ActiveXInstance;
    IOleCommandTarget o = (IOleCommandTarget)iSP.QueryService(ref NativeInterop.SID_STopSID_STopFrameBrowser, ref NativeInterop.IID_IOleCommandTarget);
    object varTrue = (object)true; object varOut = null;

o.Exec(ref NativeInterop.CGID_InternetExplorer, NativeInterop.IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW, 0, ref varTrue, ref varOut);

#endregion

class NativeInterop
{
    public static readonly uint IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW = 5;
    public static readonly uint IECMDID_GET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW = 6;
    public static Guid CGID_InternetExplorer = new Guid(0xeb7eed00,0xf74d,0x11d2,0xbb,0x7f,0x00,0x10,0x4b,0x35,0xe7,0xf9);
    public static Guid SID_STopSID_STopFrameBrowser = new Guid("{A9227C3C-7F8E-11d0-8CB0-00A0C92DBFE8}");
    public static Guid IID_IOleCommandTarget = new Guid("b722bccb-4e68-101b-a2bc-00aa00404770");
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
internal interface IServiceProvider
{
    [return: MarshalAs(UnmanagedType.IUnknown)]
    object QueryService(ref Guid guidService, ref Guid riid);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct OLECMDTEXT
{
    public uint cmdtextf;
    public uint cwActual;
    public uint cwBuf;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public char rgwz;
}

[StructLayout(LayoutKind.Sequential)]
public struct OLECMD
{
    public uint cmdID;
    public uint cmdf;
}

[[ComImport, Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleCommandTarget
{
     //IMPORTANT: The order of the methods is critical here.

     void QueryStatus(ref Guid pguidCmdGroup, UInt32 cCmds,

[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] OLECMD[] prgCmds, ref OLECMDTEXT CmdText);
     void Exec(ref Guid pguidCmdGroup, uint nCmdId, uint nCmdExecOpt, ref object pvaIn, ref object pvaOut);
}

In the event that Internet Explorer is turned off, a WebOC-hosting application will fail to open new windows if InvokeDefaultBrowser is not set to TRUE.

-Eric