首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >OCX AfxOleRegisterTypeLib失败,错误为0x80040200

OCX AfxOleRegisterTypeLib失败,错误为0x80040200
EN

Stack Overflow用户
提问于 2019-09-20 23:47:14
回答 2查看 919关注 0票数 2

我将OCX库从an 2010/Win7 7升级到an 2019/Win7 10。但是,当我尝试从提升的命令提示符使用RegSvr32.exe时,我会收到错误0x0040200。我做了一些调试,错误的调用是对AfxOleRegisterTypeLib的调用。

是的,我看到了这么一篇文章,它说“dll附近没有一个tlb文件”。其他搜索状态从管理命令提示符运行。

我在OCX控件附近没有TLB。如果我尝试使用tlbexp.exe创建一个,则会得到以下错误:

错误file:///C:\pathto.ocx‘:无法加载文件或程序集’TlbExp或其依赖项之一。预计该模块将包含程序集清单。

TlbExp命令行(用作所有cmd.exe的管理员):

代码语言:javascript
运行
复制
"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获取它想要的信息,只是一个想法。

代码语言:javascript
运行
复制
<?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也是如此。

将OCX文件放置在C:\Windows\System32 32中没有帮助。

对于任何查看DLL的人来说,这些相同的DLL在Win7框上都能很好地工作。下面是关于非Windows DLL的更多信息

  • PlxApi720_x64.dll: PLXv7.2API( Broadcom芯片是PCIe交换机(想想USB/网络交换机,只是w/PCIe通道)
  • LSIDirectAccess.dll: LSI API是一个自包含的DLL,允许软件与LSI HBA适配器对话。
  • Ipp*.dll:Ipp前缀是重新分配(x64)文件使用的DLL,这里是2011版,需要更新到最新和最好的版本,更不用说现在的免费API了。这些都在System32文件夹中。

以下是代码:

代码语言:javascript
运行
复制
// 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.exeActiveX Controls (OCX/DLL)的,这就是我所拥有的。RegSvr32用于动态加载模块,因此是DllRegister入口点。

有什么想法?

进一步测试的备注

  1. (星期六9/21/2019)当我升级时,我创建了一个空的C++ DLL项目,然后添加了所有的文件,将目标扩展名更改为OCX,遍历旧的项目设置,并且当它们与希望保持不变的新项目文件合理地对齐时。我想做一个测试,看看一个全新的OCX项目会发生什么。我看到,对于ActiveX中的项目类型,有一种类似于"MFC控件“的东西。我创建了它,并看到我得到了不同的基本文件,但更重要的是,RegSvr32.exe工作。这意味着要么错误是最初的项目文件,所以我需要导入到一个干净的项目或导入,如果可能的话,一片片,看看什么东西坏了。
  2. (2019周六9/21/2019)新的测试项目没有提供一个清单文件,而且TlbExp.exe失败了,错误消息与我真正的项目相同。我去添加新的项目,并看到了“包装清单”。这个清单文件虽然仍然会产生相同的TlbExp.exe错误,但与上面的应用程序清单文件看起来完全不同。我创建了另一个新的MFC ActiveX Control项目,并从上面添加了清单,仅更改名称,并看到该项目拒绝构建抛出错误c1010001值的属性“级别”在不同的清单片段中不相等。2) LNK1327在运行mt.exe过程中发生故障。这告诉我,原始的Win7项目和我的Win10项目文件中可能有一些错误,否则VS应该把这些错误抛给我。这并不能解释为什么即使在测试项目中,TlbExp.exe也会失败。可能清单中的一些属性是必需的。我只是留下了缺省值。

包装清单(这是我第一次看到这些。我总是看到app.manifest那种。)

代码语言:javascript
运行
复制
<?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>
  1. 这个文章有一种有趣的方法,即创建一个C++ DLL,然后调用LoadLibrary(dll),然后调用GetProcAddress(module, "DllRegisterServer"),查看哪个GetProcAddress(module, "DllRegisterServer")失败了。在我的例子中,这两种功能都成功了。这意味着作者错过了另一个失败分支,这两个API调用并不是RegSvr32.exe所做的唯一事情。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-18 22:46:44

虽然我还没有走到尽头,因为我在OCX上有aximp.exe / tlbimp.exe问题,但我发现了阻止我注册ActiveX控件的问题,这就是这里的问题。

答案是主CPP文件中的GUID

(我正在进行我的研究,因为我找不到任何人解释RegSvr32.exe是如何工作的以及它是如何工作的。我希望它能帮助其他人。)

代码语言:javascript
运行
复制
const GUID CDECL _tlid = { 0xFE5C7D88,0xD53C,0x4977,{0xBA,0x56,0x4B,0xF3,0x02,0x0A,0x5D,0x8A} };

在主注册函数STDAPI DllRegisterServer(void)中使用的GUID必须与IDL中的GUID匹配:

代码语言:javascript
运行
复制
[uuid(FE5C7D88-D53C-4977-BA56-4BF3020A5D8A), version(1.0),
helpfile("DriveOps.hlp"),
helpstring("DriveOps ActiveX Control module"),
control]
library DriveOpsLib
{
...
}

我有两个不同的价值观,因此失败了。

这是我用来发现问题的方法和研究,但首先我要说明注册函数,因为这是关键。

代码语言:javascript
运行
复制
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;
}

正如我在问题中提到的那样,失败就在这条线上。

代码语言:javascript
运行
复制
if (!AfxOleRegisterTypeLib(hiTypeLib, _tlid))

我已经在互联网上找到了RegSvr32.exe的源代码。它是位于GitHub中的微软VCSamples-master资源的一部分。

直接链接到RegSvr32.exe这里

直接链接下载zip:这里

代码是一种死胡同,因为它告诉我什么应该是显而易见的,即这个实用程序称为DLL的DllRegisterServer入口点来完成所有的工作。我应该知道的,但是,好吧,我必须看到它才有意义。

使用procmon.exe,并没有透露任何信息,对注册表的各种调用就像读取一种外语一样,没有帮助。

在这里,我画了一个空白,直到我想到要获得AfxOleRegisterTypeLib的源代码,因为这是失败的。我想看看那个东西到底做了什么,以及源文件ctlreg.cpp第113行的内容。

我仍然在考虑procmon的评论和注册表问题,但我想代码会告诉我是哪一个。这花了我一点研究,但我找到了代码。我喜欢微软的共享代码。他们的错误信息是没有帮助的,但能够真正看到他们试图这样做完全是有帮助的。

以下是代码:

代码语言:javascript
运行
复制
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上没有失败,因为错误消息是不同的,这意味着我失败了:

代码语言:javascript
运行
复制
        ASSERT(IsEqualGUID(tlid, tlidActual));

我详细研究了代码和条目参数。我决定将此函数内容复制并粘贴到OCX中的真实注册代码中,以便在调试时获得进一步的可见性。我想看看这些价值观。

当然,我看到了两个不同的GUID值,一个来自顶部,一个来自_tlid,另一个来自实例句柄。我拿出了我的方便的TextPad文本编辑器,虽然Visual Studio有一个Find in Files,但是TextPad非常容易使用。这导致了整个解决方案中的另一个实例,即DriveOps.idl。直到那一刻为止,那个文件对我来说毫无意义,但我突然发现这里的GUIDRegSvr32.exe从实例句柄中提取的那个。

我统一了ID,重新构建,现在RegSvr32.exe不再抱怨了。是的,既然我拿到密码了,它别无选择,只能注册。它不修改注册表是一个不同的故事和问题,我可以说,但这是另一个问题。RegSvr32.exe现在毫无怨言地注册。

(是的,我仍然有tlbimp.exeaximp.exe,并将我的OCX项目添加到我的WinForms项目问题中,但是在这个过程中,我得到了一些教训。我想,行号的不同可能是微软在标题中做了一些修改,无论哪种方式,功能都是一样的。)

票数 0
EN

Stack Overflow用户

发布于 2021-12-29 17:10:34

太棒了。在所有这些情况下,IDL都有一个与DLL / OCX在注册代码中不同的GUID。它是如何改变的,我没有调查,但是能够通过从项目生成的*.idl文件中读取新的GUID来解决这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58036192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档