我正在使用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,这意味着我调用了辅助函数:
CreateComObject(CLASS_GP2010);
大多数情况下,此函数都会成功。但是,在同一个可执行文件、同一个进程中,有时候,调用
CoCreateInstance
会失败,并显示以下错误信息:Unspecified error (0x80004005 = E_FAIL)
再次调用该函数可能会成功,也可能失败。没有(明显的)规律。
这不是我的COM dll
如果这是我编写的一个普通的 COM dll,我会从DLL_ATTACH
开始放置OutputDebugString
,当有人尝试调用DllGetClassObject
时,我会确认COM是否正确加载了我的DLL,并且它正在正确地请求实例化一个类。
不幸的是,这不是一个COM dll;它是一个.NET程序集dll。而COM子系统并不简单地“加载”我的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 之前),其中您无法将不同版本的 .NET 运行时加载到同一进程中:
这样做会引入 CLR 版本依赖性,可能与主机进程期望的 CLR 版本冲突
在使用COM包装器时,MSDN上的一篇文章中也提到了这种故障模式;您有选项指定clrVersion
:
如果已经加载了CLR的另一个版本,并且指定的版本可以在进程内并排加载,则会加载指定的版本;否则将使用加载的CLR。这可能会导致加载失败。
如果这是我的Windows XP上间歇性加载失败的原因,或者是.NET框架之前的旧版本,我该如何让mscoree.dll
告诉我呢?
如果原因是其他什么,我怎样才能让.NET告诉我呢?
mscoree.dll
被加载到进程中。你可以记录被加载的版本,然后在遇到故障时,检查进程生命周期内是否已经加载了不同的版本。如果是 CLR 版本冲突的问题,那么唯一可能的解释就是一个调皮的 shell 扩展使用了 .net,而不应该这样做。 - David HeffernanHRESULT
为0x80004005
是E_FAIL
(参见http://msdn.microsoft.com/en-us/library/windows/desktop/aa378137.aspx)。调试CCW和RCW的东西很难。这个.NET代码是你自己的吗?你能调试它吗?这可能是一个不错的开始:http://limbioliong.wordpress.com/2011/06/18/research-topic-hidden-ccw-per-com-client-app/ - Jeroen Wiert Pluimers