当定义在C#COM类您通常有这样的签名:返回成功代码
void Login(string user,string password)
的AUTOMAGIC COM互操作包装意味着从C++调用时:
- 抛出一个异常被转换到故障
HRESULT
- 返回没有东西转换成回国
S_OK
但是,如果要返回S_OK
以外的成功代码,该怎么办?如S_FALSE
还是一些自定义的“成功,但...”的价值?
注意:我在C#中定义类,并想知道如何控制COM互操作。不在C#中基于IDL中的现有接口实现类。
当定义在C#COM类您通常有这样的签名:返回成功代码
void Login(string user,string password)
的AUTOMAGIC COM互操作包装意味着从C++调用时:
HRESULT
S_OK
但是,如果要返回S_OK
以外的成功代码,该怎么办?如S_FALSE
还是一些自定义的“成功,但...”的价值?
注意:我在C#中定义类,并想知道如何控制COM互操作。不在C#中基于IDL中的现有接口实现类。
HRESULT
通常是仅有错误代码的数据。它很少用于传达成功; S_FALSE
是唯一明确定义的例外。在S_FALSE
的情况下,它通常仅当结果类型是COM布尔型(VARIANT_BOOL
)和HRESULT
被映射到S_FALSE
当返回(下)是用VARIANT_FALSE
(和S_OK
时VARIANT_TRUE
)。
对于COM和.Net/COM边界错误(from here),维基百科也谈到了HRESULT
;
在.NET Framework中,从本机过渡到托管代码时,HRESULT/IErrorInfo错误代码会转换为CLR异常;并且CLR异常在从受管理的本地COM代码转换时转换为HRESULT/IErrorInfo错误代码。
虽然没有定论,但肯定不会重新执行该HRESULT
通常被视为一个错误代码的事实。访问IErrorInfo
可能会提供更多的数据,但我不确定它会如您所期望或期望的那样。
This MSDN article确实提供了更多关于如何映射COM错误和异常的信息,并再次支持错误代码;
COM方法通过返回HRESULT报告错误; .NET方法通过抛出异常来报告它们。运行时间处理两者之间的转换。 .NET Framework中的每个异常类都映射到HRESULT。
要支持“成功代码”,您可以使用额外的[out]
参数。如果代码不在您的控制范围内,您可以编写一个精简的COM对象来为您映射该对象,然后在.Net对象中使用该对象。
或者,你可以使用PreserveSigAttribute
,但据我所知,它不会翻译错误例外,所以你需要做的是自己(一个测试来验证这个建议)。使用[PreserveSig]
注解该方法应该可以做到。
你提出一个很好的例子,S_FALSE是一个异常,并且最好避免。我在这里注意到它特别指出“不能区分定期返回两个或更多不同成功代码的COM方法,例如S_OK或S_FALSE。” https://msdn.microsoft.com/en-us/library/bb164625.aspx –
您必须在方法声明中使用[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。
现在,不执行对HRESULT的.NET异常的automagic编组,是吗?所以我的C#方法不应该在发生失败的情况下抛出异常,而是始终使用C风格的方法?如果抛出什么会发生什么? –
[从C#COM DLL返回小号\ _FALSE]的可能的复制( http://stackoverflow.com/questions/2592684/returning-s-false-from-ac-sharp-com-dll) – user1
它与我所问的标题相同,但实际上是一个非常不同的问题(就像我理解它) - 他正在从IDL工作 - > C# –