Don*_*nie 10 c c# unmanaged managed
我是与非托管库交互的新手.我有一个非托管的C函数,它通过函数内的引用修改字符串.我在从C#传递字符串并通过C函数修改它时遇到了麻烦.
这是C函数:
__declspec(dllexport) void __stdcall Test(char* name)
{
*name = "Bar";
}
Run Code Online (Sandbox Code Playgroud)
这是C#DLL导入代码:
[DllImport(@"C:/blah/mylibrary.dll")]
public extern static string Test(string name);
Run Code Online (Sandbox Code Playgroud)
这是我用来调用函数的代码:
string s = "foo";
Test(s);
//I want s to be "Bar" after the above line
Run Code Online (Sandbox Code Playgroud)
我尝试在字符串参数上使用"ref"和"out",并尝试将编组作为LPStr.根据我的尝试,我得到一个错误
"作为String传入的指针不能位于进程地址空间的底部64K."
要么
"试图读取或写入受保护的内存.这通常表明其他内存已损坏."
我确定我只是用我的指针做一些愚蠢的事情.有人可以帮我确定合适的C#代码,使"s"等于"bar"吗?
谢谢
Rem*_*anu 12
你的C Test函数没有像你说的那样做.它只需要一个局部变量(name)并将其分配给一个固定的字符串.为了做你所说的,它必须在以下地址指向的地址中进行复制操作name:
__declspec(dllexport) void __stdcall Test(char* name)
{
strcpy(name, "Bar");
}
Run Code Online (Sandbox Code Playgroud)
当然,由于您的函数签名不正确(未指定缓冲区长度),因此这样的操作是等待的灾难.
考虑到C函数如上所述,那么您应该遵循Default Marshaling for Strings中指定的规则:
在某些情况下,必须将固定长度的字符缓冲区传递给非托管代码以进行操作.在这种情况下,简单地传递字符串不起作用,因为被调用者无法修改传递的缓冲区的内容.即使字符串是通过引用传递的,也无法将缓冲区初始化为给定的大小.
解决方案是将StringBuilder缓冲区作为参数而不是字符串传递.StringBuilder可以被被调用者解除引用和修改,前提是它不超过StringBuilder的容量.它也可以初始化为固定长度.例如,如果将StringBuilder缓冲区初始化为N的容量,则封送程序会提供大小为(N + 1)个字符的缓冲区.+1表示非托管字符串具有空终止符而StringBuilder不具有空终止符.
所以你的DLL应该是这样的:
[DllImport(@"C:/blah/mylibrary.dll")]
public extern static string Test(StringBuilder name);
Run Code Online (Sandbox Code Playgroud)
并通过传递适当大小来调用它StringBuilder:
StringBuilder foo = new StringBuilder(256);
Test(foo);
Run Code Online (Sandbox Code Playgroud)
如果添加长度参数,则会在C接口中添加一些完整性.