C#引用C++代碼

来源:http://www.cnblogs.com/roucheng/archive/2016/04/23/cscpp.html
-Advertisement-
Play Games

現在在Windows下的應用程式開發,VS.Net占據了絕大多數的份額。因此很多以前搞VC++開發的人都轉向用更強大的VS.Net。在這種情況下,有很多開發人員就面臨瞭如何在C#中使用C++開發好的類的問題。下麵就用一個完整的實例來詳細說明怎樣用托管C++封裝一個C++類以提供給C#使用。 比如,現 ...


 現在在Windows下的應用程式開發,VS.Net占據了絕大多數的份額。因此很多以前搞VC++開發的人都轉向用更強大的VS.Net。在這種情況下,有很多開發人員就面臨瞭如何在C#中使用C++開發好的類的問題。下麵就用一個完整的實例來詳細說明怎樣用托管C++封裝一個C++類以提供給C#使用。
    比如,現在有一個工程名為NativeCppDll的由C++編寫的DLL,裡面輸出了一個CPerson類。下麵是具體的代碼:

// NativeCppDll.h
#pragma once
#ifndef LX_DLL_CLASS_EXPORTS
    #define LX_DLL_CLASS __declspec(dllexport)
#else
    #define LX_DLL_CLASS __declspec(dllimport)
#endif

// hovertree.com
class LX_DLL_CLASS CPerson
{
public:
    CPerson();
    CPerson(const wchar_t *pName, const wchar_t cSex, int iAge);
    void SetName(const wchar_t *pName);
    wchar_t * GetName();
    void SetSex(const wchar_t cSex);
    wchar_t GetSex();
    void SetAge(int iAge);
    int GetAge();
    wchar_t * GetLastError();
private:
    wchar_t m_szName[128];
    wchar_t m_cSex;
    int m_iAge;
    wchar_t m_szLastError[128];
    void ShowError();
};
// NativeCppDll.cpp
#include "stdafx.h"
#include "NativeCppDll.h"
#include <iostream>
#include <tchar.h>
using namespace std;
CPerson::CPerson()
{
    wcscpy_s(m_szName, _T("No Name"));
    m_cSex = 'N';
    m_iAge = 0;
    wcscpy_s(m_szLastError, _T("No Error"));
}
CPerson::CPerson(const wchar_t *pName, const wchar_t cSex, int iAge)
{
    wcscpy_s(m_szLastError, _T("No Error"));
    SetName(pName);
    SetSex(cSex);
    SetAge(iAge);
}
void CPerson::SetName(const wchar_t *pName)
{
    if ((pName == NULL) || (wcslen(pName) == 0) || (wcslen(pName) > 127))
    {
        wcscpy_s(m_szName, _T("No Name"));
        wcscpy_s(m_szLastError, _T("The length of the input name is out of range."));
        ShowError();
        return;
    }
    wcscpy_s(m_szName, pName);
}
wchar_t * CPerson::GetName()
{
    return m_szName;
}
void CPerson::SetSex(const wchar_t cSex)
{
    if ((cSex != 'F') && (cSex != 'M') && (cSex != 'm') && (cSex != 'f'))
    {
        m_cSex = 'N';
        wcscpy_s(m_szLastError, _T("The input sex is out of [F/M]."));
        ShowError();
        
        return;
    }
    m_cSex = cSex;
}
wchar_t CPerson::GetSex()
{
    return m_cSex;
}
void CPerson::SetAge(int iAge)
{
    if ((iAge < 0) || (iAge > 150))
    {
        m_iAge = 0;
        wcscpy_s(m_szLastError, _T("The input age is out of range."));
        ShowError();
        return;
    }
    m_iAge = iAge;
}
int CPerson::GetAge()
{
    return m_iAge;
}
wchar_t * CPerson::GetLastError()
{
    return m_szLastError;
}
void CPerson::ShowError()
{
    cerr << m_szLastError << endl;
}

這是一個很典型的由C++開發的DLL,輸出一個完整的C++類。如果現在要求開發一個C#工程,需要用到這個DLL中輸出的C++類CPerson,該怎麼辦呢?針對這個例子來說,類CPerson非常小,可以用C#重新寫一個跟這個C++類一樣的類。可是,如果需要的C++類很大,或者很多的時候,重寫工程將非常龐大。而且這樣沒有對現有的代碼進行重用,浪費了現有資源,開發起來費時費力。
    當然,還是有方法解決這個問題的。那就是用托管C++將C++類給封裝一下,然後再提供給C#來使用。下麵就用代碼來詳細說明怎樣用托管C++來封裝上面的那個C++類。
    首先,要創建一個托管C++的DLL工程ManageCppDll,然後在裡面添加下麵的代碼:   

// ManageCppDll.h
#pragma once
#define LX_DLL_CLASS_EXPORTS
#include "../NativeCppDll/NativeCppDll.h"
using namespace System;
namespace ManageCppDll 
{
    public ref class Person
    {
    // 包裝所有類CPerson的公有成員函數
    public:
        Person();
        Person(String ^ strName, Char cSex, int iAge);
        ~Person();
        property String ^ Name
        {
            void set(String ^ strName);
            String ^ get();
        }// hovertree.com
        property Char Sex
        {
            void set(Char cSex);
            Char get();
        }
        property int Age
        {
            void set(int iAge);
            int get();
        }
        String ^ GetLastError();
    private:
        // 類CPerson的指針,用來調用類CPerson的成員函數
        CPerson *m_pImp;
    };
};

從這個頭文件就能看出來,這是對C++類CPerson的包裝。類Person的所有公有成員函數都跟C++類CPerson一樣,只不過成員函數的參數和返回值就改成了托管C++的類型,這也是讓類Person能在C#中使用的首要條件。當然只需要對公有成員函數進行封裝,對於保護成員函數和私有成員函數則不必做任何封裝。
    類Person僅有一個私有的成員變數:一個類CPerson的指針。而類Person的所有成員函數的實現都是靠這個CPerson指針來調用類CPerson的相應成員函數來實現。
    下麵是具體的實現代碼:

// ManageCppDll.cpp
#include "stdafx.h"
#include "ManageCppDll.h"
#include <vcclr.h>
namespace ManageCppDll 
{
    // 在構造函數中創建類CPerson的對象併在析構函數中將該對象銷毀
    // 所有的成員函數實現都是通過指針m_pImp調用類CPerson的相應成員函數實現
    Person::Person()
    {
        m_pImp = new CPerson();
    }
    Person::Person(String ^ strName, Char cSex, int iAge)
    {
        // 將string轉換成C++能識別的指針 hovertree.com
        pin_ptr<const wchar_t> wcName = PtrToStringChars(strName);
        m_pImp = new CPerson(wcName, cSex, iAge);
    }
    Person::~Person()
    {
        // 在析構函數中刪除CPerson對象
        delete m_pImp;
    }
    void Person::Name::set(String ^ strName)
    {
        pin_ptr<const wchar_t> wcName = PtrToStringChars(strName);
        m_pImp->SetName(wcName);
    }
    String ^ Person::Name::get()
    {
        return gcnew String(m_pImp->GetName());
    }
    void Person::Sex::set(Char cSex)
    {
        m_pImp->SetSex(cSex);
    }
    Char Person::Sex::get()
    {
        return m_pImp->GetSex();
    }
    void Person::Age::set(int iAge)
    {
        m_pImp->SetAge(iAge);
    }
    int  Person::Age::get()
    {
        return m_pImp->GetAge();
    }
    String ^ Person::GetLastError()
    {
        return gcnew String(m_pImp->GetLastError());
    }
};

 如果要在C#中使用類Person,首先要添加對ManageCppDll.dll的引用,然後就可以像用普通的C#類一樣的使用類Person了。比如下麵這樣的代碼:

using ManageCppDll;
Person person = new Person();
person.Name = "StarLee";
person.Sex = 'M';
person.Age = 28;
// 何問起

 熟悉設計模式的看了上面的代碼肯定會發現,這樣的設計跟BRIDGE模式如出一轍。其實,上面的方法也算是一種BRIDGE模式,由托管C++充當了C#中使用用C++開發的類的橋梁。另外,這種形式也可以理解為ADAPTER模式,托管C++類Person就是C++類CPerson的一個適配器。通過這個橋梁,可以很容易的重用以前用C++開發的類,讓這些C++類繼續在C#中發揮它們的效用,讓開發變得事半功倍。

http://www.cnblogs.com/roucheng/

http://www.cnblogs.com/roucheng/p/3521864.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一章 Android系統移植與驅動開發 Android源代碼定製完全屬於自己的嵌入式系統,但是支持的設備不多,所以要移植,而在移植的過程中使用的不得不提的是驅動開發。 Android系統構架主要包括四個層次:Linux內核,C/C++代碼庫,Android SDK API,應用程式。在第一層Lin ...
  • 一、禁止root用戶遠程登錄: 將 permitRootLogin 後面的值改成 no 如下圖: 然後再重啟sshd服務即可,如下: 二、更改ssh遠程登錄埠: 去掉#後,將 Port 值改成 18206,如下圖: 重啟sshd服務即可. 三、限制ssh登錄用戶數量: 去掉#後,將 MaxSess ...
  • ngx_http_upstream_module用於將多個伺服器定義成伺服器組,而由proxy_pass,fastcgi_pass等指令引用 (1)upstream name {...} 定義一個後端伺服器組,name為組名,只能用於http上下文中 (2) server address [para ...
  • sudo apt-get install shutter 然後配合系統快捷鍵,我定義的和qq的截屏一樣的。用著感覺很舒服。 ...
  • Debian系統的普通用戶需要安裝軟體時,往往會收到“Permission denied”的提示,這時候需要root許可權。那麼如何在不登陸超級管理員賬戶的前提下擁有root許可權呢?對於大多數Linux系統來說,我們可以通過“sudo”命令來獲取root許可權,或者通過“su”登陸超級管理員賬戶來進行各 ...
  • C#泛型是一種高復用性、安全和高效的技術,通過類型參數可以將參數的聲明、實現推遲到客戶代碼中。但是這種延遲卻降低了類型參數在泛型定義中的可操作性。例如資源釋放。 但是如果T實現了IDisposable介面,則上面代碼可能存在資源泄露的風險。但是由於不知道T是否實現了IDisposable介面,所以不 ...
  • 菜鳥要飛系列目錄 1.(菜鳥要飛系列)一,基於Asp.Net MVC5的後臺管理系統(前言) 2.(菜鳥要飛系列)二,基於Asp.Net MVC5的後臺管理系統(實現登陸功能) 3.(菜鳥要飛系列)三,基於Asp.Net MVC5的後臺管理系統(用戶的增刪改查功能) 4.(菜鳥要飛系列)四,基於As ...
  • 最近由於伺服器變更為Linux系統.MsSql for Linux什麼時候出來到生產環境使用還是要很長時間的.於是考慮使用Mysql資料庫,ORM使用EF.於是先踩下坑順便記錄一下,有需要的tx可以參考下.當你考慮使用EF連接Mysql的時候肯定是已經在網上搜了一堆教程.網上教程基本都是使用控制台做 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...