I combined the functionality of webbrowsercontrol ObjectForScripting (source) to call C# functions from javascript and a proxy for that webbrowser control (source).
Each function on its own works. But when i combine them, the calls from javascript doesn't work anymore. Errormessage is
Object doesn't support property or method "Test"
Sourcecode for an example is on the bottom.
You can try both functionality when commenting and uncommenting this block in Form1_Load
// Comment this block for Callback working
object obj = webBrowser1.ActiveXInstance;
IOleObject oc = obj as IOleObject;
oc.SetClientSite(Proxy as IOleClientSite);
I guess the problem is the function QueryService
from the interface IServiceProvider
. I tried to pin it down with the GUID from Scriptmanager
but found no solution.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ProxyTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
proxy Proxy = new proxy();
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("about:blank");
// Comment this block for Callback working
object obj = webBrowser1.ActiveXInstance;
IOleObject oc = obj as IOleObject;
oc.SetClientSite(Proxy as IOleClientSite);
//Proxy settings are not necessary
Proxy._currentUsername = ""; // Username
Proxy._currentPassword = ""; // Password
Proxy.SetProxyServer(""); //IP:PORT
webBrowser1.ObjectForScripting = new Scriptmanager();
Application.DoEvents();
webBrowser1.DocumentText =
"<html><head><script>" +
"function test(message) { alert(message); }" +
"</script></head><body><button " +
"onclick=\"window.external.Test('called from script code')\">" +
"call client code from script code</button>" +
"</body></html>";
}
}
[ComVisible(true)]
public class Scriptmanager
{
public void Test(string text)
{
MessageBox.Show(text);
}
}
public class proxy : IOleClientSite, IServiceProvider, IAuthenticate
{
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption,
IntPtr lpBuffer, int lpdwBufferLength);
private Guid IID_IAuthenticate = new Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b");
private const int INET_E_DEFAULT_ACTION = unchecked((int)0x800C0011);
private const int S_OK = unchecked((int)0x00000000);
private const int INTERNET_OPTION_PROXY = 38;
private const int INTERNET_OPEN_TYPE_DIRECT = 1;
private const int INTERNET_OPEN_TYPE_PROXY = 3;
internal string _currentUsername;
internal string _currentPassword;
internal void SetProxyServer(string proxy)
{
//Create structure
INTERNET_PROXY_INFO proxyInfo = new INTERNET_PROXY_INFO();
if (proxy == null)
{
proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
}
else
{
proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
proxyInfo.proxy = Marshal.StringToHGlobalAnsi(proxy);
proxyInfo.proxyBypass = Marshal.StringToHGlobalAnsi("local");
}
// Allocate memory
IntPtr proxyInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(proxyInfo));
// Convert structure to IntPtr
Marshal.StructureToPtr(proxyInfo, proxyInfoPtr, true);
bool returnValue = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY,
proxyInfoPtr, Marshal.SizeOf(proxyInfo));
}
#region IOleClientSite Members
public void SaveObject()
{
// TODO: Add Form1.SaveObject implementation
}
public void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk)
{
// TODO: Add Form1.GetMoniker implementation
}
public void GetContainer(object ppContainer)
{
ppContainer = this;
}
public void ShowObject()
{
// TODO: Add Form1.ShowObject implementation
}
public void OnShowWindow(bool fShow)
{
// TODO: Add Form1.OnShowWindow implementation
}
public void RequestNewObjectLayout()
{
// TODO: Add Form1.RequestNewObjectLayout implementation
}
#endregion
#region IServiceProvider Members
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
int nRet = guidService.CompareTo(IID_IAuthenticate);
if (nRet == 0)
{
nRet = riid.CompareTo(IID_IAuthenticate);
if (nRet == 0)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IAuthenticate));
return S_OK;
}
}
ppvObject = new IntPtr();
return INET_E_DEFAULT_ACTION;
}
#endregion
#region IAuthenticate Members
public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword)
{
IntPtr sUser = Marshal.StringToCoTaskMemAuto(_currentUsername);
IntPtr sPassword = Marshal.StringToCoTaskMemAuto(_currentPassword);
pszUsername = sUser;
pszPassword = sPassword;
return S_OK;
}
#endregion
}
public struct INTERNET_PROXY_INFO
{
public int dwAccessType;
public IntPtr proxy;
public IntPtr proxyBypass;
}
#region COM Interfaces
[ComImport, Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
void SetClientSite(IOleClientSite pClientSite);
void GetClientSite(IOleClientSite ppClientSite);
void SetHostNames(object szContainerApp, object szContainerObj);
void Close(uint dwSaveOption);
void SetMoniker(uint dwWhichMoniker, object pmk);
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void InitFromData(IDataObject pDataObject, bool
fCreation, uint dwReserved);
void GetClipboardData(uint dwReserved, IDataObject ppDataObject);
void DoVerb(uint iVerb, uint lpmsg, object pActiveSite,
uint lindex, uint hwndParent, uint lprcPosRect);
void EnumVerbs(object ppEnumOleVerb);
void Update();
void IsUpToDate();
void GetUserClassID(uint pClsid);
void GetUserType(uint dwFormOfType, uint pszUserType);
void SetExtent(uint dwDrawAspect, uint psizel);
void GetExtent(uint dwDrawAspect, uint psizel);
void Advise(object pAdvSink, uint pdwConnection);
void Unadvise(uint dwConnection);
void EnumAdvise(object ppenumAdvise);
void GetMiscStatus(uint dwAspect, uint pdwStatus);
void SetColorScheme(object pLogpal);
}
[ComImport, Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleClientSite
{
void SaveObject();
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void GetContainer(object ppContainer);
void ShowObject();
void OnShowWindow(bool fShow);
void RequestNewObjectLayout();
}
[ComImport, GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
[ComImport, GuidAttribute("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]
public interface IAuthenticate
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword);
}
#endregion
}
Update 01.11.2016 This tip from Sheng Jiang 蒋晟 was really good. I almost have a working example. The messagebox is shown after the click. Sadly afterwards comes a InvalidVariant exception. Anybody has a guess what's wrong. I'm stuck again. Here is the current code.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ProxyTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
proxy Proxy = new proxy();
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("about:blank");
// Comment this block for Callback working
object obj = webBrowser1.ActiveXInstance;
IOleObject oc = obj as IOleObject;
oc.SetClientSite(Proxy as IOleClientSite);
//Proxy settings are not necessary
Proxy._currentUsername = ""; // Username
Proxy._currentPassword = ""; // Password
Proxy.SetProxyServer(""); //IP:PORT
webBrowser1.ObjectForScripting = new Scriptmanager();
Application.DoEvents();
webBrowser1.DocumentText =
"<html><head><script>" +
"function test(message) { alert(message); }" +
"</script></head><body><button " +
"onclick=\"window.external.Test('called from script code')\">" +
"call client code from script code</button>" +
"</body></html>";
}
}
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IScriptmanager
{
void Test(string text);
}
[ComVisible(true)]
public class Scriptmanager : IScriptmanager
{
public void Test(string text)
{
MessageBox.Show(text);
}
}
public class proxy : IOleClientSite, IServiceProvider, IAuthenticate, IDocHostUIHandler
{
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption,
IntPtr lpBuffer, int lpdwBufferLength);
private Guid IID_IAuthenticate = new Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b");
private const int INET_E_DEFAULT_ACTION = unchecked((int)0x800C0011);
private const int S_OK = unchecked((int)0x00000000);
private const int INTERNET_OPTION_PROXY = 38;
private const int INTERNET_OPEN_TYPE_DIRECT = 1;
private const int INTERNET_OPEN_TYPE_PROXY = 3;
internal string _currentUsername;
internal string _currentPassword;
IDocHostUIHandler _baseIDocHostUIHandler;
internal void SetProxyServer(string proxy)
{
//Create structure
INTERNET_PROXY_INFO proxyInfo = new INTERNET_PROXY_INFO();
if (proxy == null)
{
proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
}
else
{
proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
proxyInfo.proxy = Marshal.StringToHGlobalAnsi(proxy);
proxyInfo.proxyBypass = Marshal.StringToHGlobalAnsi("local");
}
// Allocate memory
IntPtr proxyInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(proxyInfo));
// Convert structure to IntPtr
Marshal.StructureToPtr(proxyInfo, proxyInfoPtr, true);
bool returnValue = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY,
proxyInfoPtr, Marshal.SizeOf(proxyInfo));
}
#region IOleClientSite Members
public void SaveObject()
{
// TODO: Add Form1.SaveObject implementation
}
public void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk)
{
// TODO: Add Form1.GetMoniker implementation
}
public void GetContainer(object ppContainer)
{
ppContainer = this;
}
public void ShowObject()
{
// TODO: Add Form1.ShowObject implementation
}
public void OnShowWindow(bool fShow)
{
// TODO: Add Form1.OnShowWindow implementation
}
public void RequestNewObjectLayout()
{
// TODO: Add Form1.RequestNewObjectLayout implementation
}
#endregion
#region IServiceProvider Members
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
int nRet = guidService.CompareTo(IID_IAuthenticate);
if (nRet == 0)
{
nRet = riid.CompareTo(IID_IAuthenticate);
if (nRet == 0)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IAuthenticate));
return S_OK;
}
}
ppvObject = new IntPtr();
return INET_E_DEFAULT_ACTION;
}
#endregion
#region IAuthenticate Members
public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword)
{
IntPtr sUser = Marshal.StringToCoTaskMemAuto(_currentUsername);
IntPtr sPassword = Marshal.StringToCoTaskMemAuto(_currentPassword);
pszUsername = sUser;
pszPassword = sPassword;
return S_OK;
}
#endregion
#region IDocHostUIHandler Members
public uint ShowContextMenu(uint dwID, ref tagPOINT ppt, [MarshalAs(UnmanagedType.IUnknown)] object pcmdtReserved, [MarshalAs(UnmanagedType.IDispatch)] object pdispReserved)
{
const int MenuNotHandled = 1;
return MenuNotHandled;
}
public void GetHostInfo(ref DOCHOSTUIINFO pInfo)
{
// turn three flags on
pInfo.dwFlags |= (uint)(DOCHOSTUIFLAG.DOCHOSTUIFLAG_SCROLL_NO |
DOCHOSTUIFLAG.DOCHOSTUIFLAG_NO3DBORDER |
DOCHOSTUIFLAG.DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE);
}
public void ShowUI(uint dwID, ref object pActiveObject, ref object pCommandTarget, ref object pFrame, ref object pDoc)
{
//throw new NotImplementedException();
}
public void HideUI()
{
// throw new NotImplementedException();
}
public void UpdateUI()
{
// throw new NotImplementedException();
}
public void EnableModeless(int fEnable)
{
//throw new NotImplementedException();
}
public void OnDocWindowActivate(int fActivate)
{
//throw new NotImplementedException();
}
public void OnFrameWindowActivate(int fActivate)
{
//throw new NotImplementedException();
}
public void ResizeBorder(ref tagRECT prcBorder, int pUIWindow, int fFrameWindow)
{
//throw new NotImplementedException();
}
public uint TranslateAccelerator(ref tagMSG lpMsg, ref Guid pguidCmdGroup, uint nCmdID)
{
const int KillAccelerator = 0;
const int AllowAccelerator = 1;
const int WM_KEYDOWN = 0x0100;
if (lpMsg.message != WM_KEYDOWN)
// allow message
return AllowAccelerator;
if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
return AllowAccelerator;
// disable the Ctrl-N and Ctrl-P accelerators
lpMsg.wParam &= 0xFF; // get the virtual keycode
if ((lpMsg.wParam == 'N') || ((lpMsg.wParam == 'P')))
return KillAccelerator;
// allow everything else
return AllowAccelerator;
}
public void GetOptionKeyPath([MarshalAs(UnmanagedType.BStr)] ref string pchKey, uint dw)
{
// throw new NotImplementedException();
}
public uint GetDropTarget(int pDropTarget, ref int ppDropTarget)
{
const int S_OK = 0;
return S_OK;
}
//public object GetDropTarget(ref object pDropTarget)
//{
// return pDropTarget;
//}
public void GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch)
{
ppDispatch = new Scriptmanager();
}
public uint TranslateUrl(uint dwTranslate, [MarshalAs(UnmanagedType.BStr)] string pchURLIn, [MarshalAs(UnmanagedType.BStr)] ref string ppchURLOut)
{
const int NotTranslated = 1;
return NotTranslated;
}
public IDataObject FilterDataObject(IDataObject pDO)
{
return null;
}
#endregion
}
public struct INTERNET_PROXY_INFO
{
public int dwAccessType;
public IntPtr proxy;
public IntPtr proxyBypass;
}
public struct tagRECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct tagPOINT
{
public int x;
public int y;
}
public enum DOCHOSTUITYPE
{
DOCHOSTUITYPE_BROWSE = 0,
DOCHOSTUITYPE_AUTHOR = 1
}
public enum DOCHOSTUIDBLCLK
{
DOCHOSTUIDBLCLK_DEFAULT = 0,
DOCHOSTUIDBLCLK_SHOWPROPERTIES = 1,
DOCHOSTUIDBLCLK_SHOWCODE = 2
}
[Flags()]
public enum DOCHOSTUIFLAG
{
DOCHOSTUIFLAG_DIALOG = 0x00000001,
DOCHOSTUIFLAG_DISABLE_HELP_MENU = 0x00000002,
DOCHOSTUIFLAG_NO3DBORDER = 0x00000004,
DOCHOSTUIFLAG_SCROLL_NO = 0x00000008,
DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE = 0x00000010,
DOCHOSTUIFLAG_OPENNEWWIN = 0x00000020,
DOCHOSTUIFLAG_DISABLE_OFFSCREEN = 0x00000040,
DOCHOSTUIFLAG_FLAT_SCROLLBAR = 0x00000080,
DOCHOSTUIFLAG_DIV_BLOCKDEFAULT = 0x00000100,
DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY = 0x00000200,
DOCHOSTUIFLAG_OVERRIDEBEHAVIORFACTORY = 0x00000400,
DOCHOSTUIFLAG_CODEPAGELINKEDFONTS = 0x00000800,
DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8 = 0x00001000,
DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 = 0x00002000,
DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE = 0x00004000,
DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION = 0x00010000,
DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION = 0x00020000,
DOCHOSTUIFLAG_THEME = 0x00040000,
DOCHOSTUIFLAG_NOTHEME = 0x00080000,
DOCHOSTUIFLAG_NOPICS = 0x00100000,
DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000,
DOCHOSTUIFLAG_DISABLE_EDIT_NS_FIXUP = 0x400000,
DOCHOSTUIFLAG_LOCAL_MACHINE_ACCESS_CHECK = 0x800000,
DOCHOSTUIFLAG_DISABLE_UNTRUSTEDPROTOCOL = 0x1000000
}
[StructLayout(LayoutKind.Sequential)]
public struct DOCHOSTUIINFO
{
public uint cbSize;
public uint dwFlags;
public uint dwDoubleClick;
[MarshalAs(UnmanagedType.BStr)]
public string pchHostCss;
[MarshalAs(UnmanagedType.BStr)]
public string pchHostNS;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagMSG
{
public IntPtr hwnd;
public uint message;
public uint wParam;
public int lParam;
public uint time;
public tagPOINT pt;
}
#region COM Interfaces
[ComImport, Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
void SetClientSite(IOleClientSite pClientSite);
void GetClientSite(IOleClientSite ppClientSite);
void SetHostNames(object szContainerApp, object szContainerObj);
void Close(uint dwSaveOption);
void SetMoniker(uint dwWhichMoniker, object pmk);
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void InitFromData(IDataObject pDataObject, bool
fCreation, uint dwReserved);
void GetClipboardData(uint dwReserved, IDataObject ppDataObject);
void DoVerb(uint iVerb, uint lpmsg, object pActiveSite,
uint lindex, uint hwndParent, uint lprcPosRect);
void EnumVerbs(object ppEnumOleVerb);
void Update();
void IsUpToDate();
void GetUserClassID(uint pClsid);
void GetUserType(uint dwFormOfType, uint pszUserType);
void SetExtent(uint dwDrawAspect, uint psizel);
void GetExtent(uint dwDrawAspect, uint psizel);
void Advise(object pAdvSink, uint pdwConnection);
void Unadvise(uint dwConnection);
void EnumAdvise(object ppenumAdvise);
void GetMiscStatus(uint dwAspect, uint pdwStatus);
void SetColorScheme(object pLogpal);
}
[ComImport, Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleClientSite
{
void SaveObject();
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void GetContainer(object ppContainer);
void ShowObject();
void OnShowWindow(bool fShow);
void RequestNewObjectLayout();
}
[ComImport, GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
[ComImport, GuidAttribute("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]
public interface IAuthenticate
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword);
}
[ComImport()]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[GuidAttribute("bd3f23c0-d43e-11cf-893b-00aa00bdce1a")]
public interface IDocHostUIHandler
{
[PreserveSig]
uint ShowContextMenu(
uint dwID,
ref tagPOINT ppt,
[MarshalAs(UnmanagedType.IUnknown)] object pcmdtReserved,
[MarshalAs(UnmanagedType.IDispatch)] object pdispReserved
);
void GetHostInfo(ref DOCHOSTUIINFO pInfo);
void ShowUI(uint dwID, ref object pActiveObject, ref object pCommandTarget, ref object pFrame, ref object pDoc);
void HideUI();
void UpdateUI();
void EnableModeless(int fEnable);
void OnDocWindowActivate(int fActivate);
void OnFrameWindowActivate(int fActivate);
void ResizeBorder(ref tagRECT prcBorder, int pUIWindow, int fFrameWindow);
[PreserveSig]
uint TranslateAccelerator(ref tagMSG lpMsg, ref Guid pguidCmdGroup, uint nCmdID);
void GetOptionKeyPath([MarshalAs(UnmanagedType.BStr)] ref string pchKey, uint dw);
uint GetDropTarget(int pDropTarget, ref int ppDropTarget);
//object GetDropTarget(ref object pDropTarget);
[PreserveSig]
void GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch);
[PreserveSig]
uint TranslateUrl(
uint dwTranslate,
[MarshalAs(UnmanagedType.BStr)] string pchURLIn,
[MarshalAs(UnmanagedType.BStr)] ref string ppchURLOut
);
IDataObject FilterDataObject(IDataObject pDO);
}
#endregion
}