P/Invoke and string array

M

Maxim Kazitov

Hi,

I try to invoke function with following prototype from external DLL :
LONG Fun1(LONG n, LPCSTR* lpNames, LPLONG lpStatus);
n - number of element in Names;
lpNames - is in/out string array (function can modify array);
lpStatus - is in/out long array (function can modify array);

But I can't create appropriated function declaration in C# . I try :
Int32 Fun1(Int32 n, String[] names, Int32[] status)
Int32 Fun1(Int32 n, ref string[] names, ref int[] status);
Int32 Fun1([MarshalAs(UnmanagedType.LPArray)] String[] names, ref IntPtr
status);

But nothing works properly.

Should I use "fixed" statement ?

Thanks,
Max
 
N

Nicholas Paldino [.NET/C# MVP]

Maxim,

The fixed statement won't help you here.

The problem is that when you send an array of any sort to the unmanaged
realm, the P/Invoke layer doesn't know exactly how much information to
marshal back. Because of this, it only marshals back the first element.

In order to get around this, you will have to marshal the string array
yourself, creating an array of IntPtr structures representing the strings to
be marshaled. If you know that Fun1 won't change the addresses of the
strings in the array that is passed to it, you can declare the function like
this:

[DllImport("somedll.dll")]
public static extern int Fun1(int n, IntPtr[] lpNames, IntPtr lpStatus);

Then, what you have to do is create an IntPtr array which you will
marshal the strings to (using the static StringToCoTaskMemAnsi method, or
something similar).

The same applies for the lpStatus parameter. Instead of an array of
IntPtrs though, you only need one. You have to declare the memory for the
array you are passing, the size of which is the number of elements times the
number of bytes for each element (in this case, four). Once you declare
that unmanaged memory block (once again, using the methods on the Marshal
class), you have to copy the values to the block of unmanaged memory.

After the call is made, you will have to unmarshal everything. Every
four bytes in the unmanaged memory block represented by IntPtr will
represent the elements in the array that were passed. Every element in the
IntPtr array represents a pointer to a string, which you will have to
marshal back.

Finally, you have to make sure that you free all the memory that you
allocated, using, yes, you guessed it, the static methods on the Marshal
class.

Hope this helps.
 

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