【发布时间】: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;好问题。你应该解释
0x80004005的HRESULT是E_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