我发布这篇文章主要是为了其他遇到这个奇怪问题的人,如果有人能解释为什么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一定有一些特别之处。
也许元数据被清除并重新收集?有人能解释更多吗?