Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Не удаётся подключить Dll

#c_sharp #cpp #dll


К проекту на C# подключаю библиотеку C++, библиотека полностью рабочая.
Руководство по подключению взял тут.

[DllImport("C:\\Users\\Zaki\\Desktop\\SetsGen.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern string GetSets(string ids, int power);

public void DllSub(string param)
{
   try
   {
      string myAns = GetSets(param, 3);
      string[] tokens = myAns.Split('/');
      foreach (var token in tokens)
      {
         Console.WriteLine(token);
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
}


Нативная сигнатура функции GetSets в Dll выглядит следующим образом: 

std::string GetSets(std::string ids, int power)


Получаю исключение при обращении к портированной функции GetSets:


  An unhandled exception of type 'System.AccessViolationException'
  occurred in Test.exe
  
  Additional information: Attempted to read or write protected memory.
  This is often an indication that other memory is corrupt.


Какие могут быть причины и как исправить?
    


Ответы

Ответ 1



Причины могут быть разные: Ошибка в реализации нативной функции. Чтобы её исключить, попробуйте сделать пустую GetSets и пересобрать DLL. Проблемы совместимости DLL и С# кода. Был случай, когда DLL, собранная в C++Builder приводила к ошибкам на стадии выполнения. Пересборка компилятором MS решила проблему на корню. Неправильно передаются аргументы в функцию. См. маршалинг строк. Если сигнатура нативной функции содержит сложные типы из стандартной библиотеки C++ (в том числе и std::string), использовать такую функцию в P/Invoke будет проблематично (читай как невозможно). Разные компиляторы по-разному реализуют стандартные классы, поэтому передавать между модулями такие типы довольно опасно. В данном случае наиболее правильное решение будет заключаться в том, чтобы экспортировать функцию, принимающую const char* (си-строку), а дальше в потрохах DLL уже можно использовать и std::string для удобства.

Ответ 2



Проблем тут несколько, одна из которых — возвращаемое значение из нативной функции (std::string). В двух словах — стандартными методами вам не вернуть строку из нативного метода результатом. Вторая проблема — строки в C# имеют кодировку Unicode, а нативная std::string имеет кодировку ASCII. Советую использовать std::wstring в нативном методе, CharSet = CharSet.Unicode в маршаллинге и возвращать результат как показано тут: «Return a std::wstring from C++ into C#», «Passing strings from C# to C++ dll and back — minimal example». P. S. С C++ CLI все намного лучше в плане маршаллинга.

Комментариев нет:

Отправить комментарий