寫操作之前,還是扼要的說一下托管與非托管C++的區別好了,其實我也並沒有深入了解過托管C++的特點所在,其最大的特征就是可以由系統來調試回收相關的代碼資源,跟C#的特性一樣,只是編程風格跟C++類似而已,因此,這決定了C#與托管C++是可以完美結合在一起的。托管C++生成的dll跟C#生成的dll應該說是沒區別的,之所以產生托管C++這種怪物,完全是因為微軟在極力推崇C#,必須要兼顧不同語言間交互。
好吧,接下來正經的寫一下過程。先擺出目的:我手上有一個C++寫的類ClassA),想在C#下調用這個類,可是C#是沒有簡單的像dllimport這樣的方法獲取非托管C++ dll裡的類。我的解決方法是,生成一個托管C++的dll,因為托管代碼與非托管代碼是不能在一個文件裡混編的,所以我必須將ClassA用托管C++的手段封裝一下,然後生成一個dll,以供C#調用。
也許我這裡說得很繞,請看下面的教程,會很明了的。
一、建立CLR類庫工程
其實,我挺想忽略類似這些步驟的,一幅圖能說明的問題我就不多說,反正建立一個CLR類庫工程,其命名暫定為ManageClass,這是工程名,請勿混淆,如下圖,沒什麼注意事項可言的。抱怨一下,為啥BKJIA沒法在編輯裡縮小圖片的,PS好麻煩)
二、一個非托管C++的例子
我手上有一個用非托管C++寫的類NativeClass,它本身是屬於另外一個非托管C++工程,現在我直接將這個類文件拷貝到本工程的目錄下去,簡單起見,這個類我內聯在一個頭文件裡,如果是其他比較大型的類,必要將NativeClass.h裡#include到的其他文件也一並拷貝到本新建工程目錄下,然後將這些文件添加到VS的資源管理器下,如下圖所示:
上圖中,除了NativeClass.h文件是我添加進去的,其他都是工程自帶的東西,其中ManageClass.h及ManageClass.cpp是要生成dll所動用到的東西,暫時先不管,我們看一下NativeClass.h裡的內容:
#pragma once class _declspec(dllexport) NativeClass { private: int nCount; public: NativeClass(void) { this->nCount = 0; } ~NativeClass(void) { } int GetCount(void) { return this->nCount; } void Increase(void) { this->nCount++; } void Clear(void) { this->nCount = 0; } };
類的內容簡單到我不忍直視,像類頭的_declspec(dllexport)字段其實可要可不要的,只是我懶得刪除而已。
三、非裝成托管C++的內容
這一步是很關鍵的,之所以有這麼一步,是因為托管C++與非托管C++沒法混編,於是乎我將托管代碼將上面的NativeClass類封裝了一下,本來按規范而言我應該將函數聲明與實現分開寫,但我承認我又偷懶了,只在ManageClass.h裡作修改,雖然沒有用到ManageClass.cpp,但無論如何也別將這個文件刪除,否則是沒法生成dll的。我的封裝代碼如下:
// ManageClass.h #pragma once #include "NativeClass.h" using namespace System; namespace ManageClass { public ref class NativeClassEx { // TODO: 在此處添加此類的方法。 private: NativeClass * m_pnClass; public: NativeClassEx(void) { this->m_pnClass = new NativeClass(); } ~NativeClassEx(void) { delete this->m_pnClass; } int GetCount(void) { return this->m_pnClass->GetCount(); } void Increase(void) { this->m_pnClass->Increase(); } void Clear(void) { this->m_pnClass->Clear(); } protected: !NativeClassEx(void) { delete this->m_pnClass; } }; }
別告訴我上面的代碼你沒看懂,我會建議你找塊豆腐撞腦袋的。
四、生成托管C++的dll
其實到了這一步就結了,你直接點編譯,就會在工程外的Debug文件夾裡生成ManageClass.dll了,務必要看清,經過封裝後,我新的類名是叫NativeClassEx,請在使用時注意一下。
五、項目測試dll
調用托管C++的dll跟調用C#的dll沒任何區別,新建一個測試工程我用的是WinForm的窗體工程),名字叫DllTest,在解決方案資源管理器裡將剛剛生成的那個ManageClass.dll添加到引用裡,使用using ManageClass,然後你就可以用了,其測試代碼就幾句話:
NativeClassEx testCalss = new NativeClassEx(); Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString()); testCalss.Increase(); testCalss.Increase(); testCalss.Increase(); Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString()); testCalss.Clear(); Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString());
編譯一下,看輸出窗口,類還是完美運行得了的。
六、注意事項
1、盡管C#與托管C++很大程度上兼容,但還是要注意基本類型外的對齊問題,像結構體、string類這些,最好入口參數除了基本類型其他都別用,這點請參考我上一篇文章;
2、我嘗試用托管C++封裝我寫OpenCV類,類裡再調用了OpenCV的dll即C#調用托管dll,托管dll調用非托管dll),編譯通過,但實際運行不行,裡面有什麼問題暫時不清楚;
3、建議,沒什麼事別用這種方法來調用類,C#中調用dll的函數才是最具保障的。
4、示例工程請在這裡下載,用前記得先編譯好dll,並確保添加了引用,可能會有一些關於CPU類型選擇的warning,請諸位自力更生了。
本文出自 “幾縷蕭雨鎖清秋” 博客,請務必保留此出處http://joeyliu.blog.51cto.com/3647812/1297961