Сбой регистрации COM с кодом ошибки 0xC0000005

Я работаю над устаревшим проектом, который содержит несколько C ++ COM Dll. Каждый раз, когда решение строится на отладочной конфигурации, процесс сборки выдает ошибки для каждого COM-проекта:

Error   10  error MSB3073: The command "regsvr32 /s /c "D:\*****removed intentionally****_d.dll"echo regsvr32 exec. time > ".\Debug\regsvr32.trg"echo Server registration done!
:VCEnd
" exited with code -1073741819.

Я недавно присоединился к этому проекту, поэтому, когда я спросил об этом, мне сказали, что все просто игнорируют эти ошибки, потому что решение успешно строится на второй сборке.

Я решил копнуть глубже, и кажется, что сама регистрация COM завершается успешно (что объясняет, почему 2-я сборка не попыталась зарегистрироваться), но вызов regsvr32 возвращает код ошибки (0xC0000005). И это то, что не удалось построить.

Я также попытался удалить регистрацию из пользовательского шага сборки, и вместо этого решил зарегистрироваться в окне свойств компоновщика «Register Output = YES», и получил ту же ошибку.

Я попытался отладить regsvr32 с одним из DLL и обнаружил следующие вещи:

  1. Сначала я не мог установить точку останова в DllRegisterServer, затем я попытался отладить версию regsvr32 для X86 (из Windows \ SysWOW64), и только тогда я смог сломать DllRegisterServer. Может кто-нибудь объяснить это?

  2. DllRegisterServer завершается успешно и возвращает S_OK.

  3. После возврата DllRegisterServer создается исключение со следующим исключением и трассировкой стека:

Исключение первого шанса в 0x759849c1 в regsvr32.exe: 0xC0000005: Место чтения нарушения доступа 0x005bf028.

oleaut32.dll!_MemFree@4()  + 0x25 bytes
oleaut32.dll!OLE_TYPEMGR::Release()  + 0x1b138 bytes
oleaut32.dll!ReleaseAppData()  + 0x317 bytes
oleaut32.dll!_OACleanup@0()  + 0x5 bytes
ole32.dll!wCoUninitialize(COleTls & Tls, int fHostThread)  Line 2830    C++
ole32.dll!CoUninitialize()  Line 2620   C++
regsvr32.exe!_wWinMain@16()  + 0xa77 bytes
regsvr32.exe!__initterm_e()  + 0x1b1 bytes
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

Итак, что вы думаете об этом? Должен ли я игнорировать это, как и остальная часть команды (продукт отлично работает в разработке и производстве)?

У вас есть идея, почему я получу нарушение прав доступа, даже если регистрация прошла успешно? Есть ли какой-либо другой процесс / логика, которая запускается после регистрации COM DLL? какие-либо другие направления?

Это код для класса, который обрабатывает регистрацию:

   CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_C3DT2D, CC3DT2D)
END_OBJECT_MAP()

class CMy3DT2DApp : public CWinApp
{
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMy3DT2DApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL

//{{AFX_MSG(CMy3DT2DApp)
// NOTE - the ClassWizard will add and remove member functions here.
//    DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CMy3DT2DApp, CWinApp)
//{{AFX_MSG_MAP(CMy3DT2DApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
//    DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CMy3DT2DApp theApp;

BOOL CMy3DT2DApp::InitInstance()
{
_Module.Init(ObjectMap, m_hInstance, &LIBID_MY3DT2DLib);
return CWinApp::InitInstance();
}

int CMy3DT2DApp::ExitInstance()
{
_Module.Term();
return CWinApp::ExitInstance();
}

/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE

STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK : S_FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _Module.GetClassObject(rclsid, riid, ppv);
}

/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry

STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
return _Module.RegisterServer(TRUE);
}

/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry

STDAPI DllUnregisterServer(void)
{
return _Module.UnregisterServer(TRUE);
}

5

Решение

Таким образом, очевидно, виновником был инструмент под названием Визуальный детектор утечки, который присоединяется при включении в исходный файл.

Мы обнаружили это, начав с нового проекта ATL (как предложил Мануэлл), и добавили функциональность обратно по одному шагу за раз.
В тот момент, когда мы добавили некоторый код, связанный с другой DLL-библиотекой, включающей vld.h, ошибки регистрации вернулись.

Таким образом, мы удалили все ссылки на VLD, и теперь мы успешно регистрируемся, даже с оригинальным размещенным кодом.

Мы даже нашли этот немного красоты…

Спасибо всем за помощь!

4

Другие решения

Я думаю, что повреждение памяти вызвано смешением кода ATL и MFC для инициализации / завершения.

Если вы используете VS2010 для создания элемента управления MFC ActiveX, вы заметите, что:

1 CMy3DT2DApp должно происходить из COleControlModuleне из CWinApp

2 InitInstance а также ExitInstance метод должен вызывать COleControlModule::InitInstance а также COleControlModule::ExitInstance

3 DllRegisterServer должен быть:

AFX_MANAGE_STATE(_afxModuleAddrThis);

if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);

if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);

return NOERROR;

4 аналогичная реализация для DllUnregisterServer (с помощью AfxOleUnregisterTypeLib)

5 Нет реализации для DllCanUnloadNow

Одним из решений может быть подавление всех ссылок на CComModule _Module и использование обычного кода MFC.

Другим решением было бы позволить DLL быть обычным ATL Dll.

Вы должны использовать мастер VS2010, чтобы показать вам два вида кодовой базы.
(После создания библиотеки ATL используйте параметр меню «Добавить класс» и выберите «Управление ATL»

Решение в значительной степени зависит от использования функций MFC и / или ATL в остальном коде.

Совет: сделайте DLL полной MFC, подавьте «модуль atl», а затем добавьте поддержку ATL, используя Добавление поддержки ATL в существующее приложение MFC

4

По вопросам рекламы [email protected]