从c#中定义的COM类返回成功代码

本文关键字:返回 成功 代码 COM 定义 | 更新日期: 2023-09-27 18:17:45

当你在c#中定义一个COM类时,你通常有这样的签名:

void Login(string user,string password)
自动COM互操作包装意味着当从c++调用时:
  • 抛出异常被转换为失败HRESULT
  • 不返回任何值转换为返回S_OK

但是,如果您想返回S_OK以外的成功代码,该怎么办?例如S_FALSE或一些自定义的"成功,但是……"值?

注意:我正在用c#定义类,想知道如何控制COM互操作的功能。没有在c#中实现基于IDL中已有接口的类

从c#中定义的COM类返回成功代码

HRESULT通常是一个只有错误码的基准。它很少被用来表达成功;S_FALSE是唯一定义良好的例外。在S_FALSE的情况下,它通常只在结果类型为COM布尔值(VARIANT_BOOL)时使用,当返回(输出)为VARIANT_FALSE时将HRESULT映射为S_FALSE(当VARIANT_TRUE时将S_OK)。

维基百科还讨论了HRESULT对于COM和。net/COM边界错误的情况;

在。net框架中,当从本机代码转换为托管代码时,HRESULT/IErrorInfo错误代码被转换为CLR异常;当从托管到本机COM代码转换时,CLR异常被转换为HRESULT/IErrorInfo错误代码。

虽然不是决定性的,但它确实强化了HRESULT通常被视为错误代码的事实。访问IErrorInfo可能会提供一些更多的数据,但我不确定它会像你期望的或希望的那样。

这篇MSDN文章提供了更多关于如何映射COM错误和异常的信息,同样支持错误代码;

COM方法通过返回HRESULTs报告错误;. net方法通过抛出异常来报告它们。运行时处理两者之间的转换。. net框架中的每个异常类都映射到一个HRESULT。

支持"成功码"您可以使用额外的[out]参数。如果代码不在您的控制范围内,您可以编写一个瘦COM对象来为您映射它,然后在。net对象中使用它。

或者,您可以使用PreserveSigAttribute,但据我所知,它不会将错误转换为异常,因此您需要自己做(建议进行测试以验证这一点)。用[PreserveSig]注释该方法应该可以达到目的。

必须在方法声明中使用[PreserveSig]属性。也就是说,它保留了方法签名,并防止类型库导出器重写方法签名以使其与COM兼容。返回类型必须int,以便与HRESULT兼容。

你的例子很简单:

   void Login(string user, string password);

就变成:

   [PreserveSig]
   int Login(string user, string password);

当它是一个非void返回类型的方法时,它就更复杂了。然后必须按照类型库导出器的方式重写它。将其作为ref关键字的额外参数添加。所以:

   bool Login(string user, string password);

就变成:

   [PreserveSig]
   int Login(string user, string password, ref bool success);

请记住,S_FALSE的值是1,而不是0。