我将OCX库从VS2010 / Win7升级到VS2019 / Win10。该项目生成,但是当我尝试从提升的命令提示符下使用RegSvr32.exe
时,收到错误0x0040200。我做了一些调试,令人讨厌的呼叫是对AfxOleRegisterTypeLib
的呼叫。
是,我看到了this 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
(又名Dependency Walker 64-bit
),并且没有缺少的组件DLL。它很好地找到了它们,就像RegSvr32.exe一样。
在C:\ Windows \ System32中放置OCX文件无济于事。
对于任何查看DLL的人,这些相同的DLL在Win7盒中都可以正常工作。这是有关非Windows DLL的更多信息
Ipp
前缀是Intel 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程序集。 RegSvr32.exe
代表ActiveX Controls (OCX/DLL)
,这就是我所拥有的。 RegSvr32用于动态加载的模块,因此是DllRegister入口点。
想法?
进一步测试的注意事项
(Saturday 9/21/2019)升级时,我创建了一个空的C ++ DLL项目,然后添加了所有文件,将目标扩展名更改为OCX,并通过了旧的项目设置,并在合理的情况下将其与新的对齐希望保持不变的项目文件。我想做一个测试,看看一个全新的OCX项目会发生什么。我看到VS2019中的项目类型存在诸如“ MFC ActiveX控件”之类的东西。我创建了该文件,并看到了不同的基本文件,但更重要的是RegSvr32.exe可以运行。这意味着错误是最初的项目文件,因此,如果可能的话,我需要导入到一个干净的项目或逐个导入,然后查看出现问题的地方。
((Saturday 9/21/2019)新的测试项目没有清单文件,并且TlbExp.exe
失败,并显示了与我的真实项目相同的错误消息。我去添加新物品,看到“包装清单”。该清单文件尽管仍会产生相同的TlbExp.exe错误,但与上面的应用程序清单文件看起来有很大不同。我创建了另一个新的MFC ActiveX Control
项目,并从上面添加了清单,只是更改了名称,然后看到该项目拒绝构建并抛出1)错误c1010001属性“ level”的值在不同的清单片段中不相等。和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>
LoadLibrary(dll)
,然后调用该GetProcAddress(module, "DllRegisterServer")
以查看哪个失败。好吧,就我而言,这两个功能都成功了。这意味着作者错过了另一个失败分支,并且这两个API调用不是RegSvr32.exe
唯一要做的事情。尽管我还没有走到尽头,因为我在OCX上遇到aximp.exe
/ tlbimp.exe
问题,但我发现了阻止我注册ActiveX控件的问题,这就是这里的问题。
答案是主CPP文件中的GUID
:
((我正在做研究,因为我找不到任何人解释RegSvr32.exe
的工作原理和作用。我希望与大家分享,希望它能对其他人有所帮助。)
const GUID CDECL _tlid = { 0xFE5C7D88,0xD53C,0x4977,{0xBA,0x56,0x4B,0xF3,0x02,0x0A,0x5D,0x8A} };
在主注册功能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))
我已经在互联网上找到RegSvr32.exe
的源代码。它是GitHub
中Microsoft VCSamples-master
源的一部分。
直接链接到RegSvr32.exe
:here
直接链接下载zip:here
该代码是一种死胡同,正如它告诉我的,应该是显而易见的,即该实用程序调用DLL的DllRegisterServer
入口点来完成所有工作。我应该知道这一点,但是,好吧,我必须看到它才有意义。
使用procmon.exe
,没有透露任何信息,并且对注册表的各种调用就像在阅读外语一样,没有帮助。
在这里我画了一个空白,直到我想到要获取AfxOleRegisterTypeLib
的源代码,因为那是失败的。我想查看该操作的结果以及源文件ctlreg.cpp
的第113行的内容。
我仍在思考procmon
的评论和注册表问题,但我认为代码可以告诉我哪个。我花了一些时间进行研究,但发现了code。我喜欢Microsoft共享代码。他们的错误消息没有帮助,但是能够真正看到他们正在尝试的操作完全有帮助。
这里是代码:
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
值,其中一个是顶部,我的_tlid
,另一个是从实例句柄返回的值。尽管TextPad
有一个Visual Studio
,但我还是取出了方便的Find in Files
文本编辑器,但是TextPad的使用非常方便。这导致整个解决方案中的另一个实例,即DriveOps.idl
。直到那一刻,该文件对我来说都没有任何意义,但突然我发现GUID
是RegSvr32.exe
从实例句柄中拉出的那个文件。
我统一了ID,对其进行了重建,现在RegSvr32.exe
不再抱怨。是的,自从我有了代码后,除了注册外别无选择。据我所知,它不修改注册表是一个不同的故事和问题,但这是另一个问题。 RegSvr32.exe
现在进行注册,无需投诉。
((是的,我仍然有tlbimp.exe
,aximp.exe
,并将OCX项目添加到我的WinForms
项目问题中,但是在过程中我发现了这件事并学到了一些东西。我猜可能行号有所不同是Microsoft在标头中所做的一些更改,无论哪种方式,功能都相同。)