Click here to Skip to main content
15,892,809 members
Articles / Desktop Programming / Win32

Writing a BHO in Plain C++

Rate me:
Please Sign up or sign in to vote.
4.88/5 (45 votes)
6 Jun 2009CPOL17 min read 211.1K   10.5K   128  
How to write an Internet Explorer plug-in (Browser Helper Object - BHO) using just C++ and the Windows API; no ATL or MFC involved!
/*
 Copyright (C) 2009 Moutaz Haq <cefarix@gmail.com>
 This file is released under the Code Project Open License <http://www.codeproject.com/info/cpol10.aspx>
*/

#include "common.h"
#include <Olectl.h>
#include "ClassFactory.h"

// Our DLL-global reference count. This is incremented and decremented as objects are created and destroyed by the DLL.
volatile LONG DllRefCount=0;
// Our DLL's HINSTANCE
HINSTANCE hInstance=NULL;
// This our BHO's CLSID. It is a globally unique identifier (GUID) which identifies our BHO's main class to the system. It was generated by the guidgen.exe utility.
// {3543619C-D563-43f7-95EA-4DA7E1CC396A}
const CLSID CLSID_IEPlugin = { 0x3543619c, 0xd563, 0x43f7, { 0x95, 0xea, 0x4d, 0xa7, 0xe1, 0xcc, 0x39, 0x6a } }; // The CLSID in binary format

// Called when the DLL is loaded into the process, attached or detached from a thread, and unloaded from the process
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
	UNREFERENCED_PARAMETER(lpvReserved);
	TCHAR mainexe[1024];
	int len;

	if(fdwReason==DLL_PROCESS_ATTACH) { // we only care about when the DLL is loaded into the process
		hInstance=hinstDLL; // store our HINSTANCE
		DisableThreadLibraryCalls(hInstance); // Disable calls to DllMain on thread attach/detach. Increases performance since we don't need those notifications anyways.
		// Get the full path of the main executable module of the process that loaded us
		// Since explorer.exe sometimes also loads BHOs, we want to stop the DLL from loading if we are being loaded by explorer.exe
		// Note that we can't check if we are being loaded into iexplore.exe, because other processes can have legitimate reasons for loading us as well
		//  such as regsvr32.exe for registering and unregistering our COM class.
		GetModuleFileName(NULL,mainexe,1024);
		len=_tcsnlen(mainexe,1024);
		if(len>12 && _tcsicmp(mainexe+len-12,_T("explorer.exe"))==0) return FALSE;
	}
	return TRUE;
}

// Called by COM to get a reference to our CClassFactory object
STDAPI DllGetClassObject(REFIID rclsid,REFIID riid,LPVOID *ppv)
{
	HRESULT hr;

	// We only support one class, make sure rclsid matches CLSID_IEPlugin
	if(!IsEqualCLSID(rclsid,CLSID_IEPlugin)) return CLASS_E_CLASSNOTAVAILABLE;
	// Make sure the ppv pointer is valid
	if(IsBadWritePtr(ppv,sizeof(LPVOID))) return E_POINTER;
	// Set *ppv to NULL
	(*ppv)=NULL;
	// Create a new CClassFactory object
	CClassFactory *pFactory=new CClassFactory;
	// If we couldn't allocate the new object, return an out-of-memory error
	if(pFactory==NULL) return E_OUTOFMEMORY;
	// Query the pFactory object for the requested interface
	hr=pFactory->QueryInterface(riid,ppv);
	// If the requested interface isn't supported by pFactory, delete the newly created object
	if(FAILED(hr)) delete pFactory;
	// Return the same HRESULT as CClassFactory::QueryInterface
	return hr;
}

// This function is called by COM to determine if the DLL safe to unload.
// We return true if no objects from this DLL are being used and the DLL is unlocked.
STDAPI DllCanUnloadNow()
{
	if(DllRefCount>0) return S_FALSE;
	return S_OK;
}

// This function is called to register our DLL in the system, for example, by regsvr32.exe
// We register ourselves with both COM and Internet Explorer
STDAPI DllRegisterServer()
{
	HKEY hk;
	TCHAR dllpath[1024];
	DWORD n;

	// Get the full path to this DLL's file so we can register it
	GetModuleFileName(hInstance,dllpath,1024);
	// Create our key under HKCR\\CLSID
	if(RegCreateKeyEx(HKEY_CLASSES_ROOT,_T("CLSID\\") CLSID_IEPlugin_Str,0,NULL,0,KEY_ALL_ACCESS,NULL,&hk,NULL)!=ERROR_SUCCESS) return SELFREG_E_CLASS;
	// Set the name of our BHO
	RegSetValueEx(hk,NULL,0,REG_SZ,(const BYTE*)_T("CodeProject Example BHO"),24*sizeof(TCHAR));
	RegCloseKey(hk);
	// Create the InProcServer32 key
	if(RegCreateKeyEx(HKEY_CLASSES_ROOT,_T("CLSID\\") CLSID_IEPlugin_Str _T("\\InProcServer32"),0,NULL,0,KEY_ALL_ACCESS,NULL,&hk,NULL)!=ERROR_SUCCESS) return SELFREG_E_CLASS;
	// Set the path to this DLL
	RegSetValueEx(hk,NULL,0,REG_SZ,(const BYTE*)dllpath,(_tcslen(dllpath)+1)*sizeof(TCHAR));
	// Set the ThreadingModel to Apartment
	RegSetValueEx(hk,_T("ThreadingModel"),0,REG_SZ,(const BYTE*)_T("Apartment"),10*sizeof(TCHAR));
	RegCloseKey(hk);
	// Now register the BHO with Internet Explorer
	if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\\") CLSID_IEPlugin_Str,0,NULL,0,KEY_ALL_ACCESS,NULL,&hk,NULL)!=ERROR_SUCCESS) return SELFREG_E_CLASS;
	// I believe the following tells explorer.exe not to load our BHO
	n=1;
	RegSetValueEx(hk,_T("NoExplorer"),0,REG_DWORD,(const BYTE*)&n,sizeof(DWORD));
	RegCloseKey(hk);
	return S_OK;
}

// This function is called to unregister our DLL in the system, for example, by regsvr32.exe
// We remove our registration entries from both COM and Internet Explorer
STDAPI DllUnregisterServer()
{
	// Remove the Internet Explorer BHO registration
	RegDeleteKey(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\\") CLSID_IEPlugin_Str);
	// Remove the COM registration, starting with the deeper key first since RegDeleteKey is not recursive
	RegDeleteKey(HKEY_CLASSES_ROOT,_T("CLSID\\") CLSID_IEPlugin_Str _T("\\InProcServer32"));
	RegDeleteKey(HKEY_CLASSES_ROOT,_T("CLSID\\") CLSID_IEPlugin_Str);
	return S_OK;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions