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

时间:2015-10-15 10:59:45

标签: c# c++ .net com com-interop

在C#中定义COM类时,通常会有如下签名:

void Login(string user,string password)

自动COM互操作包装器意味着从C ++调用时:

  • 抛出异常会转换为失败HRESULT
  • 返回任何内容都不会转换为返回S_OK

但是,如果您想要返回S_OK以外的成功代码,该怎么办?例如S_FALSE或某些习惯"成功,但......"值?

注意:我在C#中定义了类,并想知道如何控制COM互操作的功能。不基于IDL中的现有接口在C#中实现类。

2 个答案:

答案 0 :(得分:3)

HRESULT通常只是一个错误代码数据。它很少用于传达成功; S_FALSE是唯一明确定义的例外。在S_FALSE的情况下,它通常仅在结果类型为COM布尔值(VARIANT_BOOL)时使用,并且HRESULT在返回时返回(S_FALSEVARIANT_FALSES_OK时为VARIANT_TRUE

维基百科还讨论了HRESULT的COM错误和.Net / COM边界(from here);

  

在.NET Framework中,当从本机代码转换为托管代码时,HRESULT / IErrorInfo错误代码将转换为CLR异常;从托管COM转换为本机COM代码时,CLR异常转换为HRESULT / IErrorInfo错误代码。

虽然没有定论,但肯定会重新强调HRESULT通常被视为错误代码的事实。访问IErrorInfo可能会提供更多数据,但我不确定它是否符合您的预期或期望。

This MSDN article确实提供了有关如何映射COM错误和异常的更多信息,再次支持错误代码;

  

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

支持"成功代码"您可以使用其他[out]参数。如果代码在您的控件之外,您可以编写一个瘦COM对象来为您映射,然后在.Net对象中使用它。

或者,您可以使用PreserveSigAttribute但据我所知,它不会将错误转换为异常,因此您需要自己执行此操作(验证此操作的测试)建议)。用[PreserveSig]注释方法应该可以解决问题。

答案 1 :(得分:2)

您必须在方法声明中使用[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。