C++中如何通过VARIANT*将IDispatch*从存根服务端传递到客户端?
问题:存根库中GetEventHandler方法的正确实现方式
我正在创建一个存根库,用于在不依赖第三方服务端库(其依赖我没有的基础设施)的情况下测试客户端。客户端与存根库均为32位,运行在64位机器上,注册表项创建于HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID。
类型库中定义的目标方法:
[id(0x00000003)] SCODE GetEventHandler([out] VARIANT* Handler);
客户端导入类型库后生成的代码:
SCODE GetEventHandler(VARIANT * Handler) { SCODE result; static BYTE parms[] = VTS_PVARIANT; InvokeHelper(0x3, DISPATCH_METHOD, VT_ERROR, (void*)&result, parms, Handler); return result; }
客户端代码:
VARIANT eventHandlerVariant; VariantInit(&eventHandlerVariant); V_VT(&eventHandlerVariant) = VT_DISPATCH; V_DISPATCH(&eventHandlerVariant) = NULL; SCODE sCode = cAutomationServer.GetEventHandler(&eventHandlerVariant); IDispatch *eventHandler = V_DISPATCH(&eventHandlerVariant);
存根库的调度映射:
BEGIN_DISPATCH_MAP(AutomationServer, CCmdTarget) DISP_FUNCTION_ID(AutomationServer, "GetEventHandler", 0x3, GetEventHandler, VT_ERROR, VTS_VARIANT) END_DISPATCH_MAP()
之前尝试的两种实现及问题:
- 第一种实现:客户端获取到的
eventHandler为NULL
SCODE AutomationServer::GetEventHandler(VARIANT *Handler) { AFX_MANAGE_STATE(AfxGetModuleState()); IDispatch *iDispatch = GetIDispatch(TRUE); V_DISPATCH(Handler) = iDispatch; return 0L; }
- 第二种实现:客户端触发
COleException异常,提示“Invalid callee”
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; }
正确实现方式
代码实现
SCODE AutomationServer::GetEventHandler(VARIANT *Handler) { AFX_MANAGE_STATE(AfxGetModuleState()); // 初始化输出VARIANT,确保结构处于有效状态 VariantInit(Handler); // 获取IDispatch指针,TRUE参数自动调用AddRef IDispatch* pDispatch = GetIDispatch(TRUE); // 设置VARIANT的类型和指向的IDispatch对象 V_VT(Handler) = VT_DISPATCH; V_DISPATCH(Handler) = pDispatch; // 返回成功的SCODE return S_OK; }
关键说明
- 必须初始化输出VARIANT:
VariantInit(Handler)是COM编程的基本要求,避免结构中存在垃圾数据导致后续操作异常。 - 正确管理引用计数:
GetIDispatch(TRUE)会自动对返回的IDispatch指针调用AddRef(),确保客户端拿到指针后可以正常调用Release(),避免内存泄漏或非法访问。 - 禁止直接赋值未初始化的VARIANT:第二种实现中的
*Handler = variant错误,因为variant未初始化,直接赋值会触发内存错误,导致“Invalid callee”异常。 - 调度映射参数验证:当前
DISP_FUNCTION_ID使用VTS_VARIANT是正确的,MFC中VTS_VARIANT对应VARIANT*类型的参数,与方法定义匹配。
另外,客户端代码中VariantInit后手动设置V_VT为VT_DISPATCH属于多余操作,存根库会重新初始化并设置正确的类型,但该写法不会引发问题。
内容的提问来源于stack exchange,提问作者Stephen
相关产品推荐
相关产品推荐

