在IIS内的第16个托管线程上,从COM库转换到接口失败(InvalidCastException,WinRT源自错误0



我发布这篇文章主要是为了其他遇到这个奇怪问题的人,如果有人能解释为什么IIS/Cassini是个魔鬼的话。

在大多数情况下,我们可以成功地将ODL中定义的Dispatch对象转换为

[ uuid(GUID_FOO) ]
dispinterface IFooDisp
{
... properties & methods.
};
[ uuid(GUID_FOO_COCLASS),noncreatable ]
coclass FooDisp
{
[default] dispinterface IFooDisp;
};

到以下接口

[ uuid(GUID_BAR) ]
interface IBar : IUnknown
{
... some methods
}

以上两个都是在一个注册的C++OLE/COM自动化DLL中实现的,类型库用于创建一个互操作DLL及其regasm’d。

因此,在C#中,我们可以成功地重复调用

myFoo as IBar

(IBar) myFoo

没有任何麻烦。直到

我们发现,如果我们打开一个网页,转到服务器上的URL,关闭浏览器并重复16次(Cassini或IIS(,当创建第16个托管线程时,转换突然失败,并出现以下潜在异常:

Exception Thrown at 0x75151812 (KernelBase.dll) in My.exe: 
WinRT originate error - 0x80040155 : 'Failed to find proxy registration for IID: {GUID_BAR}.' 

测试时

(myFoo as IBar)!=null

强制转换突然返回null。但对象本身仍然有效,可以被询问,只是不再投射。

为什么它在第16个线程上失败,并且事先工作良好?附言:一切都设置为STA。我该如何解决这个问题?

我可以告诉您如何修复它,将oleautomation添加到IBar属性中。但我不知道为什么有必要。

我是怎么到那里的

考虑到那个错误代码,我检查了注册表,正如我从痛苦的经历中知道的那样,C#或OLE喜欢在注册表中定义接口,这样它就知道该做什么,而不是使用Interops/TLB的细节。

在搜索时,我发现注册表中没有包含GUID_BAR作为键,因此没有像所有其他接口一样的代理/存根详细信息。

抓住救命稻草,我想,如果它只需要注册表项就可以存在呢?所以我一个接一个地添加属性,直到右边的一个推送了注册表设置,将oleautomation添加到IBar接口属性中就完成了任务。它突然修复了它,不再出现故障。

但我不知道为什么C#一直工作到第16个托管线程。每个线程都有自己的一组对象(没有跨线程调用,托管线程到COM线程的1:1映射(。在尝试用自动测试重现这一点时,只需创建数百个线程并进行类似的工作不会导致相同的失败。IIS一定有一些特别之处。

也许元数据被清除并重新收集?有人能解释更多吗?

最新更新