C++ 之动态链接库DLL使用注意事项及C#调用详解

C++ 之动态链接库DLL使用注意事项及C#调用详解

  • 有时候算法开发完成之后需要封装成动态链接库DLL来进行集成,一方面增加了算法or代码的复用或者广泛使用性,另一方面也起了保密的效果
  • 平时封装成DLL之后放到一台新的电脑上会出现问题,所以本文总结一下其中问题及解决方式
  • C#调用DLL这个和C++也有不同之处,至于详细解释,后边慢慢增加
  • 关于C++ 与 C# 之间的数据对应关系,可以参考我的另一篇文章:https://blog.csdn.net/yohnyang/article/details/128355275

1. DLL封装

1.1 封装

  • 当C++开发好了code后,封装可以有两种方式:

      1. VS中新建DLL项目,可以将开发的code复制到新项目中,编译生成DLL。一般新建一个DLL项目后,会自动生成如下几个文件:
cpp 复制代码
//**************************************************************************************************
//framework.h
#pragma once

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

//**************************************************************************************************
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"
#endif //PCH_H

//**************************************************************************************************
// pch.cpp: 与预编译标头对应的源文件

#include "pch.h"
#include<iostream>

// 当使用预编译的头时,需要使用此源文件,编译才能成功。

//**************************************************************************************************
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.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;
}

将想要封装的code填充到pch中:

cpp 复制代码
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"

extern "C" _declspec(dllexport) int test1(int a, float* output);

#endif //PCH_H

//***********************************************************************************************
// pch.cpp: 与预编译标头对应的源文件

#include "pch.h"
#include<iostream>

// 当使用预编译的头时,需要使用此源文件,编译才能成功。

int test1(int a, float* output)
{
	output[0] = a;
	printf("test1 ok....");
	return 1;
}
  • 另一种封装方式就是直接在C++项目中包含常用头文件,然后将输出文件有.exe改为.dll,其他属性酌情修改~
cpp 复制代码
#inlcude<Windows.h>

1.2 查询DLL依赖

  • 打开VS2019目录下自带的命令行窗口,输入命令dumpbin /dependents xx.dll 查询即可:

  • 如果调用时无法打开,可以先查询一下依赖,然后在编译电脑中找出相关的.dll复制到目标路径下即可,一般是在C:/ 盘路径下的C:\Windows\System32 文件夹中及环境变量路径下进行 search

    • C++ 调用.dll打不开时会有提示缺少哪个
    • C# 调用.dll打不开时只会提示无法找到.dll

2. 调用

2.1 C++ 调用

  • 新建VS项目,右键项目名称添加新建项 test_0.cpp,编写测试code:
cpp 复制代码
/*
* 测试dll
*/
#include <iostream>
#include <Windows.h>

int main()
{
    typedef int(*testFunc)();
    HMODULE module = LoadLibrary(L".\\Dll1.dll");
    if (module == NULL)
    {
        std::cout << "加载DemoDLL.dll动态库失败\n" << std::endl;
        return -1;
    }
    else {
        std::cout << "加载成功...\n";
    }

    testFunc test1 = (testFunc)GetProcAddress(module, "test1");
    test1();

    return 1;
}

2.2 C# 调用

  • 新建VS 中C#空项目,将Dll1.dll放到 .\bin\x64\Release 目录下,然后 coding ex:
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        public class ABC
        {
            [DllImport(@"Dll1.dll", EntryPoint = "test1", CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
            public static extern int test1(int a, float[] output);

        }

        static void Main(string[] args)
        {
            float[] data = new float[10];
            ABC.test1(3,data);
            Console.ReadLine();
        }
    }
}
相关推荐
大锦终11 分钟前
递归回溯综合练习
c++·算法·深度优先
AI即插即用17 分钟前
即插即用系列(代码实践)专栏介绍
开发语言·人工智能·深度学习·计算机视觉
码农水水25 分钟前
蚂蚁Java面试被问:混沌工程在分布式系统中的应用
java·linux·开发语言·面试·职场和发展·php
喵了meme26 分钟前
c语言经验分享
c语言·开发语言
晚风吹长发31 分钟前
初步了解Linux中的动静态库及其制作和使用
linux·运维·服务器·数据结构·c++·后端·算法
Knight_AL1 小时前
用 JOL 验证 synchronized 的锁升级过程(偏向锁 → 轻量级锁 → 重量级锁)
开发语言·jvm·c#
啊阿狸不会拉杆1 小时前
《数字图像处理》第 4 章 - 频域滤波
开发语言·python·数字信号处理·数字图像处理·频率域滤波
风之歌曲1 小时前
c++高精度模板
c++·算法·矩阵
crescent_悦1 小时前
C++:Find Coins
c++
千谦阙听1 小时前
双链表:比单链表更高效的增删查改
数据结构·链表·visual studio