2009-10-07 29 views
8

希望這是一個沒有腦子的簡單問題,但它表明我缺乏C++的專業知識。我是一名C#程序員,過去曾與其他人的C++/C dll一起完成了P/Invoke的大量工作。然而,這次我決定自己編寫一個包裝C++ dll(非託管),然後從C#調用我的包裝DLL。如何設置一個C++函數使其可以被p/invoke使用?

我馬上遇到的問題是我無法定義可以通過p/invoke找到的C++函數。我不知道這個語法是什麼,但這裏是我試圖至今:

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「的切入點插件\ TestDLL.dll」。

當然,這肯定是C++端非常簡單的東西,我只是不知道它的語法。

回答

12

您需要使用extern "C"以及__declspec(export),就像這樣:

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

有關詳情,請參閱MSDN on Marshalling Types

+0

完美無瑕!過去我也嘗試過只有外部的「C」,但那不起作用。它直到加入_declspec(dllexport)纔會失敗。 – x4000 2009-10-07 20:26:55

1

您必須將此函數與extern "C"公開,否則名稱會發生​​錯位。

1

C++編譯器會修改函數的名稱,以合併有關參數和返回類型的信息。這被稱爲名稱修改。另一方面,C編譯器不會破壞你的函數名稱。

你可以告訴C++編譯器的工作與使用extern "C" C編譯器:

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

要使用P/Invoke,你的名字一定不會缺胳膊少腿從C#調用函數。因此,您可以將C函數實際導出爲C#。如果你想用C++來實現功能,你可以編寫一個C函數來調用實現該功能的C++函數。

6

擴展裏德的正確答案。

當通過PInvoke公開C++函數時,您可能遇到的另一個問題是使用無效類型。 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); 
} 
+0

是的,正是這種原因,我正在編寫一個包裝器C++ dll,而不是試圖直接調用所有我需要的函數。我的目標是爲P/Invoke創建一個更簡單的接口,同時讓所有複雜的回調和複雜類型等都留在C++端。好點! – x4000 2009-10-07 20:37:25

+0

@ x4000,我採取了完全相同的方法。除了一個新的DLL,我只是將包裝函數添加到同一個DLL。更多的DLL會更清潔。 – JaredPar 2009-10-07 20:58:04

+0

我包裝的最初的DLL是由第三方,所以這不是我的選擇。但是你是對的,我認爲在很多方面,儘可能將包裝與被包裝的內容分開是更清潔的。 – x4000 2009-10-07 21:28:37

1

做一些喜歡這樣的:

#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> 

和you'l看到了錯位的名字和你所有容易導出函數順序,那麼它只是一個事ØpInvoking他們

0

構建所有項目, Win32平臺和適當的位(例如x86或x64)構建選項。

相關問題