Search code examples
visual-c++structcomatlidl

Returning a struct from COM


I am working on an ATL project in Visual Studio which exposes a COM object which defines a structure.

I have the following COM method defined in my *.idl:

[id(2)] HRESULT CheckOut([in] CHAR* feature, [in] CHAR* version, [out] CerberusCheckoutDetails* details, [out] CerberusErrorDetails* error);

My *.idl defines this structure:

[
    uuid(527568A1-36A8-467A-82F5-228F7C3AC926),
    version(1.0)
]
typedef struct CerberusErrorDetails {
    INT ErrorCode;
    BSTR ErrorMessage;
} CerberusErrorDetails;

My implementation returns this structure at some point:

int result = checkout(feature, version, 1, 0, remoteServerName);
if (result != 0)
{
    error = new CerberusErrorDetails();
    error->ErrorCode = result;
    error->ErrorMessage = _bstr_t(errstring()).Detach();
    return result;
}

I call it like this:

CerberusNativeLib::CerberusErrorDetails *error = new CerberusNativeLib::CerberusErrorDetails();
if (session->CheckOut(feature, version, details, error) != S_OK)
            std::wcout << error->ErrorCode << ": " << error->ErrorMessage << std::endl;

My issue is that error->ErrorCode is 0 but it should be -95 (stepping through the code, I can see that result is -95) and error->ErrorMessage is always NULL but it should contain an actual error message as errstring() returns a char * which is filled, such as Error trying to connect.. Why is that? I want to return a structure. Do I have to allocate it in some special way from the calling side or from the COM object side? Can someone provide an example of how to do this please?


Solution

  • Without a complete example, it's hard to know exactly what you're trying to do. But it would appear that you may want to write the following

    CerberusNativeLib::CerberusErrorDetails error;
    if (session->CheckOut(feature, version, details, &error) != S_OK)
    

    (no new, address of struct on the stack passed) and

    int result = checkout(feature, version, 1, 0, remoteServerName);
    if (result != 0)
    {
        error->ErrorCode = result;
        error->ErrorMessage = _bstr_t(errstring()).Detach();
        return result;
    }
    

    (again, no new). Notice this has little to do with COM.