获取COM对象以在C#中除S_OK(0)之外的任何结果抛出异常

Ale*_*all 5 c# com

我正在努力升级到一个广泛使用COM/MFC /(谁知道有多少其他技术)的项目.作为升级的一部分,我们尝试将尽可能多的功能移植到托管C#代码中,但遗憾的是有些东西无法移动(原因我不会进入).其中一个问题是严重滥用COM的代码段,并返回HRESULT中的指针,这些指针稍后会被转换为各种其他COM接口实现对象.我已经尝试了以下代码将HRESULT转换为指针,然后我可以从中获取接口:

        MyComInterfaceInCS myObj = null;

        try
        {
            world.GetTD_MyComInterfaceInCS();
        }
        catch (COMException comException)
        {
            int pointerValue = Marshal.GetHRForException(comException);

            IntPtr myObjPointer = new IntPtr(pointerValue);

            myObj = (MyComInterfaceInCS) Marshal.GetObjectForIUnknown(myObjPointer);
        }
Run Code Online (Sandbox Code Playgroud)

.... 但是,没有抛出COM异常,我猜它是因为指针不是负值,因此技术上不是COM错误.有没有办法在对象上配置COM以在任何事件上抛出COM异常但是S_OK(0)?

dka*_*man 5

两个想法:

  1. 找到并杀死(或严重伤害)实施此库的人
  2. 在托管C++中实现一个包装器,因为您需要直接获取方法调用的HResult,而我想不出使用interop的方法.

编辑

另一种选择是在C#中声明COM接口,使得每个方法的签名返回一个HRESULT并使用[out retval]作为返回值.这将使您获得并检查所有方法调用的HRESULT,而不仅仅是抛出COMException的方法.

默认情况下,COM interop typeimport"修复"方法签名,以便在托管端删除HRESULT返回,并且interop层抛出E_FAIL等异常,基本上丢弃S_OK,S_FALSE等.

本文有一些解释,PreserveSig attriubte文档有一些额外的细节.

这可能需要您手动声明所有COM接口而不是使用tlbimp,但是您可以获得tlbimp来保留COM方法的签名.

这样你就可以完全保留在C#中了,但是我会选择托管C++,因为它更容易以非标准的方式与COM进行交互.