Вопрос

У меня есть эта функция в Visual C ++ DLL

char * __stdcall GetMessage(int id) {
char buffer[250];
.
.
.
strcpy(buffer, entry); // entry is a char * that has allocated 250 chars
return (char *)buffer;
}

я пытаюсь импортировать эту функцию из C # с помощью следующего кода

[DllImport("mydll.dll", CharSet=CharSet.Ansi)]
public static extern string GetMessage(int id);

Я пытаюсь представить это в окне сообщения, в конце строки всегда есть странные символы.Есть какие-нибудь предложения, как преодолеть эту проблему?

Это было полезно?

Решение

Я еще раз подчеркну тот факт, что ваш код на C ++ недопустим.Вы возвращаете указатель на локальную переменную во фрейме стека, который больше не является допустимым при возврате функции.То, что это работает сейчас, - просто случайность.Как только вы вызовете другую функцию, пространство стека будет использовано повторно, что приведет к повреждению содержимого буфера.Это гарантированно произойдет, когда вы вызовете этот код из C #, реализация P / Invoke marshaller перезапишет фрейм стека и повредит буфер.

Что еще хуже, маршаллер P / Invoke попытается освободить буфер.Он будет предполагать, что буфер был выделен CoTaskMemAlloc() и вызовет CoTaskMemFree(), чтобы освободить буфер.Это приведет к молчаливому сбою в Windows XP и более ранних версиях, но приведет к сбою вашей программы в Vista и выше.

Что является одним из решений вашей проблемы, используйте CoTaskMemAlloc() для выделения буфера вместо использования локальной переменной.Самое лучшее решение - позволить вызывающей функции передать буфер, который будет заполнен строкой.Таким образом, вызывающий может решить, как выделить буфер, и очистить его по мере необходимости.Сигнатура функции должна выглядеть следующим образом:

extern "C" __declspec(dllexport)
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize);

Используйте strcpy_s(), чтобы безопасно заполнить буфер и избежать любого переполнения буфера.Тогда соответствующее объявление C # было бы следующим:

[DllImport("mydll.dll")]
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize);

и называется вот так:

var sb = new StringBuilder(250);
GetMessage(id, sb, sb.Capacity);
string retval = sb.ToString();

Другие советы

Из библиотеки DLL вы возвращаете массив символов, т. е.буфер, который находится в стеке внутри функции GetMessage, и когда выполняется возврат, данные перепутываются, поскольку буфер извлекается из стека и также является локальным для стека, отсюда и странные символы, которые вы видите.Есть два способа исправить это: изменить объявление переменной buffer на значение указателя и malloc перед ее возвратом или объявить ее как статическую.

char *buffer;
if (!(buffer = (char *)malloc((250 * sizeof(char)) + 1)){
   // Handle the out of memory condition
}
// Now the buffer has 250 + 1 for null terminating character.

Или

static char buffer[250];

Также можете ли вы уточнить переменную указателя входа - является ли она глобальной?

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

Попробуйте использовать StringBuilder для типа возвращаемого значения и пропустите атрибут CharSet:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top