綜述 : 本文章介紹.Net 環境下C# 通過托管C++調用本地C++ Dll文件, 示例環境為:VS2010, .Net4.0, Win7. 具體事例為測試C++, C#, 及C#調用本地C++Dll文件進行浮點運算效率的一部分. 如果需要查看三者的效率, 請繼續閱讀下面的文章.
a 創建本地CPP類庫
1. 創建本地CPP的Dll ---->EfficiencyNativeCPPDLL
2. 點擊下一步 注意選擇為DLL(D)項, 然后選擇完成.
3.書寫DLL文件
3.1
EfficiencyNativeCppDll.h #pragma once #ifndef GoWin_DLL_CLASS_EXPORTS //該類可導出 #define GoWin_DLL_CLASS __declspec(dllexport) #else //該類可導入 #define GoWin_DLL_CLASS __declspec(dllimport) #endif #define NPARTS 1000 #define DIMS 3 class GoWin_DLL_CLASS EfficiencyNativeCppDll { public: EfficiencyNativeCppDll(void); ~EfficiencyNativeCppDll(void); void InitPositions(); void UpdatePositions(); double ComputePot(); double Pot; private: double _r[DIMS][NPARTS]; };
3.2
EfficiencyNativeCppDll.cpp #define WIN32_LEAN_AND_MEAN // 從 Windows 頭文件中排除極少使用的信息 #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> EfficiencyNativeCppDll::EfficiencyNativeCppDll(void) { Pot = 0; } EfficiencyNativeCppDll::~EfficiencyNativeCppDll(void) { printf("~EfficiencyNativeCppDll is called"); } void EfficiencyNativeCppDll::InitPositions() { for(int i = 0; i < DIMS; i++) { for (int j = 0; j < NPARTS; j++) { _r[i][j] = 0.5 + (double)rand()/RAND_MAX; } } } void EfficiencyNativeCppDll::UpdatePositions() { for(int i = 0; i < DIMS; i++) { for (int j = 0; j < NPARTS; j++) { _r[i][j] -= 0.5 + (double)rand()/RAND_MAX; } } } double EfficiencyNativeCppDll::ComputePot() { double distx, disty, distz, dist; double pot; distx = 0; disty = 0; distz = 0; pot = 0; for(int i=0; i<NPARTS; i++ ) { for(int j=0; j<i-1; j++ ) { distx = pow( (_r[0][j] - _r[0][i]), 2 ); disty = pow( (_r[1][j] - _r[1][i]), 2 ); distz = pow( (_r[2][j] - _r[2][i]), 2 ); dist = sqrt( distx + disty + distz ); pot += 1.0 / dist; } } this->Pot = pot; return pot; }
在Release狀態下生成, 會得到 EfficiencyNativeCPPDLL.dll 和 EfficiencyNativeCPPDLL.lib兩種文件 其中EfficiencyNativeCPPDLL.dll用于后面的CLR/C++調用; 而EfficiencyNativeCPPDLL.lib則用于Native C++的調用; 這在效率對比一文中會用到.
b 創建C++/CLI類庫
1. 添加新建項目 EfficiencyCLRWrapper
2. 項目 EfficiencyCLRWrapper需要對項目EfficiencyNativeCPPDLL中的EfficiencyNativeCppDll.h 和 EfficiencyCLRWrapper.dll引用
2.1 引用EfficiencyNativeCppDll.h
有兩種方式, 可任選一種
a) 將EfficiencyNativeCppDll.h直接復制到 項目 EfficiencyCLRWrapper中, 這很簡單 不再描述
b) 更改 項目 EfficiencyCLRWrapper屬性設置中包換目錄選項, 以包含文件EfficiencyNativeCppDll.h
b.1) 看到右側的包含目錄了嗎? 點擊后選擇 編輯
b.2) 我這里選擇了把EfficiencyNativeCPPDLL文件夾及項目EfficiencyNativeCPPDLL的Release文件夾均包含在內了
2.2 引用完成后書寫C++/CLR代碼
2.2.1 頭文件
EfficiencyCLRWrapper.h #pragma once #include "EfficiencyNativeCppDll.h" #define GoWin_DLL_CLASS using namespace System; namespace EfficiencyCLRWrapper { public ref class CLRWrapper { private: EfficiencyNativeCppDll * _pNtvCppPro; public: CLRWrapper(void); ~CLRWrapper(void); void InitPositions(); void UpdatePositions(); double ComputePot(); property double Pot { double get(); void set(double value); } }; }
2.2.2 主體文件
#include "EfficiencyCLRWrapper.h" using namespace EfficiencyCLRWrapper; CLRWrapper::CLRWrapper(){ this->_pNtvCppPro = new EfficiencyNativeCppDll();} CLRWrapper::~CLRWrapper(){} double CLRWrapper::ComputePot() { return this->_pNtvCppPro->ComputePot(); } void CLRWrapper::InitPositions() { this->_pNtvCppPro->InitPositions(); } void CLRWrapper::UpdatePositions() { this->_pNtvCppPro->UpdatePositions(); } double CLRWrapper::Pot::get() { return this->_pNtvCppPro->Pot; } void CLRWrapper::Pot::set(double value) { this->_pNtvCppPro->Pot = value; }
2.2.3 將形成如下樹結構:
3. 千萬不要忘記的一點就是在項目EfficiencyCLRWrapper中對EfficiencyNativeCPPDLL的引用, 否則依舊無法生成, 如圖:
4 這個時候 對項目EfficiencyCLRWrapper在Release下生成則可以得到 文件 CLRCPPWrapper.dll
C 創建C# 控制臺應用程序
1 添加C#項目 ConsoleEfficiencyCSInvokeCLRDll
2. 添加對項目 EfficiencyCLRWrapper的引用
3. 因項目ConsoleEfficiencyCSInvokeCLRDll須間接調用EfficiencyNativeCPPDLL.dll因此 跟上面相同可用兩種方法解決
可任選其一
a) 將以生成的EfficiencyNativeCPPDLL.dll復制到項目ConsoleEfficiencyCSInvokeCLRDll的bin/Release文件夾下 不再具體描述
b) 添加項目ConsoleEfficiencyCSInvokeCLRDll屬性中調試中的工作目錄 如圖:
4. 在Program.cs文件中做CS的調用
namespace EfficiencyCSInvokeCLRDll { class Program { static void Main(string[] args) { CLRWrapper provider = new CLRWrapper(); const int NITER = 201; provider.InitPositions(); provider.UpdatePositions(); int start = Environment.TickCount; for (int i = 0; i < NITER; i++) { provider.Pot = 0.0; //低效模式 /*provider.ComputePot(); if (i % 10 == 0) Console.WriteLine("{0}: Potential: \t {1}", i, provider.Pot()); */ //高效模式 if (i % 10 == 0) Console.WriteLine("{0}: Potential: \t {1}", i, provider.ComputePot()); provider.UpdatePositions(); } int stop = Environment.TickCount; Console.WriteLine("Seconds = {0,10}", (double)(stop - start) / 1000); Console.ReadKey(); } } }
運行結果:
結果一般在0.240至00.281之間
硬件環境: Inter(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz 2.53GHz RAM 共4G(2.46GB可用)
疑問:
這里面有兩點疑問
1. 在CS調用中標出的高效模式和低效模式; 無非一個是直接調用函數返回值一個是調用函數后讀取屬性, 但是執行效率相差接近10倍.
2. 在C++/CLR中紅色表示的構造函數中申請的內存不曉得何時釋放.
文章列表