首页 > 代码库 > .Net 环境下C# 通过托管C++调用本地C++ Dll文件

.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 3class 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_CLASSusing 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中红色表示的构造函数中申请的内存不晓得何时释放.