【问题标题】:Getting the error message of a COM method called from C#获取从 C# 调用的 COM 方法的错误消息
【发布时间】:2017-12-25 12:18:08
【问题描述】:

这是我的 IDL:

[
    object,
    uuid(61B0BFF7-E9DF-4D7E-AFE6-49CC67245257),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface ICrappyCOMService : IDispatch {
    typedef
    [
        uuid(C65F8DE6-EDEF-479C-BD3B-17EC3F9E4A3E),
        version(1.0)
    ]
    struct CrapStructure {
        INT ErrorCode;
        BSTR ErrorMessage;
    } CrapStructure;
    [id(1)] HRESULT TestCrap([in] INT errorCode, [in] BSTR errorMessage, [in, out] CrapStructure *crapStructure);
};
[
    uuid(763B8CA0-16DD-48C8-BB31-3ECD9B9DE441),
    version(1.0),
]
library CrappyCOMLib
{
    importlib("stdole2.tlb");
    [
        uuid(F7375DA4-2C1E-400D-88F3-FF816BB21177)      
    ]
    coclass CrappyCOMService
    {
        [default] interface ICrappyCOMService;
    };
};

这是我的 C++ 实现:

STDMETHODIMP CCrappyCOMService::InterfaceSupportsErrorInfo(REFIID riid)
{
    static const IID* const arr[] = {
        &IID_ICrappyCOMService
    };
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
        if (InlineIsEqualGUID(*arr[i], riid))
            return S_OK;
    }
    return S_FALSE;
}

STDMETHODIMP CCrappyCOMService::TestCrap(INT errorCode, BSTR errorMessage, CrapStructure *crapStructure) {
    memset(crapStructure, 0, sizeof(CrapStructure));
    crapStructure->ErrorCode = errorCode;
    crapStructure->ErrorMessage = errorMessage;
    ICreateErrorInfo* pCreateErrorInfo;
    CreateErrorInfo(&pCreateErrorInfo);
    pCreateErrorInfo->AddRef();
    pCreateErrorInfo->SetDescription(errorMessage);
    pCreateErrorInfo->SetGUID(IID_ICrappyCOMService);
    pCreateErrorInfo->SetSource(L"CCrappyCOMService::TestCrap");
    IErrorInfo* pErrorInfo;
    pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void**)&pErrorInfo);
    pErrorInfo->AddRef();
    SetErrorInfo(errorCode, pErrorInfo);
    pErrorInfo->Release();
    pCreateErrorInfo->Release();
    return E_FAIL;
}

这是我调用 TestCrap 方法的 C# 代码:

static void Main(string[] args)
{
    var service = new CrappyCOMService();
    var crapStructure = new CrapStructure();
    try
    {
        service.TestCrap(1337, "This is bananas.", ref crapStructure);
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception.ToString());
    }
    Console.WriteLine(crapStructure.ErrorCode);
    Console.WriteLine(crapStructure.ErrorMessage);
}

我似乎不知道如何回读我传递给IErrorInfo 的错误消息。我在这里错过了什么吗?我在this guide 之后实现了ISupportErrorInfo,它在Wikipedia 上说:

在 .NET Framework 中,会翻译 HRESULT/IErrorInfo 错误代码 从本机代码转换到托管代码时进入 CLR 异常; 和 CLR 异常被转换为 HRESULT/IErrorInfo 错误代码 从托管 COM 代码转换到本机 COM 代码时。

如何正确设置和取回错误信息?

当前异常消息是

对 COM 组件的调用返回了错误 HRESULT E_FAIL。

...但我希望它会返回这是香蕉。

【问题讨论】:

  • 你应该养成使用ATL安全COM指针类msdn.microsoft.com/en-us/library/ezzw7k98.aspx的习惯
  • 您是假设我的错误代码和消息正在被垃圾收集,还是因为我没有使用AddRef?无论如何,我更新了代码,但正如他们所说,我们在这里有更大的鱼要炒。我仍在试图弄清楚如何让该错误消息将自身映射到 CLR 异常中。
  • 不,我认为 COM 对象根本没有被释放,只是使用原始指针非常容易出错并且对小猫不友好。我刚刚做了一些研究并查看了一些 MS 示例,您的代码对我来说似乎很好。 :)
  • 小猫应该保持爪子#.
  • 您的问题并未显示您的 C++ 代码在其QueryInterface 中是否正确支持ISupportsErrorInfo

标签: c# c++ .net com atl


【解决方案1】:

您应该始终在代码中进行适当的错误检查。这个电话:

SetErrorInfo(errorCode, pErrorInfo);

返回 E_INVALIDARG,因为第一个参数必须为 0,根据 official documentation。替换为:

SetErrorInfo(0, pErrorInfo);

它会起作用的。

【讨论】:

  • 嗨,西蒙,感谢您的帮助!我有一个后续问题,有没有办法支持添加自定义错误代码返回?
  • 我可以设置一个非 COM HRESULT,这似乎在 C# 世界中设置了错误代码,但在我的其他问题上,人们抱怨这是一种非标准方法:stackoverflow.com/questions/45203290/…跨度>
  • 您可以将 E_FAIL 替换为任意数字(设置了高位),您将在COMException.HResult 中获得该数字。
  • 是的,任何负数。和我想的一样。这里的其他一些人有点误导,例如说 -1 是无效的 HRESULT,但最终我可以将我的错误代码设置为我想要的任何值,这仍然会遵循 COM 标准。
  • 我对这一切有一个相关的后续问题:stackoverflow.com/questions/45215419/… 我感觉你可能以前见过这个问题!西蒙,如果你能抽出时间来帮助我,请看看!
猜你喜欢
  • 2014-02-09
  • 1970-01-01
  • 2021-01-20
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多