在 C# 中添加 COM 引用生成的代理存根时方法的返回值

Posted

技术标签:

【中文标题】在 C# 中添加 COM 引用生成的代理存根时方法的返回值【英文标题】:The return value of methods when adding a COM Reference generated proxy stub in C# 【发布时间】:2017-08-24 07:04:17 【问题描述】:

我的 ATL 项目中有这个方法,它公开了一个 COM 对象(sn-p 取自我的 *.idl 文件):

[id(1)] HRESULT Create([in, string] CHAR* location, [out] CerberusErrorDetails* details);

在注册我的对象并从我的托管 C# 代码中添加对它的引用后,它会为此方法生成以下代理存根 C# 代码:

[DispId(1)]
void Create(string location, out CerberusErrorDetails details);

这个存根对我来说有一些问题,我一直无法解决。首先,它不会在托管代码中返回int 值(相对于返回的HRESULT)来告诉我实际发生了什么错误。其次,该方法将抛出异常而不是返回错误代码。有没有办法让函数返回一个int,这样我就可以解析details对象,如果它不返回0,或者有没有其他方法可以得到我想要的行为?任何帮助是极大的赞赏。如果您需要更多详细信息,请随时提问,我会更新问题。谢谢!

【问题讨论】:

是的,它会引发异常,因为这是处理 .NET 中错误的正常方式。如果您需要检查,该异常确实会暴露 HResult 属性。 @Damien_The_Unbeliever 太糟糕了,他们自动以 .NET 方式处理结果。无论如何,奇怪的是,如果我将调用包装在一个 try-catch 块中,我会得到一个System.AccessViolationException,否则我会得到一个System.Runtime.InteropServices.COMException......所以无论哪种方式,我的应用程序仍然崩溃。为什么会如此令人沮丧? 我强烈怀疑从 .NET 编写 COM 组件并与它进行互操作的人数与仅 使用 .NET COM 组件的人数相比相形见绌。网。强迫每个人都学习两种错误处理技术将是残酷和不寻常的。如果您需要更多帮助,我认为您必须创建一个 MCVE。 @Damien_The_Unbeliever 我无法真正创建完整的 MCVE,因为如果没有适当的许可,我从 COM 对象内部调用的第三方库是不可再分发的。简而言之,我的项目是 C# wrapper -> MSVC++ COM Object -> C wrapper -> 3rd party library in C. 【参考方案1】:

是的,可以绕过 COM 互操作层的默认异常转换行为。但是,您必须重新定义本机 COM 接口并使用 PreserveSig 属性装饰所有方法:

[ComImport]
[Guid("xxx-yyy-zzz")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICOMInterfaceImp

     [PreserveSig]
     int Create(string location, out CerberusErrorDetails details);

然后你就可以在你的客户端中使用这个接口了:

ICOMInterfaceImp obj = (ICOMInterfaceImp)new CoClassImpl();

作为替代方案,您也可以使用来自 here 的更新的类型库导入器 (tlbimp.exe) 并传递 /PreserveSig 标志。

【讨论】:

以上是关于在 C# 中添加 COM 引用生成的代理存根时方法的返回值的主要内容,如果未能解决你的问题,请参考以下文章

我可以建议“生成方法存根”在 Visual C# 中存储新生成代码的位置吗?

C# 动态调用 WebService (转)

C# 调用WebService的方法

C#中Winform动态调用Webservice的方法(转)

C#中怎么调用WebService

无法在 Mono 中编译 svcutil 生成的 C#