C#與C++的混合編程


 

C#寫界面比較方便,而C++則擅長寫算法,所以將兩者結合起來將會加快程序的開發速度,並保證程序的質量。但C#C++的混合編程有很多細節問題需要注意,下面簡要列舉一些並指出相應的解決辦法。

       1. 將本機C++代碼(指非托管C++)編譯成一個dll,供C#調用,調用方法為 [DllImport(×××.dll)] 。但是這里只能從 DLL 導出函數,不能導出類(還沒有測試能否導出變量)。不能導出類是因為本機C++是非托管的,與C#的語言方式不兼容。也就是說,不能將此類dll作為引用 添加到C#工程中,IDE會提示不是一個程序集。

       2. 利用CLR C++(指托管C++)編寫輸出類庫,供C#使用,由於CLR C++C#都符合CLS規范,所以兩者可以無縫集成,在一個解決方案里包含這兩種語言的項目。生成的DLL可以導出類。但是CLR C++與傳統C++有很大的區別,可以認為是另一種不同的語言,學習它也要話費很大的精力,所以這種方法也有些麻煩。CLR C++不兼容本機C++的很多內容,但可以利用指針來操作。

 

3. 利用CLR C++把本機C++代碼包裝起來,做一個wrapper。這種方法比較好,而且在設計模式里還有一個專門的名稱。首先創建一個C#項目寫界面,然后添加一 個CLR C++類庫項目和一個本機C++ DLL項目。本機C++ DLL項目里面是算法代碼,可以導出類;在CLR C++類庫項目里寫一個類,私有成員為本機C++ 類的指針(不能用類的實例,因為CLS不支持混合類型),公共成員為本機C++ DLL類中的相應功能。C#調用CLR C++類,CLR C++類再調用本機C++ 類,表示如下:

Native C++   ==>> Managed C++ Wrapper ==>> C# GUI

 

如果按照上面的方法做會出現一些問題。比如本機C++文件DLLClass.h

 

// 此類是從DllClass.dll 導出的

classDLLCLASS_APICDllClass {

public:

       CDllClass(void);

       // TODO: 在此添加您的方法。

};

 

托管C++文件AlgoCLR.h

namespaceAlgoCLR {

    publicrefclassClass1

    {

    public:

       Class1();

       ~Class1();

       !Class1();

       voidFunction();

    private:

       void *pcls;

    };

}

 

C#文件program.cs

Class1cls = newClass1();

cls.Function();

 

全部編譯成功后開始調試,調試器會停在 Class1cls = newClass1() 處,提示出現FileNotFoundException異常:

未處理 System.IO.FileNotFoundException Message="找不到指定的模塊。 (異常來自 HRESULT:0x8007007E)" Source="======" StackTrace:        ======.Program.Main(String[] args)        System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)        System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)        Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()        System.Threading.ThreadHelper.ThreadStart_Context(Object state)        System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)        System.Threading.ThreadHelper.ThreadStart() InnerException:

 

去掉Class1cls = newClass1() 這一行則不會出現問題。這是因為程序需要本機C++DLL,而它沒有找到。在TargetDir(即××\bin\Debug目錄)里沒有本機C++ DLL,但是有CLR C++DLL,所以我們只需要將本機C++DLL復制到該目錄中即可。在C#項目的屬性”->“生成事件生成后事件命令行中輸入

copy $(SolutionDir)Debug\DllClass.dll $(TargetDir)

DllClass.dll為本機C++代碼生成的DLL。然后編譯運行,就可以看到正確的結果。附生成事件語法:

命令行編輯框

包含要為預先生成或后期生成運行的事件。

注意

在運行 .bat 文件的所有后期生成命令之前添加一個 call 語句。例如,call C:\MyFile.batcall C:\MyFile.bat call C:\MyFile2.bat

展開編輯框,顯示要插入命令行編輯框中的宏列表。

宏表

列出可用的宏及其值。有關每個宏的說明,請參見下面的“宏”。一次只能選擇將一個宏插入命令行編輯框中。

插入

將在宏表中選擇的宏插入命令行編輯框中。

可以使用以下任意宏來指定文件位置,或在存在多重選擇的情況下獲取輸入文件的實際名稱。這些宏不區分大小寫。

 
說明

$(ConfigurationName)

當前項目配置的名稱(例如,“Debug|Any CPU”)。

$(OutDir)

輸出文件目錄的路徑,相對於項目目錄。這解析為“輸出目錄”屬性的值。它包括尾部的反斜杠“\”。

$(DevEnvDir)

Visual Studio 2005 的安裝目錄(定義為驅動器 + 路徑);包括尾部的反斜杠“\”。

$(PlatformName)

當前目標平台的名稱。例如“AnyCPU”。

$(ProjectDir)

項目的目錄(定義為驅動器 + 路徑);包括尾部的反斜杠“\”。

$(ProjectPath)

項目的絕對路徑名(定義為驅動器 + 路徑 + 基本名稱 + 文件擴展名)。

$(ProjectName)

項目的基本名稱。

$(ProjectFileName)

項目的文件名(定義為基本名稱 + 文件擴展名)。

$(ProjectExt)

項目的文件擴展名。它在文件擴展名的前面包括“.”。

$(SolutionDir)

解決方案的目錄(定義為驅動器 + 路徑);包括尾部的反斜杠“\”。

$(SolutionPath)

解決方案的絕對路徑名(定義為驅動器 + 路徑 + 基本名稱 + 文件擴展名)。

$(SolutionName)

解決方案的基本名稱。

$(SolutionFileName)

解決方案的文件名(定義為基本名稱 + 文件擴展名)。

$(SolutionExt)

解決方案的文件擴展名。它在文件擴展名的前面包括“.”。

$(TargetDir)

生成的主輸出文件的目錄(定義為驅動器 + 路徑)。它包括尾部的反斜杠“\”。

$(TargetPath)

生成的主輸出文件的絕對路徑名(定義為驅動器 + 路徑 + 基本名稱 + 文件擴展名)。

$(TargetName)

生成的主輸出文件的基本名稱。

$(TargetFileName)

生成的主輸出文件的文件名(定義為基本名稱 + 文件擴展名)。

$(TargetExt)

生成的主輸出文件的文件擴展名。它在文件擴展名的前面包括“.”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM