1、問題情形
創建ATL項目時,使用VC每增加一個COM類,就會生成一個對應的rgs文件。
在vista及win7系統中,如果增加了HKLM註冊表項,而生成的程序並不是以管理員身份運行時,就會出現本該寫入HKCU的某些註冊表項並沒有被寫入。
2、問題原因
由於調用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;
}
3、解決辦法:
查看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;
}