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