title: Calling C++ function from JavaScript script running in a web browser control
body: <p>I have embedded a web browser control in my c++ application. I want javascript running in the web browser control to be able to call a c++ function/method.</p>
  
  <p>I have found mentions of three ways to do this:</p>
  
  <ol>
  <li>Implement an ActiveX component that acts as a middle man. (Implementation details here: <a href="http://blogs.msdn.com/b/nicd/archive/2007/04/18/calling-into-your-bho-from-a-client-script.aspx" rel="nofollow noreferrer">http://blogs.msdn.com/b/nicd/archive/2007/04/18/calling-into-your-bho-from-a-client-script.aspx</a>)</li>
  <li>Use window.external. (Also discussed in the link above, but no implementation provided)</li>
  <li>Add a custom object to the window object</li>
  </ol>
  
  <p>I want to go with the third option, but I haven't found any working examples on how to do that. Can someone please show me how to do it, or link to a working example on the net somewhere.</p>
  
  <p>The closest to an example that I have found is the first reply by Igor Tandetnik in <a href="http://groups.google.com/group/microsoft.public.inetsdk.programming.webbrowser_ctl/browse_frm/thread/afb353de46bae2f8" rel="nofollow noreferrer">a thread in the webbrowser_ctl news group</a>. But I'm afraid I need more help than that.</p>
  
  <p>I'm embedding an IWebBrowser2 control and I am not using MFC, ATL or WTL.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Going by the pseudo-code given by Igor in the thread I linked earlier, and code found in the codeproject article "<a href="http://www.codeproject.com/KB/COM/javascriptfromcpp.aspx?display=PrintAll" rel="nofollow noreferrer">Creating JavaScript arrays and other objects from C++</a>" I've produced some code.</p>
  
  <pre><code>void WebForm::AddCustomObject(IDispatch *custObj, std::string name)
  {
      IHTMLDocument2 *doc = GetDoc();
      IHTMLWindow2 *win = NULL;
      doc-&gt;get_parentWindow(&amp;win);
  
      if (win == NULL) {
          return;
      }
  
      IDispatchEx *winEx;
      win-&gt;QueryInterface(&amp;winEx);
  
      if (winEx == NULL) {
          return;
      }
  
      int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, NULL, 0);
      BSTR objName = SysAllocStringLen(0, lenW);
      MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, objName, lenW);
  
      DISPID dispid; 
      HRESULT hr = winEx-&gt;GetDispID(objName, fdexNameEnsure, &amp;dispid);
  
      SysFreeString(objName);
  
      if (FAILED(hr)) {
          return;
      }
  
      DISPID namedArgs[] = {DISPID_PROPERTYPUT};
      DISPPARAMS params;
      params.rgvarg = new VARIANT[1];
      params.rgvarg[0].pdispVal = custObj;
      params.rgvarg[0].vt = VT_DISPATCH;
      params.rgdispidNamedArgs = namedArgs;
      params.cArgs = 1;
      params.cNamedArgs = 1;
  
      hr = winEx-&gt;InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &amp;params, NULL, NULL, NULL); 
  
      if (FAILED(hr)) {
          return;
      }
  }
  </code></pre>
  
  <p>The code above runs all the way through, so everything looks alright that far.</p>
  
  <p>I call AddCustomObject when I receive the DISPID_NAVIGATECOMPLETE2 DWebBrowserEvents2 event passing this as <code>*custObj</code>:</p>
  
  <pre><code>class JSObject : public IDispatch {
  private:
      long ref;
  
  public:
      // IUnknown
      virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
      virtual ULONG STDMETHODCALLTYPE AddRef();
      virtual ULONG STDMETHODCALLTYPE Release();
  
      // IDispatch
      virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
      virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
          ITypeInfo **ppTInfo);
      virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
          LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
      virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
          LCID lcid, WORD wFlags, DISPPARAMS *Params, VARIANT *pVarResult,
          EXCEPINFO *pExcepInfo, UINT *puArgErr);
  };
  </code></pre>
  
  <p>Noteworthy implementations might be</p>
  
  <pre><code>HRESULT STDMETHODCALLTYPE JSObject::QueryInterface(REFIID riid, void **ppv)
  {
      *ppv = NULL;
  
      if (riid == IID_IUnknown || riid == IID_IDispatch) {
          *ppv = static_cast&lt;IDispatch*&gt;(this);
      }
  
      if (*ppv != NULL) {
          AddRef();
          return S_OK;
      }
  
      return E_NOINTERFACE;
  }
  </code></pre>
  
  <p>and </p>
  
  <pre><code>HRESULT STDMETHODCALLTYPE JSObject::Invoke(DISPID dispIdMember, REFIID riid,
      LCID lcid, WORD wFlags, DISPPARAMS *Params, VARIANT *pVarResult,
      EXCEPINFO *pExcepInfo, UINT *puArgErr)
  {
      MessageBox(NULL, "Invoke", "JSObject", MB_OK);
      return DISP_E_MEMBERNOTFOUND;
  }
  </code></pre>
  
  <p>Unfortunately I never get the "Invoke" message box when I try to use the "JSObject" object from the javascript code.</p>
  
  <pre><code>JSObject.randomFunctionName();  // This should give me the c++ "Invoke" message
                                  // box, but it doesn't
  </code></pre>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p>I implemented <code>GetIDsOfNames</code> like so:</p>
  
  <pre><code>HRESULT STDMETHODCALLTYPE JSObject::GetIDsOfNames(REFIID riid,
      LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
  {
      HRESULT hr = S_OK;
  
      for (UINT i = 0; i &lt; cNames; i++) {
          std::map&lt;std::wstring, DISPID&gt;::iterator iter = idMap.find(rgszNames[i]);
          if (iter != idMap.end()) {
              rgDispId[i] = iter-&gt;second;
          } else {
              rgDispId[i] = DISPID_UNKNOWN;
              hr = DISP_E_UNKNOWNNAME;
          }
      }
  
      return hr;
  }
  </code></pre>
  
  <p>and this is my constructor</p>
  
  <pre><code>JSObject::JSObject() : ref(0)
  {
      idMap.insert(std::make_pair(L"execute", DISPID_USER_EXECUTE));
      idMap.insert(std::make_pair(L"writefile", DISPID_USER_WRITEFILE));
      idMap.insert(std::make_pair(L"readfile", DISPID_USER_READFILE));
  }
  </code></pre>
  
  <p>with the DISPID_USER_* constants defined as private class members</p>
  
  <pre><code>class JSObject : public IDispatch {
  private:
      static const DISPID DISPID_USER_EXECUTE = DISPID_VALUE + 1;
      static const DISPID DISPID_USER_WRITEFILE = DISPID_VALUE + 2;
      static const DISPID DISPID_USER_READFILE = DISPID_VALUE + 3;
  
      // ...
  };
  </code></pre>
  
  <p><strong>EDIT 3, 4 and 5:</strong></p>
  
  <p>Moved to <a href="https://stackoverflow.com/questions/3754268/returning-string-to-javascript-from-c-function">a separate question</a></p>
  
  <p><strong>EDIT 6:</strong></p>
  
  <p>Made <a href="https://stackoverflow.com/questions/3754268/returning-string-to-javascript-from-c-function">a separate question</a> out of the "returning a string" edits. That way I can accept <a href="https://stackoverflow.com/users/168225/georg-fritzsche">Georg's</a> reply as that answers the original question.</p>
  
  <p><strong>EDIT 7:</strong></p>
  
  <p>I have gotten a few requests for a fully working, self contained, example implementation. Here it is: <a href="https://github.com/Tobbe/CppIEEmbed" rel="nofollow noreferrer">https://github.com/Tobbe/CppIEEmbed</a>. Please fork and improve if you can :)</p>