我在C ++ DLL中有一个函数,需要一个输入。我正在尝试将该输入用作C#调用的输出。
这是我的C ++函数:
MYAPI int testStuff3(unsigned char* str)
{
printf("%s\n", str);
str = (unsigned char*)malloc(9);
str[0] = 'G';
str[1] = 'o';
str[2] = 'o';
str[3] = 'd';
str[4] = 'b';
str[5] = 'y';
str[6] = 'e';
str[7] = '!';
str[8] = '\0';
return 1;
}
这是C#代码:
public class Program
{
[DllImport("NativeLib.dll")]
private static extern int testStuff3([In, Out] IntPtr str);
static void Main(string[] args)
{
IntPtr junk3 = IntPtr.Zero;
int ret = testStuff3(junk3);
Byte[] stuff3 = new byte[9];
Marshal.Copy(junk3, stuff3, 0, 9);
}
}
调用Marshal.Copy时,出现错误,指出来源(junk3)不能为空。
这将不起作用,从C#发送指向C ++ DLL的空指针,并让DLL分配内存并将其存储在内部并将其返回给调用方吗?我想将其保留为IntPtr而不是StringBuilder,因为数据在最终代码中不一定是字符串。只是C ++中的一个无符号char数组,我希望IntPtr指向它。
我为IntPtr传递尝试了[In,Out],[Out],out和ref的不同变体。
答案 0 :(得分:0)
从不允许内存分配跨越DLL边界。那就是疯狂和/或斯巴达。
(对于pedantic:您可以分配内存,然后再传递一个指针,只要您将所有权传回以释放它,或保证将同一分配器用作合同的一部分即可。但这仍然是尽量避免。)
通常,要使用字符串输出参数,应传递StringBuilder
作为参数,并将其容量设置为最大预期长度。然后,在本机代码中,您只需填充此现有缓冲区。
有关示例,请参见“固定长度的字符串缓冲区”部分here。
答案 1 :(得分:-1)
您的C ++函数不会修改传递的字符串。它使用malloc分配一个新变量,将其存储在忘记传递的值的局部变量中,然后返回泄漏的内存。
如果出于某种原因要进行手动编组,则可能需要这样的操作(假设这是Windows的操作):
MYAPI BOOL __stdcall testStuff3( char** pp )
{
if( nullptr == pp )
return FALSE; // null pointer
if( nullptr != *pp )
{ // Print & release an old string
printf( "%s\n", *pp );
CoTaskMemFree( *pp );
*pp = nullptr;
}
// Allocate a new one
const char* const str = CoTaskMemAlloc( 9 );
if( nullptr == str ) return FALSE;
strncpy( str, "Goodbye!", 9 );
*pp = str;
return TRUE;
}
C#:
public class Program
{
[DllImport( "NativeLib.dll" )]
private static extern bool testStuff3( [In, Out] ref IntPtr str );
static void Main( string[] args )
{
IntPtr ptr = IntPtr.Zero;
if( testStuff3( ref ptr ) )
{
Console.WriteLine( Marshal.PtrToStringAnsi( ptr ) );
Marshal.FreeCoTaskMem( ptr );
}
}
}
但是,除非您有充分的理由,否则我不建议您这样做。在大多数情况下,自动编组会更好。对于C#-> C ++,它非常简单,在C ++中为const char*
或const wchar_t*
,在C#中为string
(具有正确的属性)。对于C ++-> C#,您可以在C#中分配StringBuilder,将char*
或wchar_t*
传递给C ++,并在另一个参数中缓冲长度。
答案 2 :(得分:-1)
感谢您的帮助!
这就是我最终得到的结果。
C ++函数:
MYAPI int testStuff4(wchar_t* str)
{
unsigned char* stuff = (unsigned char*)malloc(10);
stuff[0] = 'G';
stuff[1] = 'o';
stuff[2] = 'o';
stuff[3] = 'd';
stuff[4] = 'b';
stuff[5] = 'y';
stuff[6] = 'e';
stuff[7] = '!';
stuff[8] = '\0';
mbstowcs(str, (const char*)stuff, 1024);
free(stuff);
return 1;
}
C#函数:
public class Program
{
[DllImport("NativeLib.dll")]
private static extern int testStuff4(IntPtr str);
static void Main(string[] args)
{
IntPtr junk4 = Marshal.AllocHGlobal(1024);
int ret = testStuff4(junk4);
string junkString = Marshal.PtrToStringUni(junk4);
Console.WriteLine(junkString);
Marshal.FreeHGlobal(junk4);
}
}