COM:访问冲突导致BSTR的SafeArray

时间:2012-05-04 13:12:20

标签: c++ com variant safearray

以下代码工作正常,非常感谢您使用一个COM客户端,但是使用新客户端(相同软件的更新版本)string_array_to_bstr_safearray_variant会引发访问冲突并且一切都会死亡。

任何人都可以告诉我,如果我做错了,我之前就已经逃脱了......?我没有正确分配内存吗?

#include "comutil.h"

void string_array_to_bstr_safearray_variant(long arraylength,char ** in_array,VARIANT *out_variant)
{
    CComSafeArray<BSTR> out_array;
    ATLENSURE_SUCCEEDED(out_array.Create(arraylength));
    for (int i=0;i<arraylength;i++)
        ATLENSURE_SUCCEEDED(out_array.SetAt(i,_com_util::ConvertStringToBSTR(in_array[i])));
    CComVariant ccv(out_array);
    HRESULT hr = ccv.Detach(out_variant);
    ATLENSURE_SUCCEEDED(hr);
}

//names: output parameter to contain variant holding safearray of bstrs
STDMETHODIMP CCalculation::get_output_shortnames(VARIANT* names)
{
    char** names_array = calc_get_short_output_names(calc); //this works fine
    string_array_to_bstr_safearray_variant(output_length,names_array,names); //this fails before returning
    return S_OK;
}

修改:调试程序信息

如果没有调试器,我会收到访问冲突。

使用调试器逐步执行此代码似乎可行。 output_length设置正确; out_array已正确创建并填充,因此我可以通过变量观看来out_variant。但是,COM客户端仍然失败,说"lisp value has no coercion to VARIANT with this type: #<safearray...>"(这很奇怪,因为客户端的先前版本很好地解释了返回值)。它然后崩溃抱怨它是内存不足。

在调试器中运行代码,但是让它运行而不是步进,它在CComVariant的构造函数内部失败,抱怨因为对SafeArrayCopy的内部调用失败而抛出了无效的参数。

编辑:在最近的另一个步骤中它在循环中失败了,所以问题可能是CComSafeArray,因为@terriblememory建议?

2 个答案:

答案 0 :(得分:1)

CComSafeArray的文档实际上并不表示它支持BSTR。 BSTR的功能标志是否在底层SAFEARRAY中设置? (这不是一个真正的答案,但我没有业力只是评论,抱歉!)

答案 1 :(得分:1)

最后我找到了答案!问题中张贴的代码是正确的。早期的代码导致了未定义的行为:

STDMETHODIMP CCalculation::configure(VARIANT radii) // radii contains a safearray of doubles
{
CComSafeArray<double> radii_sa;
radii_sa.Attach(radii.parray);
ULONG num_radii = radii_sa.GetCount();

//unpack radii array into c-style array
double *radii_array = new double[num_radii];
for (long i=0;i<num_radii;i++)
radii_array[i] = radii_sa.GetAt(i);

//...do something with radii_array...

delete[] radii_array;

return S_OK;
}

你是否发现了故意的错误? COM规则说半径由客户端拥有,而不是我的dll。通过附加到它然后让包装超出范围,我正在释放safearray。通过在return语句之前添加它来修复:

radii_sa.Detach();