Как настроить функцию C++, чтобы она могла использоваться p / invoke?
надеюсь, это безмозглый простой вопрос, но он показывает мое отсутствие опыта работы с 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 = @"PluginsTestDLL.dll";
[DllImport( InterfaceLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "TestFunc" ), SuppressUnmanagedCodeSecurity]
internal static extern bool TestFunc();
все компилируется, но когда я выполняю этот вызов c# p / invoke, я получаю систему.EntryPointNotFoundException: не удалось найти точку входа с именем 'TestFunc' в DLL ' ПлагиныTestDLL.в DLL'.
конечно, это должно быть что-то невероятно простое на C++, что я просто не знаю синтаксиса.
6 ответов
вы захотите использовать extern "C"
а также __declspec(export)
, например:
extern "C" _declspec(dllexport) bool TestFunc()
{
return true;
}
для получения полной информации см. MSDN по типам маршалинга.
расширение правильного ответа Рида.
еще одна проблема, с которой вы можете столкнуться при отображении функции 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);
}
компилятор C++ изменяет имена ваших функций для включения информации о параметрах и типах возвращаемых данных. Это называется коверканье имени. С другой стороны, компилятор C не искажает имена ваших функций.
вы можете сказать компилятору c++ работать как компилятор C, используя extern "C"
:
extern "C" __declspec(dllexport) bool TestFunc { return true; }
чтобы вызвать функции из C# с помощью P / Invoke, ваши имена не должны быть искажены. Таким образом, вы можете экспортировать функции C на C#. Если вы хотите функциональность, которая будет реализована в C++, вы можете написать функцию C, которая просто вызывает функцию C++, реализующую функциональность.
сделать что-то вроде этого:
#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>
и вы увидите искаженное имя и порядковый номер всех ваших легко экспортируемых функций, то это просто вопрос о pInvoking их