Хорошо ... дело сложное.Действительно сложно.
Я должен предупредить, что для доступа к этим методам предпочтительнее другой метод.Создайте функцию C для каждого метода или используйте COM.Выберите, какой метод вы предпочитаете.Оба метода требуют некоторой работы на стороне C ++.
Поскольку мы пытаемся сейчас ответить на вопрос, мы пытаемся вызвать метод из класса C ++.
Первая проблема:
Вам нужно украсить все классы или методы классов с помощью __declspec (экспорт).Если символ не экспортируется, вы не сможете получить к нему доступ.Конечно, это не очень хорошо работает с шаблонами.
Вторая проблема:
Методы класса используют соглашение о вызовах __thiscall.Для P / Invoke по умолчанию требуется соглашение __stdcall.
Однако вы можете изменить атрибут CallingConvention на CallingConvention.ThisCall в DllImportAttribute, поэтому проблема решена.
Третья проблема:
Каждый компилятор C ++есть собственный способ генерирования экспортированных имен членов C ++!
Сначала в этом посте я предполагаю, что DLL была скомпилирована с Microsoft Visual C ++!Не знаю с другими компиляторами, что может произойти.
Атрибут DllImport требует точного имени метода.Так как он генерируется компилятором C ++, абсолютно нет простого способа восстановить имя без просмотра таблицы экспорта DLL (это связано с виртуальными объектами, перегрузками, пространствами имен, именами классов и т. Д.).
Единственный способ, которым я знаю, чтобы получить имя метода, - это использовать утилиту dll dump, например, я часто использую «dumpbin.exe / EXPORTS file.dll».Это распечатает ваши dll методы.Вы также можете использовать rtti для печати имен методов, это может помочь вам отобразить экспорт dll с вашим кодом.
Теперь мы можем написать наш dllimport.Например.
[DllImport(
"MyDll.dll",
EntryPoint="?MyFunction@CMyClass@@QAEXH@Z",
CallingConvention=CallingConvention.ThisCall)]
public static extern void MyFunction(IntPtr myClassObject, int parameter);
Атрибут EntryPoint является точным именем вашего экспортируемого метода.
Хорошо, мы закончили, но давайте проанализируем проблемы в этом:
Четвертая проблема
Не существует официального документа от Microsoft, в котором объясняется, как именно генерируются имена методов для экспорта в c ++, и поэтому экспортированные имена могут измениться, если вы измените исходный код C ++.
ЭтоЭто самая большая головная боль, которую вы можете испытать на этом пути!
Пятая проблема
Сборщик мусора и безопасное удаление объектов ... Вместо IntPtr используйте SafeHandles, оба, если вы собираетесь использовать функции Сиили если вы используете способ C ++.
Вы можете определить SafeHandle, который представляет указатель на ваш объект C ++.Этот SafeHandle должен вызывать деструктор вашего объекта C ++ в переопределенной функции ReleaseHandle.
Заключение
Как я уже говорил, просто использовать функции C или COM-объекты будет проще, более переносимо и менее утомительно.
COM-взаимодействие было построено, чтобы избежать проблем с собственными функциями компилятора C ++.Com - это старая технология, у которой много проблем и странных вещей, но она все еще работает, все еще поддерживается и будет поддерживаться в течение длительного времени.
Если ваш граф объектов в C ++ будет довольно сложным,используйте COM.Инструмент C # tlbimp автоматически генерирует классы C #, которые связываются с COM-объектами на лету, без необходимости делать какие-либо DllImport.
Если вам нужны простые вещи, просто используйте простой C.