我有一个包含两个项目的解决方案:一个 C# 控制台应用程序和一个 C 库。 C 库有一个返回 HRESULT 的函数。我需要以某种方式更改此函数以使其向我的 C# 代码返回一个字符串。它应该是这样的:
C#:
[DllImport("MyLib.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern long MyFunction(bunch of params, [MarshalAs(UnmanagedType.BStr)] out string text);
C:
extern "C" HRESULT __declspec(dllexport) MyFunction(bunch of params, BSTR* text)
{
PWSTR finalResult;
//lots of code
(*text) = SysAllocString(finalResult);
//cleanup code
}
我可以更改这两个项目。但是,无法知道字符串的大小。因此,我尝试在 C 库中分配字符串,但这会导致访问冲突异常和各种问题。解决这个问题的最佳方法是什么?
最佳答案
哇!将近 3 年了,这个问题没有正确的答案!
至少根据我的经验,从非托管中传输字符串的正确方法是将 StringBuilder
类与表示“缓冲区”.
像这样:
// C#
[DllImport("MyLib.dll",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.Cdecl)]
public static extern bool MyFunction(
// other parameters,
StringBuilder buffer,
[MarshalAs(UnmanagedType.U4)] int bufferSize
);
// C:
extern "C" __declspec(dllexport) BOOL MyFunction(bunch of params, LPTSTR* text, unsigned int textSize)
{
char *mySourceString = doSomethingAndReturnString(bunch of params);
if ( textSize < strlen(mySourceString)) {
SetLastError(ERROR_INSUFFICIENT_BUFFER)
return FALSE;
}
strncpy(text, mySourceString, strlen(mySourceString))
return TRUE;
}
并以这种方式使用它:
StringBuilder sb = new StringBuilder(128);
while (!NativeMethods.MyFunction(/*other parameters*/, sb, sb.Capacity))
{
if (Marshal.GetLastWin32Error() != 0x7A) {
// throw
}
// Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER
sb.Capacity *= 2;
}
关于c# - 使用 P/Invoke 获取字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8126662/