从 IE 工具栏按钮调用 BHO
Invoke BHO from IE toolbar button
我正在编写 IE BHO,它必须在单击 IE 工具栏按钮时调用。
我有正常运行的 BHO,它是 dll 函数 DllMain DllGetClassObject
等。还有实现 IObjectWithSite
和 IOleCommandTarget
的 COM class 和实现 IClassFactory
的 class 工厂.我知道它有效,因为我连接了 EventSinc
并且它调用了 OnDocumentComplete 和其他事件。
我在 DllRegisterServer
函数中有注册码,并且 regsvr32.exe
它已成功安装。
现在我想添加 IE 工具栏按钮,它会在单击时调用 BHO 功能,所以我找到了这篇文章 Adding Toolbar Buttons 并根据它向我的 DllRegisterServer
添加了按钮注册。还向上面提到的 com object 和 'implemented' Exec 方法添加了 IOleCommandTarget
以及写入文件的代码(以检查是否调用了 Exec)。重新编译卸载并再次安装后,在按钮上单击 DllGetClassObject
要求第一次单击,但所有连续单击都没有任何反应。
那么有什么问题吗?
来自 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__
因此,在单击按钮时,ie 从创建 ie 选项卡时调用 DllGetClassObject 的同一线程调用 DllGetClassObject。它创建新的 bho 实例并调用 IOleCommandTarget::Exec。如果在 DllGetClassObject 中尝试查询接口旧的 ClassFactory 对象(它也重用之前创建的对象),则会发生崩溃。因此,似乎必须在单击按钮时创建 bho 的新实例。
我正在编写 IE BHO,它必须在单击 IE 工具栏按钮时调用。
我有正常运行的 BHO,它是 dll 函数 DllMain DllGetClassObject
等。还有实现 IObjectWithSite
和 IOleCommandTarget
的 COM class 和实现 IClassFactory
的 class 工厂.我知道它有效,因为我连接了 EventSinc
并且它调用了 OnDocumentComplete 和其他事件。
我在 DllRegisterServer
函数中有注册码,并且 regsvr32.exe
它已成功安装。
现在我想添加 IE 工具栏按钮,它会在单击时调用 BHO 功能,所以我找到了这篇文章 Adding Toolbar Buttons 并根据它向我的 DllRegisterServer
添加了按钮注册。还向上面提到的 com object 和 'implemented' Exec 方法添加了 IOleCommandTarget
以及写入文件的代码(以检查是否调用了 Exec)。重新编译卸载并再次安装后,在按钮上单击 DllGetClassObject
要求第一次单击,但所有连续单击都没有任何反应。
那么有什么问题吗?
来自 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__
因此,在单击按钮时,ie 从创建 ie 选项卡时调用 DllGetClassObject 的同一线程调用 DllGetClassObject。它创建新的 bho 实例并调用 IOleCommandTarget::Exec。如果在 DllGetClassObject 中尝试查询接口旧的 ClassFactory 对象(它也重用之前创建的对象),则会发生崩溃。因此,似乎必须在单击按钮时创建 bho 的新实例。