Passing array adresses and pointers to C DLL from C#

D

dumliks

Hi, I have some problems with marshaling data to and from C DLL file;

C definitoin for function is:

int32 s7_get_multiple_read_cnf(
void *od_ptr, /* In call, must be null*/
uint16 *result_array, /* Returned adress of an array of uint16*/
uint16 *var_length_array, /*In call and Returned adress of an array
uint16 */
void *value_array /* Returned, pointer of buffer provided by user
programm*/
);


I can`t tell how this function executes, because this is "s732.dll" DLL
file from Siemens for S7 communications. But basicly, all the arrays
should be the same size, because this function writes readed data form
Profibus to these arrays.

In C# function definitios is this:
[DllImport("s732std.dll", SetLastError=true, CharSet=CharSet.Ansi,
CallingConvention = CallingConvention.Winapi)]
public static extern Int32 s7_get_multiple_read_cnf(IntPtr od_ptr,
[In,Out] UInt16[] rec_msg_array, [In,Out] UInt16[] var_lenght_array,
ref IntPtr var_value_array);

I call this function like that:
int ret;
UInt16[] msg_result_array = new UInt16[3];
UInt16[] var_length_array = new UInt16[3];
var_length_array[0] = 2;
var_length_array[1] = 2;
var_length_array[2] = 2;

Int16[] var_value_array = new Int16[3];

IntPtr my_var_value_pointer = Marshal.AllocHGlobal(Marshal.SizeOf(new
System.Int16())*(var_value_array.Length));
Marshal.Copy(var_value_array, 0, my_var_value_pointer,
var_value_array.Length);

ret = s7_get_multiple_read_cnf(new IntPtr(0), msg_result_array,
var_length_array, ref my_var_value_pointer);

The problem is that, if DLL function have to read one element,
everything is fine, but if DLL function have to read more than one
element, I recieve NullreferenceException!!!!!


any ideas????
 
N

Nicholas Paldino [.NET/C# MVP]

Since you want to get the values back, you are going to have to marshal
the arrays manually. The runtime does not know how many elements you are
being set when sent back, so it only marshals the first one (or tries to).

What you want to do is declare your function like this:

[DllImport("s732std.dll", SetLastError=true, CharSet=CharSet.Ansi)]
public static extern Int32 s7_get_multiple_read_cnf(IntPtr od_ptr, IntPtr
rec_msg_array, IntPtr var_lenght_array, IntPtr var_value_array);

Then, you will have to allocate and write to the unmanaged memory (using
the methods on the Marshal class), call the function, then read it back when
the function completes.

You can also do this in unsafe code as well (and would be much easier to
do as well).

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