We extended our legacy C++ DCOM application last week, and when the developer wrote the C#.Net end to call the new method, we were getting the error:
System.Runtime.InteropServices.SafeArrayTypeMismatchException
The developer that had added the method stated it worked, and pointed to his Delphi test app that worked happily.
Reviewing the method code it all looked fine. Single stepping through the code there where no problems.
The help for this exception says:
The exception thrown when the type of the incoming SAFEARRAY does not match the type specified in the managed signature.
But as we are dynamically calling the method like this:
objAddType = Type.GetTypeFromProgID("DCOM_OBJECT_NAME.COMPANY_CLASS_A");
objAdd = Activator.CreateInstance(objAddType);
object[] input = {};
object result = objAddType.InvokeMember("MethodName", BindingFlags.InvokeMethod, null, objAdd, input);
There was no was no signature.
This is for this Method:
VARIANT CompanyClassAObject::MethodName(void)
{
VARIANT vaResult;
VariantInit(&vaResult);
SAFEARRAY* sfa = GetSafeArray();
vaResult.vt = VT_UI1 | VT_ARRAY;
vaResult.parray = sfa;
return vaResult;
}
with the body of GetSafeArray looked like:
SAFEARRAYBOUND sfabounds[1];
sfabounds[0].lLbound = 0;
sfabounds[0].cElements = bytes_needed;
SAFEARRAY *sfa = SafeArrayCreate(VT_I1, 1, sfabounds);
if(sfa)
{
void *data;
if(SafeArrayAccessData(sfa, &data) == S_OK)
{
memcpy(data, buffer, bytes_needed);
SafeArrayUnaccessData(sfa);
delete buffer;
return sfa;
}
}
The problem ended up being that the SafeArray is created as VT_I1
type but when it is put into the variant type it was typed as VT_UI1
. So the .Net runtime was picking up the conflict and correctly complaining, and once you know what the error is, the exception message make sense. Funny that!
Setting the SafeArrayCreate to use VT_UI1 and every thing worked.