I think the .Net COM interop has some kind of a problem with marshaling the SAFEARRAY of VT_UI2 to char[]. You could work around this on the .Net side by using a ushort[] array and converting to string for use with StringBuilder.Insert.
COM interop - pass a char[] array

I want to call a .NET method through .Invoke with a char[] parameter:
StringBuilder.Insert(int index, char[] value)
I reasoned that from C++, I should pass a safearray of VT_UI2, with variant type VT_ARRAY+VT_UI2, and that would be marshaled to a char[]. But I get an "incorrect parameter" error. Any recommendations?
Thanks
6 answers
Sort by: Most helpful
-
RLWA32 30,216 Reputation points
2020-12-27T21:09:25.603+00:00 haton 21 Reputation points2020-12-28T07:01:47.897+00:00 Yes, that is what I am observing.
Is it worth reporting the problem to Microsoft? I guess i am not the first one to stumble upon this.haton 21 Reputation points2020-12-30T10:50:40.267+00:00 Follow-up: I still try to .Invoke a .NET Framework method which wants a char[] parameter. I tried a sly hack: generate the char[] on the managed side.
I wrote a small C# class which generates a new char[] in method X() and returns a pointer by calling Marshal.GetIUnknownForObject.
I call this method X() from the unmanaged side through COM interop, and get the pointer result. To test the result, I cast this pointer to an Object and pass it again to the managed side to methods Y() and Z(). I hoped this object would be received as a char[] array but the results puzzle me:- the object isn't accepted by method Y() which wants a char[] array parameter (Incorrect Parameter),
- it is accepted by method Z() which wants an Object parameter,
- Console.WriteLine(a.GetType()) prints 'System.Char[]',
- the parameter can be cast to a char[] array and the contents can be read correctly!
I haven't reach my goal but maybe I am on to something? I would be super grateful for any advice.
--C#
using System; using System.IO; using System.Runtime.InteropServices;
public class XHelper {
public IntPtr X() {
char[] a=new char[2] {'A', 'B'};
return Marshal.GetIUnknownForObject(a);
}
public void Y(char[] a){ // fails with INVALID PARAMETER
Console.WriteLine(a.GetType());
Console.WriteLine(((char[])a)[0]);
}
public void Z(Object a){ //parameter is accepted as Object
Console.WriteLine(a.GetType()); //DISPLAYS System.Char[]
Console.WriteLine(((char[])a)[0]); //DISPLAYS A (correct first character)
}
}haton 21 Reputation points2020-12-30T12:34:14.827+00:00 I don't have control about the system methods I call.
But I can run some code bits of my own in parallel.The unmanaged part looks like:
//----
XHelper helper=new XHelper;VARIANT v;
dispidX=...(dispid of X method)
dispidY=...(dispid of Y method)
dispidZ=...(dispid of Z method)
helper->invoke (dispidX, IID_NULL, 0x400, DISPATCH_METHOD, null, &v, null, null);
//result variant is ant IntPtr, with type VT_UINT//prepare Invoke arguments
VARIANT *args = new VARIANT[1];
args[0]=v;
args[0].vt = VT_UNKNOWN; //force to interpret v as an Object//invoke Y
DISPPARAMS dp;
dp.cArgs=1;
dp.rgvarg = args;
helper->invoke (dispidY, IID_NULL, 0x400, DISPATCH_METHOD, &dp, &v, null, null);
//---(This experiment is a first step. To be of any use, the next step would be to create the char[] array on the managed side based on a pointer provided from the unmanaged side).
I don't think its a matter of correctly calling IDispatch::Invoke. As far as I can tell the .Net COM interop is improperly returning E_INVALIDARG for a call to IDispatch:;:Invoke that is passing correct parameters.
If you look at the type library generated for a .Net COM Server you can see that it contains exactly the same method parameters for an interface method that has an [in] parameter of ushort[] or char[]. Each method in the type library uses [in] SAFEARRAY(unsigned short) for the parameter. Pass a SAFEARRAY of VT_UI2 to an interface method expecting ushort[] and all is well. Pass the same SAFEARRAY to an interface method expecting char[] and you get E_INVALIDARG, even though the call is properly structured and conforms to the generated type library.