I am working with an existing code base made up of some COM interfaces written in C++ with a C# front end. There is some new functionality that needs to be added, so I'm having to modify the COM portions. In one particular case, I need to pass an array (allocated from C#) to the component to be filled.
What I would like to do is to be able to pass an array of int to the method from C#, something like:
// desired C# signature
void GetFoo(int bufferSize, int[] buffer);
// desired usage
int[] blah = ...;
GetFoo(blah.Length, blah);
A couple of wrenches in the works:
- C++/CLI or Managed C++ can't be used (COM could be done away with in this case).
- The C# side can't be compiled with /unsafe (using Marshal is allowed).
The COM interface is only used (an will only ever be used) by the C# part, so I'm less concerned with interoperability with other COM consumers. Portability between 32 and 64 bit is also not a concern (everything is being compiled and run from a 32 bit machine, so code generators are converting pointers to integers). Eventually, it will be replaced by just C++/CLI, but that is a ways off.
My initial attempt
is something similar to:
HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
And the output TLB definition is (seems reasonable):
HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);
Which is imported by C# as (not so reasonable):
void GetFoo(int bufferSize, ref int buffer);
Which I could use with
int[] b = ...;
fixed(int *bp = &b[0])
{
GetFoo(b.Length, ref *bp);
}
...except that I can't compile with /unsafe.
At the moment
I am using:
HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);
Which imports as:
void GetFoo(int bufferSize, int buffer);
And I need use use it like:
int[] b = ...;
GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
try
{
GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
}
finally
{
bPin.Free();
}
Which works..., but I'd like to find a cleaner way.
So, the question is
Is there an IDL definition that is friendly to the C# import from TLB generator for this case? If not, what can be done on the C# side to make it a little safer?