zoukankan      html  css  js  c++  java
  • .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 <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: 	 {1}", i, provider.Pot());
                     */
    
                    //高效模式                
                    if (i % 10 == 0)
                        Console.WriteLine("{0}: Potential: 	 {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中红色表示的构造函数中申请的内存不晓得何时释放.

  • 相关阅读:
    setjmp()和longjmp()函数
    C语言过程活动记录
    【剑指Offer】字符串的排列
    python剑指offer系列二叉树中和为某一值的路径
    二叉搜索树的后续遍历
    如何设置学习率
    各种机器学习算法的优缺点(未完成)
    机器学习中梯度下降法和牛顿法的比较
    特征图大小的计算
    为什么L1稀疏,L2平滑?
  • 原文地址:https://www.cnblogs.com/tuyile006/p/3804223.html
Copyright © 2011-2022 走看看