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

Casting to an interface from a COM library fails on the 16th managed thread within IIS (InvalidCastException, WinRT originate error 0x80040155)

我主要是为遇到这个奇怪问题的其他人发布这篇文章,如果有人能解释为什么 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 中实现,类型库用于创建 Interop DLL 并重新加载。

所以在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

演员表returns一下子null了。但是对象本身仍然有效,可以被询问,只是不再被铸造了。

为什么它在第 16 个线程上失败,并且事先可以正常工作? P.s。一切都设置为 STA。我该如何解决这个问题?

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

我是怎么到那里的?

鉴于该错误代码,我检查了注册表,正如我从痛苦的经历中了解到的那样,C# 或 OLE 喜欢在注册表中定义接口,因此它知道该做什么,而不是使用 Interops/TLB.

在搜索时,我发现注册表不包含 GUID_BAR 作为键,因此没有 proxy/stub 详细信息,就像所有其他界面一样。

抓住救命稻草我想,如果它只需要存在注册表项怎么办? 因此,我一个一个地添加属性,直到正确的一个将注册表设置推入,将 oleautomation 添加到 IBar 接口属性就可以了。一下子就修好了,再也没有施法失败了

但我不知道为什么 C# 在第 16 个托管线程之前运行良好。每个线程都有自己的一组对象(没有跨线程调用,以及托管到 COM 线程的 1:1 映射)。在尝试通过自动化测试重现此问题时,简单地创建数百个线程并执行类似的工作不会导致相同的失败。 IIS一定有什么特别之处。

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