如何通过引用修改字符串的非托管C库来发送字符串



我是与非托管库交互的新手。我有一个非托管C函数,它通过在函数中引用来修改字符串。我在从C#传递字符串并用C函数修改它时遇到了问题。

这是C函数:

__declspec(dllexport) void __stdcall Test(char* name)
{
    *name = "Bar";
}

这是C#DLL导入代码:

[DllImport(@"C:/blah/mylibrary.dll")]
public extern static string Test(string name);

这是我用来调用函数的代码:

string s = "foo";
Test(s);
//I want s to be "Bar" after the above line

我曾尝试在字符串参数上使用"ref"one_answers"out",并尝试将Marshaling作为LPStr。根据我的尝试,我要么得到像这样的错误

"作为字符串传入的指针不得位于进程地址空间的底部64K中。"

"试图读取或写入受保护的内存。这通常表明其他内存已损坏。"

我确信我只是在用我的指针做一些愚蠢的事情。有人能帮我确定合适的C#代码,使"s"等于"bar"吗?

感谢

您的C Test函数不会像您所说的那样执行任何操作。它所做的一切都是获取一个局部变量(name)并将其分配给一个固定字符串。要执行您所说的操作,必须将复制操作到name:所指向的地址

__declspec(dllexport) void __stdcall Test(char* name)
{
    strcpy(name, "Bar");
}

当然,这样的操作是一场等待中的灾难,因为您有不正确的函数签名(没有指定缓冲区长度)。

考虑到C函数如上所述,那么您应该遵循字符串默认编组中指定的规则:

在某些情况下,固定长度必须将字符缓冲区传递到要操作的非托管代码。简单地传递字符串是行不通的在这种情况下,因为被调用者不能修改传递的缓冲器即使字符串被传递通过引用,没有办法将缓冲区初始化为给定大小。

解决方案是通过StringBuilder缓冲区作为参数而不是字符串。StringBuilder可以由取消引用和修改被调用者,前提是它没有超过StringBuilder。也可以是初始化为固定长度。对于例如,如果初始化StringBuilder缓冲区的容量为N、 封送拆收器提供的缓冲区大小(N+1)个字符。+1账户对于非托管字符串具有null终止符,而StringBuilder没有。

所以你的DLL应该是这样的:

[DllImport(@"C:/blah/mylibrary.dll")]
public extern static string Test(StringBuilder name);

并通过传递适当大小的StringBuilder:来调用它

StringBuilder foo = new StringBuilder(256);
Test(foo);

如果您添加了一个长度参数,那么C接口将增加一些健全性。

相关内容

  • 没有找到相关文章

最新更新