Строки в C ++? - PullRequest
       4

Строки в C ++?

1 голос
/ 05 октября 2011

Моя проблема в том, что у меня есть некоторые функции в DLL, некоторые из этих функций, например:

#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
 return s;
}

Всякий раз, когда я пытаюсь вызвать эту функцию из C #, вот код, который я использую:

[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);

Я получаю ошибку: вызов функции PInvoke 'Packer' разбалансировал стек.Это вероятно потому, что управляемая подпись PInvoke не соответствует неуправляемой целевой подписи.Убедитесь, что соглашение о вызовах и параметры подписи PInvoke совпадают с целевой неуправляемой подписью.

Я предполагаю, что получаю эту ошибку, потому что у меня нет правильных объявлений для функции, может кто-нибудь подсказать мне, как это исправить, спасибо взаранее

Ответы [ 4 ]

7 голосов
/ 05 октября 2011

std::string не может использоваться с PInvoke, потому что C ++ не имеет ABI для своих объектов, который необходим для правильной очистки стека, копирования объектов и т. Д. Это одна из самых больших проблем C ++.

Вы должны использовать char* указатели и простые API C.Проще говоря, PInvoke не работает с C ++.

5 голосов
/ 06 октября 2011

Как я уверен, вы уже знаете, C ++ std::string на самом деле шаблон. Только при создании экземпляра шаблона (например, std::basic_string<char>) точная компоновка объектов этого типа и подписи методов определяются компилятором C ++.

К сожалению, только рассматриваемый компилятор C ++ имеет доступ ко всей соответствующей информации (такой как исходный код шаблона) для принятия таких решений. Вот почему не-C функции, такие как шаблоны, как правило, не «переносимы» даже между различными компиляторами C ++, не говоря уже о C ++ и C #.

Кроме того, имена C ++ обычно "искажаются" в зависимости от компилятора C ++.

Вам придется изменить сигнатуру вашего собственного метода, чтобы он стал «чистой» функцией C:

  • Убедитесь, что нет искажения имен в C ++, объявив функцию как extern "C" (вы уже это делаете).
  • Используйте параметр char* вместо std::string.
  • Возвращайте char* результат вместо std::string, но будьте очень осторожны как вы это делаете.
  • Убедитесь, что ваш DllImportAttribute.CallingConvention соответствует __cdecl, __stdcall или __fastcall в вашем C.
4 голосов
/ 05 октября 2011

Проблема здесь в том, что вы используете класс STL string, который C # не знает, как маршалировать. У вас есть два варианта здесь:

  1. рефакторинг вашего кода C ++ для работы с char * буферами. Или напишите обертку или перегрузку или что-то, что использует char * вместо string.
  2. Напишите оболочку C ++ / CLI вокруг ваших функций C ++, которая использует System::String и вызывает строковые версии STL внутри.
2 голосов
/ 05 октября 2011

Если память не используется, если не указано иное, P / Invoke предполагает, что соглашение о вызовах равно __stdcall. Если это так, изменение вашей __cdecl на __stdcall должно решить первую проблему. Как указывает @Adam Rosenfield, вам, вероятно, также нужно передать и вернуть char const *, а не string. C # и C ++ почти наверняка имеют несколько иное представление о том, что представляет собой строка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...