Как настроить функцию C ++, чтобы она могла использоваться p / invoke? - PullRequest
8 голосов
/ 08 октября 2009

Надеюсь, это бездумно простой вопрос, но он показывает мой недостаток опыта в C ++. Я программист на C #, и в прошлом я проделал большую работу с P / Invoke с другими библиотеками C ++ / C. Тем не менее, на этот раз я решил написать оболочку C ++ dll (неуправляемую) сам, а затем вызываю мою оболочку dll из C #.

Проблема, с которой я немедленно столкнулся, заключается в том, что я не могу определить функцию C ++, которую можно найти с помощью p / invoke. Я не знаю, каков синтаксис для этого, но вот что я пытаюсь до сих пор:

extern bool __cdecl TestFunc()
{
  return true;
}

Первоначально у меня просто было это, но оно также не работало:

bool TestFunc()
{
  return true;
}

А затем на стороне C # у меня есть:

    public const string InterfaceLibrary = @"Plugins\TestDLL.dll";

    [DllImport( InterfaceLibrary, CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "TestFunc" ), SuppressUnmanagedCodeSecurity]
    internal static extern bool TestFunc();

Все компилируется, но когда я выполняю этот вызов C # p / invoke, я получаю System.EntryPointNotFoundException: Невозможно найти точку входа с именем 'TestFunc' в DLL 'Plugins \ TestDLL.dll'.

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

Ответы [ 6 ]

13 голосов
/ 08 октября 2009

Вы захотите использовать extern "C", а также __declspec(export), например:

extern "C" _declspec(dllexport)  bool TestFunc()
{
    return true;
}

Для получения полной информации см. MSDN о распределении типов .

7 голосов
/ 08 октября 2009

Расширение правильного ответа Рида.

Другая проблема, с которой вы можете столкнуться при использовании функции C ++ через PInvoke, - использование недопустимых типов. PInvoke может действительно поддерживать только маршаллинг примитивных типов и простых старых типов данных / структур классов.

Например, предположим, что TestFunc имеет следующую подпись

void TestFunc(std::string input);

Даже добавления extern "C" и __declspec(dllexport) будет недостаточно для раскрытия функции C ++. Вместо этого вам нужно будет создать вспомогательную функцию, которая будет отображать только PInvoke-совместимые типы и затем вызываться в основную функцию. Например

void TestFunc(const std::string& input) { ... }

extern "C" _declspec(dllexport)  void TestFuncWrapper(char* pInput) {
  std::string input(pInput);
  TestFunc(input);
}
1 голос
/ 26 января 2011

Сделай что-нибудь подобное:

#define EXPORT extern "C" __declspec(dllexport)

А затем объявите любую функцию с ключевым словом EXPORT, например, функцию c ++

BOOL getString(TCHAR* string, DWORD size);

станет

EXPORT BOOL getString(TCHAR* string, DWORD size);

тогда самое интересное: перейдите на консоль VS и введите:

dumpbin /EXPORTS <PATH_TO_GENERATED_DLL>

и вы увидите искаженное имя и порядковый номер всех ваших легко экспортируемых функций, тогда просто вызовите их

1 голос
/ 08 октября 2009

Компилятор C ++ изменяет имена ваших функций, чтобы включить информацию о параметрах и типах возвращаемых данных. Это называется искажением названия. С другой стороны, компилятор C не искажает имена ваших функций.

Вы можете указать компилятору C ++ работать как компилятор C, используя extern "C":

extern "C" __declspec(dllexport) bool TestFunc { return true; }

Для вызова функций из C # с использованием P / Invoke ваши имена не должны быть искажены. Следовательно, вы можете экспортировать функции C в C #. Если вы хотите, чтобы функциональность была реализована в C ++, вы можете написать функцию C, которая просто вызывает функцию C ++, реализующую эту функциональность.

1 голос
/ 08 октября 2009

Вы должны выставить эту функцию с помощью extern "C", иначе имя искажается.

0 голосов
/ 24 февраля 2016

Сборка всего проекта на платформе Win32 и соответствующая опция сборки (например, x86 или x64).

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