Marshalling how to access dlls with pointer arguments

cornelius1729

New member
Joined
Jan 21, 2009
Messages
4
Im trying to write an interface to OpenBUGS (http://mathstat.helsinki.fi/openbugs/) from a C#.NET application. This requires accessing the unmanaged code in the dll BRugs.dll. (Header file here: http://mathstat.helsinki.fi/openbugs/Manuals/Developer/BRugs.html).

I found an example of someone trying to do the same thing, but they used unsafe code, which Id rather avoid. (See http://stackoverflow.com/questions/212155/memory-accessviolationexception-error-calling-dll-from-c)

Ill show you my code so far, and then I have a couple of questions.

Heres the class that deals with the interface:

class BRugs
{
[DllImport(@"c:\Program Files\OpenBUGS\brugs.dll", CharSet = CharSet.Ansi, EntryPoint = "CmdInterpreter")]
public static unsafe extern void CmdInterpreter(ref string command, int* len, int* res); //How do I rewrite this without unsafe?

public static int CmdInterpreterWrapperUnsafe(string command)
{
int success = -1;
unsafe
{
int len = command.ToCharArray().Length;
int* len_ptr = &len;
int res = 0;
int* res_ptr = &res;
BRugs.CmdInterpreter(ref command, len_ptr, res_ptr);
success = *res_ptr;
}
return (success);
}

public static int CmdInterpreterWrapperMarshal(string command)
{
int success = -1;
int len = command.ToCharArray().Length;
IntPtr len_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));
Marshal.WriteInt32(len_ptr, len);
int res = 0;
IntPtr res_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));
Marshal.WriteInt32(res_ptr, res);
try
{
BRugs.CmdInterpreter(ref command, len_ptr, res_ptr); //What arguments should this take?
success = res; //Is this right?
}
finally
{
Marshal.FreeHGlobal(len_ptr);
Marshal.FreeHGlobal(res_ptr);
}
return (success);
}
}
(Full project code attached.)


The unsafe version seems to run okay, but is presumably subject to the same problems found in the forums post I linked to (and is unsafe).

The Marshalled version does not build; the compiler complains that System.IntPtr cannot be converted to int*.

Sorry about all this preamble, here is my question.

What is the correct way of specifying arguments to CmdInterpreter? It seems that ref string works for char** but is this good practise? And most importantly, what about int*, or double*?

Thanks in advance.
 

Attachments

Have you tried passing the int parameters as ref?
C#:
[DllImport(@"c:\Program Files\OpenBUGS\brugs.dll", CharSet = CharSet.Ansi, EntryPoint = "CmdInterpreter")]
      public static extern void CmdInterpreter(ref string command, ref int len, ref int res);  //How do I rewrite this without unsafe?

That way you might be able to do away with unsafe code and just declare you variables as normal int variables.
 
Thank you.

Ive just had another play around with this and it seems that passing scalar types like int, double etc. by ref works fine. For arrays, you need to use [MarshalAs(UnmanagedType.LPArray)] double[], (or whatever).

This way the unsafe code can be avoided.
 
Back
Top