Reputation: 39
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
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
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