【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);
}