从Javascript调用BHO方法? [英] Calling BHO method from Javascript?

查看:214
本文介绍了从Javascript调用BHO方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从javascript调用我的BHO方法。问题与以下帖子中所述相同:

I am trying to call my BHO method from the javascript. The problem is same as stated in the the following posts:


  1. 从Javascript函数调用BHO

  2. http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e -4795-4d9e-9b07-5b9c9eca62fb /

  3. 从Web浏览器控件中运行的JavaScript脚本调用C ++函数

  1. Call BHO from Javascript function
  2. http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e-4795-4d9e-9b07-5b9c9eca62fb/
  3. Calling C++ function from JavaScript script running in a web browser control

第三个链接是另一个关于它的SO帖子,但我不了解需求和代码。此外,共享工作示例在Windows 7上保持崩溃,即8和windows vista,即7。

Third link is another SO post talking about it, but I did not understand the need and code. Also the shared working sample keeps crashing on windows 7 with ie 8 and windows vista with ie 7.

如果它有助于我的BHO使用ATL用C ++编写。

If it helps my BHO is written in C++ using ATL.

我尝试了什么:

我写了一个非常基本的BHO和尝试了这里提到的方法 Igor Tandetnik 。没有生成异常但是当我在IE中打开以下html文件时它会说对象未定义

I have written a very basic BHO and tried the approach as mentioned here by Igor Tandetnik. There is no exception generated but when I open the following html file in IE then it says object undefined.

<html>
    <head>
        <script language='javascript'>
            function call_external(){
                try{
                alert(window.external.TestScript);
                //JQueryTest.HelloJquery('a');
                }catch(err){
                    alert(err.description );
                }
            }
        </script>
    </head>
    <body id='bodyid' onload="call_external();">
        <center><div><span>Hello jQuery!!</span></div></center>
    </boay>
</html>

问题:


  1. 请说明是否可以通过javascript公开和调用BHO方法,或者是否必须使用activex公开它(在 href中通过 jeffdav 回答=http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e-4795-4d9e-9b07-5b9c9eca62fb/\"rel =nofollow noreferrer> [2] ) ?如果是,那么该怎么做。

  2. 基本上我想扩展 window.external 但是上面链接中显示的方式< a href =http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e-4795-4d9e-9b07-5b9c9eca62fb/\"rel =nofollow noreferrer> [2] 使用 var x = new ActiveXObject(MySampleATL.MyClass); ;调用约定是相同还是不同?

  1. Please clarify whether is it possible to expose and call BHO method from javascript or do i have to expose it using an activex (as answered by jeffdav in [2] )? If yes then how to do it.
  2. Basically i want to extend the window.external but the way shown in the above link [2] uses var x = new ActiveXObject("MySampleATL.MyClass");; Is both the calling conventions are same or different?

注意:


  1. 在SO上有一个相关的帖子,它提示可以插入这个 [id(1),helpstring(方法DoSomething)] HRESULT DoSomething(); 在BHO IDL文件中。我不确定它是如何完成的,也无法通过谷歌找到任何支持资源。

  2. 我知道这篇文章调用你的bho-from-a-客户端脚本,但没有尝试过,因为它正在使用ActiveX解决问题。

  3. 我避免使用ActiveX的原因主要是出于安全限制。

  1. There is a related post on SO which gives hint that it is possible through inserting this [id(1), helpstring("method DoSomething")] HRESULT DoSomething(); in the BHO IDL file. I am not sure how it was done and couldn't find any supporting resource through google.
  2. I am aware of this post calling-into-your-bho-from-a-client-script, but haven't tried it as it is solving the problem using ActiveX.
  3. My reason to avoid ActiveX is primarily due to the security restrictions.

编辑1



似乎有一种方法可以扩展 window.external 。查看。特别是标题为的部分IDocHostUIHandler :: GetExternal:扩展DOM。现在假设我们的IDispatch接口位于实现IDocHostUIHandler的同一对象上。然后我们可以这样做:

Edit 1


It seems there is a way to extend the window.external. Check this. Specially the section titled IDocHostUIHandler::GetExternal: Extending the DOM.Now assuming our IDispatch interface is on the same object that implements IDocHostUIHandler. Then we can do something like this:

HRESULT CBrowserHost::GetExternal(IDispatch **ppDispatch) 
{
    *ppDispatch = this;
    return S_OK;
}

这种方法的问题就是赢了不附加到现有的Windows方法,而是替换它们。请告诉我是否错了。

The problem with this approach is that it won't append to the existing windows methods, but rather replace them. Please tell if I am wrong.

编辑2



BHO类:

Edit 2


The BHO Class:

class ATL_NO_VTABLE CTestScript :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CTestScript, &CLSID_TestScript>,
    public IObjectWithSiteImpl<CTestScript>,
    public IDispatchImpl<ITestScript, &IID_ITestScript, &LIBID_TestBHOLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDispEventImpl<1, CTestScript, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
{
public:
    CTestScript()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_TESTSCRIPT)

DECLARE_NOT_AGGREGATABLE(CTestScript)

BEGIN_COM_MAP(CTestScript)
    COM_INTERFACE_ENTRY(ITestScript)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()



    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:
    BEGIN_SINK_MAP(CTestScript)
        SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
        //SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigationComplete)
    END_SINK_MAP()

    void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
    //void STDMETHODCALLTYPE OnNavigationComplete(IDispatch *pDisp, VARIANT *pvarURL);

    STDMETHOD(SetSite)(IUnknown *pUnkSite);

    HRESULT STDMETHODCALLTYPE DoSomething(){
        ::MessageBox(NULL, L"Hello", L"World", MB_OK);
        return S_OK;
    }
public:

//private:
    // InstallBHOMethod();

private:
    CComPtr<IWebBrowser2>  m_spWebBrowser;
    BOOL m_fAdvised;
};

// TestScript.cpp:CTestScript的实现

// TestScript.cpp : Implementation of CTestScript

#include "stdafx.h"
#include "TestScript.h"


// CTestScript

STDMETHODIMP CTestScript::SetSite(IUnknown* pUnkSite)
{
    if (pUnkSite != NULL)
    {
        HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
        if (SUCCEEDED(hr))
        {
            hr = DispEventAdvise(m_spWebBrowser);
            if (SUCCEEDED(hr))
            {
                m_fAdvised = TRUE;              
            }
        }
    }else
    {
        if (m_fAdvised)
        {
            DispEventUnadvise(m_spWebBrowser);
            m_fAdvised = FALSE;
        }
        m_spWebBrowser.Release();
    }
    return IObjectWithSiteImpl<CTestScript>::SetSite(pUnkSite);
}

void STDMETHODCALLTYPE CTestScript::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
        CComPtr<IDispatch> dispDoc;
        CComPtr<IHTMLDocument2> ifDoc;
        CComPtr<IHTMLWindow2> ifWnd;
        CComPtr<IDispatchEx> dispxWnd;

        HRESULT hr = m_spWebBrowser->get_Document( &dispDoc );
        hr = dispDoc.QueryInterface( &ifDoc );      
        hr = ifDoc->get_parentWindow( &ifWnd );
        hr = ifWnd.QueryInterface( &dispxWnd );

        // now ... be careful. Do exactly as described here. Very easy to make mistakes
        CComBSTR propName( L"myBho" );
        DISPID dispid;
        hr = dispxWnd->GetDispID( propName, fdexNameEnsure, &dispid );

        CComVariant varMyBho( (IDispatch*)this );
        DISPPARAMS params;
        params.cArgs = 1;
        params.cNamedArgs = 0;
        params.rgvarg = &varMyBho;            
        params.rgdispidNamedArgs = NULL;
        hr = dispxWnd->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
            &params, NULL, NULL, NULL );

}

Javascript:

The Javascript:

<script language='javascript'>
            function call_external(){
                try{
                alert(window.ITestScript);
                }catch(err){
                    alert(err.description );
                }
            }
        </script>

编辑3



之后花了三天时间,我想我应该采取ActiveX路径。编写一个基本的activex只是简单易用的方法,并且可以在所有主要的IE版本上进行测试。我将这个问题保持开放,请参阅Uri的回答中的评论(非常感谢他)。我已经尝试了他的大部分建议(除了4和5)。 我还建议您查看MSDN IDispatcEx示例。如果您找到解决方案,请发帖,如果我找到解决方案,那么我肯定会在这里更新。

Edit 3


After spending three days on this, I think I should take the ActiveX path. Writing a basic activex is just way to easy, written one and tested on all major IE releases. I am leaving this question as open, please see comments in Uri's answer (many thanks to him). I have tried most of his suggestions (except for 4 and 5). I will also suggest you to see the MSDN IDispatcEx sample. If you find a solution then please post, if I find a solution then I will definitely update here.

编辑4



查看我在URI中的最后评论帖子。问题已解决。

Edit 4


See my last comment in URI's post. Issue Resolved.

推荐答案

Igor Tandetnik的方法是正确的方法。这篇文章的问题在于示例代码(至少在我发现的几页上)是不完整的。我有很多试验和错误,直到我开始工作。
以下是我的代码的大部分功能:

Igor Tandetnik's method is the correct approach. The problem with the post is that the sample code (at least on the few pages I spotted it) is that it wasn't complete. I had many trials and errors, until I got it working. Here is good chunk of my code that does the trick:

假设您有一个类CMyBho,并且您希望为Java脚本公开IMyBho自动化对象

Say you have a class CMyBho, and you want to expose IMyBho automation object for Java scripts

类定义:

您可以从标准CComObjectRootEx和CComCoClass派生,使其共同创建。您有IObjectWithSiteImpl(重用此基类实现的m_spUnkSite)。 IDispatchImpl实现您的自动化对象,IDispatchEventImpl是从浏览器获取通知的接收器:

Class definition:
You derive from the standard CComObjectRootEx, and CComCoClass to make it 'co creatble'. You have IObjectWithSiteImpl (reuse the m_spUnkSite implemented by this base class). IDispatchImpl implements your automation object, and IDispatchEventImpl is the sink to get notifications from the browser:

class ATL_NO_VTABLE CMyBho
    : public CComObjectRootEx<CComSingleThreadModel>
    , public CComCoClass<CMyBho, &CLSID_MyBho>
    , public IObjectWithSiteImpl<CMyBho>
    , public IDispatchImpl<IMyBho, &IID_IMyBho, &LIBID_MyBhoLib, 1, 0>
    , IDispatchEventImpl<1, CMyBho, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
{
    ...

public:
    BEGIN_COM_MAP(CMyBho)
        COM_INTERFACE_ENTRY(IMyBho)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IObjectWithSite)
    END_COM_MAP()

    ...

    BEGIN_SINK_MAP(CMyBho)
        SINK_ENTRY_EX( 1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocComplete )
    END_SINK_MAP()

    ...

private:
    CComPtr<IWebBrowser2> m_ifbrz;          // pointer to the hosting browser

}

接下来,SetSite方法,您在哪里注册以获得通知。不要忘记调用基类。

Next, the SetSite method, where you register to get notification. Don't forget to call the base class.

STDMETHODIMP CMyBho::SetSite( IUnknown* unkSite )
{
    ...
    hr = IObjectWithSiteImpl::SetSite( unkSite );
    if( unkSite ) {
        ...
        // advise to browser event.
        CComPtr<IServiceProvider> ifsp;
        hr = m_spUnkSite.QueryInterface( &ifsp );
        hr = ifsp->QueryService( SID_SwebBrowserApp, IID_IWebBrowser2, &m_ifbrz );
        hr = DispEventAdvise( m_ifbrz );
    }
    else {
        // release various resources (m_ifbrz will be released automatically by its dtor)
        ...
    }
...
}

当文档加载完成后,将调用此函数:

When document load is complete, this function will be called:

void STDMETHODCALLTYPE CMyBho::onDocComplete( IDispatch* dispBrz, VARIANT* pvarUrl )
{
    CComPtr<IDispatch> dispDoc;
    CComPtr<IHTMLDocument2> ifDoc;
    CComPtr<IHTMLWindow2> ifWnd;
    CComPtr<IDispatchEx> dispxWnd;

    hr = m_ifbrz->get_Document( &dispDoc );
    hr = dispDoc.QueryInterface( &ifDoc );      
    hr = ifDoc->get_parentWindow( &ifWnd );
    hr = ifWnd.QueryInterface( &dispxWnd );

    // now ... be careful. Do exactly as described here. Very easy to make mistakes
    CComBSTR propName( L"myBho" );
    DISPID dispid;
    hr = dispxWnd->GetDispID( propName, fdexNameEnsure, &dispid );

    CComVariant varMyBho( (IDispatch*)this );
    DISPPARAMS params;
    params.cArgs = 1;
    params.cNamedArgs = 0;
    params.rgvarg = &varMyBho;            
    params.rgdispidNamedArgs = NULL;
    hr = dispxWnd->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
                           &params, NULL, NULL, NULL );
}

至于你的其他问题:


  • 显然,我的回答意味着你可以从你的BHO创建一个自动化对象来编写脚本。您的对象也可以使用新的ActiveXObject进行实例化。在这种情况下,不要忘记告诉IE你的对象是安全的脚本(旁注:让你的BHO安全的脚本。确保恶意网站将无法利用你的BHO)。

  • Evidently, my answer implies that you can makes an automation object available for scripting from your BHO. It is also possible your object will be instantiated with new ActiveXObject. In that case don't forget to tell IE your object is safe for scripting (side note: make your BHO safe for scripting. make sure malicious web site won't be able to exploit your BHO).

我认为window.myBho比window.external.myBho更好。从语义上讲,'external'是指mshtml
浏览器控件托管在另一个应用程序中。

I think that window.myBho is a better place than window.external.myBho. Semantically, 'external' is when the mshtml browser control is hosted within another application.

希望这个帮助。

这篇关于从Javascript调用BHO方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆