c++internet-explorercombho

Invoke BHO from IE toolbar button


I am writing IE BHO, which has to be invoked when IE toolbar button is clicked. I have functioning BHO, which is dll functions DllMain DllGetClassObject etc. also COM class which implements IObjectWithSite and IOleCommandTarget and class factory which implements IClassFactory. I know that it works because i had EventSinc connected and it called OnDocumentComplete and other events.

I have registration code in DllRegisterServer function and with regsvr32.exe it succesfully instaled.

Now i wanted to add IE toolbar button which would call BHO functionality on click, so i've found this article Adding Toolbar Buttons and added button registration to my DllRegisterServer according to it. Also added IOleCommandTarget to mentioned above com object and 'implemented' Exec method with code that writes to file (to check if Exec called). After recompile uninstal and install again, on button click DllGetClassObject called for first click and nothing happens for all consecutive clicks.

So what can be wrong ?

Toolbar button registration part from DllRegisterServer

if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\") CLSID_IEPlugin_Str, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL) != ERROR_SUCCESS) return SELFREG_E_CLASS;
RegSetValueEx(hk, _T("ButtonText"), 0, REG_SZ, (const BYTE*)_T("BHO Toolbar Button"), sizeof("BHO Toolbar Button") * sizeof(TCHAR));
RegSetValueEx(hk, _T("Default Visible"), 0, REG_SZ, (const BYTE*)_T("Yes"), sizeof("Yes") * sizeof(TCHAR));
RegSetValueEx(hk, _T("CLSID"), 0, REG_SZ, (const BYTE*)_T("{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}"), sizeof("{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}") * sizeof(TCHAR));
RegSetValueEx(hk, _T("ClsidExtension"), 0, REG_SZ, (const BYTE*)_T("{29DE271C-7936-4C23-BD79-18F6AB7A4AA4}"), sizeof("{29DE271C-7936-4C23-BD79-18F6AB7A4AA4}") * sizeof(TCHAR));
RegCloseKey(hk);

COM class CObjectWithSite header :

#ifndef __OBJECTWITHSITE_H__
#define __OBJECTWITHSITE_H__

#include <Ocidl.h>
#include <Exdisp.h>

class CObjectWithSite : public IObjectWithSite, public IOleCommandTarget
{
public:

    // Constructor and destructor
    CObjectWithSite();
    virtual ~CObjectWithSite();

    // IUnknown methods
    STDMETHODIMP QueryInterface(REFIID riid,void** ppvObject);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    // IObjectWithSite methods
    STDMETHODIMP SetSite(IUnknown* pUnkSite);
    STDMETHODIMP GetSite(REFIID riid,void** ppvSite);

    // IOleCommandTarget methods
    STDMETHODIMP QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText);
    STDMETHODIMP Exec(const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, VARIANT* pvaOut);

protected:
    UINT m_uRefCount;
    IWebBrowser2* m_pSite   = nullptr;  // the currently set site
    IConnectionPoint* m_pCP = nullptr;  // the active connection point interface
    DWORD m_adviseCookie;               // used by ConnectEventSink() and DisconnectEventSink() in conjunction with pCP
};

#endif // __OBJECTWITHSITE_H__

Solution

  • So, on button click ie calls DllGetClassObject from the same thread from which DllGetClassObject was called when ie tab created. It creates new instance of bho and calls IOleCommandTarget::Exec. If in DllGetClassObject trying to query for interface old ClassFactory object (which also reuses created earlier object), crash occurs. So it seems that on button click new instance of bho has to be created.