I just found the answer to this, if anyone else gets a similar problem.
The code posted above is quite correct. What was happening was this, which got executed earlier in the C++:
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 (autocad) 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:
The lisp code didn't try to access radii after sending it to the C++, so this is probably why I got away with it in Acad 2011. 2012/2013 must try to access this data for some reason - or clean it up - why knows. Either way, undefined behaviour, my fault... and if you've got COM problems in 2011/2012 then double check all your C++ code!