C++ OCX AfxOleRegisterTypeLib失败,错误为0x80040200
我将OCX库从VS2010/Win7升级到VS2019/Win10。但是,当我尝试从提升的命令提示符使用C++ OCX AfxOleRegisterTypeLib失败,错误为0x80040200,c++,visual-studio,mfc,activex,regsvr32,C++,Visual Studio,Mfc,Activex,Regsvr32,我将OCX库从VS2010/Win7升级到VS2019/Win10。但是,当我尝试从提升的命令提示符使用RegSvr32.exe时,我收到错误0x0040200。我做了一些调试,错误的调用是调用AfxOleRegisterTypeLib 是的,我看过一篇SO文章,其中指出“dll附近缺少tlb文件”。要从管理命令提示符运行的其他搜索状态 我在OCX控制装置附近没有TLB。如果尝试使用tlbexp.exe创建一个,则会出现以下错误: TlbExp:错误TX0000:无法加载文件或程序集的file
RegSvr32.exe
时,我收到错误0x0040200。我做了一些调试,错误的调用是调用AfxOleRegisterTypeLib
是的,我看过一篇SO文章,其中指出“dll附近缺少tlb文件”。要从管理命令提示符运行的其他搜索状态
我在OCX控制装置附近没有TLB。如果尝试使用tlbexp.exe
创建一个,则会出现以下错误:
TlbExp:错误TX0000:无法加载文件或程序集的file:///C:\“pathto.ocx”或其依赖项之一。模块应包含程序集清单
TlbExp命令行(用于以管理员身份运行所有cmd.exe):
我确实使用了dependends64
(也称为Dependency Walker 64位
),并且没有缺少组件DLL。它可以很好地找到它们,就像RegSvr32.exe一样
将OCX文件放在C:\Windows\System32中没有帮助
对于任何查看DLL的人来说,这些DLL在Win7机器上都可以正常工作。以下是有关非Windows DLL的更多信息
- PlxApi720_x64.dll:PLX v7.2 API(Broadcom PLX芯片是一个PCIe交换机(想想USB/网络交换机,只是带PCIe通道)
- LSI DirectAccess.dll:LSI API是一个自包含的dll,允许软件与LSI HBA RAID适配器通信
- Ipp*.dll:
前缀是英特尔code Composer Studio重新分发(x64)文件所使用的dll,这里是2011版,是一个旧版本,需要更新为最新和最大版本,更不用说现在的免费API。这些文件都在Ipp
文件夹中System32
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB); // <- failure line, through debugging
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
LPCTSTR pszFileName, LPCTSTR pszHelpDir)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
CString strPathName;
TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
strPathName.ReleaseBuffer();
LPTYPELIB ptlib = NULL;
// If a filename was specified, replace final component of path with it.
if (pszFileName != NULL)
{
int iBackslash = strPathName.ReverseFind('\\');
if (iBackslash != -1)
strPathName = strPathName.Left(iBackslash+1);
strPathName += pszFileName;
}
if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
{
ASSERT_POINTER(ptlib, ITypeLib);
LPTLIBATTR pAttr;
GUID tlidActual = GUID_NULL;
if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
{
ASSERT_POINTER(pAttr, TLIBATTR);
tlidActual = pAttr->guid;
ptlib->ReleaseTLibAttr(pAttr);
}
// Check that the guid of the loaded type library matches
// the tlid parameter.
ASSERT(IsEqualGUID(tlid, tlidActual));
if (IsEqualGUID(tlid, tlidActual))
{
// Register the type library.
if (SUCCEEDED(RegisterTypeLib(ptlib, T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
bSuccess = TRUE;
}
RELEASE(ptlib);
}
else
{
TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
}
return bSuccess;
}
RegSvr32.exe
所做的唯一事情虽然我还没有走到尽头,因为我在OCX上遇到了
aximp.exe
/tlbimp.exe
问题,但我发现了阻止我注册ActiveX控件的问题,这就是这里的问题
答案是主CPP文件中的GUID
:
(我正在进行研究,因为我找不到任何人解释RegSvr32.exe如何工作以及它的作用。我想与大家分享,希望它能帮助其他人。)
在主注册函数STDAPI DllRegisterServer(void)
中使用的必须与IDL中存在的GUID
匹配:
[uuid(FE5C7D88-D53C-4977-BA56-4BF3020A5D8A), version(1.0),
helpfile("DriveOps.hlp"),
helpstring("DriveOps ActiveX Control module"),
control]
library DriveOpsLib
{
...
}
我有两个不同的值,因此失败了
这是我用来发现问题的方法和研究,但首先我要说明注册函数,因为这也是关键
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
HINSTANCE hiTypeLib = AfxGetInstanceHandle();
if (!AfxOleRegisterTypeLib(hiTypeLib, _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
正如我相信问题中提到的那样,失败就在这条线上
if (!AfxOleRegisterTypeLib(hiTypeLib, _tlid))
我已经在internet上找到了RegSvr32.exe
的源代码。它是位于VCSamples master
中的MicrosoftGitHub
源代码的一部分
直接链接到RegSvr32.exe
:
下载zip的直接链接:
代码是一条死胡同,因为它告诉了我什么应该是显而易见的,即调用DLL的DllRegisterServer
入口点来完成所有工作的实用程序。我应该知道这一点,但是,我必须看到它才有意义
使用procmon.exe
,没有任何意义,对注册表的各种调用就像阅读外语一样,没有任何帮助
在这里我画了一个空白,直到我想到获取AfxOleRegisterTypeLib
的源代码,因为这是失败的。我想看看这东西到底做了什么,以及源文件ctreg.cpp
的第113行是什么
我仍然在思考procmon
的评论和一个注册表问题,但我想代码会告诉我是哪一个。我花了一些研究,但我发现了。我喜欢Microsoft共享代码。他们的错误消息没有帮助,但能够真正看到他们试图做什么完全有帮助
代码如下:
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB); // <- failure line, through debugging
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
LPCTSTR pszFileName, LPCTSTR pszHelpDir)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
CString strPathName;
TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
strPathName.ReleaseBuffer();
LPTYPELIB ptlib = NULL;
// If a filename was specified, replace final component of path with it.
if (pszFileName != NULL)
{
int iBackslash = strPathName.ReverseFind('\\');
if (iBackslash != -1)
strPathName = strPathName.Left(iBackslash+1);
strPathName += pszFileName;
}
if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
{
ASSERT_POINTER(ptlib, ITypeLib);
LPTLIBATTR pAttr;
GUID tlidActual = GUID_NULL;
if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
{
ASSERT_POINTER(pAttr, TLIBATTR);
tlidActual = pAttr->guid;
ptlib->ReleaseTLibAttr(pAttr);
}
// Check that the guid of the loaded type library matches
// the tlid parameter.
ASSERT(IsEqualGUID(tlid, tlidActual));
if (IsEqualGUID(tlid, tlidActual))
{
// Register the type library.
if (SUCCEEDED(RegisterTypeLib(ptlib, T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
bSuccess = TRUE;
}
RELEASE(ptlib);
}
else
{
TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
}
return bSuccess;
}
我一直收到一个ASSERT
,因此尽管第113行确实在非代码行上,但实际的失败是显而易见的。我知道我没有在ASSERT\u指针上失败,因为错误消息不同,这意味着我在以下位置失败:
ASSERT(IsEqualGUID(tlid, tlidActual));
我详细查看了代码和输入参数。我决定将此函数内容复制并粘贴到OCX中的真实注册代码中,以在调试时获得进一步的可见性。我想查看值
果然,我看到了两个不同的GUID
值,一个来自顶部,一个是我的\u tlid
,另一个是从实例句柄返回的。我拿出了一个方便的TextPad
文本编辑器,尽管Visual Studio
有一个在文件中查找,但TextPad非常容易使用。这导致了t中的另一个实例整个解决方案,即在DriveOps.idl
中。在那之前,该文件对我来说毫无意义,但突然我发现GUID
就是从实例句柄中提取的RegSvr32.exe
我统一了ID,重建了,现在不再抱怨了。是的,因为我得到了代码,它别无选择,只能注册。它没有修改注册表与我所能说的是不同的故事和问题,但这是另一个问题。RegSvr32.exe现在注册而没有抱怨
(是的,我仍然有tlbimp.exe
,aximp.exe
,并将我的OCX项目添加到我的WinFormsBOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
LPCTSTR pszFileName, LPCTSTR pszHelpDir)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
CString strPathName;
TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
strPathName.ReleaseBuffer();
LPTYPELIB ptlib = NULL;
// If a filename was specified, replace final component of path with it.
if (pszFileName != NULL)
{
int iBackslash = strPathName.ReverseFind('\\');
if (iBackslash != -1)
strPathName = strPathName.Left(iBackslash+1);
strPathName += pszFileName;
}
if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
{
ASSERT_POINTER(ptlib, ITypeLib);
LPTLIBATTR pAttr;
GUID tlidActual = GUID_NULL;
if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
{
ASSERT_POINTER(pAttr, TLIBATTR);
tlidActual = pAttr->guid;
ptlib->ReleaseTLibAttr(pAttr);
}
// Check that the guid of the loaded type library matches
// the tlid parameter.
ASSERT(IsEqualGUID(tlid, tlidActual));
if (IsEqualGUID(tlid, tlidActual))
{
// Register the type library.
if (SUCCEEDED(RegisterTypeLib(ptlib, T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
bSuccess = TRUE;
}
RELEASE(ptlib);
}
else
{
TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
}
return bSuccess;
}
ASSERT(IsEqualGUID(tlid, tlidActual));