程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 在C#調用C++的DLL簡析(二)—— 生成托管dll

在C#調用C++的DLL簡析(二)—— 生成托管dll

編輯:關於C語言

寫操作之前,還是扼要的說一下托管與非托管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好麻煩)

205824549.jpg


二、一個非托管C++的例子


我手上有一個用非托管C++寫的類NativeClass,它本身是屬於另外一個非托管C++工程,現在我直接將這個類文件拷貝到本工程的目錄下去,簡單起見,這個類我內聯在一個頭文件裡,如果是其他比較大型的類,必要將NativeClass.h裡#include到的其他文件也一並拷貝到本新建工程目錄下,然後將這些文件添加到VS的資源管理器下,如下圖所示:

210658121.jpg


上圖中,除了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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved