Unless there's too many combinations, I'd say the best way is to simply have multiple DllImport
s for the various argument types. For example:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParamInt32(string param_name, ref int param_value);
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParamSingle(string param_name, ref float param_value);
You can then call them properly as
var intVal = 42;
setParamInt32("param", ref intVal);
var floatVal = 42.0f;
setParamSingle("param", ref floatVal);
Using ref IntPtr
is wrong in either case - the only reason it works at all is that in 32-bit applications, IntPtr
is a 32-bit integer internally. However, it's supposed to be a pointer. A proper use would be something like this:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, IntPtr param_value);
Note that the ref
isn't there - IntPtr
is already an indirection.
To call this, you'll need to allocate some memory, and get a pointer to that - or, use a GCHandle
to refer directly to a managed object:
var intValue = 42;
var handle = GCHandle.Alloc(intValue, GCHandleType.Pinned);
setParam("param", handle.AddrOfPinnedObject());
Make sure to dispose of the managed handle properly, of course - pinned handles are a huge pain for the GC.
Manually copying the data to unmanaged memory and back also isn't exactly hard:
var ptr = Marshal.AllocCoTaskMem(sizeof(int));
try
{
Marshal.WriteInt32(ptr, 42);
setParam("param", ptr);
// If you need to read the value back:
var result = Marshal.ReadInt32(ptr);
}
finally
{
Marshal.FreeCoTaskMem(ptr);
}
But I'd simply stick with automatic marshalling unless you have a very good reason not to.