C# 中的 Char * 编组

发布于 2024-08-12 06:04:08 字数 428 浏览 7 评论 0原文

我在 Visual C++ DLL 中有这个函数,

char * __stdcall GetMessage(int id) {
char buffer[250];
.
.
.
strcpy(buffer, entry); // entry is a char * that has allocated 250 chars
return (char *)buffer;
}

我试图用以下代码从 C# 导入这个函数,

[DllImport("mydll.dll", CharSet=CharSet.Ansi)]
public static extern string GetMessage(int id);

我试图在 MessageBox 中呈现它,它在字符串末尾总是有奇怪的符号。有什么建议如何克服这个问题?

I have this function in Visual C++ DLL

char * __stdcall GetMessage(int id) {
char buffer[250];
.
.
.
strcpy(buffer, entry); // entry is a char * that has allocated 250 chars
return (char *)buffer;
}

i am trying to import this function from C# with the following code

[DllImport("mydll.dll", CharSet=CharSet.Ansi)]
public static extern string GetMessage(int id);

I am trying to present this in a MessageBox it always has strange symbols in the end of the string. Any suggestions how to overcome this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

恏ㄋ傷疤忘ㄋ疼 2024-08-19 06:04:08

我将再次强调您的 C++ 代码无效这一事实。您将返回指向堆栈帧上的局部变量的指针,该指针在函数返回时不再有效。它现在起作用只是一个意外。一旦调用另一个函数,堆栈空间就会被重用,从而破坏缓冲区内容。当您从 C# 调用此代码时,肯定会发生这种情况,P/Invoke 编组器实现将覆盖堆栈帧并损坏缓冲区。

更糟糕的是,P/Invoke 编组器将尝试释放缓冲区。它将假设缓冲区是由 CoTaskMemAlloc() 分配的,并调用 CoTaskMemFree() 来释放缓冲区。在 Windows XP 及更早版本上,这会默默地失败,但在 Vista 及更高版本上,程序会崩溃。

这是解决您的问题的一种方法,使用 CoTaskMemAlloc() 来分配缓冲区而不是使用局部变量。全面的更好的解决方案是让函数的调用者传递缓冲区,以填充字符串。这样,调用者可以决定如何分配缓冲区并根据需要清理它。函数签名应如下所示:

extern "C" __declspec(dllexport)
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize);

使用 strcpy_s() 安全地填充缓冲区并避免任何缓冲区溢出。相应的 C# 声明将是:

[DllImport("mydll.dll")]
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize);

并像这样调用:

var sb = new StringBuilder(250);
GetMessage(id, sb, sb.Capacity);
string retval = sb.ToString();

I'll re-emphasize the fact that your C++ code is invalid. You are returning a pointer to a local variable on a stack frame that is no longer valid when the function returns. That it works now is merely an accident. As soon as you call another function, the stack space will be reused, corrupting the buffer content. This is guaranteed to happen when you call this code from C#, the P/Invoke marshaller implementation will overwrite the stack frame and corrupt the buffer.

To make matters worse, the P/Invoke marshaller will try to free the buffer. It will assume that the buffer was allocated by CoTaskMemAlloc() and call CoTaskMemFree() to release the buffer. That will silently fail on Windows XP and earlier but crash your program on Vista and up.

Which is one solution to your issue, use CoTaskMemAlloc() to allocate the buffer instead of using a local variable. The all-around better solution is to let the caller of the function pass the buffer, to be filled with the string. That way, the caller can decide how to allocate the buffer and clean it up as necessary. The function signature should look like this:

extern "C" __declspec(dllexport)
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize);

Use strcpy_s() to safely fill the buffer and avoid any buffer overflow. The corresponding C# declaration would then be:

[DllImport("mydll.dll")]
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize);

and called like this:

var sb = new StringBuilder(250);
GetMessage(id, sb, sb.Capacity);
string retval = sb.ToString();
↘紸啶 2024-08-19 06:04:08

从DLL中,您返回一个字符数组,即缓冲区,该缓冲区位于GetMessage函数内的堆栈上,并且当执行返回时,数据被弄乱,因为缓冲区从堆栈中弹出并且也是堆栈本地的,因此你所看到的奇怪的人物。有两种方法可以解决此问题,将缓冲区变量声明更改为指针并在返回之前对其进行 malloc 或将其声明为静态变量。

char *buffer;
if (!(buffer = (char *)malloc((250 * sizeof(char)) + 1)){
   // Handle the out of memory condition
}
// Now the buffer has 250 + 1 for null terminating character.

或者

static char buffer[250];

另外,您能否澄清一下入口指针变量 - 这是全局的吗?

希望这有帮助,
此致,
汤姆.

From the DLL you are returning an array of chars i.e. buffer which is on the stack within the GetMessage function, and when the return is executed the data is messed up since the buffer is popped off the stack and is local to the stack also, hence the strange characters you are seeing. There is two ways you can fix this, change the buffer variable declaration to be of a pointer and malloc it before returning it or declare it as a static.

char *buffer;
if (!(buffer = (char *)malloc((250 * sizeof(char)) + 1)){
   // Handle the out of memory condition
}
// Now the buffer has 250 + 1 for null terminating character.

Or

static char buffer[250];

Also can you clarify entry pointer variable - is that global?

Hope this helps,
Best regards,
Tom.

謸气贵蔟 2024-08-19 06:04:08

尝试使用 StringBuilder 作为返回类型并省略 CharSet 属性:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);

Try using a StringBuilder for the return type and leave out the CharSet attribute:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文