DLL编程的导入导出,__declspec(dllimport),__declspec(dllexport)

宏学习记录001 —— #ifndef、__declspec(dllexport)、extern “C“ 宏学习记录: #ifndef、__declspec(dllexport)、extern "C" 的使用方法 阅读详情

在Windows DLL编程时,可使用__declspec(dllimport)关键字导入函数或者变量。

 
__declspec(dllimport),函数的导入
 
当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。但如果你显示地导入函数,编译器会产生质量更好的代码。由于编译器确切地知道了一个函数是否在一个DLL中,它就可以产生更好的代码,不再需要间接的调用转接。
 
Win32的PE格式(Portable Executable Format)把所有导入地址放在一个导入地址表中。下面用一个具体实例说明使用__declspec(dllimport)导入函数和不使用的区别:
 
假设func是一个DLL中的函数,现在在要生成的.exe的main函数中调用func函数,并且不显示地导入func函数(即没有:__declspec(dllimport)),代码示例如下:
int main()
{
    func();
}
 
编译器将产生类似这样的调用代码:
call func
 
然后,链接器把该调用翻译为类似这样的代码:
call 0x40000001       ; ox40000001是"func"的地址
 
并且,链接器将产生一个Thunk,形如:
0x40000001: jmp DWORD PTR __imp_func
 
这里的imp_func是func函数在.exe的导入地址表中的函数槽的地址。然后,加载器只需要在加载时更新.exe的导入地址表即可。
 
而如果使用了__declspec(dllimport)显示地导入函数,那么链接器就不会产生Thunk(如果不被要求的话),而直接产生一个间接调用。因此,下面的代码:
__declspec(dllimport) void func1(void);
void main(void) 
{
     func1();
}
 
将调用如下调用指令:
call DWORD PTR __imp_func1
 
因此,显示地导入函数能有效减少目标代码(因为不产生Thunk)。另外,在DLL中使用DLL外的函数也可以这样做,从而提高空间和时间效率。
 

__declspec(dllimport),变量的导入
 
与函数不同的是,在使用DLL中的变量时,需要显示地导入变量。使用__declspec(dllimport)关键字导入变量。若在DLL中使用.def导出变量,则应使用DATA修饰变量,而不是使用已经被遗弃的CONSTANT。因为CONSTANT可能需要使用指针间接访问变量,不确定什么时候会出问题。

DLL定义的全局变量可以被调用进程访问,DLL也可以访问调用进程的全局数据。

/* 文件名:lib.h */

#ifndef LIB_H
#define LIB_H
extern int dllGlobalVar;
#endif

/* 文件名:lib.cpp */

#include "lib.h"
#include <windows.h>
int dllGlobalVar;


BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
dllGlobalVar = 100; //在dll被加载时,赋全局变量为100
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}


;文件名:lib.def
;在DLL中导出变量
LIBRARY "dllTest"
EXPORTS
dllGlobalVar CONSTANT
;或dllGlobalVar DATA
GetGlobalVar


从lib.h和lib.cpp中可以看出,全局变量在DLL中的定义和使用方法与一般的程序设计是一样的。若要导出某全局变量,我们需要在.def文件的EXPORTS后添加:

变量名 CONSTANT   //过时的方法

或

变量名 DATA     //VC++提示的新方法

在主函数中引用DLL中定义的全局变量:

#include <stdio.h>
#pragma comment(lib,"dllTest.lib")
extern int dllGlobalVar;
int main(int argc, char *argv[])
{
printf("%d ", *(int*)dllGlobalVar);
*(int*)dllGlobalVar = 1;
printf("%d ", *(int*)dllGlobalVar);

return 0;
}


特别要注意的是用extern int dllGlobalVar声明所导入的并不是DLL中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用DLL中的全局变量。这一点,从*(int*)dllGlobalVar可以看出。因此在采用这种方式引用DLL全局变量时,千万不要进行这样的赋值操作:

dllGlobalVar = 1;

其结果是dllGlobalVar指针的内容发生变化,程序中以后再也引用不到DLL中的全局变量了。

在应用工程中引用DLL中全局变量的一个更好方法是:

#include <stdio.h>
#pragma comment(lib,"dllTest.lib")
extern int __declspec(dllimport) dllGlobalVar; //用__declspec(dllimport)导入
int main(int argc, char *argv[])
{
printf("%d ", dllGlobalVar);
dllGlobalVar = 1; //这里就可以直接使用, 无须进行强制指针转换
printf("%d ", dllGlobalVar);
return 0;
}

通过__declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是其地址了,笔者建议在一切可能的情况下都使用这种方式。

(通过程序测试,只用__declspec(dllexport)导出也能以本身形式使用全局变量)


__declspec(dllexport),导出

先看代码:以下是在dev-c++里建立自已的dll时的dll.h里面的代码,这里面有一个:_declspec(dllexport)

#ifndef _DLL_H_
#define _DLL_H_//防重复定义

#if BUILDING_DLL
#define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
#define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */


DLLIMPORT void HelloWorld (void);


#endif /* _DLL_H_ */

 

上面代码里面的_delcspce(dllexport)被定义为宏,这样可以提高程序的可读性!这个的作是是将函数定义为导出函数,也就是说这个函数要被包含这个函数的程序之外的程序调用!本语句中就是:void Helloword(void):

摘自msdn:在 32 位编译器版本中,可以使用 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。__declspec(dllexport) 将导出指令添加到对象文件。


若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:

__declspec(dllexport) void __cdecl Function1(void);


若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:

class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };


生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将 __declspec(dllexport) 添加到头文件中的声明。若要提高代码的可读性,请为 __declspec(dllexport) 定义一个宏并对正在导出的每个符号使用该宏:

#define DllExport   __declspec( dllexport ) 

__declspec(dllexport) 将函数名存储在 DLL 的导出表中。

GCC编译DLL报错:definition is marked dllimport ;__declspec(dllexport)和__declspec(dllimport)的作用 目录实践中的错误信息__declspec(dllexport)和__declspec(dllimport) 实践中的错误信息 头文件如下: // main.h #ifndef __MAIN_H__ #define __MAIN_H__ #ifdef BUILD_DLL #define DLL_EXPORT __declspec(dllexport) #else #define DLL_EXPORT __declspec(dllimport) #endif extern "C" { 阅读详情

相关推荐

Windows平台下C++动态库的__declspec(dllexport)和__declspec(dllimport)的作用

和是Windows平台下用来导出和导入函数、变量和类的关键字。它们的正确使用可以确保动态链接库的正确运行,并且可以避免因为符号未导出或导入不正确而引起的链接错误。在编写动态链接库时,我们需要使用将需要导出的符号标记出来;在使用动态链接库的程序中,我们需要使用来声明从外部DLL文件中导入的符号。这样可以确保动态链接库的正确使用,提高代码的可移植性和可维护性。

h a 6 6 6 c k 为 你解决复杂难题! 1358

关于__declspec(dllimport)的理解

一、基本概念 _declspec(dllexport)与_declspec(dllimport)都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。 主要区别在于:dllexport是在这些类、函数以 及数据的申明的时候使用。用过表明这些东西可以被外部函数使用,即(dllexport)是把DLL中的相关代码(类,函数,数据)暴露出来为其他应用程 序使用。而 dllimport关键字是在外部程序需要使用DLL内相关内容时使用的关键字。 二、初步理解 考虑下面的需求,

IT界的小菜比 1万+

闲人闲谈PS之十二——WBS-BOM在装备制造项目中的实战解析

本文深入解析了WBS-BOM在装备制造项目中的核心应用。针对按订单设计/生产的行业痛点,WBS-BOM作为项目专属物料清单,完美连接SAP PS与PP模块,确保MRP能基于项目进行精准物料需求计算,实现从设计到生产的全链路项目化跟踪与管理。

weixin_29284885的博客 399

__declspec(dllexport)是什么

__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面。 他们都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。 dllexport是在这些类、函数以及数据的申明的时候使用。用他表明这些东西可以被外部函数使用,即(dllexport)是把 DLL中的相关代码(类,函数,数据)暴露出来为其他应用程序使用。使用了(dllexport)关键字,相当于声明了紧接在(dll

nb_zsy的博客 1万+

手写Socket Web服务器:深入HTTP协议底层原理

HTTP协议是Web通信的基石,其本质是一套严格定义的文本格式与状态交互规范。理解它需回归传输层——TCP连接建立、请求响应格式(如状态行、头/体分隔符\r\n\r\n)、字符编码与字节长度一致性等核心原理。这些知识直接决定CORS拦截、中文乱码、Content-Length错误等高频问题的排查效率。在现代框架封装日益厚重的今天,亲手用Socket实现一个可被Chrome识别的极简Web服务器,成为掌握Web运行机制最有效的实践路径。本文即以DebugLZQ经典案例为蓝本,还原从URI解析、DNS查询、So

weixin_40192258的博客 534

汇川AM402、H3U和上位机C#ModebusTcp通讯

目录一、测试任务二、测试环境三、PLC工程1、组态配置2、ip地址、端口号 3、全局变量定义四、C#端Winform程序创建1创建主界面 2、创建子窗口 3、运行生成,界面效果4、Modebus协议说明5、Modebus操作说明六、测试1、寄存器读测试 2、MW1300寄存器的BIT位3、写寄存器测试4、PLC断电或者断网 七、工程下载连接1、PLC作为ModebusTCP端,端口号都是502,PC端上位机软件作为TcpClient去连接多台PLC。PC端读写PLC寄存器。2、PC端在有的PLC断电、断网的

panjinliang066333的博客 2万+

总结一下__declspec(dllimport)的作用

作者:朱金灿来源:http://blog.youkuaiyun.com/clever101/      是时候总结一下__declspec(dllimport)的作用了。可能有人会问:__declspec(dllimport)和__declspec(dllexport)是一对的,在动态链接库中__declspec(dllexport)管导出,__declspec(dl

clever101的专栏 2万+

解决Visual C++2008安装失败,error 1935

重装系统后Visual C++没了,其他都能装上但VC2008会报这个error 1935。鉴于我把网上所有的解决方法排了一遍错,我也不知道是哪一步起效,所以就都放上来了。特别注意:报error 1935的错误原因可能不尽相同,比如我的报错开头为An error occurred,结尾为HRESULT:0x80070005。80070005 拒绝访问通常是权限问题,安装Visual C++无法写入文件夹或注册表(直接跳转第7步)

weixin_44427808的博客 1万+

理解 __declspec(dllexport)和__declspec(dllimport)

首先要知道,头文件是C++的接口文件,不仅本工程需要使用头文件来进行编译,给其他工程提供dll的时候也要提供此dll的头文件才能让其他人通过编程的方式来使用dll。记住:头文件要给自己用还要给别人用。 头文件中声明了方法,在提供者那里方法应该被声明为__declspec(dllexport),在使用者那里,方法应该被声明为__declspec(dllimport)。 比如一个项目中的Class中含有一个静态变量,生成dll的时候只采用了__declspec(dllexport) 如下: ...

yaotuzhi的博客 9207

深入解析Dataloader中shuffle机制与随机种子对模型训练的影响

本文深入探讨了Dataloader中shuffle机制与随机种子对机器学习模型训练的影响。通过实际案例分析,详细解释了数据打乱顺序的必要性、随机种子的正确设置方法以及两者协同工作的原理,帮助开发者避免常见陷阱并提升模型训练效果。

weixin_29166013的博客 140

让Claude连续写代码24小时会发生什么?揭秘长时运行”架构背后的工程逻辑与未来

AI长时运行实验揭示软件开发新范式 Claude Opus通过Harness框架24小时独立开发全栈应用的成功实验,展示了AI从辅助工具向异步协作者的进化。实验采用"上下文轮转"机制解决记忆管理难题,将任务拆解为微周期并通过文件系统同步进度。核心突破在于:1)TDD成为AI自治基石,200+测试用例确保开发不偏航;2)文件取代对话成为AI间高效沟通介质;3)开发者角色重构为需求定义和框架设计者。该实验证明,通过严谨的架构约束和验收标准,AI可完成复杂长周期任务,预示着软件开发将从手工作坊

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 1089

利用__declspec(dllexport)和__declspec(dllimport)在Windows平台编写和使用DLL的小例子

关于 `__declspec(dllexport)` 和 `__declspec(dllimport)` 这两个关键字在上大学期间就没见过几次面,直到毕业后在公司项目的代码中又遇到过几次,每次也是绕着走,生怕和它产生什么联系,只知道它和动态链接库 `DLL` 有关,但是当前这个项目中几乎没有用到自己写的动态链接库,所以我也就心安理得的躲了它这么久...

AlbertS Home of Technology 4176

Unity 面试篇|(六)数据结构和算法篇 【全面总结 | 持续更新】

先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的数(10000中最小的),将这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样遍历完后,堆中的10000个数就是所需的最大的10000个。桶排序是计数排序的升级版。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。这样处理就可以分别在每个文件的10^6个数据中找出最大的10000个数,合并到一起在再找出1000*10000中的最终的结果。

游戏开发小Y的博客 12万+

Windows DLL编程中的导入导出:__declspec(dllimport) ,__declspec(dllexport) ,

在Windows DLL编程时,可使用__declspec(dllimport)关键字导入函数或者变量。 函数的导入     当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。但如果你显示地导入函数,编译器会产生质量更好的代码。由于编译器确切地知道了一个函数是否在一个DLL中,它就可以产生更好的代码,不再需要间接的调用转接。     Win32的PE

stone_kingnet的专栏 1万+

python读取并可视化npy格式的深度图文件以及将其保存为jpg图片的方法

  npy文件是无法直接打开的,它里面包含的是一个矩阵格式的数据,可以用于存储图像。为了对其进行可视化,需要将其转换为图像。这里需要用到numpy包以及matplotlib包,没有的话就pip install一下吧。现进入包含有npy文件的目录(我的该目录下有一个名为0000.npy的文件),然后打开一个终端,执行python进入pythn命令行模式,依次输入如下代码即可: import numpy as np import matplotlib.pyplot as plt depthmap = np.lo

zeeq的博客 5万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

dllimport 和dllexport使用总结

int main(void) { func1(); }

xdfyoga1的专栏 6781

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

__declspec(dllexport)与__declspec(dllimport)

区别        他们都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。       dllexport是在这些类、函数以及数据的申明的时候使用。用他表明这些东西可以被外部函数使用,即(dllexport)是把 DLL中的相关代码(类,函数,数据)暴露出来为其他应用程序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)...

huangyimo的专栏 5万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

dllimport与dllexport作用与区别

    我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。但是,MSDN文档里面,对于__declspec(dllimport)的说明让人感觉有点奇怪,先来看看...

冷月醉雪的博客 1万+

__declspec(dllexport)和__declspec(dllimport)

在Windows中,动态链接库(DLL)是作为函数和资源的共享库的一种可执行文件。动态链接是操作系统功能。它可使执行文件调用函数或使用存储在单独文件中的资源。可从使用这些函数和资源的可执行文件中对其分别进行部署。DLL不是独立的可执行文件。DLL在调用它们的应用程序的上下文中运行。操作系统将DLL加载到应用程序的内存空间中。此操作要么在加载应用程序时(隐式链接)完成,要么在运行时按需(显示链接)完成。DLL还可以在可执行文件之间轻松共享函数和资源。多个应用程序可同时访问内存中单个DLL副本的内容。

huangjh2017的博客 2627

【C语言笔记】dll库“__declspec”属性关键字总结,dllexport,dllimport

_declspec 是在 Windows 平台上用于控制导出和导入符号的属性关键字,在 C/C++ 中经常用于 DLL 开发。__declspec(dllexport) 和 __declspec(dllimport) 是其常见用法,用于在编写 DLL 时标记函数或变量的可见性。在编写 DLL 时用于标记函数或变量,表示它们应该被导出,以便其他模块可以访问。用于将函数或变量从 DLL 中导出,使其可供外部使用。在函数或变量声明之前使用,告诉编译器将其放入导出表中。

专注音频,高效工作,快乐生活! 3588

__declspec(dllimport)与__declspec(dllexport)及__stdcall 作用总结

调用协议常用场合 __stdcall:Windows API默认的函数调用协议。 __cdecl:C/C++默认的函数调用协议。 __fastcall:适用于对性能要求较高的场合。 函数参数入栈方式 __stdcall:函数参数由右向左入栈。 __cdecl:函数参数由右向左入栈。 __fastcall:从左开始不大于4字节的参数放入CPU的ECX和EDX寄存器,其余参数从右向左入栈。 问题一:__fastcall在寄存器中放入不大于4字节的参数,故性能较高,适用于需要高性能的场合。 栈内数据清除方式 _.

Alone的博客 3775

c++中的__declspec(dllexport) 和 __declspec(dllimport)

是Microsoft Visual C++特有的修饰符,用于声明在动态链接库(DLL)中定义的函数和变量,以便在另一个模块中使用。它告诉编译器该函数或变量是从 DLL 中导入的,而不是在当前模块中定义的。当你在一个项目中使用 DLL 时,你需要告诉编译器这些函数和变量是从 DLL 中导入的。这样,编译器就会在链接时查找相应的函数和变量的定义,并将其地址替换为导入的 DLL 中的地址。举个例子,假设你有一个名为MyDLL的 DLL,其中有一个函数。在你的项目中使用这个 DLL 时,你需要在项目中使用。

zengchenAAA的博客 2388

MFC(C++)中 __declspec(dllexport) 和 __declspec(dllimport)的作用

从static变量导出问题解析 __declspec(dllexport) 和 __declspec(dllimport)的作用 这段时间要把tinyxml从静态库弄成动态库,要用到__declspec(dllexport)和__declspec(dllimport)来导出dll和lib文件。终于弄明白了export和import的作用,下面从使用的角度来说明一下他们的功能。   首...

acoolgiser的博客 3326
上一篇: _variant_t 数据类型介绍
下一篇: __declspec(dllimport)的作用
imJaron
博客等级 码龄11年 121粉丝 286原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值