You may receive failure messages while unregistering a DLL that you were able to correctly register before (832926)
The information in this article applies to:
- Microsoft Visual C++ .NET (2003)
- Microsoft Visual C++ .NET (2002)
- Microsoft .NET Framework 1.1
- Microsoft .NET Framework 1.0
SUMMARYWhen you try to unregister a DLL by using the Regsvr32 /u command, you may receive failure messages with return code values that indicate the Access is denied error message or the Error accessing the OLE registry error message.
This problem occurs when you try to implement
scripting categories that require registry modification.
This article
describes how to resolve this problem by adding scripting categories in the
category map macro. This article also describes how you can keep both the DLL registration procedure and the DLL unregistration procedure
simpler. SYMPTOMSYou may receive failure messages with either the return code value of 0x80070005
or the return code value of 0x8002801c. These failure messages occur when you try to unregister a DLL that you were able to correctly register before. The
return code values that are mentioned previously indicate the Access is denied error message and the Error accessing
the OLE registry error message, respectively. You notice this problem when
you try to explicitly register and then unregister some scripting
categories. For example, this problem may occur when you try to
explicitly register and to unregister object safety scripting categories while
implementing the object safety category helper functions that are available in
the Microsoft ActiveX Software Development Kit (SDK). This problem may also occur when you try to delete some sub keys
in the DllUnregisterServer method.CAUSE This problem occurs because there are two implemented category keys that are not being unregistered in the registry.
Typically, the keys are added, and the keys are deleted by using the CLSID_StdComponentCategoriesMgr COM object. If you do not create the CLSID_StdComponentCategoriesMgr COM object during unregistration, you cannot delete the keys that you added. You may receive the
Access is denied error message when you try to delete the sub keys.RESOLUTIONTo resolve this problem, you must add a category map with
all the categories that you want to implement. You put the category map with all the categories that you want to implement in your object header
file after all the other maps in your object header file. The Active Template Library (ATL) macros then handle the registering and the unregistering of the categories that you want to implement,
and no additional code is required. To add a category map with
all the categories that you want to implement, follow these steps:
- Start Microsoft Visual Studio .NET 2002 or Visual Studio .NET 2003.
- On the File menu, point to
New, and then click Project.
The
New Project dialog box appears. - Under Project Types, click Visual
C++ Projects.
- Under Templates, click ATL
Project.
- In the Name box, type
Q832926, and then click OK.
- In the ATL Project Wizard - Q832926 dialog
box, click Application Settings.
- Clear the Attributed option, and
then click Finish.
- In Solution Explorer, right-click the
Q832926 project node, point to Add, and then
click Add Class.
- In the Add Class - Q832926 dialog box,
click Generic C++ Class under Templates, and
then click Open.
- In the Generic C++ Class Wizard - Q832926
dialog box, type helpers in the Class
name box, and then click Finish.
- In Solution Explorer, double-click the
Helpers.h file in the Header Files
folder.
- Replace the code in the Helpers.h file with the following code:
// Helpers.h: Declarations of object safety category helper functions.
#include "comcat.h"
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid); - In Solution Explorer, double-click the
Helpers.cpp file in the Source Files
folder.
- Replace the code in the Helpers.cpp file with the following code:
// Helpers.cpp: Implementation of object safety category helper functions.
// (Copied from the ActiveX SDK docs.)
#include "stdafx.h"
#include "helpers.h"
/////////////////////////////////////////////////////////////////////////////
// CreateComponentCategory - This makes sure that the component category exists in the registry.
// (Copied from the ActiveX SDK docs.)
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{
ICatRegister* pcr = NULL ; // interface pointer
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr))
return hr;
// This makes sure that the HKCR\Component Categories\{..catid...}
// key is registered.
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
// This makes sure that the provided description is not too long.
// Only copy the first 127 characters if it is:
UINT len = (UINT)wcslen(catDescription);
if (len > 127)
len = 127;
wcsncpy(catinfo.szDescription, catDescription, len);
// This makes sure that the description is null terminated.
catinfo.szDescription[len] = 0;
hr = pcr->RegisterCategories(1, &catinfo);
if ( FAILED(hr) )
return hr;
hr = pcr->Release();
if ( FAILED(hr) )
return hr;
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// RegisterCLSIDInCategory - This registers the class clsid as implementing the category catid.
// (Copied from the ActiveX SDK docs.)
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Register this category as being "implemented" by
// the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if ( pcr != NULL)
{
hr = pcr->Release();
}
return hr;
}
- In Solution Explorer, double-click the
Q832926.cpp file in the Source Files
folder.
- In the
Code window, add the following code after the #include statements:
#include "helpers.h"
#include <objsafe.h> - In the Code window, add the following code before the
DllRegisterServer function:
GUID clsid =
{ 0x84C0B6F1, 0x8036, 0x4D7C, { 0xB0, 0x2F, 0x4B, 0x53, 0x7B, 0x79, 0x72, 0x05 } }; - Replace the code in the DllRegisterServer
function with the following code:
// This registers the object, the typelib, and all the interfaces in the typelib.
HRESULT hr = _AtlModule.DllRegisterServer();
if ( FAILED(hr) )
return hr;
//Uncomment the following block of code to reproduce the problem:
/*
// Mark as safe for scripting-failure OK.
hr = CreateComponentCategory(CATID_SafeForScripting,
L"Controls that are safely scriptable");
if (SUCCEEDED(hr))
// Only register if the category exists.
RegisterCLSIDInCategory(clsid, CATID_SafeForScripting);
else
{
TCHAR szMsg[256];
_stprintf(szMsg, _T("Register safe-for-scripting failed: hr=%08X"), hr);
::MessageBox(NULL, szMsg, _T("ContactUpload"), MB_OK);
return E_FAIL;
}
// Mark as safe for data initialization.
hr = CreateComponentCategory(CATID_SafeForInitializing,
L"Controls safely initializable from persistent data");
if (SUCCEEDED(hr))
// Only register if the category exists.
RegisterCLSIDInCategory(clsid, CATID_SafeForInitializing);
else
{
TCHAR szMsg[256];
_stprintf(szMsg, _T("Register safe-for-initializing failed: hr=%08X"), hr);
::MessageBox(NULL, szMsg, _T("ContactUpload"), MB_OK);
return E_FAIL;
}*/
return S_OK; - Replace the code in the
DllUnregisterServer function with the following code:
HRESULT hr = _AtlModule.DllUnregisterServer();
if ( FAILED(hr) )
return hr;
//Uncomment the following block of code to reproduce the problem:
/*#if _WIN32_WINNT >= 0x0400
hr = UnRegisterTypeLib(LIBID_Q832926Lib, 1, 0,
LOCALE_NEUTRAL, SYS_WIN32);
#endif*/
return hr; - In Solution Explorer, right-click the
Q832926 project node, point to Add, and then
click Add Class.
- In the Add Class - Q832926 dialog box,
click ATL Control under Templates, and then
click Open.
- In the ATL Control Wizard - Q832926 dialog
box, type MyATLCtrl in the Short
name box.
- Click Options, and then click Connection points.
- Click Finish.
- In Solution Explorer, double-click the
MyATLCtrl.h file in the Header Files
folder.
- Add the following code after the CONNECTION_POINT_MAP map declaration and the MSG_MAP map declaration.
//Comment the following category map to reproduce the problem:
///**** Add this to fix the unregister problem. *******/////
BEGIN_CATEGORY_MAP(CMyATLCtrl)
IMPLEMENTED_CATEGORY(CATID_SafeForScripting)
IMPLEMENTED_CATEGORY(CATID_SafeForInitializing)
END_CATEGORY_MAP()
///************ END OF FIX *******///// - Press CTRL+SHIFT+S to save the
project.
- Press CTRL+SHIFT+B to build the
solution.
The solution builds successfully, and the Q832926.dll file is registered automatically. - Click Start, and then click
Run.
- In the Open box, type regsvr32
/u PathToDll\Q832926.dll, and then click
OK.
You receive the following message
that the DLL is successfully unregistered:
DllUnregisterServer in
PathToDll\Q832926.dll succeeded.
Note PathToDll is a
placeholder for the directory path of the Q832926.dll file.
REFERENCESFor additional information about category macros, visit the following Microsoft Developer Network (MSDN) Web site:
Modification Type: | Minor | Last Reviewed: | 1/6/2006 |
---|
Keywords: | kbcode kberrmsg kbRegistry kbDLL kbATLServer kbActiveXScript kbprb KB832926 kbAudDeveloper |
---|
|