Getting the error message of a COM method called f

2019-07-31 13:28发布

问题:

Here is my 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;
    };
};

Here is my C++ implementation:

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;
}

Here is my C# code which calls the TestCrap method:

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);
}

I can't seem to figure out how to read back the error message I am passing to IErrorInfo. Am I missing something here? I implemented ISupportErrorInfo following this guide and it says on Wikipedia that:

In the .NET Framework, HRESULT/IErrorInfo error codes are translated into CLR exceptions when transitioning from native to managed code; and CLR exceptions are translated to HRESULT/IErrorInfo error codes when transitioning from managed to native COM code.

How can I properly set and get back the error message?

The current exception message is

Error HRESULT E_FAIL has been returned from a call to a COM component.

...but I expect it to return This is bananas..

回答1:

You should always do proper error checking in your code. This call:

SetErrorInfo(errorCode, pErrorInfo);

returns E_INVALIDARG because the first argument must be 0 as per official documentation. Replace it by:

SetErrorInfo(0, pErrorInfo);

And it will work.



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