【问题标题】:Calling C# BHO methods from Javascript (still not working)从 Javascript 调用 C# BHO 方法(仍然无法正常工作)
【发布时间】:2013-02-10 17:00:55
【问题描述】:

我完全按照this 回答并阅读并重新阅读了所有谷歌发现。不幸的是,大多数人都只是引用答案的复制和粘贴(包括“停止将头撞到墙上去庆祝!”)句子,它对我不起作用......所以经过半天的工作我真的要开始敲我的头了...

我的简单错误: javascript windows.myExtension 对象是“未定义的”,因此在其上调用 Foo 会引发错误。请参阅下面的完整来源。似乎该属性集在 javascript 端是不可见的。

更多信息:

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

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

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

请让我帮忙运行这个... 提前谢谢

简单的测试页面:

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
    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 
    </script>
    <title></title>
</head>
<body>

</body>
</html>

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。试试这个 hack 测试:setTimeout(function() { console.log(window.myExtension); }, 1000); 1 秒后它应该向控制台输出一些东西。此时,应该加载文档并且您应该得到答案。请在此测试后报告。
  • 感谢您的想法。我已经试过了,现在又试了。这不是时间问题。 window.myExtension 在延迟调用中仍未定义:-(
  • @Dalorzo 请停止琐碎的编辑,例如在不需要的地方添加标签。我浏览了您的历史记录,您最近提出的大部分修改建议都应该被拒绝。通过进行此类微不足道的(通常是错误的和/或不完整的)编辑,您会不必要地将旧问题放到首页。
  • @Rob W 我不认为它们微不足道。我希望这些能让更多的人看到一个悬而未决的问题。最后,老问题值得回答。
  • @g.pickardou 嗨,你成功了,所以解决这个问题?

标签: c# internet-explorer com bho


【解决方案1】:

我对此有一个 hack-y 解决方案。它现在对我有用,所以我把它贴在这里。如果我遇到任何问题,我会更新这篇文章。

@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有什么用,不检查是否为空有什么影响等等。

【讨论】:

  • 如果有人在新标签页中打开链接或按下刷新按钮超过 2 次,此解决方案将不起作用。
【解决方案2】:

试试 window.external.myExtension(); 据我所知,外部是保存您表单的对象。 此外,如果这不起作用 - 请务必先尝试简单的事情,然后反其道而行之。

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

[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."));
}

【讨论】:

    猜你喜欢
    • 2012-03-06
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    相关资源
    最近更新 更多