【问题标题】:How to diagnose COM-callable wrapper object creation failure?如何诊断 COM 可调用包装对象创建失败?
【发布时间】:2013-07-24 02:05:42
【问题描述】:

我正在使用 CoCreateInstance 创建一个 COM 对象(从本机代码):

const 
   CLASS_GP2010: TGUID = "{DC55D96D-2D44-4697-9165-25D790DD8593}";

hr = CoCreateInstance(CLASS_GP2010, nil, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IUnknown, out unk);

其实我是在Delphi,也就是说我调用了helper函数:

CreateComObject(CLASS_GP2010);

大多数情况下,此函数都会成功。但有时,在同一个可执行文件中,在同一个进程中,对CoCreateInstance 的调用会失败,并显示:

Unspecified error (0x80004005 = E_FAIL)

再次调用函数可能成功,也可能失败。没有(明显的)韵律或理由。

这不是我的 COM dll

如果这是我编写的普通 COM dll,我会开始将OutputDebugString 放入DLL_ATTACH,当有人尝试调用DllGetClassObject 时,我会确认COM 是正确的加载我的 DLL,并且它正确地要求实例化一个类。

很遗憾,它不是 COM dll;这是一个 .NET 程序集 dll。还有 COM 子系统 does not simply "load" 我的 dll。相反,COM 被指示加载mscoree.dll

HKEY_CLASSES_ROOT
   CLSID
      {DC55D96D-2D44-4697-9165-25D790DD8593}
         InprocServer32
            @default = mscoree.dll

mscoree.dll 导出所需的GetClassObject 函数。所以mscoree.dll 是返回E_FAIL 的人,而不是我。在我的开发机器上从未发生过故障,但在客户机器上总是间歇性地失败。

如何启用 .NET 日志记录?

问题是,因为mscoree.dll 是返回E_FAIL 的那个(而不是任何有用的东西):我如何让它告诉我问题出在哪里?

例如,似乎唯一遇到故障的客户(除了是唯一大量使用 COM 对象的客户)碰巧在 Windows XP 上。也许他们遇到了 .NET 框架(版本 4 之前)中的已知错误,您 cannot load different versions of the .NET runtime into the same process:

这样做会引入一个 CLR 版本依赖关系,它可能与宿主进程期望的 CLR 版本冲突

这种故障模式在an article on MSDN when using COM wrappers中也有说明;您有选项指定clrVersion:

如果已经加载了另一个版本的 CLR,并且可以在进程中并行加载指定的版本,则加载指定的版本;否则,使用加载的 CLR。这可能会导致加载失败。

如果这我在 Windows XP 或 .NET 框架上的早期版本中间歇性加载失败的原因,我如何让 mscoree.dll 告诉我?

如果原因是其他原因,我如何让 .NET 告诉我?

【问题讨论】:

  • 您可以在您的程序中添加一些诊断信息,以便随时将mscoree.dll 加载到您的进程中。您会注意到加载了哪个版本,然后当您遇到故障时,请检查您是否在该过程的生命周期内加载了不同的版本。如果是 CLR 版本冲突的问题,那么一个合理的解释是一个顽皮的 shell 扩展,它在不应该使用 .net 时使用。
  • @DavidHeffernan 我如何在运行时记录模块加载?我从未见过模块加载/卸载的唯一方法是在 Delphi 的 Event Log 中。 Bonus Chatter:我的第一人称单数代词的大小写是故意的。
  • +1;好问题。你应该解释0x80004005HRESULTE_FAIL(参见msdn.microsoft.com/en-us/library/windows/desktop/aa378137.aspx)调试CCW 和RCW 的东西很难。 .NET 代码是你的吗?可以调试吗?这可能是一个好的开始:limbioliong.wordpress.com/2011/06/18/…
  • 我会考虑使用 SysInternals 的 ProcMon 来收集客户环境的日志。它是收集组件无法提供的深度系统交互日志的绝佳资源。运行该工具确实会影响性能,因此客户必须知道开始收集日志,然后在问题重现后停止并向您发送跟踪信息。

标签: .net delphi com ccw com-callable-wrapper


【解决方案1】:

您可以使用程序集绑定失败日志记录功能 - 需要启用它,然后您可以使用融合日志查看器查看结果 http://msdn.microsoft.com/en-us/library/e74a18c4(v=vs.110).aspx 不确定如何将其安装到您的客户端计算机上。

当我第一次阅读这篇文章时,我的第一个想法似乎是在 win xp 机器上最常见的是这是一个 .net 版本/位明智的问题,或者您的 .net dll 是否缺少这些机器上不存在的依赖项。

【讨论】:

  • 问题是该对象在某个时刻创建良好,然后在下一次调用期间失败,然后再次工作。 dll 仍然存在。
【解决方案2】:

至少,如果您要在 Visual Studio 的调试器中运行它,您可能能够捕获第一次机会异常并获得一些洞察力。至少,您想知道 E_FAIL 会导致什么样的错误。即使您没有调试符号,您也应该能够做到这一点。

此外,即使您无法在同一个进程中加载​​多个 .NET 虚拟机,通过一些手动操作 App.config 和 .dll 清单,您也可以在同一个 .NET 虚拟机中加载 .dll即使它们是针对不同的编译器编译的。

最后,检查应用程序事件下的 windows 事件查看器,看看那里是否记录了任何内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 2010-09-11
    • 2018-03-13
    相关资源
    最近更新 更多