我不理解下面的代码,它正在使用我的c ++,但它只是不想使用c#。 你能帮我理解这里有什么问题,我想我必须说我对C#来说是新手。
My_Lib.h
extern "C" __declspec(dllexport) void __cdecl get(char** buffer);
My_lib.c
void get(char** buffer)
{
*buffer = (char*)calloc(6, sizeof(char));
assert(*buffer);
buffer[5] = '\0';
*buffer = "Hello";
}
在我的C#----->
中public static class NativeMethods
{
[DllImport("My_C_Lib.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern void get(char** buffer);
}
//////////////////// Main()///////
unsafe
{
char* my_buf;
NativeMethods.get(&my_buf);
string s = new string(my_buf);
Console.WriteLine(s);
}
注意:实际上当我从c ++调用这个c函数时我的DLL工作正常但正如我上面所说的那样,不是在C#中,没有错误,但C#中的字符串变量打印出一些未定义的sibols,但是DLL“工作” 提前谢谢!!!
答案 0 :(得分:1)
代码几乎是正确的,但是......
C DLL在C#中不起作用,但在C ++中起作用
在C和C ++中char
是一种8位数据类型。在C#char
中是一个16位数据类型。
这意味着C#期望get()
函数返回的指针应该是“宽字符串”,而在C ++中则需要“ANSI字符串”。
我只是改变了程序中的一行:
*buffer = "H\0e\0l\0l\0o\0\0\0";
......它有效!
您当然也可以使用现代C编译器的“宽字符串”功能:
void get(wchar_t** buffer)
{
*buffer = L"Hello";
}
顺便说一下
您的计划中还有其他错误:
*buffer = (char*)calloc(6, sizeof(char));
...
*buffer = "Hello";
这没有任何意义:
第二行(*buffer = "Hello";
)将不将字符串复制到calloc
分配的内存中,但它会写入字符串"Hello"
的地址变量buffer
和calloc
返回的值(地址)被覆盖(并丢失)。
答案 1 :(得分:0)
最好的办法是将C函数的PInvoke签名更改为ref IntPtr
:
[DllImport("My_C_Lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void get(ref IntPtr buffer);
要调用它,您需要实例化IntPtr并通过引用C函数传递它(这与在C中声明char *
并通过地址传递它类似):
IntPtr ptr;
get(ref ptr);
// ptr is now an unmanaged pointer to the allocated string
现在,您需要convert the pointed-to string to a managed string
。为此,您必须复制该字符串。
string str = Marshal.PtrToStringAnsi(ptr);
PtrToString...()
变体。ptr
,因为它是由非托管代码分配的。您必须使用适用于您的DLL的适当机制自由释放它(理想情况下,DLL应该提供相应的自由函数,因为它是首先分配内存的那个)。get()
成功,ptr
不是IntPtr.Zero
。get()
返回的时间与释放指针的时间之间发生异常,则try/finally
construct是您的朋友。(旁白:请注意get
在C#中是Contextual Keyword,因此虽然您可以将其用作标识符,但您可能不愿意为了避免混淆。)