如何传递可以从本机写入c#的空字符串缓冲区?
我正在尝试从托管代码中获取一个字符串到我的非托管代码中:
unmanaged dll:
typedef int (__stdcall * GetNameFromDictionaryCallback)(ULONGLONG id, WCHAR * name); declspec(dllexport) void __stdcall UnmanagedSetNameLookupCallback(GetNameFromDictionaryCallback fn) { GetNameFromDictionaryCallback GetNameFromDictionary = fn; WCHAR * value = new WCHAR[256]; ULONGLONG key = 0x250000000DA44785; GetNameFromDictionary(key, value); // reverse P/Invoke call to C# function wprintf_s("%ls", value); // just to display the result for simplicity delete value; }
托管dll:
public class ProgramInterop { private delegate int GetNameFromDictionaryCallback(UInt64 key, string value); private static GetNameFromDictionaryCallback mGetNameInstance; private Dictionary dict; private ProgramInterop() { mGetNameInstance = new GetNameFromDictionaryCallback(GetNameFromDictionary); UnmanagedSetNameLookupCallback(mGetNameInstance); } public bool GetNameFromDictionary(UInt64 key, string value) { return dict.TryGetValue(key, out value); } [DllImport("Unmanaged.dll")] private static extern void UnmanagedSetNameLookupCallback(GetNameFromDictionaryCallback fn); }
在我的托管程序中,我的字符串看起来很好,但在非托管端变成了垃圾。 我没有复制所有代码,但我认为这说明了我要完成的任务。 如果我以错误的方式解决这个问题或者我犯了错误,请告诉我。 谢谢。
试试这个:
delegate int GetNameFromDictionaryCallback( UInt64 key, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder value); public bool GetNameFromDictionary(UInt64 key, StringBuilder value) { string s; if (dict.TryGetValue(key, out s)) { value.Append(s); return true; } return false; }
我遇到了这个问题 ,试图将一个字符串从C#返回到C.我遇到了很多死胡同,但是在codeproject 上的 Olivier Levrey建议使用IntPtr
来完成这个任务。 该解决方案对我很有用。
目前您有此委托声明:
private delegate int GetNameFromDictionaryCallback(UInt64 key, string value);
我立即想到的是, value
实际上, value
应该是一个out
参数,比如IDictionary<,>.TryGetValue(key, out value)
。 因为string value
没有提供任何语义机会来返回实际值,所以它被裸体声明! 正如@dtb建议的那样,经常提供的一个选项是使用StringBuilder
。 对我来说,我得到了你得到的结果 – 返回C方的字符串是gobbledygook。 但Olivier的解决方案奏效了。
修改您的委托以使用IntPtr
作为value
:
private delegate int GetNameFromDictionaryCallback(UInt64 key, IntPtr value);
value
表示我们可以为其分配值的非托管字符串。 实现这一目标的实际步骤有点混乱,但它最终会起作用。
假设您有一些要返回到C端的字符串,这是您需要实现的代码,以便将其内容传输到IntPtr
value
:
// Convert from managed to unmanaged string and store in `sPtr` IntPtr sPtr = Marshal.StringToHGlobalAnsi(s); // Create a byte array to receive the bytes of the unmanaged string (including null terminator) var sBytes = new byte[s.Length + 1]; // Copy the the bytes in the unmanaged string into the byte array Marshal.Copy(sPtr, sBytes, 0, s.Length); // Copy the bytes from the byte array into the buffer Marshal.Copy(sBytes, 0, buffer, sBytes.Length); // Free the unmanaged string Marshal.FreeHGlobal(sPtr);
完成此操作后,您的返回值已复制到以value
命名的内存缓冲区中。