0

I'm using the WebBrowser control in a C# WPF application. I need to execute the Paste command programmatically, and I do this using the following statement:

WebBrowser.Document.ExecCommand("paste", false, null);

This works perfectly on my local machine; however, it does not work in our production environment. The command simply does nothing. Luckily, I've determined the cause of this problem to be an IE security restriction, based on this post.

The fix is to modify the security level in IE to be medium (Tools > Internet Options > security > Internet > Medium level).

By following the answer from that post, the problem can be fixed. However, in our production environment, the IE security settings are set to high and cannot be modified because of security policies. So this fix cannot be used.

I have seen another post about adding a custom security mananger, and this sounds like a possible fix for this problem.

However, I've been unable to determine exactly which IInternetSecurityManager methods I need to implement or how to implement them. I've defined the interface and I've gotten the methods to be called, but I'm currently just returning INET_E_DEFAULT_ACTION for all of them.

public class MyWebBrowser : WebBrowser
{

    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        return new ExtendedWebBrowserSite(this);
    }

    protected class ExtendedWebBrowserSite : WebBrowserSite, IInternetSecurityManager, IServiceProvider
    {
        private static readonly Guid SID_IInternetSecurityManager = new Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B");

        WebBrowser _host;

        public ExtendedWebBrowserSite(WebBrowser host) : base(host)
        {
            _host = host;
        }

        public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
        {
            if (guidService == SID_IInternetSecurityManager && riid == SID_IInternetSecurityManager)
            {
                ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
                return HRESULTS.S_OK;
            }
            ppvObject = IntPtr.Zero;
            return HRESULTS.E_NOINTERFACE;
        }

        #region IInternetSecurityManager Implementation

        public int SetSecuritySite([In] IntPtr pSite)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetSecuritySite([Out] IntPtr pSite)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int MapUrlToZone([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out uint pdwZone, uint dwFlags)
        {
            pdwZone = 0;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref uint pcbSecurityId, uint dwReserved)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, uint dwAction, out byte pPolicy, uint cbPolicy, byte pContext, uint cbContext, uint dwFlags, uint dwReserved)
        {
            pPolicy = 0;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int QueryCustomPolicy([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref uint pcbPolicy, ref byte pContext, uint cbContext, uint dwReserved)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int SetZoneMapping(uint dwZone, [In, MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, uint dwFlags)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetZoneMappings(uint dwZone, out IEnumString ppenumString, uint dwFlags)
        {
            ppenumString = null;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }


        #endregion IInternetSecurityManager Implementation
    }
}

Which methods should I be implementing in order to fix the paste feature, and how?

oaky_afterbirth
  • 125
  • 3
  • 15

1 Answers1

0

Okay, so I believe I've figured it out. I have an implementation that does fix the problem, although I have not thoroughly tested it yet, so it may or may not have some unwanted side effects.

If you extend the WebBrowser control (let's call it MyWebBrowser) and then override the CreateWebBrowserSiteBase method, you can provide your own WebBrowserSite-derived class (let's call it ExtendedWebBrowserSite) that implements the necessary COM interfaces (in this case, IServiceProvider and IInternetSecurityManager).

Then in the ExtendedWebBrowserSite class, we need to implement the IServiceProvider.QueryService method such that it will return the correct implementation of IInternetSecurityManager. And then we also need to implement all the methods of IInternetSecurityManager. The important method here is IInternetSecurityManager.ProcessUrlAction, which needs to override the default logic. The rest of the IInternetSecurityManager methods need only to return INET_E_DEFAULT_ACTION, to ensure that the default security manager handles those actions. The IInternetSecurityManager.ProcessUrlAction method should check if the action is URLACTION_SCRIPT_PASTE. If it is, then we should set the pPolicy out parameter to URLPOLICY_ALLOW and return S_OK. Otherwise, we should return INET_E_DEFAULT_ACTION. I'm pretty sure that if we return INET_E_DEFAULT_ACTION, it doesn't matter what value you set pPolicy to, as it would be ignored. Correct me if I'm wrong here.

MyWebBrowser:

class MyWebBrowser : System.Windows.Forms.WebBrowser
{
    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        return new ExtendedWebBrowserSite(this);
    }
}

ExtendedWebBrowserSite:

class ExtendedWebBrowserSite : WebBrowserSite, IInternetSecurityManager, IServiceProvider
{

    // constructor omitted

    int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
    {
        if (guidService == SID_IInternetSecurityManager && riid == SID_IInternetSecurityManager)
        {
            ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
            return HRESULTS.S_OK;
        }
        ppvObject = IntPtr.Zero;
        return HRESULTS.E_NOINTERFACE;
    }

    int IInternetSecurityManager.ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, uint dwAction, out byte pPolicy, uint cbPolicy, byte pContext, uint cbContext, uint dwFlags, uint dwReserved)
    {
        // If action is a paste, then we want to allow it, regardless of the inherited IE security policy.
        if (dwAction == URLActionFlags.URLACTION_SCRIPT_PASTE)
        {
            pPolicy = URLPolicyFlags.URLPOLICY_ALLOW;
            return HRESULTS.S_OK;
        }

        // I think we can set the policy to whatever arbitrary value we want here. 
        // Because if we return INET_E_DEFAULT_ACTION, the policy value will just be ignored.
        pPolicy = URLPolicyFlags.URLPOLICY_ALLOW;
        return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
    }

    // Other IInternetSecurityManager methods omitted for brevity...
    // Other IInternetSecurityManager methods should all return INET_E_DEFAULT_ACTION to ensure that the default security manager handles them.
}

COM Interface Definitions

[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
    [PreserveSig]
    int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
[ComImport, Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInternetSecurityManager
{
    [PreserveSig] 
    int SetSecuritySite([In] IntPtr pSite);

    [PreserveSig] 
    int GetSecuritySite([Out] IntPtr pSite);

    [PreserveSig] 
    int MapUrlToZone([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out UInt32 pdwZone, UInt32 dwFlags);

    [PreserveSig] 
    int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref UInt32  pcbSecurityId, uint dwReserved);

    [PreserveSig] 
    int ProcessUrlAction([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, UInt32 dwAction, out byte pPolicy, UInt32 cbPolicy, byte pContext, UInt32 cbContext, UInt32 dwFlags, UInt32 dwReserved);

    [PreserveSig]
    int QueryCustomPolicy([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref UInt32 pcbPolicy, ref byte pContext, UInt32 cbContext, UInt32 dwReserved);

    [PreserveSig]
    int SetZoneMapping(UInt32 dwZone, [In,MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, UInt32 dwFlags);

    [PreserveSig]
    int GetZoneMappings(UInt32 dwZone, out IEnumString ppenumString, UInt32 dwFlags);
}
oaky_afterbirth
  • 125
  • 3
  • 15