• C#调用C++ DLL动态库的两种方式


    第一种方式:C++导出函数, c#dllimport 的方式

    在很多地方都看到过,如[dllimport “user32.dll”]这种代码,调用windows API,就是通过这种方式实现。

    例子:新建C++项目,创建动态链接库(DLL),然后添加头文件textdll.h

    #pragma once
    #ifdef A_EXPORTS
    #define DLL_API __declspec(dllexport)
    #else
    #define DLL_API __declspec(dllimport)
    #endif
    
    extern "C" DLL_API void MessageBoxShow();   //通过extern “C” 使MessageBoxShow方法为一个导出方法,外部可见 

    然后,dllmain.cpp中添加代码:

    #include "stdafx.h"
    #include "textdll.h"
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    
    #ifdef _MANAGED
    #pragma managed(push, off)
    #endif
    
    void MessageBoxShow()
    {
        MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
    }
    
    
    #ifdef _MANAGED
    #pragma managed(pop)
    #endif

    编译通过后,找到目录下生成的DLL(TESTDLL.dll),拷贝出来,放到C#的debug目录(程序目录)下, 然后新建C#程序:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;  //必须要添加该引用
    using System.Text;
    using System.Threading.Tasks;
    
    namespace dlltest
    {
        class Program
        {
            [DllImport("TESTDLL.dll")]  //最关键的,导入该dll
            public extern static void MessageBoxShow();
            static void Main(string[] args)
            {
                MessageBoxShow();
            }
        }
    }

    然后运行可以看到结果:成功的调用了C++DLL中的方法。

    第二种方式:

    通过C++/CLI作为中间层,因为C++/CLI即可调用.NET的类库,又可调用C++原生库,

    所以可以通过C# 调用 C++/CLI 再调用 C++ DLL这样的三层调用方式完成。

    1、创建一个c++空项目

      项目创建完成,我们添加一个类,写几个方法,这儿就简单写一个计算器的加减乘除吧!

    在CaculateData.h中添加如下代码,定义几个函数声明;

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    #ifdef CaculateDLL_EXPORTS
    #define Calculate_EXPORTS __declspec(dllexport)
    #else
    #define Calculate_EXPORTS __declspec(dllimport)
    #endif
    
    extern "C" Calculate_EXPORTS int Add(int numberA, int numberB);
    
    extern "C" Calculate_EXPORTS int Subtract(int numberA, int numberB);
    
    extern "C" Calculate_EXPORTS int Multiplication(int numberA, int numberB);
    
    extern "C" Calculate_EXPORTS  int Divided(int numberA, int numberB);
    
    class CaculateData
    {
    public:
        CaculateData();
        ~CaculateData();
    
    };

    可以看到,#ifdef的宏没有定义,所以我们需要添加一个宏:

    项目右键---属性---配置属性---C/C++---预处理器---预处理器定义,将定义的宏添加进去;

    可以看到,定义好了,颜色就变成紫色的,说明已经声明了宏;

    在CaculateData.cpp中实现这几个方法;

    #include "CaculateData.h"
    #include <iostream>
    
    CaculateData::CaculateData()
    {
    }
    
    
    CaculateData::~CaculateData()
    {
    }
    
    Calculate_EXPORTS int Add(int numberA, int numberB)
    {
        return numberA + numberB;
    }
    
    Calculate_EXPORTS int Subtract(int numberA, int numberB)
    {
        return numberA - numberB;
    }
    
    Calculate_EXPORTS int Multiplication(int numberA, int numberB)
    {
        return numberA * numberB;
    }
    
    Calculate_EXPORTS int Divided(int numberA, int numberB)
    {
        if (numberB == 0) {
            std::cout << "除数不能为空" << std::endl;
        }
        return numberA / numberB;
    }

    修改C++工程项目输出目录,这儿主要是便于CLI引用,我们这儿同意定义到Testinvoking项目的输出目录..inDebug etcoreapp2.2

    (修改步骤:项目右键—属性—配置属性—常规—输出目录)

    配置类型修改为:动态库.dll (修改步骤:项目右键—属性—配置属性—常规—配置类型)

    然后生成;

    2、新建一个CLR项目

    这个项目就是来实现C#调用C++的

    因为需要调用Caculate.dll,所以需要引用它;

    配置属性—VC++目录—库目录(把刚刚生成Caculate.dll的路径添加进去)

     同时引用库:

     添加一个类InvokeCon.cpp,用它来调用Caculate.dll中的方法

     InvokeCon.cpp代码如下:

    #include "InvokeCon.h"
    
    InvokeCon::InvokeCon()
    {
    }
    
    int InvokeCon::AddCli(int numberA, int numberB)
    {
        return Add(numberA, numberB);
    }
    
    int InvokeCon::SubtractCli(int numberA, int numberB)
    {
        return Subtract(numberA, numberB);
    }
    
    int InvokeCon::MultiplicationCli(int numberA, int numberB)
    {
        return Multiplication(numberA, numberB);
    }
    
    int InvokeCon::DividedCli(int numberA, int numberB)
    {
        return Divided(numberA, numberB);
    }

    InvokeCon.h代码:

    #pragma once
    
    #include <iostream>
    #include "C:Users	jysource
    eposTestInvokingCaculateCaculateData.h"//引用库声明对应文件路径
    public ref class InvokeCon
    {
    public:
        InvokeCon();
    
        int AddCli(int numberA, int numberB);
        int SubtractCli(int numberA, int numberB);
        int MultiplicationCli(int numberA, int numberB);
        int DividedCli(int numberA, int numberB);
    };

    然后编译,修改编译类型为动态库dll

    3、c#通过引用CliDll.dll来调用Caculate中的方法

     然后生成:此时就产生了CliDll.dll库

    1、添加对Dll的引用;

    2、在C#项目中添加测试代码:

    可以看到,此时就能够调用多个方法,而且会有方法名提示!

    using System;
    
    namespace TestInvoking
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("---------c#通过CLI调用C++类方法---------");
                    Console.Write("请输入numberA:");
                    int numberA = Convert.ToInt32(Console.ReadLine());
                    Console.Write("请输入numberB:");
                    int numberB = Convert.ToInt32(Console.ReadLine());
    
                    InvokeCon invoke = new InvokeCon();
                    int addResult = invoke.AddCli(numberA, numberB);
                    int subResult = invoke.SubtractCli(numberA, numberB);
                    int mutilResult = invoke.MultiplicationCli(numberA, numberB);
                    int divResult = invoke.DividedCli(numberA, numberB);
    
                    Console.WriteLine($"the {numberA} And {numberB} sum is:{addResult};sub is:{subResult};Mutil is:{mutilResult};div is:{divResult}");
                }
                catch(Exception ex)
                {
                    Console.WriteLine($"ex:{ex}");
                }
    
                Console.WriteLine("执行成功");
                Console.ReadLine();
            }
        }
    }

     OK,完成!

    代码已经放到了github,需要的朋友可以去看,就是这篇文章简单的demo:

    github地址:https://github.com/tomorrowGooddays/Invoke

  • 相关阅读:
    使用 PIVOT 和 UNPIVOT 行转列 列转行 报表统计 函数
    HAVING 子句 (SQL Server Compact)
    浅谈C#抽象类和C#接口
    大型高并发高负载网站的系统架构
    瞬时响应:网站的高性能架构
    Python之Subprocess模块
    Python之JSON序列
    Saltstack生产案例之系统初始化
    Saltstack配置管理
    CentOS6.5安装配置PPTP
  • 原文地址:https://www.cnblogs.com/jshchg/p/12898853.html
Copyright © 2020-2023  润新知