第一部分: C++开发BHO之HelloWorld
开发工具VS2010。
步骤如图:
生成的HelloWorldBHO.h的代码如下:
- // HelloWorldBHO.h : CHelloWorldBHO 的声明
- #pragma once
- #include "resource.h" // 主符号
- #include "HelloWorld_i.h"
- #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
- #error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"
- #endif
- using namespace ATL;
- // CHelloWorldBHO
- class ATL_NO_VTABLE CHelloWorldBHO :
- public CComObjectRootEx<CComSingleThreadModel>,
- public CComCoClass<CHelloWorldBHO, &CLSID_HelloWorldBHO>,
- public IObjectWithSiteImpl<CHelloWorldBHO>,
- public IDispatchImpl<IHelloWorldBHO, &IID_IHelloWorldBHO, &LIBID_HelloWorldLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
- {
- public:
- CHelloWorldBHO()
- {
- }
- DECLARE_REGISTRY_RESOURCEID(IDR_HELLOWORLDBHO)
- DECLARE_NOT_AGGREGATABLE(CHelloWorldBHO)
- BEGIN_COM_MAP(CHelloWorldBHO)
- COM_INTERFACE_ENTRY(IHelloWorldBHO)
- COM_INTERFACE_ENTRY(IDispatch)
- COM_INTERFACE_ENTRY(IObjectWithSite)
- END_COM_MAP()
- DECLARE_PROTECT_FINAL_CONSTRUCT()
- HRESULT FinalConstruct()
- {
- return S_OK;
- }
- void FinalRelease()
- {
- }
- public:
- };
- OBJECT_ENTRY_AUTO(__uuidof(HelloWorldBHO), CHelloWorldBHO)
HelloWorldBHO.cpp的代码如下:
- // HelloWorldBHO.cpp : CHelloWorldBHO 的实现
- #include "stdafx.h"
- #include "HelloWorldBHO.h"
- // CHelloWorldBHO
HelloWorld.cpp的代码如下:
- // HelloWorld.cpp : DLL 导出的实现。
- #include "stdafx.h"
- #include "resource.h"
- #include "HelloWorld_i.h"
- #include "dllmain.h"
- // 用于确定 DLL 是否可由 OLE 卸载。
- STDAPI DllCanUnloadNow(void)
- {
- return _AtlModule.DllCanUnloadNow();
- }
- // 返回一个类工厂以创建所请求类型的对象。
- STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
- {
- return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
- }
- // DllRegisterServer - 在系统注册表中添加项。
- STDAPI DllRegisterServer(void)
- {
- // 注册对象、类型库和类型库中的所有接口
- HRESULT hr = _AtlModule.DllRegisterServer();
- return hr;
- }
- // DllUnregisterServer - 在系统注册表中移除项。
- STDAPI DllUnregisterServer(void)
- {
- HRESULT hr = _AtlModule.DllUnregisterServer();
- return hr;
- }
- // DllInstall - 按用户和计算机在系统注册表中逐一添加/移除项。
- STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
- {
- HRESULT hr = E_FAIL;
- static const wchar_t szUserSwitch[] = L"user";
- if (pszCmdLine != NULL)
- {
- if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0)
- {
- ATL::AtlSetPerUserRegistration(true);
- }
- }
- if (bInstall)
- {
- hr = DllRegisterServer();
- if (FAILED(hr))
- {
- DllUnregisterServer();
- }
- }
- else
- {
- hr = DllUnregisterServer();
- }
- return hr;
- }
dllmain.cpp的代码如下:
- // dllmain.cpp : DllMain 的实现。
- #include "stdafx.h"
- #include "resource.h"
- #include "HelloWorld_i.h"
- #include "dllmain.h"
- CHelloWorldModule _AtlModule;
- // DLL 入口点
- extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
- {
- hInstance;
- return _AtlModule.DllMain(dwReason, lpReserved);
- }
HelloWorld.rgs的内容如下:
- HKCR
- {
- }
HelloWorldBHO.rgs的内容如下:
- HKCR
- {
- NoRemove CLSID
- {
- ForceRemove {22024CC8-9043-49C7-AC80-A803A2912BF6} = s 'HelloWorldBHO Class'
- {
- ForceRemove Programmable
- InprocServer32 = s '%MODULE%'
- {
- val ThreadingModel = s 'Apartment'
- }
- TypeLib = s '{D05D8B0F-8126-4FE2-BC3D-D5A5248E7025}'
- Version = s '1.0'
- }
- }
- }
HelloWorld.idl的内容:
- // HelloWorld.idl : HelloWorld 的 IDL 源
- //
- // 此文件将由 MIDL 工具处理以
- // 产生类型库(HelloWorld.tlb)和封送处理代码。
- import "oaidl.idl";
- import "ocidl.idl";
- [
- object,
- uuid(9C44C518-EEBE-4126-B368-5B901F840255),
- dual,
- nonextensible,
- pointer_default(unique)
- ]
- interface IHelloWorldBHO : IDispatch{
- };
- [
- uuid(D05D8B0F-8126-4FE2-BC3D-D5A5248E7025),
- version(1.0),
- ]
- library HelloWorldLib
- {
- importlib("stdole2.tlb");
- [
- uuid(22024CC8-9043-49C7-AC80-A803A2912BF6)
- ]
- coclass HelloWorldBHO
- {
- [default] interface IHelloWorldBHO;
- };
- };
HelloWorld.idl中的CLSID是22024CC8-9043-49C7-AC80-A803A2912BF6
其他的文件,暂时不重要。
修改HelloWorldBHO.h:
1、增加头文件
- #include <shlguid.h>
- #include <exdispid.h>
2、增加一个公有的SetSite方法:
- public:
- STDMETHOD(SetSite)(IUnknown *pUnkSite);
3、增加私有的成员变量:
- private:
- CComPtr<IWebBrowser2> m_spWebBrowser;
- BOOL m_fAdvised;
4、多继承一个类:
- public IDispEventImpl<1, CHelloWorldBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
5、增加公有的方法OnDocumentComplete:
- BEGIN_SINK_MAP(CHelloWorldBHO)
- SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
- END_SINK_MAP()
- // DWebBrowserEvents2
- void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
修改HelloWorldBHO.cpp,实现那两个方法:
- STDMETHODIMP CHelloWorldBHO::SetSite(IUnknown* pUnkSite)
- {
- if (pUnkSite != NULL)
- {
- // Cache the pointer to IWebBrowser2.
- HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
- if (SUCCEEDED(hr))
- {
- // Register to sink events from DWebBrowserEvents2.
- hr = DispEventAdvise(m_spWebBrowser);
- if (SUCCEEDED(hr))
- {
- m_fAdvised = TRUE;
- }
- }
- }
- else
- {
- // Unregister event sink.
- if (m_fAdvised)
- {
- DispEventUnadvise(m_spWebBrowser);
- m_fAdvised = FALSE;
- }
- // Release cached pointers and other resources here.
- m_spWebBrowser.Release();
- }
- // Call base class implementation.
- return IObjectWithSiteImpl<CHelloWorldBHO>::SetSite(pUnkSite);
- }
- void STDMETHODCALLTYPE CHelloWorldBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
- {
- // Retrieve the top-level window from the site.
- HWND hwnd;
- HRESULT hr = m_spWebBrowser->get_HWND((LONG_PTR*)&hwnd);
- if (SUCCEEDED(hr))
- {
- // Output a message box when page is loaded.
- MessageBox(hwnd, L"Hello World!", L"BHO", MB_OK);
- }
- }
dllmain.cpp的DllMain修改成:
- extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
- {
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- DisableThreadLibraryCalls(hInstance);
- }
- return _AtlModule.DllMain(dwReason, lpReserved);
- }
修改HelloWorld.rgs:
修改成:
- HKLM {
- NoRemove SOFTWARE {
- NoRemove Microsoft {
- NoRemove Windows {
- NoRemove CurrentVersion {
- NoRemove Explorer {
- NoRemove 'Browser Helper Objects' {
- ForceRemove '{D2F7E1E3-C9DC-4349-B72C-D5A708D6DD77}' = s 'HelloWorldBHO' {
- val 'NoExplorer' = d '1'
- }
- }
- }
- }
- }
- }
- }
- }
其中的{D2F7E1E3-C9DC-4349-B72C-D5A708D6DD77},需要改成HelloWorld.idl中的CLSID,当前文件的CLSID是
{22024CC8-9043-49C7-AC80-A803A2912BF6}
修改完后:
HelloWorldBHO.h:
- // HelloWorldBHO.h : CHelloWorldBHO 的声明
- #pragma once
- #include "resource.h" // 主符号
- #include <shlguid.h>
- #include <exdispid.h>
- #include "HelloWorld_i.h"
- #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
- #error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"
- #endif
- using namespace ATL;
- // CHelloWorldBHO
- class ATL_NO_VTABLE CHelloWorldBHO :
- public CComObjectRootEx<CComSingleThreadModel>,
- public CComCoClass<CHelloWorldBHO, &CLSID_HelloWorldBHO>,
- public IObjectWithSiteImpl<CHelloWorldBHO>,
- public IDispatchImpl<IHelloWorldBHO, &IID_IHelloWorldBHO, &LIBID_HelloWorldLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
- public IDispEventImpl<1, CHelloWorldBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
- {
- public:
- CHelloWorldBHO()
- {
- }
- DECLARE_REGISTRY_RESOURCEID(IDR_HELLOWORLDBHO)
- DECLARE_NOT_AGGREGATABLE(CHelloWorldBHO)
- BEGIN_COM_MAP(CHelloWorldBHO)
- COM_INTERFACE_ENTRY(IHelloWorldBHO)
- COM_INTERFACE_ENTRY(IDispatch)
- COM_INTERFACE_ENTRY(IObjectWithSite)
- END_COM_MAP()
- DECLARE_PROTECT_FINAL_CONSTRUCT()
- HRESULT FinalConstruct()
- {
- return S_OK;
- }
- void FinalRelease()
- {
- }
- public:
- STDMETHOD(SetSite)(IUnknown *pUnkSite);
- BEGIN_SINK_MAP(CHelloWorldBHO)
- SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
- END_SINK_MAP()
- // DWebBrowserEvents2
- void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
- private:
- CComPtr<IWebBrowser2> m_spWebBrowser;
- BOOL m_fAdvised;
- };
- OBJECT_ENTRY_AUTO(__uuidof(HelloWorldBHO), CHelloWorldBHO)
HelloWorldBHO.cpp:
- // HelloWorldBHO.cpp : CHelloWorldBHO 的实现
- #include "stdafx.h"
- #include "HelloWorldBHO.h"
- // CHelloWorldBHO
- STDMETHODIMP CHelloWorldBHO::SetSite(IUnknown* pUnkSite)
- {
- if (pUnkSite != NULL)
- {
- // Cache the pointer to IWebBrowser2.
- HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
- if (SUCCEEDED(hr))
- {
- // Register to sink events from DWebBrowserEvents2.
- hr = DispEventAdvise(m_spWebBrowser);
- if (SUCCEEDED(hr))
- {
- m_fAdvised = TRUE;
- }
- }
- }
- else
- {
- // Unregister event sink.
- if (m_fAdvised)
- {
- DispEventUnadvise(m_spWebBrowser);
- m_fAdvised = FALSE;
- }
- // Release cached pointers and other resources here.
- m_spWebBrowser.Release();
- }
- // Call base class implementation.
- return IObjectWithSiteImpl<CHelloWorldBHO>::SetSite(pUnkSite);
- }
- void STDMETHODCALLTYPE CHelloWorldBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
- {
- // Retrieve the top-level window from the site.
- HWND hwnd;
- HRESULT hr = m_spWebBrowser->get_HWND((LONG_PTR*)&hwnd);
- if (SUCCEEDED(hr))
- {
- // Output a message box when page is loaded.
- MessageBox(hwnd, L"Hello World!", L"BHO", MB_OK);
- }
- }
dllmain.cpp:
- // dllmain.cpp : DllMain 的实现。
- #include "stdafx.h"
- #include "resource.h"
- #include "HelloWorld_i.h"
- #include "dllmain.h"
- CHelloWorldModule _AtlModule;
- // DLL 入口点
- extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
- {
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- DisableThreadLibraryCalls(hInstance);
- }
- return _AtlModule.DllMain(dwReason, lpReserved);
- }
HelloWorld.rgs:
- HKLM {
- NoRemove SOFTWARE {
- NoRemove Microsoft {
- NoRemove Windows {
- NoRemove CurrentVersion {
- NoRemove Explorer {
- NoRemove 'Browser Helper Objects' {
- ForceRemove '{22024CC8-9043-49C7-AC80-A803A2912BF6}' = s 'HelloWorldBHO' {
- val 'NoExplorer' = d '1'
- }
- }
- }
- }
- }
- }
- }
- }
目前要修改的也就那么几个文件,然后关闭安全软件,进行build,生成的dll会自动注册到注册表里去,如图:
before:
after:
然后打开IE,如图:
也可以在IE的管理加载项中看到,工具-管理加载项:
可以启用或者禁用BHO。
这样,就完成了HelloWorld版本的BHO的开发。
但是,这样注册的BHO, 在IE管理加载项里面显示“未验证”,解决这也问题,
请看下一篇博文《BHO劫持数字证书验证与DLL后门通道(二)》