I am trying to understand how to marshall the char* type by passing and modifying strings back and forth between managed & unmanaged code. Managed to unmanaged code seems to work fine, but the opposite does not work. Is IntPtr suited for this situation?
C
EXPORT char* CharTest(char* ptchar, unsigned char* ptuchar)
{
ptchar[0] = 'x';
ptchar[1] = 'y';
printf("%s %s\n", ptchar, ptuchar);
return(ptchar);
}
C#
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest(string ptchar, string ptuchar);
static void Main()
{
string ptchar = "ptchar";
string ptuchar = "ptuchar";
Console.WriteLine(Marshal.PtrToStringAnsi(CharTest(ptchar, ptuchar)));
}
Output
xychar ptuchar
x?J
Thank you!
You could declare the return type of the imported function as string
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static string CharTest(string ptchar, string ptuchar);
But because of the fact that you are actually returning one of the parameters, you would have to rely on the marshaller not freeing the parameter buffer before copying the return buffer.
You have two further options:
try/finally
in case of exceptions[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest(IntPtr ptchar, string ptuchar);
static void Main()
{
string ptchar = "ptchar";
string ptuchar = "ptuchar";
IntPtr ptcharPtr = IntPtr.Zero;
try
{
ptcharPtr = Marshal.StringToHGlobalAnsi(ptchar);
Console.WriteLine(Marshal.PtrToStringAnsi(CharTest(ptcharPtr, ptuchar)));
}
finally
{
Marshal.FreeHGlobal(ptcharPtr);
}
}
StringBuilder
which means it will be copied both ways. In this case you do not need to look at the return value as it will be the same as the parameter.[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest([In, Out] StringBuilder ptchar, string ptuchar);
static void Main()
{
StringBuilder ptchar = new StringBuilder("ptchar");
string ptuchar = "ptuchar";
CharTest(ptchar, ptuchar);
Console.WriteLine(ptchar);
}