任务 - 提供用于从 C++ DLL 注销并从 C# 使用它的缓冲区
我做了什么(而且是错的) C++伪代码:
wchar_t* _out;
int _outsize;
extern "C" __declspec(dllexport) void setOut(wchar_t* out, int outsize){
_out = out;
_outsize = outsize;
}
void logOut(wstring& message){
const wchar_t* m = message.c_str();
wcscat_s(_out,_outsize,m);
}
extern "C" __declspec(dllexport) void worker() {
logOut(L"start");
doWork();
logOut(L"finish");
}
我在 C# 中做了什么(通常用于 outstring)
[DllImport(LibraryName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
extern public static void setOut([MarshalAs(UnmanagedType.LPWStr)]StringBuilder buf, int size);
[DllImport(LibraryName, CallingConvention = CallingConvention.StdCall)]
extern public static void worker();
public void Run(){
const int bufsize = 1024;
var buf = new StringBuilder(bufsize);
setOut(buf, bufsize);
doWork();
Assert.True(buf.ToString().Contains("start"));
}
失败 - 有两个变体 - 有时进程中止,有时缓冲区为空。
在调试期间,我发现这是我的大错误 - setOut 中的 wchar_t* 参数仅在第一次调用 setOut
时是有效指针(因此,如果我要在其中写一些东西 - 我将在调用者中捕获数据).但在它之后,在第二次调用发生之前 (worker()
) 指针变得无效。
因此我可以看到 StringBuilder 编码为单个 PInvoke 周期的临时指针。
那么,是否可以通过某种方式提供长期有效的 CLI <-> C++ 字符串缓冲区? (我知道我可以使用文件或映射文件或 tcp 套接字,但它不是很好,问题是是否可以使用 StringBuilder 或 char[] 或 byte[])?
最佳答案
编码分配一个单独的临时缓冲区(这是 out
指向的内容)然后在函数退出时将其内容复制到 StringBuilder 中。
由于这种行为,out
指针仅可用于通过将字符串复制到该指针来传回数据,例如通过从内部调用 wcscat_s(out, outsize,m)
相同或嵌套的功能;
要修复代码,请考虑更改 worker()
签名以将 out
参数直接传递给该函数:
void worker(wchar_t* out, size_t outsize)
{
setOut(out, outsize);
....
setOut(NULL, 0);
}
另一个[不太优雅]的选择是在代码中显式编码:
[DllImport(LibraryName, CallingConvention = CallingConvention.StdCall)]
extern public static void setOut(IntPtr buf, int size);
char[] buffer = new char[bufferSize];
// Specify size in bytes leaving room for terminal \0
IntPtr outPtr = Marshal.AllocHGlobal((bufferSize + 1) * sizeof(char) );
try
{
setOut(outPtr, bufferSize);
worker();
setOut(IntPtr.Zero, 0);
Marshal.Copy(outPtr, buffer, 0, bufferSize);
}
finally
{
Marshal.FreeHGlobal(outPtr);
}
// use buffer.
关于c# - 如何正确地将长生命周期缓冲区从 C# 发送到 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33507164/