.Net 环境下C# 通过托管C++调用本地C++ Dll文件
综述 : 本文章介绍.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
#include
#include
#include
#include
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 { for(int j=0; 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中红色表示的构造函数中申请的内存不晓得何时释放.
发表评论