天天看點

C#調用C++ DLL類方法(轉)--托管

 C++的優勢在于高效靈活,C#的優勢在于簡單易用,兩者結合起來對項目開發來說是件好事,而且C++不容易反編譯,也保障了代碼的安全性,如果一些核心算法使用C#編寫,那麼保密就是一個問題。

C++生成的DLL一般隻提供函數接口,不能直接用C#調用C++寫的類,這樣非常不友善,于是經過半天的反複測試,終于确定了一套可行的方案,下面就是整個流程的一個範例。

(1)編寫C++類Mask,類前面的extern "C" class _declspec(dllexport)這麼一串修飾符是必備的,不然無法導出類。

[cpp] view plain copy print?

//Mask類頭檔案mask.h

#pragma once

extern "C" class _declspec(dllexport) Mask

{

public:

Mask(char* inputFile,int* maskValue,int maskLength);

virtual void Run(void);

~Mask(void);

private:

char* _inputFile;

int* _maskValue;

int _maskLength;

};

(2)Mask類内部實作,這裡使用char*和int*這兩個有代表性的參數,C#向C++進行參數的傳遞是很難弄的一步。

//Mask類實作檔案mask.cpp

Mask::Mask(char* inputFile ,int* maskValue,int maskLength)

_inputFile=new char[strlen(inputFile)+1];

strcpy(_inputFile,inputFile);

_maskValue=new int[maskLength];

_maskLength=maskLength;

for(int i=0;i<maskLength;i++)

_maskValue[i]=maskValue[i];

}

void Mask::Run(void)

Mask::~Mask(void)

if (_inputFile)

{

delete [] _inputFile;

_inputFile=NULL;

}

if (_maskValue)

delete [] _maskValue;

_maskValue=NULL;

可以設定生成類型為DLL,然後将debug目錄下的dll檔案和lib檔案找到,留待下一步使用。

(3)編寫C++.NET類MaskCLR,C++.NET我一直認為就是個擺設,沒想到也能派上用場,難得啊,也不完全是個廢物。MaskCLR可以調用Mask類,注意函數的參數已經變成String ^和int*,現在是.NET環境,使用指針沒那麼友善了。

//MaskCLR類頭檔案,用來包裝Mask類MaskCLR.h

#include " mask.h" //這個就是上面的Mask頭檔案

public ref class MaskCLR

MaskCLR(String ^ inputFile,int* maskValue,int maskLength);

virtual void Run(void) override;

(4)MaskCLR類内部實作,首先要處理參數類型問題,将String ^類型轉為char*。在MaskCLR:: Run函數内部調用Mask類,Mask是DLL導出的類。

// MaskCLR類内部實作MaskCLR.cpp

#include "MaskCLR.h"

MaskCLR::MaskCLR(String ^ inputFile,int* maskValue,int maskLength)

_inputFile=GlobeFunction::StringToChar(inputFile);

_maskValue=maskValue;

void MaskCLR:: Run(void)

Mask mask(_inputFile, _maskValue,_maskLength);

mask.Run();

(5)将String ^類型轉為char*,可以利用StringToHGlobalAnsi這個.NET自帶的函數。

[csharp] view plain copy print?

char* GlobeFunction::StringToChar(String ^str)

return (char*)(Marshal::StringToHGlobalAnsi(str)).ToPointer();

(6)最終生成了兩個DLL檔案,一個是原始C++編寫的,另一個是托管C++編寫的,托管dll隻是個外殼,最終還是調用原始dll,是以這兩個dll要放在一起。下面終于進入C#環境了,首先将托管dll添加引用到C#工程中,C++.NET和C#可以直接互用。

(7)由于有個int*類型參數,在C#裡指針屬于不安全代碼,是以使用unsafe關鍵字将涉及到指針的代碼包括起來,在工程屬性裡設定允許使用不安全代碼。定義int指針需要使用stackalloc關鍵字,建立一個int數組,對數組指派後,将指針傳遞給類函數。

//c#調用托管dll中的MaskCLR類form1.cs

unsafe

int* value = stackalloc int[1];

value[0] = 0;

MaskCLR mask = new MaskCLR("D:\\臨時\\mask8.tif", value, 1);