Pergunta

The following code worked just fine thank you with one COM client, but with a new client (the updated version of the same software) string_array_to_bstr_safearray_variant throws an access violation and everything dies.

Can anyone tell me if I'm doing something wrong that I was getting away with before..? Am I failing to allocate memory properly?

#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;
}

Edit: Debugger info

Without a debugger, I get an access violation.

Stepping through this code with the debugger it appears to work. output_length is set correctly; out_array is created and filled correctly and so is out_variant as far as I can tell through variable watching. However, the COM client still fails, saying "lisp value has no coercion to VARIANT with this type: #<safearray...>" (which is odd because a previous version of the client interprets the return value just fine). It then crashes complaining that it's out of memory.

Running the code inside the debugger, but letting it run rather than stepping, it failed inside the constructor of CComVariant, complaining of an invalid argument thrown because the inner call to SafeArrayCopy failed.

Edit: on another recent step-through it failed in the loop, so maybe the problem is with CComSafeArray as @terriblememory suggests?

Foi útil?

Solução 2

Well finally I found the answer to this! The code posted in the question is correct as it is. There was earlier code causing undefined behaviour:

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;
}

Did you spot the deliberate mistake? COM rules say that radii is owned by the client, not my dll. By attaching to it then letting the wrapper go out of scope, I was deallocating the safearray. Fixed by adding this before the return statement:

radii_sa.Detach();

Outras dicas

The documentation for CComSafeArray doesn't actually say it supports BSTRs. Is the feature flag for BSTRs being set in the underlying SAFEARRAY? (This isn't really an answer, but I don't have the karma to just comment, sorry!)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top