SAFEARRAY(BSTR)作为DCOM中的[out]参数无法返回字符串

时间:2016-06-30 08:10:28

标签: c++ dcom bstr safearray

我想写一个DCOM服务器和一个客户端,以便他们可以交换一些数据。双方都是使用MS Visual Studio 2008编译的,客户端使用纯WinAPI连接,代理/存根是一个单独的dll(如果有任何问题)。问题是,我无法返回一个字符串数组(它已正确填充,但客户端收到一个空字符串数组)。

服务器: COM接口的IDL声明具有以下方法:

[id(7)] HRESULT foo([in] int arg1, [out] SAFEARRAY(int)* arg2, [out] SAFEARRAY(BSTR)* arg3);

实现,标题由Studio生成:

HRESULT STDMETHODCALLTYPE CoClass::foo(int arg1, SAFEARRAY** arg2, SAFEARRAY** arg3){
    SAFEARRAYBOUND bounds;
    bounds.cElements = arg1;
    bounds.lBound = 0;
    *arg2 = SafeArrayCreate(VT_INT, 1, &bounds);
    *arg3 = SafeArrayCreate(VT_BSTR, 1, &bounds);
    for(LONG i=0; i<arg1; ++i){
        int int_value = 42;
        BSTR string_value = SysAllocString(L"Hello");
        //string_value is correct here
        SafeArrayPutElement(*arg2, &i, &int_value);
        SafeArrayPutElement(*arg3, &i, &string_value);
        //string_value isn't destroyed here (explicitly, at least)
    }
    return ERROR_SUCCESS;
}

客户端:包含Studio生成的标题:

virtual /* [id] */ HRESULT STDMETHODCALLTYPE foo(
    /* [in] */ int arg1,
    /* [out] */ SAFEARRAY * *arg2,
    /* [out] */ SAFEARRAY * *arg3) = 0;

来电者代码(pInterface已正确初始化,其他来电成功):

SAFEARRAY *pInts = NULL, *pStrings = NULL;
HRESULT error = pInterface->foo(23, &pInts, &pStrings);
// in debugger:
// error is ERROR_SUCCESS, pInts filled properly, 
// pStrings is an array of 23 NULLs

其他详情:

  • IDL文件中没有ID 7的其他方法;
  • 使用[out] BSTR *str有效,字符串会正确返回;
  • pInterface已收到CoCreateInstanceEx来电;
  • 系统上没有旧版本的服务器;
  • 代码将在没有更新的情况下在Windows XP上运行,因此使用Visual Studio 2008是一个难以绕过的约束。

有没有人知道我做错了什么?

1 个答案:

答案 0 :(得分:3)

答案由评论部分的 Hans Passant 提供。

答案是:SAFEARRAYintBSTR添加元素的语法不同:

// SAFEARRAY **intArray, **stringArray; LONG i;
int int_value = 42;
BSTR string_value = SysAllocString(L"Hello");

SafeArrayPutElement(*intArray, &i, &int_value);
//SafeArrayPutElement(*stringArray, &i, &string_value); //WRONG!
SafeArrayPutElement(*stringArray, &i, string_value); //Right

请注意,阅读的语法是相同的:

// SAFEARRAY *intArray, *stringArray; LONG i;
int int_value;
BSTR string_value;

SafeArrayGetElement(intArray, &i, &int_value);
SafeArrayGetElement(stringArray, &i, &string_value);