如何传递可以从本机写入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命名的内存缓冲区中。