You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:57:25