Ioa*_*nis 2 c# c++ marshalling
我在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;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用以下代码从C#导入此函数
[DllImport("mydll.dll", CharSet=CharSet.Ansi)]
public static extern string GetMessage(int id);
Run Code Online (Sandbox Code Playgroud)
我试图在MessageBox中呈现它,它总是在字符串的末尾有奇怪的符号.有什么建议如何克服这个问题?
我会再次强调你的C++代码无效的事实.您正在返回指向堆栈帧上的局部变量的指针,该变量在函数返回时不再有效.它现在起作用仅仅是一次意外.一旦调用另一个函数,堆栈空间将被重用,破坏缓冲区内容.当您从C#调用此代码时,保证会发生这种情况,P/Invoke marshaller实现将覆盖堆栈帧并破坏缓冲区.
更糟糕的是,P/Invoke marshaller将尝试释放缓冲区.它将假设缓冲区由CoTaskMemAlloc()分配并调用CoTaskMemFree()来释放缓冲区.这将在Windows XP及更早版本中无声地失败,但会在Vista上崩溃您的程序.
哪个是您的问题的一个解决方案,使用CoTaskMemAlloc()来分配缓冲区而不是使用局部变量.全面更好的解决方案是让函数的调用者通过缓冲区,以填充字符串.这样,调用者可以决定如何分配缓冲区并根据需要进行清理.函数签名应如下所示:
extern "C" __declspec(dllexport)
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize);
Run Code Online (Sandbox Code Playgroud)
使用strcpy_s()安全地填充缓冲区并避免任何缓冲区溢出.相应的C#声明将是:
[DllImport("mydll.dll")]
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize);
Run Code Online (Sandbox Code Playgroud)
并像这样调用:
var sb = new StringBuilder(250);
GetMessage(id, sb, sb.Capacity);
string retval = sb.ToString();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2578 次 |
| 最近记录: |