c++ - OCX AfxOleRegisterTypeLib 失败并出现错误 0x80040200
问题描述
我将一个 OCX 库从 VS2010/Win7 升级到 VS2019/Win10。项目构建,但是当我尝试RegSvr32.exe
从提升的命令提示符使用时,我收到错误 0x0040200。我做了一些调试,有问题的调用是对AfxOleRegisterTypeLib
.
是的,我看到了这篇SO 文章,其中指出“dll 附近没有 tlb 文件”。其他搜索状态从管理命令提示符运行。
我在 OCX 控件附近没有 TLB。如果我尝试使用创建一个tlbexp.exe
,我会收到以下错误:
TlbExp:错误 TX0000:无法加载文件或程序集 'file:///C:\pathto.ocx' 或其依赖项之一。该模块应包含程序集清单。
TlbExp 命令行(对所有 cmd.exe 使用以管理员身份运行):
"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools\x64\tlbexp.exe" /VERBOSE "<path to OCX file>" /out:"<path to .tlb output file>"
我下载Resource Tuner
了,它很好地显示了清单。清单没有任何 TLB 信息。
我在想,也许 OCX 清单需要更多的东西来帮助TlbExp
获取它想要的信息,只是一个想法。
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="DriveOps.ocx"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
我确实使用过Depends64
(aka Dependency Walker 64-bit
) 并且没有缺少组件 DLL。它可以很好地找到所有这些,RegSvr32.exe 也是如此。
将 OCX 文件放在 C:\Windows\System32 中没有帮助。
对于任何查看 DLL 的人来说,这些相同的 DLL 在 Win7 机器上运行良好。这是有关非 Windows DLL 的更多信息
- PlxApi720_x64.dll:PLX v7.2 API(Broadcom PLX 芯片是一个 PCIe 开关(想想 USB/网络开关,只有 PCIe 通道)
- LSIDirectAccess.dll:LSI API 是一个独立的 DLL,允许软件与 LSI HBA RAID 适配器通信
- Ipp*.dll:
Ipp
前缀是英特尔 Code Composer Studio 再分发 (x64) 文件使用的 DLL,这里是 2011 版,需要更新到最新和最好的旧版本,更不用说现在免费的 API。这些都在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;
}
Intel Code Composer Studio 2011
文件在目录C:\Windows\System32
中,就像在 Win7 盒子上一样。
对于它的价值,TlbExp
在Win7盒子上也失败了,只是它注册了,这可能是UI可以添加控件的原因。我记得我曾经在Win7项目上更换过OCX,VS2010自动创建了TLB并在前面加上前缀Ax,但那是几年前的事了,所以我的记忆可能不是最准确的。尝试将 OCX 添加到 UI(.Net WinForms)失败得很惨,只是说无法添加。
OCX 确实使用最新的平台工具集 ( Visual Studio 2019 (v142)
)。
对开发新手的评论regasm.exe
是针对 .Net Assemblies 的。RegSvr32.exe
是 for ActiveX Controls (OCX/DLL)
,这就是我所拥有的。RegSvr32 用于动态加载的模块,因此是 DllRegister 入口点。
想法?
进一步测试的笔记
(星期六 9/21/2019)升级时,我创建了一个空的 C++ DLL 项目,然后添加了所有文件,通过旧项目设置将目标扩展名更改为 OCX,并在合理时将它们与新项目文件对齐保持不变。我想做一个测试,看看一个全新的 OCX 项目会发生什么。我看到VS2019中有一个项目类型的“MFC ActiveX控件”这样的东西。我创建了它并看到我得到了不同的基础文件,但更重要的是 RegSvr32.exe 有效。这意味着错误是初始项目文件,所以我需要导入一个干净的项目或逐个导入,如果可能的话,看看哪里出了问题。
(2019 年 9 月 21 日星期六)新的测试项目没有附带清单文件,并且
TlbExp.exe
失败并出现与我的真实项目相同的错误消息。我去添加新项目并看到“包裹清单”。该清单文件虽然仍然产生相同的 TlbExp.exe 错误,但看起来与上面的应用程序清单文件完全不同。我创建了另一个新MFC ActiveX Control
项目并从上面添加了清单,只是更改了名称,然后看到该项目拒绝构建抛出 1) 错误 c1010001 不同清单片段中属性“级别”的值不相等。2) 运行 mt.exe 时出现 LNK1327 故障。这告诉我原来的 Win7 项目和我的 Win10 项目文件可能有一些错误,否则 VS 应该把这些错误抛给我。TlbExp.exe
失败。也许清单中的某些属性是必需的。我只是离开了默认值。
包清单(这是我第一次看到其中一个。我总是看到 app.manifest 那种。)
<?xml version="1.0" encoding="utf-8"?>
<!-- TODO: Make sure to set the Package attributes -->
<Package xmlns="urn:Microsoft.WindowsPhone/PackageSchema.v8.00"
Owner=""
OwnerType="OEM"
Platform=""
Component=""
SubComponent="Package"
ReleaseType="Test" >
<Components>
<Driver InfSource="$(_RELEASEDIR)$(TARGETNAME).inf">
<Reference Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" />
<Files>
<!-- For kernel mode drivers, $(DRIVER_DEST) evaluates to "drivers" by default -->
<!-- For user mode drivers, $(DRIVER_DEST) evaluates to "drivers\umdf" by default -->
<File Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" DestinationDir="$(runtime.system32)\$(DRIVER_DEST)" />
</Files>
</Driver>
</Components>
</Package>
- 本文有一个有趣的方法,即创建一个 C++ DLL,然后调用
LoadLibrary(dll)
,然后GetProcAddress(module, "DllRegisterServer")
查看哪个失败。好吧,就我而言,这两个功能都成功了。这意味着作者错过了另一个失败的分支,而且这两个 API 调用并不是唯一的RegSvr32.exe
。
解决方案
虽然我还没有走到尽头,就像我在 OCX 上遇到的问题一样,但我发现了阻止我注册 ActiveX 控件的问题,这就是这里的问题aximp.exe
。tlbimp.exe
答案GUID
在主 CPP 文件中:
(我正在做我的研究,因为我找不到任何人解释它是如何RegSvr32.exe
工作的以及它做了什么。我想分享一下,希望它可以帮助别人。)
const GUID CDECL _tlid = { 0xFE5C7D88,0xD53C,0x4977,{0xBA,0x56,0x4B,0xF3,0x02,0x0A,0x5D,0x8A} };
在主注册函数中使用的STDAPI DllRegisterServer(void)
必须与GUID
IDL 中的当前匹配:
[uuid(FE5C7D88-D53C-4977-BA56-4BF3020A5D8A), version(1.0),
helpfile("DriveOps.hlp"),
helpstring("DriveOps ActiveX Control module"),
control]
library DriveOpsLib
{
...
}
我有 2 个不同的值,因此失败了。
这是我用来发现问题的方法和研究,但首先我将说明注册功能,因为这又是关键。
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))
我已经RegSvr32.exe
在互联网上找到了源代码。它是GitHub
位于VCSamples-master
.
直接链接RegSvr32.exe
:这里
下载 zip 的直接链接:这里
该代码是一种死胡同,因为它告诉我应该显而易见的事情,即该实用程序调用DllRegisterServer
DLL 的入口点来完成所有工作。我应该知道这一点,但是,好吧,我必须看到它才有意义。
使用procmon.exe
, 没有任何意义,对注册表的各种调用就像阅读外语一样,没有帮助。
在这里,我画了一个空白,直到我想到要获取 的源代码AfxOleRegisterTypeLib
,因为那是失败的。我想看看那东西到底做了什么,以及 source file 的第 113 行是什么ctlreg.cpp
。
我仍在考虑评论procmon
和注册表问题,但我认为代码会告诉我是哪一个。我花了一些时间研究,但我找到了代码。我喜欢微软共享代码。他们的错误消息没有帮助,但能够真正看到他们正在尝试做的事情完全有帮助。
这是代码:
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_POINTER
,因为该错误消息不同,这意味着我失败了:
ASSERT(IsEqualGUID(tlid, tlidActual));
我详细查看了代码以及入口参数。我决定将这个函数内容复制并粘贴到我的 OCX 中的真实注册码中,以便在调试时获得进一步的可见性。我想看看价值观。
果然,我看到了 2 个不同GUID
的值,一个来自顶部,一个是 my _tlid
,另一个是从实例句柄返回的。我拿出我方便的TextPad
文本编辑器,虽然Visual Studio
有一个Find in Files
,但 TextPad 更容易使用。这导致了整个解决方案中的另一个实例,即在DriveOps.idl
. 直到那一刻之前的那个文件对我来说毫无意义,但突然我发现GUID
这里就是RegSvr32.exe
从实例句柄中拉出的那个。
我统一了ID,重建了,现在RegSvr32.exe
不再抱怨了。是的,既然我得到了代码,它别无选择,只能注册。它不修改注册表与我所知的情况和问题不同,但这是另一个问题。RegSvr32.exe
现在注册没有投诉。
(是的,我仍然有tlbimp.exe
, aximp.exe
, 并将我的 OCX 项目添加到我的WinForms
项目问题中,但我得到了这个东西舔并在这个过程中学到了一些东西。我猜行号的差异可能是微软在标题中所做的一些更改,无论哪种方式, 功能看起来是一样的。)
推荐阅读
- php - 如何从 id_item 将元素移动到另一个数组
- python - 消息从本地 python 传递到 chrome 扩展
- r - 计算R中的时间差时如何跳过NA
- python - 如何在 python 3.8 中使“for”循环遍历文本文件的所有行?
- c# - DataTable Select 方法中列值的 Replace() 函数
- linq - LINQ Query 可以返回 DataTable 每一列的计数
- spring-boot - maven liquibase插件不忽略文件路径中的前导/
- c - stdio.h 包含函数的定义或声明?
- python - 计算两种不同产品之间的更好价值
- r - 是否可以调整 R 制图包中的不透明度?