2009-10-07 13 views
8

Mam nadzieję, że jest to pytanie bezmyślnie proste, ale pokazuje mój brak wiedzy z C++. Jestem programistą C# i w przeszłości robiłem obszerne prace z P/Invoke z bibliotekami C++/C innych ludzi. Jednak tym razem postanowiłem napisać osobną bibliotekę C++ (niezarządzanego), a następnie wywołuję moją bibliotekę otworkową z C#.Jak skonfigurować funkcję C++, aby mogła być używana przez p/invoke?

Problem, na który napotykam od razu, polega na tym, że nie mogę zdefiniować funkcji C++, którą można znaleźć za pomocą p/invoke. Nie wiem, co składnia do tego jest, ale tutaj jest to, co usiłuję do tej pory:

extern bool __cdecl TestFunc() 
{ 
    return true; 
} 

Początkowo po prostu musiałem to, ale to nie działa albo:

bool TestFunc() 
{ 
    return true; 
} 

I następnie po stronie C#, mam:

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

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

Wszystko kompiluje, ale kiedy wykonać to C# p/wywołać rozmowę, mam System.EntryPointNotFoundException: Nie można odnaleźć punktu wejścia o nazwie „TestFunc” w bibliotece DLL " Wtyczki \ TestDLL.dll ".

To musi być coś niesamowicie prostego na końcu C++, którego po prostu nie znam składni.

Odpowiedz

12

będziemy chcieli użyć extern "C" jak __declspec(export), tak:

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

Aby uzyskać szczegółowe informacje, patrz MSDN on Marshalling Types.

+0

Idealne, to zrobiło! Próbowałem też mieć extern "C" w przeszłości, ale to nie zadziałało. Zawodzi, dopóki nie zostanie dodany _declspec (dllexport). – x4000

1

Musisz ujawnić tę funkcję z extern "C" w przeciwnym razie nazwa zostanie zniekształcona.

1

Kompilator C++ modyfikuje nazwy funkcji w celu włączenia informacji o parametrach i typach zwracanych. Nazywa się to manglingiem nazw. Z drugiej strony kompilator języka C nie modyfikuje nazw funkcji.

Można powiedzieć, że kompilator C++ do pracy jako kompilatora C z użyciem extern "C":

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

Wywołanie funkcji z C# za pomocą P/Invoke, nazwy nie powinny być zniekształcone. Dlatego możesz eksportować funkcje C do C#. Jeśli chcesz, aby funkcja była zaimplementowana w C++, możesz napisać funkcję C, która po prostu wywołuje funkcję C++ implementującą tę funkcjonalność.

6

Rozszerzanie poprawnej odpowiedzi Reeda.

Kolejny problem, na który można się natknąć podczas eksponowania funkcji C++ za pośrednictwem PInvoke, to używanie nieprawidłowych typów. PInvoke może w rzeczywistości obsługiwać wyłącznie sortowanie typów pierwotnych i zwykłych starych klas danych/klas.

Na przykład, załóżmy TestFunc miał następujący podpis

void TestFunc(std::string input); 

Nawet dodanie extern "C" i __declspec(dllexport) nie wystarczy, aby odsłonić funkcji C++. Zamiast tego należy utworzyć funkcję pomocniczą, która eksponuje tylko typy kompatybilne z PInvoke, a następnie wywoływana w funkcji głównej.Na przykład

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

extern "C" _declspec(dllexport) void TestFuncWrapper(char* pInput) { 
    std::string input(pInput); 
    TestFunc(input); 
} 
+0

Tak, to jest właśnie ten powód, dla którego piszę otkrywującą bibliotekę C++, zamiast próbować wywoływać wszystkie funkcje, których potrzebuję bezpośrednio. Moim celem jest stworzenie prostszego interfejsu dla P/Invoke, przy jednoczesnym pozostawieniu całej wymaganej złożoności z callbackami i złożonymi typami itp., Pozostając po stronie C++. Słuszne uwagi! – x4000

+0

@ x4000, Podjęłam już to samo podejście. Z wyjątkiem zamiast nowej biblioteki DLL, właśnie dodałem funkcje opakowania do tej samej biblioteki DLL. Więcej DLL byłoby czystsze. – JaredPar

+0

Początkowa biblioteka DLL, którą pakuję, jest własnością strony trzeciej, więc nie była to opcja dla mnie. Ale masz rację, myślę, że pod wieloma względami czystsze jest oddzielanie owijki od zawartości, która jest opakowana, kiedy to możliwe. – x4000

1

zrobić coś lubi to:

#define EXPORT extern "C" __declspec(dllexport) 

A potem zadeklarować dowolną funkcję ze słowem kluczowym eksportowych na przykład c funkcji ++

BOOL getString(TCHAR* string, DWORD size); 

staną

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

to zabawa część: Idź do konsoli VS i typ:

dumpbin /EXPORTS <PATH_TO_GENERATED_DLL> 

i you'l zobaczyć zniekształcone nazwy i porządkowe wszystkich swoich łatwo eksportowanych funkcji, to jest to po prostu kwestia o pInvoking im

0

Kompilacja wszystkich projektów z Platforma Win32 i odpowiedni bit (np x86 lub x64) opcja kompilacji.