创建ATL项目时,使用VC每增加一个COM类,就会生成一个对应的rgs文件。
在vista及win7系统中,如果增加了HKLM注册表项,而生成的程序并不是以管理员身份运行时,就会出现本该写入HKCU的某些注册表项并没有被写入。
由于调用DllRegisterServer时,如果加载的rgs文件中的注册表项中的某一项写入注册表失败,后面的就不写入了。
以下是ATL源码:可以看出,注册如果出错,就break了。
ATLINLINE ATLAPI AtlComModuleRegisterServer(_ATL_COM_MODULE* pComModule, BOOL bRegTypeLib, const CLSID* pCLSID) { ATLASSERT(pComModule != NULL); if (pComModule == NULL) return E_INVALIDARG; ATLASSERT(pComModule->m_hInstTypeLib != NULL); HRESULT hr = S_OK; for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++) { if (*ppEntry != NULL) { _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; if (pCLSID != NULL) { if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) continue; } hr = pEntry->pfnUpdateRegistry(TRUE); if (FAILED(hr)) break; hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, pEntry->pfnGetCategoryMap(), TRUE ); if (FAILED(hr)) break; } } if (SUCCEEDED(hr) && bRegTypeLib) hr = AtlRegisterTypeLib(pComModule->m_hInstTypeLib, 0); return hr; }
查看ATL源代码,DllRegisterServer的实现源码是这样的:
HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) throw() { LCID lcid = GetThreadLocale(); SetThreadLocale(LOCALE_SYSTEM_DEFAULT); // registers object, typelib and all interfaces in typelib T* pT = static_cast<T*>(this); HRESULT hr = pT->RegisterAppId(); if (SUCCEEDED(hr)) hr = pT->RegisterServer(bRegTypeLib); SetThreadLocale(lcid); return hr; }
因此,只需要在定义模块的module类中重写RegisterServer即可。
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) throw() { (pCLSID); (bRegTypeLib); HRESULT hr = S_OK; #ifndef _ATL_NO_COM_SUPPORT for (_ATL_OBJMAP_ENTRY** ppEntry = _AtlComModule.m_ppAutoObjMapFirst; ppEntry < _AtlComModule.m_ppAutoObjMapLast; ppEntry++) { if (*ppEntry != NULL) { _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; if (pCLSID != NULL) { if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) continue; } hr = pEntry->pfnUpdateRegistry(TRUE); if (FAILED(hr)) continue; hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, pEntry->pfnGetCategoryMap(), TRUE ); if (FAILED(hr)) continue; } } if (SUCCEEDED(hr) && bRegTypeLib) hr = AtlRegisterTypeLib(_AtlComModule.m_hInstTypeLib, 0); #endif #ifndef _ATL_NO_PERF_SUPPORT if (SUCCEEDED(hr) && _pPerfRegFunc != NULL) hr = (*_pPerfRegFunc)(_AtlBaseModule.m_hInst); #endif return hr; }