Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7051587
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 28, 20262026-05-28T03:16:53+00:00 2026-05-28T03:16:53+00:00

I am trying to call my BHO method from the javascript. The problem is

  • 0

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

  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

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.

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

What I have tried:

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>

Question:

  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?

Note:

  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.

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;
}

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.

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 : 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 );

}

The Javascript:

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

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.

Edit 4


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

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-28T03:16:53+00:00Added an answer on May 28, 2026 at 3:16 am

    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 a good chunk of my code that does the trick:

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

    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
    
    }
    

    Next, the SetSite method, where you register to get the 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 );
    }
    

    As for your other questions:

    • Evidently, my answer implies that you can make an automation object available for scripting from your BHO. It is also possible your object will be instantiated with the 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).

    • 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.

    Hope this helped.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am trying to call the following function from a static method. File directory
In the following I am trying call action script function from js function. What
I'm trying to call a C# method from JavaScript by using ActiveXObject : var
Trying to call a function from another file in C with the following code:
I'm trying to call the OpenThemeData (see msdn OpenThemeData ) function but I couldn't
I trying to call some ejb bean method from tread. and getting error :
In trying to call a method on the CodeMirror javascript code editor. I'm new
i'm trying to call a method inside a flash movie from js, every time
I'm trying to call a function in JavaScript via Java. This works fine when
I am trying to call a c# function from f# where the c# function

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.