[Mono-dev] Problem with Marshing c arrays as UnmanagedType.LPArray using SizeParamIndex when doing Native -> Managed COM method calls.

Tom Hindle tom_hindle at sil.org
Fri Jun 12 12:59:40 EDT 2009


I have implement a Managed class which implements
System.Runtime.InteropServices.ComTypes.IStream (defined in

When I attempt to use IStream.Write from C++ I get a
System.Runtime.InteropServices.MarshalDirectiveException: Array size
control parameter must be an integral type.

IStream's Write method is Marshaled as:

void Write ([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] pv, int cb, IntPtr pcbWritten);

(which is correct : cb is an int)

Looking at the function emit_marshal_array in marshal.c in the

When checking param index type (which is 1 as SizeParamIndex == 1)
(about line 6778) the Array itself is being checked (byte[] pv) as
m->sig has had and extra parameter inserted at the beginning of its
parameter list. (which I assume is for communicating the HRESULT return
value back to the C++ as this is a COM method call.)

The following code changes Solves the problem:

Changing Line: 6785 switch (m->sig->params [param_num]->type) {
To: (m->sig->params [param_num + 1]->type) {

Changing Line: 6875 mono_mb_emit_ldarg (mb, param_num);
to mono_mb_emit_ldarg (mb, param_num + 1);

However I strongly suspect that this breaks all non COM marshaled method
calls the marshal Arrays.

So I could optionally do it by doing something like:

if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
			spec->native == MONO_NATIVE_IDISPATCH ||
			spec->native == MONO_NATIVE_INTERFACE))

(param_num is initially set from spec->data.array_data.param_num)

And so would work for COM method calls and non COM method calls.

Could someone tell me if this is the correct place to adjust the
param_num or should 
spec->data.array_data.param_num be expected to contain the adjusted


More information about the Mono-devel-list mailing list