从Javascript调用C#BHO方法(仍然无法正常工作)

我完全按照这个答案阅读并重读了所有谷歌的调查结果。 不幸的是,大部分都只是参考答案的复制和粘贴(包括“停止撞墙而去庆祝!”)的句子,这对我不起作用…所以经过半天的工作后,我真的要开始敲我的脑袋了……

我的简单错误:javascript windows.myExtension对象是’undefined’所以在它上面调用Foo会引发错误。 请参阅下面的完整资源。 看起来属性集在javascript方面是不可见的。

更多信息:

  • 我使用Debugger.Launch()语句来方便地调试我的扩展,并且命中断点,并且所有BHO扩展函数都被正确调用并运行。
  • 注释的替代(使用property.SetProperty)也不起作用,具有相同的错误:

    的console.log(window.myExtension); //写’undefined’,为什么?

  • 使用VS 2010,Windows 7 x64,IE 9

请让我帮忙运行这个… Thx提前

简单的测试页面:

    console.log(window.myExtension); // Writes undefined why? It should be an object... var result = window.myExtension.Foo("bar"); // Obviously throws and error if window.myExtension is undefined       

BrowserHelperObject.cs

 using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Expando; using Microsoft.Win32; using SHDocVw; namespace IEExtensionTest { [ComVisible(true)] [Guid("DA8EA345-02AE-434E-82E9-448E3DB7629E")] [ClassInterface(ClassInterfaceType.None)] [ProgId("MyExtension")] [ComDefaultInterface(typeof(IExtension))] public class BrowserHelperObject : IObjectWithSite, IExtension { private WebBrowser webBrowser; public int Foo(string s) { return 0; } public void OnDocumentComplete(dynamic frame, ref dynamic url) { Debugger.Launch(); dynamic window = webBrowser.Document.parentWindow; var windowEx = (IExpando)window; windowEx.AddProperty("myExtension"); window.myExtension = this; //var property = windowEx.AddProperty("MyExtension"); //property.SetValue(windowEx, this, null); } public static string BHOKEYNAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects"; [ComRegisterFunction] public static void RegisterBHO(Type type) { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true); if (registryKey == null) registryKey = Registry.LocalMachine.CreateSubKey(BHOKEYNAME); string guid = type.GUID.ToString("B"); RegistryKey ourKey = registryKey.OpenSubKey(guid); if (ourKey == null) ourKey = registryKey.CreateSubKey(guid); ourKey.SetValue("Alright", 1); registryKey.Close(); ourKey.Close(); } [ComUnregisterFunction] public static void UnregisterBHO(Type type) { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true); string guid = type.GUID.ToString("B"); if (registryKey != null) registryKey.DeleteSubKey(guid, false); } public int SetSite(object site) { if (site != null) { webBrowser = (WebBrowser)site; webBrowser.DocumentComplete += OnDocumentComplete; } else { webBrowser.DocumentComplete -= OnDocumentComplete; webBrowser = null; } return 0; } public int GetSite(ref Guid guid, out IntPtr ppvSite) { IntPtr punk = Marshal.GetIUnknownForObject(webBrowser); int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite); Marshal.Release(punk); return hr; } } 

IObjectWithSite.cs

 using System; using System.Runtime.InteropServices; namespace IEExtensionTest { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")] public interface IObjectWithSite { [PreserveSig] int SetSite([MarshalAs(UnmanagedType.IUnknown)] object site); [PreserveSig] int GetSite(ref Guid guid, out IntPtr ppvSite); } } 

IExtension.cs

 using System; using System.Runtime.InteropServices; namespace IEExtensionTest { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")] public interface IObjectWithSite { [PreserveSig] int SetSite([MarshalAs(UnmanagedType.IUnknown)] object site); [PreserveSig] int GetSite(ref Guid guid, out IntPtr ppvSite); } } 

后构建步骤配置如下(并正确运行):

 "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)" 

试试窗口。 外部 .myExtension(); 外部是我记得持有你的forms的对象。 此外,如果这不起作用 – 一定要先尝试简单的事情,然后反而采取相反的措施。

这是一个适合您的简单表单:

 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] // Note full trust. [System.Runtime.InteropServices.ComVisibleAttribute(true)] public partial class BasicJSScriptableForm : Form { private void BasicJSScriptableForm _Load(object sender, EventArgs e){ this.WebBrowser1.Navigate("yourpage"); } public string TestMethod(string input){ return string.Format("echo: {0}", input); } } 

然后在页面中:

 $(document).ready(function() { alert(window.external.TestMethod("It will hopefully work.")); } 

我对此有一个黑客解决方案。 它现在正在为我工​​作所以我在这里发布它。 如果我遇到任何问题,我会更新这篇文章。

@Eli Gassert正确识别问题。 在SetSite函数中,我们向DocumentComplete事件添加了一个处理程序。 所以当我们在$.ready()时它不会被执行。

所以我所做的是为BeforeScriptExecute事件添加处理程序。 这是我BHO.cs的相关部分

 public int SetSite(object site) { this.site = site; if(site != null) { webBrowser = (IWebBrowser2)site; ((DWebBrowserEvents2_Event)webBrowser).BeforeScriptExecute += S2_BeforeScriptExecute; //((DWebBrowserEvents2_Event)webBrowser).DocumentComplete += S2_DocumentComplete; } else { ((DWebBrowserEvents2_Event)webBrowser).BeforeScriptExecute -= S2_BeforeScriptExecute; //((DWebBrowserEvents2_Event)webBrowser).DocumentComplete -= S2_DocumentComplete; webBrowser = null; } return 0; } 

处理程序的签名是不同的,这是处理程序的代码。 这仍然在BHO.cs中

  private void S2_BeforeScriptExecute(object pDispWindow) { //if (pDisp != this.site) { return; } dynamic window = webBrowser.Document.parentWindow; IExpando windowEx = (IExpando)window; windowEx.AddProperty("myprop"); window.myprop = this; } 

我只是粘贴了DocumentComplete方法中的代码,并在顶部注释掉了条件。

结果,我能够在jquery $.ready()看到myprop 。 这解决了我的直接问题,我正在推进我的代码。

不用说,我的插件只提供了从javascript调用的方法,不需要对文档内容做任何事情。

我还不知道pDispWindow的用途是什么,不检查它是否为null的影响是什么等。