在.NET中,COM的HRESULT被封装成异常

7

初步说明:我还没有完全掌握整个“interop”事情...

在.NET中使用COM库时,所有的HRESULT方法都被包装成了当返回代码不是SUCCEEDED时抛出异常的形式。

//ATL magic exluded
class C {
    HRESULT foo(){ return E_FAIL; }
};

// usage code:
if( SUCCEEDED( c.foo() ) ) {
   // success code
} else {
   // failure code
}

这段代码的.NET对应版本如下:

try {
   c.foo();
   // success code
} catch ( Exception e ) {
   // failure code
}

有没有一种方法可以直接在.NET中访问COM返回代码,从而无需使用异常处理?
1个回答

7

是的,但您需要手动定义交互接口(而不是使用tlbimp.exe),并在相关方法上使用PreserveSig属性。

例如:

[ComImport]
[Guid("your-guid-here")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMyComInterface
{
     [PreserveSig]
     int DoSomething(out int result);
}

这相当于带有签名HRESULT DoSomething([out, retval] int *result);的COM方法。
如果您的接口非常复杂或者您在定义交互操作界面方面遇到困难,我建议使用tlbimp.exe,然后使用反编译工具(如Reflector或ILSpy)来反编译生成的接口,并根据需要进行编辑。这样可以节省工作量。 :)

我只是想更明确地指出,[PreserveSig] 是用于说明是否要将 HRESULTS 转换为异常的属性。还应该注意到,通常情况下您希望使用异常。HRESULTS 的存在仅因为并非所有语言都以相同的方式处理异常,因此需要一种基于非异常的机制来报告异常。一旦进入自己的语言环境,HRESULT 应该(理想情况下)转换为您语言的本机异常机制。 - Ian Boyd
1
这不是你想要使用 [PreserveSig] 的唯一原因。有些 COM 接口为了好或坏使用 HRESULT 作为布尔值;这些函数可以返回 S_OK、S_FALSE 或错误值。如果你不使用 [PreserveSig],就无法知道它是否返回了 S_OK 或 S_FALSE。这不仅适用于 S_FALSE,而且适用于任何非错误 HRESULT。幸运的是,这样做的 COM 类很少,但它们确实存在。 - Sven
还有一个非常奇怪的 IProgressDialog.HasUserCancelled 方法,它甚至不返回 HRESULT(像接口的其他方法一样),而是返回一个 BOOL。(几乎可以肯定这是 Windows 95 中原始接口中的一个错误,现在为了兼容性而被冻结) - Ian Boyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接