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);