作者:Alexei Evdokimov 译自:CodeGuru
使用MFC实现COM组件时,经常节省许多开发时间。例如,使用AppWizard生成的基于MFC的COM dll工程,已经自动的提供了DllRegisterServer功能的实现。然而,却没有自动生成DllUnregisterServer功能。一般情况下,DllUnregisterServer对于程序是不可缺少的,因为一个完整的程序,不仅需要自注册功能,同时也需要自卸载功能。
基于MFC实现DllRegisterServer()的方法是调用COleObjectFactory::UpdateRegistryAll()。这个方法有一个未公开的参数-(BOOL bRegister = TRUE) - 因此,我们猜测通过调用COleObjectFactory::UpdateRegistry(FALSE)将能够实卸载COM dll的功能。但是,事实并非如此。通过分析源代码,我们能够知道COleObjectFactory::UpdateRegistryAll(BOOL bRegister)通过同样的BOOL值调用COleObjectFactory::UpdateRegistry(BOOL bRegister),但是COleObjectFactory::UpdateRegistry(BOOL bRegister)的实现调用UpdateRegistry(LPCTSTR lpszProgID)函数,这个调用仅当bRegister为TRUE时注册组件,否则什么都不做!
所以,有必要写我们自己的DllUnregisterServer()。下面的代码能够实现基于MFC的DllUnregisterServer(),并且使用非常的简单。使用方法:
- 创建文件DllUnregisterServer_MFC_Impl.inl
- 把下面的代码拷贝/粘贴到新建的文件中
- 在dll的主文件.cpp中(dll_name.cpp)加入:
#include "DllUnregisterServer_MFC_Impl.inl"
- 在dll_name.def文件的EXPORTS片断中加入:
DllUnregisterServer PRIVATE
完成!现在你可以使用"regsvr32 /u dll_name.dll"完成组件的卸载了。
以下代码测试环境为VC++ 5.0, VC++ 5.0 SP3, VC++ 6.0,ANSI环境。也可用于UNICODE环境。
//************************************************************************** // Date : 11.15.98 // Header : DllUnregisterServer_MFC_Impl.inl // // Desc.: DllUnregisterServer() helper for the inproc servers that were // registered via MFC’s COleObjectFactory::UpdateRegistryAll() // // Usage: // Add ’#include "DllUnregisterServer_MFC_Impl.inl"’ to the end of // the main dll file (i.e. dll_name.cpp). // // Add ’DllUnregisterServer PRIVATE’ to EXPORTS section of the // dll_name.def. // // Caution: // Code below uses undocumented, internal MFC data structures // and functions. Therefore, probably, it will be necessary to modify // it, according to the changes in the future versions of MFC. // Code below is based on the COleObjectFactory::UpdateRegistryAll(), // in srcolefact.cpp. (srcolereg.cpp - is actual implementation of // all registry work). //************************************************************************** #include "stdafx.h"
// workaround MFC bug - no #ifndef/#endif for afximpl.h header #if !defined(CRIT_OBJECTFACTORYLIST) #include <..srcafximpl.h> #endif //!CRIT_OBJECTFACTORYLIST //************************************************************************** static HRESULT UnregisterCOMObject(REFCLSID p_clsid) { LPOLESTR t_wzProgID(NULL);
// get ProgID from CLSID and unregister... HRESULT t_hr = ::ProgIDFromCLSID(p_clsid, &t_wzProgID); if(FAILED(t_hr)) return t_hr;
// convert OLESTR to LPTSTR CString t_strProgID(t_wzProgID); LPCTSTR t_szProgID = t_strProgID.operator LPCTSTR();
// free memory ::CoTaskMemFree(t_wzProgID);
// unregister... if(AfxOleUnregisterServerClass(p_clsid, t_szProgID, t_szProgID, t_szProgID, OAT_DISPATCH_OBJECT)) return S_OK; else return E_FAIL; } //************************************************************************** // by exporting DllUnregisterServer, you can use regsvr.exe STDAPI DllUnregisterServer(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_OBJECTFACTORYLIST); for(COleObjectFactory* pFactory = pModuleState->m_factoryList; pFactory != NULL; pFactory = pFactory->m_pNextFactory) { HRESULT t_hr = UnregisterCOMObject(pFactory->GetClassID()); if(FAILED(t_hr)) { AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST); return t_hr; } } AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
#ifdef _AFXDLL AfxLockGlobals(CRIT_DYNLINKLIST); // register extension DLL factories for(CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL) { for(pFactory = pDLL->m_factoryList; pFactory != NULL; pFactory = pFactory->m_pNextFactory) { HRESULT t_hr = UnregisterCOMObject(pFactory->GetClassID()); if(FAILED(t_hr)) { AfxUnlockGlobals(CRIT_DYNLINKLIST); return t_hr; } } } AfxUnlockGlobals(CRIT_DYNLINKLIST); #endif
return S_OK; } //************************************************************************** // end of DllUnregisterServer_MFC_Impl.inl
|