且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-11-12 16:26:10

你的 C Test 函数没有像你说的那样做任何事情.它所做的一切都需要一个局部变量(name)并将其分配给一个固定的字符串.要执行您所说的操作,它必须对 name 指向的地址执行 copy 操作:

Your C Test function doesn't do anything like you said it does. All it does it takes a local variable (name) and assigns it to a fixed string. To do what you said it does it would had to do a copy operation into the address pointed to by name:

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

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

Of course, such an operation is a disaster in waiting since you have incorrect function signature (buffer lengths are not specified).

考虑到 C 函数如上,那么您应该遵循 字符串的默认封送处理:

Considering that the C function is as above, then you should follow the rules specified at Default Marshaling for Strings:

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

In some circumstances, a fixed-length character buffer must be passed into unmanaged code to be manipulated. Simply passing a string does not work in this case because the callee cannot modify the contents of the passed buffer. Even if the string is passed by reference, there is no way to initialize the buffer to a given size.

解决方案是通过一个StringBuilder 缓冲区作为参数而不是字符串.一个字符串生成器可以取消引用和修改被叫方,前提是它没有超出容量字符串生成器.它也可以初始化为固定长度.为了例如,如果您初始化一个StringBuilder 缓冲区的容量为N,封送拆收器提供了一个缓冲区大小 (N+1) 个字符.+1 帐户因为非托管字符串有一个空终止符而StringBuilder 没有.

The solution is to pass a StringBuilder buffer as the argument instead of a string. A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the capacity of the StringBuilder. It can also be initialized to a fixed length. For example, if you initialize a StringBuilder buffer to a capacity of N, the marshaler provides a buffer of size (N+1) characters. The +1 accounts for the fact that the unmanaged string has a null terminator while StringBuilder does not.

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

So your DLL should be like this:

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

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

and call it by passing a properly sized StringBuilder:

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

如果添加长度参数,C 接口会增加一些理智.

Some sanity would be added to the C interface if you add a length parameter.