I столкнулся с этой проблемой , пытаясь вернуть строку из C # в C. Я столкнулся с множеством тупиков, но Оливье Леврей в проекте кода предложил использовать IntPtr
для достижения этой цели. Решение отлично сработало для меня.
В настоящее время у вас есть это объявление делегата:
private delegate int GetNameFromDictionaryCallback(UInt64 key, string value);
Сразу приходит на ум то, что на самом деле value
должен быть параметром out
, как для IDictionary<,>.TryGetValue(key, out value)
. Для того, чтобы он был объявлен как «1014», он не предоставляет никакой семантической возможности для возврата действительного значения ! Как предполагает @dtb, один из часто доступных вариантов - использовать StringBuilder
. Для меня я получил именно тот результат, который вы получили - вернувшаяся на сторону C строка была пустяком. Но решение Оливье сработало.
Измените свой делегат, чтобы использовать IntPtr
для value
:
private delegate int GetNameFromDictionaryCallback(UInt64 key, IntPtr value);
value
представляет неуправляемую строку, которой мы можем присвоить значение. Фактические шаги для достижения этого немного беспорядок, но в конце концов это работает.
Предполагая, что у вас есть строка s
, которую вы хотите вернуть на сторону 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
.