how to pass array from managed to COM

B

Boni

Dear all,
I have written a C++ COM object:
STDMETHOD(myfunc)(INT* array)



Now I need to pass an array from c# to COM. I generated a COM interop and
the signature of the function is

myfunc(ref int)

in C# I have an array of ints.

If I call

myfunc(array[0])

and try to access from COM object the array[1],2.... they are incorrect.
Only array[0] is correct. What do I do wrong?

Thanks a lot,

Boni
 
M

Marcus Heege

Boni said:
Dear all,
I have written a C++ COM object:
STDMETHOD(myfunc)(INT* array)



Now I need to pass an array from c# to COM. I generated a COM interop and
the signature of the function is

myfunc(ref int)

in C# I have an array of ints.

If I call

myfunc(array[0])

and try to access from COM object the array[1],2.... they are incorrect.
Only array[0] is correct. What do I do wrong?

Thanks a lot,

Boni

Your function definion is:
STDMETHOD(myfunc)(INT* array)
From this function definition it is not clear what the size of the array
should be. I assume that the client and the server know the size of the
array for a reason not described so far. In this case you should define you
P/Invoke function like this:

[DllImport("....")]
static extern myfunc([MarshalAs(LPAray int[] rgi);

Marcus
 
B

Boni

Hi Marcus,
I assume that the client and the server know the size of the array for a
reason not described so far.
No the size is passed as a second function argument (sorry I skiped this in
the description)
STDMETHOD(myfunc)(INT* array, int size).
And I don't use PInvoke explicitely (Visual Studo generats Interop for me).
 
M

Marcus Heege

Boni said:
Hi Marcus,
No the size is passed as a second function argument (sorry I skiped this
in the description)
STDMETHOD(myfunc)(INT* array, int size).
And I don't use PInvoke explicitely (Visual Studo generats Interop for
me).

The COM Interop Type information generated by VS, by TLBIMP, and by
System::Runtime::Interop::TypeLibConverter is not sufficient for what you
need. This is especially the case, because the COM Type Info does not have
all the information that is necessary.

It is very likely that you have to write the type information yourself.
[
object,
uuid(... your IID ...),
oleautomation
]
interface IYourInterface : IUnknown {
STDMETHOD(myfunc)([size_is(size)] INT* array, int size);
}

in this case, you can define Interop Type Info like this one:

[
Guid("... your IID ..."),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IYouInterface
{
void myFunc([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] int[]
rgints, int size);
}
 
B

Boni

Thanks a lot Marcus, I will try that.
Marcus Heege said:
Boni said:
Hi Marcus,
No the size is passed as a second function argument (sorry I skiped this
in the description)
STDMETHOD(myfunc)(INT* array, int size).
And I don't use PInvoke explicitely (Visual Studo generats Interop for
me).

The COM Interop Type information generated by VS, by TLBIMP, and by
System::Runtime::Interop::TypeLibConverter is not sufficient for what you
need. This is especially the case, because the COM Type Info does not have
all the information that is necessary.

It is very likely that you have to write the type information yourself.
[
object,
uuid(... your IID ...),
oleautomation
]
interface IYourInterface : IUnknown {
STDMETHOD(myfunc)([size_is(size)] INT* array, int size);
}

in this case, you can define Interop Type Info like this one:

[
Guid("... your IID ..."),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IYouInterface
{
void myFunc([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] int[]
rgints, int size);
}
 
B

Boni

Just one more small question
void myFunc([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] int[]
Is the pointer passed to the array a pointer to initial array or to a copy
of this array? I.e. If I change data inside of COM using this pointer, will
initial data change?
 
W

Willy Denoyette [MVP]

No, you pass a copy, so you can't change the managed arry this way.
Anyway, the easiest way of passing array's to/from COM is by means of self
describing SAFEARRAY's. The default COM interop marshaler will take care of
data marshaling for automation types.

IDL:
HRESULT PassInOutIntArray([in, out] SAFEARRAY(long)* arr);

Declaration:
....

STDMETHOD(PassInOutIntArray)(SAFEARRAY ** arr);

Definition:

STDMETHODIMP CTest::passInOutIntArray(SAFEARRAY ** arr)
{
int* temp;
SafeArrayAccessData(*arr, (void**)&temp);
long ubound;
SafeArrayGetUBound(*arr, 1, &ubound);
for(int i = 0; i <= ubound; i++)
{
temp = temp * 2; // each element * 2
}
SafeArrayUnaccessData(*arr);
S_OK;
}

C#
....
Array iar = new int[10] { 12, 23, 45, 7, 89, 25, 12, 8, 9, 5 };a;
ComObj.PassInOutIntArray(ref iar );
foreach(int in iar)
....

No need to define the interface in C#, just set a reference to the typelib
and you are done.


Willy.


| Just one more small question
| >> void myFunc([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
int[]
| Is the pointer passed to the array a pointer to initial array or to a copy
| of this array? I.e. If I change data inside of COM using this pointer,
will
| initial data change?
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top