当前位置: 首页 > news >正文

【dll】windows下使用vs编译动态链接库dll与使用

一、需求

 编译出可供其他平台使用的基于c语言的函数库dll。

二、前言

 网上很多相关操作,但部分说明不详细或是没有配套的示意图导致操作遇到困难,且使用vs时会由于需要进行各种配置导致编译生成失败,因此才准备将每一步操作都记录下来,确保按照操作步骤能够顺利生成dll库。分为两部分,第一部分是工程创建,经过各种工程类型选择的测试,使用如下方法可减少更多的配置操作。第二部分是c代码编写,涉及到MicrosoftVC的一些关键字与声明的操作。

三、代码工程与项目操作

默认已安装且可正常使用visual stdio开发项目。

3.1新建项目

左上角标签卡,“文件”->“新建”->“项目”,如下图:

3.2使用向导新建

经试验多个项目类,其他类需要创建后进行配置,使用向导新建项目后可直接编译生成dll库。因此选择“Visual C++”->“Windows桌面”->"Windows桌面向导“,命名工程后确认生成,如下图:

 3.3选择应用程序类型

应用程序类型默认为”.exe“,此时需进入下拉选框选择”动态链接库(dll)“。然后勾选”空项目“确保新生成的工程中代码干净。如下图: 

3.4创建完成

此时工程相关操作已完成。

3.5平台切换

默认为x86平台,需切换到x64平台,否则生成的dll会造成不兼容导致无法准确读取的情况,配置如图:

四、c代码操作

文件创建与基本声明部分省略,源码会放到文章末尾的附录处。

4.1声明修饰

如需使用dll,在函数的外部声明处需使用”__declspec(dllexport)“和”__declspec(dllimport)“关键词进行修饰。

  • __declspec(dllexport):用于通过编译产生dll进行数据导出的函数
  • __declspec(dllimport):用于通过调用dll进行获取导入数据的函数

上述修饰一般在函数类型声明前,如下:

 4.2编译

编译成功后会在子目录下产生对应工程名称的dll文件,如下:

五、验证使用

验证需使用另外一个全新的项目,例如自带”hello world!“的 控制台应用。

5.1头文件声明

必备声明如下:

#include<Windows.h>//必备

 5.2读取dll文件

使用LoadLibrary函数读取,用HINSTANCE类型变量接收。

HINSTANCE hDll = LoadLibrary(_T("dll1.dll"));
if (hDll == NULL) {
	printf("lib not exist.");
	return 1;
}

 5.3定义函数类型

已知dll函数的声明类型与参数类型。

using functionPtrCreate = t_obj*(*)();
using functionPtrSetID = void(*)(t_obj*,long);
using functionPtrGetID = long(*)(t_obj*);

5.4GetProcAddress加载函数

functionPtrCreate objCreate = (functionPtrCreate)GetProcAddress(hDll, "objCreate");
functionPtrSetID objSetID = (functionPtrSetID)GetProcAddress(hDll, "objSetID");
functionPtrGetID objGetID = (functionPtrGetID)GetProcAddress(hDll, "objGetID");

5.5使用加载的函数输出结果

输入:

objSetID(temp, 10086);

 输出:

std::cout << objGetID(temp);

结果: 

附录 源码

1、dll_config_global.h

#ifndef _DLL_CONFIG_GLOBAL_H_
#define _DLL_CONFIG_GLOBAL_H_

/*逻辑分支,判断环境*/
#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#  define DLL_CONFIG_DECL_EXPORT __declspec(dllexport)//用于dll数据导出
#  define DLL_CONFIG_DECL_IMPORT __declspec(dllimport)//用于导入dll数据
#else
#  define DLL_CONFIG_DECL_EXPORT     __attribute__((visibility("default")))//失效
#  define DLL_CONFIG_DECL_IMPORT     __attribute__((visibility("default")))//失效
#endif

#endif // _DLL_CONFIG_GLOBAL_H_

 2、dll_demo.h

#ifndef _DLL_DEMO_H_
#define _DLL_DEMO_H_

/*dll编译需要使用的全局配置文件*/
#include "dll_config_global.h"

/*c库*/
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<math.h>

/*结构体类声明*/
typedef struct _obj {
	bool En;//使能
	long ID;//id
	const char * name;//一般名称
	void * data;//数据包
} t_obj;//基本对象

/*函数外部声明*/
#ifdef _cplusplus
extern "C" {
#endif // _cplusplus{}

	DLL_CONFIG_DECL_EXPORT t_obj* objCreate();
	DLL_CONFIG_DECL_EXPORT void objEnable(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objDisable(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT bool objGetEn(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objClearID(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objSetID(t_obj*obj, long val);
	DLL_CONFIG_DECL_EXPORT long objGetID(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objClearName(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objSetName(t_obj*obj, char*val);
	DLL_CONFIG_DECL_EXPORT const char* objGetName(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objClearData(t_obj*obj);
	DLL_CONFIG_DECL_EXPORT void objSetData(t_obj*obj, void*p, long length);
	DLL_CONFIG_DECL_EXPORT void* objGetData(t_obj*obj);

#ifdef _cplusplus

#endif // _cplusplus{}


#endif // _DLL_DEMO_H_

3、dll_demo.c

#include"dll_demo.h"

//----节0
/*创建基本对象*/
DLL_CONFIG_DECL_EXPORT t_obj* objCreate() {
	return (t_obj*)malloc(sizeof(t_obj));
}

//----节1
/*使能对象*/
DLL_CONFIG_DECL_EXPORT void objEnable(t_obj*obj)
{
	obj->En = true;
}
/*失能对象*/
DLL_CONFIG_DECL_EXPORT void objDisable(t_obj*obj)
{
	obj->En = false;
}
/*获取对象状态*/
DLL_CONFIG_DECL_EXPORT bool objGetEn(t_obj*obj)
{
	return obj->En;
}

//----节2
/*清空id*/
DLL_CONFIG_DECL_EXPORT void objClearID(t_obj*obj)
{
	obj->ID = 0x00;
}
/*设置id*/
DLL_CONFIG_DECL_EXPORT void objSetID(t_obj*obj,long val)
{
	obj->ID = val;
}
/*获取对象id*/
DLL_CONFIG_DECL_EXPORT long objGetID(t_obj*obj)
{
	return obj->ID;
}

//----节3
/*清空名称*/
DLL_CONFIG_DECL_EXPORT void objClearName(t_obj*obj)
{
	obj->name = NULL;
}
/*设置名称*/
DLL_CONFIG_DECL_EXPORT void objSetName(t_obj*obj,char*val)
{
	obj->name = val;
}
/*获取对象名称*/
DLL_CONFIG_DECL_EXPORT const char* objGetName(t_obj*obj)
{
	return obj->name;
}

//----节4
/*清空数据包*/
DLL_CONFIG_DECL_EXPORT void objClearData(t_obj*obj)
{
	free(obj->data);
	obj->data = NULL;
}
/*设置数据包*/
DLL_CONFIG_DECL_EXPORT void objSetData(t_obj*obj,void*p,long length)
{
	obj->data = malloc(length);
	memcpy(obj->data, p, length);
}
/*获取对象数据包*/
DLL_CONFIG_DECL_EXPORT void* objGetData(t_obj*obj)
{
	return obj->data;
}


4、dllUse.cpp

#include<iostream>
#include<Windows.h>//必备
#include<tchar.h>
//#pragma comment(lib,"dll1.lib")
typedef struct _obj {
	bool En;//使能
	long ID;//id
	const char * name;//一般名称
	void * data;//数据包
} t_obj;//基本对象

int main()
{
	HINSTANCE hDll = LoadLibrary(_T("dll1.dll"));
	if (hDll == NULL) {
		printf("lib not exist.");
		return 1;
	}
	using functionPtrCreate = t_obj*(*)();
	using functionPtrSetID = void(*)(t_obj*,long);
	using functionPtrGetID = long(*)(t_obj*);
	//找到所需要的函数
	
	functionPtrCreate objCreate = (functionPtrCreate)GetProcAddress(hDll, "objCreate");
	functionPtrSetID objSetID = (functionPtrSetID)GetProcAddress(hDll, "objSetID");
	functionPtrGetID objGetID = (functionPtrGetID)GetProcAddress(hDll, "objGetID");
	t_obj* temp = objCreate();
	objSetID(temp, 10086);
	std::cout << objGetID(temp);

}

相关文章:

  • 2022年ios证书最新申请流程
  • 普冉 PY32F003 资料和入坑方法
  • springboot+微信小程序健康饮食系统毕业设计源码280920
  • 介绍日本日置IM7583阻抗分析仪
  • 如何开始做股票量化交易?
  • 1446_TC275 DataSheet阅读笔记7_部分管脚功能的梳理
  • 优化算法|MOAVOA:一种新的多目标人工秃鹰优化算法(Matlab代码实现)
  • 基于Springboot+vue的茶叶销售商城网站 elementui
  • goframe的学习
  • 为什么 SQL 是 2022 年收入最高的编程语言
  • windows安装mysql5.7.35
  • ES6 Promise链式调用解决异步回调
  • Kotlin(十四)泛型
  • QGraphicsItem图元坐标和在场景中的坐标(六)
  • 【云原生 | Kubernetes 系列】---kube-state-metrics
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • flutter的key在widget list的作用以及必要性
  • github从入门到放弃(1)
  • idea + plantuml 画流程图
  • Javascript编码规范
  • JavaScript实现分页效果
  • JavaScript新鲜事·第5期
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • learning koa2.x
  • Map集合、散列表、红黑树介绍
  • miaov-React 最佳入门
  • Odoo domain写法及运用
  • PHP变量
  • Spring声明式事务管理之一:五大属性分析
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 工作手记之html2canvas使用概述
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 全栈开发——Linux
  • 深度学习中的信息论知识详解
  • 一道闭包题引发的思考
  • 智能合约开发环境搭建及Hello World合约
  • 主流的CSS水平和垂直居中技术大全
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​人工智能书单(数学基础篇)
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (阿里云万网)-域名注册购买实名流程
  • (蓝桥杯每日一题)love
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • .net framework4与其client profile版本的区别
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .NET框架
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .so文件(linux系统)
  • ::什么意思
  • [ IO.File ] FileSystemWatcher
  • [\u4e00-\u9fa5] //匹配中文字符
  • [20190401]关于semtimedop函数调用.txt