Stephen
Stephen

Reputation: 39

In C++, how do I pass an IDispatch* from server to client using a VARIANT*

I'm trying to create a stub library so that I can test my client without a third party server library (because it depends on infrastructure that I don't have).

The client and stub library are both 32 bit, running on a 64 bit machine. Registry entries are created in HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID

Their type library defines the method of interest as:

[id(0x00000003)]
SCODE GetEventHandler([out] VARIANT* Handler);

When I import the type library into the client, it generates this:

SCODE GetEventHandler(VARIANT * Handler)
{
    SCODE result;
    static BYTE parms[] = VTS_PVARIANT;
    InvokeHelper(0x3, DISPATCH_METHOD, VT_ERROR, (void*)&result, parms, Handler);
    return result;
}

The client code is this:

VARIANT eventHandlerVariant;
VariantInit(&eventHandlerVariant);
V_VT(&eventHandlerVariant) = VT_DISPATCH;
V_DISPATCH(&eventHandlerVariant) = NULL;
SCODE sCode = cAutomationServer.GetEventHandler(&eventHandlerVariant);
IDispatch *eventHandler = V_DISPATCH(&eventHandlerVariant);

This is the dispatch map in the stub library:

BEGIN_DISPATCH_MAP(AutomationServer, CCmdTarget)
    DISP_FUNCTION_ID(AutomationServer, "GetEventHandler", 0x3, GetEventHandler, VT_ERROR, VTS_VARIANT)
END_DISPATCH_MAP()

I tried this implementation in the stub library:

SCODE AutomationServer::GetEventHandler(VARIANT *Handler)
{
    AFX_MANAGE_STATE(AfxGetModuleState());
    IDispatch *iDispatch = GetIDispatch(TRUE); 
    V_DISPATCH(Handler) = iDispatch;
    return 0L;
}

In this case, the client gets NULL for the eventHandler.

I tried this implementation in the stub library:

SCODE AutomationServer::GetEventHandler(VARIANT *Handler)
{
    AFX_MANAGE_STATE(AfxGetModuleState());
    VARIANT variant;
    VariantInit(Handler);
    V_VT(Handler) = VT_DISPATCH;
    V_DISPATCH(Handler) = GetIDispatch(TRUE);
    *Handler = variant;
}

In this case, the client catches a COleException with message "Invalid callee", triggered the assignment to *Handler.

How should I implement the stub library method?

Upvotes: 2

Views: 69

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 597885

Since the parameter is marked as [out], GetEventHandler() is responsible for initializing the VARIANT completely, including its vt field. The caller should not be initializing the receiving VARIANT variable at all. If GetEventHandler() returns anything other than S_OK (0), the caller should just discard its VARIANT variable.

Try something more like this:

[id(0x00000003)]
SCODE GetEventHandler([out] VARIANT* Handler);
SCODE AutomationServer::GetEventHandler(VARIANT *Handler)
{
    AFX_MANAGE_STATE(AfxGetModuleState());
    VariantInit(Handler);
    V_VT(Handler) = VT_DISPATCH;
    V_DISPATCH(Handler) = GetIDispatch(TRUE);
    return 0;
}
VARIANT eventHandlerVariant;
SCODE sCode = cAutomationServer.GetEventHandler(&eventHandlerVariant);
IDispatch *eventHandler = V_DISPATCH(&eventHandlerVariant);

Upvotes: 0

Stephen
Stephen

Reputation: 39

The answer (thanks Igor) is to change VTS_VARIANT to VTS_PVARIANT in the dispatch map. I got confused because the comment for VTS_VARIANT in afxdisp.h says 'const VARIANT&' or 'VARIANT*'.

Upvotes: 1

Related Questions