Internet explorer 从Javascript调用BHO方法?

Internet explorer 从Javascript调用BHO方法?,internet-explorer,activex,atl,bho,ieaddon,Internet Explorer,Activex,Atl,Bho,Ieaddon,我试图从javascript调用我的BHO方法。问题与以下帖子中所述的相同: 第三个链接是另一篇关于它的帖子,但我不理解它的需要和代码。此外,共享工作示例在使用ie 8的windows 7和使用ie 7的windows vista上不断崩溃 如果帮助我的BHO是用C++写的,使用ATL. 我尝试过的: 我写了一个非常基本的BHO,并尝试了Igor Tandetnik所提到的方法。没有生成异常,但当我在IE中打开以下html文件时,它会显示对象未定义 <html> <

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

  • 第三个链接是另一篇关于它的帖子,但我不理解它的需要和代码。此外,共享工作示例在使用ie 8的windows 7和使用ie 7的windows vista上不断崩溃

    如果帮助我的BHO是用C++写的,使用ATL. 我尝试过的:

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

    <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>
    
    这种方法的问题是它不会附加到现有的windows方法中,而是替换它们。如果我错了,请告诉我

    编辑2
    BHO类:

    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;
    };
    
    #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 );
    
    }
    
    <script language='javascript'>
                function call_external(){
                    try{
                    alert(window.ITestScript);
                    }catch(err){
                        alert(err.description );
                    }
                }
            </script>
    
    Javascript:

    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;
    };
    
    #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 );
    
    }
    
    <script language='javascript'>
                function call_external(){
                    try{
                    alert(window.ITestScript);
                    }catch(err){
                        alert(err.description );
                    }
                }
            </script>
    
    
    函数调用_external(){
    试一试{
    警报(window.ITestScript);
    }捕捉(错误){
    警报(错误描述);
    }
    }
    
    编辑3
    在花了三天的时间之后,我想我应该选择ActiveX路径。编写一个基本的activex只是一种简单的方法,它可以编写并在所有主要的IE版本上测试。我将这个问题留待讨论,请参阅Uri回答中的评论(非常感谢他)。我试过他的大部分建议(除了第4和第5条)
    我还建议您查看MSDN IDispatcEx示例
    。如果你找到一个解决方案,然后请张贴,如果我找到一个解决方案,那么我一定会更新这里

    编辑4

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

    Igor Tandetnik的方法是正确的方法。这篇文章的问题在于示例代码(至少在我发现的几页上)不完整。我经历了很多尝试和错误,直到我让它工作。
    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;
    };
    
    #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 );
    
    }
    
    <script language='javascript'>
                function call_external(){
                    try{
                    alert(window.ITestScript);
                    }catch(err){
                        alert(err.description );
                    }
                }
            </script>
    
    下面是我的一段代码:

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

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

    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
    
    }
    
    class ATL\u NO\u VTABLE CMyBho
    :public CComObjectRootEx
    ,公共CComCoClass
    ,公共IObjectWithSiteImpl
    ,公共图书馆
    ,IDispatchEventImpl
    {
    ...
    公众:
    开始COM地图(CMyBho)
    COM_接口_条目(IMyBho)
    COM_接口_条目(IDispatch)
    COM_接口_条目(IObjectWithSite)
    END_COM_MAP()
    ...
    开始\u接收器\u映射(CMyBho)
    接收项(1,DIID\U DWebbrowserEvents 2,DISPID\u DOCUMENTCOMPLETE,OnDocComplete)
    END_SINK_MAP()
    ...
    私人:
    CComPtr m_ifbrz;//指向宿主浏览器的指针
    }
    
    接下来是SetSite方法,您可以在其中注册以获取通知。别忘了调用基类

    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)
            ...
        }
    ...
    }
    
    STDMETHODIMP CMyBho::设置站点(IUnknown*未知站点)
    {
    ...
    hr=IObjectWithSiteImpl::SetSite(未确定位置);
    如果(未确定现场){
    ...
    //建议浏览事件。
    CComPtr ifsp;
    hr=m_spUnkSite.QueryInterface(&ifsp);
    hr=ifsp->QueryService(SID_SwebBrowserApp、IID_IWebBrowser2和m_ifbrz);
    hr=分散式台钳(m_ifbrz);
    }
    否则{
    //释放各种资源(m_ifbrz将由其dtor自动释放)
    ...
    }
    ...
    }
    
    文档加载完成后,将调用此函数:

    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 );
    }
    
    void STDMETHODCALLTYPE CMyBho::onDocComplete(IDispatch*dispBrz,VARIANT*pvarUrl)
    {
    CComPtr dispDoc;
    CComPtr ifDoc;
    CComPtr ifWnd;
    CComPtr dispxWnd;
    hr=m_ifbrz->get_Document(&dispDoc);
    hr=dispDoc.QueryInterface(&ifDoc);
    hr=ifDoc->get\u parentWindow(&ifWnd);
    hr=ifWnd.QueryInterface(&dispxWnd);
    //现在…小心点。完全按照这里描述的做。很容易出错
    CComBSTR专有名称(L“myBho”);
    DISPID DISPID;
    hr=dispxWnd->GetDispID(propName、fdexnamesure和dispid);
    c变异varMyBho((IDispatch*)本;
    DISPPARAMS-params;
    参数s.cArgs=1;
    params.cNamedArgs=0;
    params.rgvarg=&varMyBho;
    params.rgdispidNamedArgs=NULL;
    hr=dispxWnd->Invoke(dispid,IID\u NULL,LOCALE\u USER\u DEFAULT,DISPATCH\u PROPERTYPUTREF,
    &参数,NULL,NULL,NULL);
    }
    
    至于你的其他问题:

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

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


    希望这有帮助。

    谢谢您的回复。我尝试了你的建议,但当我在javascript中访问bho对象时,它给了我
    未定义的对象
    。请看我的更新答案,我已经包括了BHO代码和相应的javascript。我已经更改了这两条语句
    params.rgvarg=&varTanduBar;params.rgdispidNamedArgs=null到这个
    params.rgvarg=&varMyBho;params.rgdispidNamedArgs=NULL。否则,我使用了相同的代码。此外,我还尝试了
    DISPATCH\u PROPERTYPUTREF