declspec关键字
如何编写dll文件
如果你要用VB用,在Dll中定义你的函数的时候前面要加上“__stdcall”关键字,否则VB没有办法使用。
——(1)Windows的系统目录:\windows\system;
——(2)DOS中path所指出的任何目录;
——(3)程序所在的目录;
一.动态链接库(DLL)结构
——DLL中定义有两种函数:导出函数(export function)和内部函数
(internal function),导出函数可以被其他模块调用,内部函数只能在DLL内部使用。我们在用C++定制DLL文件时,需要编写的就是包含导出函数表的模块 定义文件(.DEF)和实现导出函数功能的C++文件。下面以Sample.dll为例介绍DEF文件和实现文件的结构:
MFC扩展DLL一般用来提供派生于MFC的可重用的类,以扩展已有的MFC类库的功能。MFC扩展DLL使用MFC的动态链接版本。只有使用MFC动态 链接的可执行程序(无论是EXE还是DLL)才能访问MFC扩展DLL。MFC扩展DLL的另一个有用的功能是它可以在应用程序和它所加载的MFC扩展 DLL之间传递MFC和MFC派生对象的指针。在其它情况下,这样做是可能导致问题的。
非MFC DLL
静态链接到MFC的常规DLL
动态链接到MFC的常规DLL
MFC扩展DLL
其中非MFC DLL(non-MFC DLL)内部不使用MFC,调用非MFC DLL提供的导出函数的可执行程序可以使用MFC,也可以不使用MFC。一般来说,非MFC DLL的导出函数都使用标准的C接口(standard C interface)。
动态链接库教程(中文版)
动态链接库教程(中⽂版)什么是动态链接库?DLL三个字母对于你来说⼀定很熟悉吧,它是Dynamic Link Library 的缩写形式,动态链接库 (DLL) 是作为共享函数库的可执⾏⽂件。
动态链接提供了⼀种⽅法,使进程可以调⽤不属于其可执⾏代码的函数。
函数的可执⾏代码位于⼀个 DLL 中,该 DLL 包含⼀个或多个已被编译、链接并与使⽤它们的进程分开存储的函数。
DLL 还有助于共享数据和资源。
多个应⽤程序可同时访问内存中单个 DLL 副本的内容。
本⽂⽐较了Visual C++所⽀持的三种动态链接库,列出了各⾃不同的特点和应⽤场合,详细地描述了三种动态链接库的建⽴和调⽤的⽅法。
关键字:动态链接库;导出函数;调⽤引⾔较⼤的应⽤程序都由很多模块组成,这些模块分别完成相对独⽴的功能,它们彼此协作来完成整个软件系统的⼯作。
在构造软件系统时,如果将所有模块的源代码都静态编译到整个应⽤程序的EXE⽂件中,会产⽣⼀些问题:⼀个缺点是增加了应⽤程序的⼤⼩,它会占⽤更多的磁盘空间,程序运⾏时也会消耗较⼤的内存空间,造成系统资源的浪费;另⼀个缺点是,在编写⼤的EXE程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试;⽽且,⼀些模块的功能可能较为通⽤,在构造其它软件系统时仍会被使⽤。
Windows系统平台上提供了⼀种完全不同的较有效的编程和运⾏环境,你可以将独⽴的程序模块创建为较⼩的动态链接库(Dynamic Linkable Library,DLL)⽂件,并可对它们单独编译和测试。
在运⾏时,只有当EXE程序确实要调⽤这些DLL模块的情况下,系统才会将它们装载到内存空间中。
这种⽅式不仅减少了EXE ⽂件的⼤⼩和对内存空间的需求,⽽且使这些DLL模块可以同时被多个应⽤程序使⽤。
动态链接库概述动态链接库技术是Windows最重要的实现技术之⼀,Windows的许多新功能、新特性都是通过DLL来实现的。
【C语言】pragma
【C语⾔】pragma①#pragma comment (lib, "libgsl.a")这是告诉编译器在编译形成的.obj⽂件和.exe⽂件中加⼀条信息,使得链接器在链接库的时候要去找libgsl.a这个库,不要先去找别的库。
加⼊这条语句后,就不需要把libgsl.a这个⽂件额外通过链接器加⼊到⼯程⾥了。
#pragma comment( comment-type ,["commentstring"] )comment-type是⼀个预定义的,指定注释的类型,应该是compiler,exestr,lib,linker之⼀。
commentstring是⼀个提供为comment-type提供附加信息的字符串。
下⾯的内容转⾃⼀篇博客:#pragma 的使⽤尽管 C 和 C++ 都已经有标准,但是⼏乎每个编译器 (⼴义,包含连接器等) 扩展⼀些 C/C++ 关键字。
合理地应⽤这些关键字,有时候能使我们的⼯作⾮常⽅便。
下⾯随便说说 Visual C++ 中 #pragma指⽰符的使⽤。
⼀、⽤#pragma导出DLL函数传统的到出 DLL 函数的⽅法是使⽤模块定义⽂件 (.def),Visual C++ 提供了更简洁⽅便的⽅法,那就是“__declspec()”关键字后⾯跟“dllexport”,告诉连接去要导出这个函数,例如:__declspec(dllexport) int __stdcall MyExportFunction(int iTest);把“__declspec(dllexport)”放在函数声明的最前⾯,连接⽣成的 DLL 就会导出函数”。
上⾯的导出函数的名称也许不是我的希望的,我们希望导出的是原版的“MyExportFunction”。
还好,VC 提供了⼀个预处理指⽰符“#pragma”来指定连接选项 (不仅仅是这⼀个功能,还有很多指⽰功能) ,如下:#pragma comment(linker,"/EXPORT:MyExportFunction=_MyExportFunction@4")这下就天如⼈愿了:)。
c++ 导出函数 非导出函数
c++ 导出函数非导出函数C++是一种面向对象编程语言,同时也可以用作系统级编程语言。
在C++中,函数分为导出函数和非导出函数两种。
导出函数是可以在不同的编译单元之间进行调用的函数。
也就是说,在不同的.cpp文件中定义的函数,需要在链接时将这些函数进行链接,然后才能进行正常调用。
在C++中,导出函数需要在函数定义之前加上关键字“__declspec(dllexport)”进行声明。
下面是一个例子:```c++__declspec(dllexport) void MyExportFunction(){// 函数代码}```在使用导出函数的程序中,需要在头文件中进行声明,然后在需要进行调用的地方进行引用。
下面是一个例子:```c++// Header.h__declspec(dllimport) void MyExportFunction();#include "Header.h"{MyExportFunction();return 0;}```与导出函数相反,非导出函数是无法在不同的编译单元之间进行调用的函数。
也就是说,在不同的.cpp文件中定义的非导出函数,只能在本文件中进行调用。
在C++中,非导出函数不需要进行特殊的定义或声明。
下面是一个例子:```c++// MyFunction.cppvoid MyNonExportFunction(){// 函数代码}void MyAnotherFunction(){// 调用MyNonExportFunction函数MyNonExportFunction();}{MyAnotherFunction();return 0;}```需要注意的是,在非导出函数中使用全局变量或静态变量时,这些变量的作用域仍然是全局的,即这些变量可以被本文件中的其他函数使用。
在C++中,导出函数和非导出函数分别用于在不同的编译单元中进行调用和限制函数的作用域。
C++__declspec关键字详细用法
__declspec关键字详细用法2010-03-04 15:04__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。
其它的有关存储方式的修饰符如static与extern等是C 而__declspec是一种扩展属性的定义。
扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。
用法:__declspec ( extended-decl-modifier )extended-decl-modifier参数如下,可同时出现,中间有空格隔开:align (C++)allocateappdomaindeprecated (C++)dllimportdllexportjitintrinsicnaked (C++)noaliasnoinlinenoreturnnothrow (C++)novtableprocessproperty(C++)restrictselectanythreaduuid(C++)1.__declspec关键字应该出现在简单声明的前面。
对于出现在*或&后面或者变量声明中标识符的前面的__declspec,编译器将忽2.要注意区分__declspec是修饰类型还是修饰变量:__declspec(align(8)) struct Str b;修饰的是变量b。
其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。
__declspec(align(8)) struct Str {};修饰的是struct Str类型。
所有该类型的变量都受__declspec(align(8))影响。
align:格式:__declspec(align(n)) declarator其中,n是对齐参数,其有效值是2的整数次幂(从1到8192字节),如2,4,8,16,32或64。
参数declarator是要设置对1.使用__declspec(align(n))来精确控制用户自定义数据的对齐方式。
_declspec用法
__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。
其它的有关存储方式的修饰符如static与extern等是C和 C++语言的ANSI规范,而__declspec是一种扩展属性的定义。
扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。
用法:__declspec ( extended-decl-modifier )extended-decl-modifier参数如下,可同时出现,中间有空格隔开:align (C++)allocateappdomaindeprecated (C++)dllimportdllexportjitintrinsicnaked (C++)noaliasnoinlinenoreturnnothrow (C++)novtableprocessproperty(C++)restrictselectanythreaduuid(C++)1.__declspec关键字应该出现在简单声明的前面。
对于出现在*或&后面或者变量声明中标识符的前面的 __declspec,编译器将忽略并且不给出警告。
2.要注意区分__declspec是修饰类型还是修饰变量:__declspec(align(8)) struct Str b;修饰的是变量b。
其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。
__declspec(align(8)) struct Str {};修饰的是struct Str类型。
所有该类型的变量都受__declspec(align(8))影响。
align:格式:__declspec(align(n)) declarator其中,n是对齐参数,其有效值是的整数次幂(从到字节),如,,,,或。
参数declarator 是要设置对齐方式的数据。
1.使用__declspec(align(n))来精确控制用户自定义数据的对齐方式。
dll原理
dll原理DLL原理动态链接库(Dynamic Link Library,简称DLL)是一种Windows 操作系统中常用的库文件,它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。
本文将详细介绍DLL的原理。
一、静态链接与动态链接在介绍DLL原理之前,先来了解一下静态链接和动态链接。
1. 静态链接静态链接是指将程序所需要的库文件在编译时全部打包进可执行文件中。
这样做的好处是程序运行时不需要再加载外部库文件,因此速度较快。
但缺点也很明显,即可执行文件体积较大,在多个程序中使用相同的库时会造成重复浪费。
2. 动态链接动态链接是指在程序运行时才加载所需的库文件。
这样做的好处是节省了内存空间,并且多个程序可以共享同一个库文件。
但缺点也很明显,即运行速度较慢。
二、DLL概述1. DLL定义DLL是一个包含可由多个程序同时使用的代码和数据的库文件。
它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。
2. DLL分类根据DLL所包含函数是否可以被其他应用程序调用,DLL可以分为两种类型:(1)导出函数的DLL导出函数的DLL是指将其中一些函数导出,以便其他应用程序可以调用这些函数。
这种DLL文件通常包含一组API(Application Programming Interface,应用程序编程接口)函数。
(2)内部使用的DLL内部使用的DLL是指不导出任何函数,只供当前进程中的其他模块使用。
这种DLL文件通常包含一些共享数据和实现某些功能的代码。
三、DLL加载过程1. 加载方式当一个应用程序需要调用一个DLL中的函数时,Windows操作系统会自动加载该DLL。
Windows操作系统有两种加载方式:(1)显式链接显式链接是指在编译时就将要使用的DLL文件名和需要调用的函数名写入源代码中,并在程序运行时由操作系统自动加载该DLL文件。
(2)隐式链接隐式链接是指在编译时不将要使用的DLL文件名和需要调用的函数名写入源代码中,而是在程序运行时由操作系统自动搜索并加载相应的DLL文件。
__declspec 和 DLL导出函数
__cdecl和__stdcall都是函数调用规范(还有一个__fastcall),规定了参数出入栈的顺序和方法,如果只用VC编程的话可以不用关心,但是要在C++和Pascal等其他语言通信的时候就要注意了,只有用相同的方法才能够调用成功.另外,像printf这样接受可变个数参数的函数只有用cdecl才能够实现.__declspec主要是用于说明DLL的引出函数的,在某些情况下__declspec(dllexport)在DLL中生命引出函数,比用传统的DEF文件方便一些.在普通程序中也可以用__declspec(dllimport)说明函数是位于另一个DLL中的导出函数.例子不太好举啊,其实就是在函数声明的时候多加一个关键字,比如很多API函数就是象这样声明的:int WINAPI MessageBoxA(HWND,LPCSTR,LPSTR,UINT);而WINAPI实际上就是__stdcall.大多数API都采用__stdcall调用规范,这是因为几乎所有的语言都支持__stdcall调用.相比之下,__cdecl只有在C语言中才能用.但是__cdecl调用有一个特点,就是能够实现可变参数的函数调用,比如printf,这用__stdcall调用是不可能的.__fastcall这种调用规范比较少见,但是在Borland C++ Builder中比较多的采用了这种调用方式.如果有共享代码的需要,比如写DLL,推荐的方法是用__stdcall调用,因为这样适用范围最广.如果是C++语言写的代码供Delphi这样的语言调用就必须声明为__stdcall,因为Pascal不支持cdecl调用(或许Delphi的最新版本能够支持也说不定,这个我不太清楚).在其他一些地方,比如写COM组件,几乎都用的是stdcall调用.在VC或Delphi或C++Builder里面都可以从项目设置中更改默认的函数调用规范,当然你也可以在函数声明的时候加入__stdcall,__cdecl,__fastcall关键字来明确的指示本函数用哪种调用规范.__declspec一般都是用来声明DLL中的导出函数.这个关键字也有一些其他的用法,不过非常罕见.关于DLL的函数:动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal function)。
#pragma预处理指令详解
#pragma 预处理指令详解2007-10-23 20:24在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为: #pragma para其中para为参数,下面来看一些常用的参数。
(1)message 参数message参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
其使用方法为:#pragma message("消息文本")当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。
假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏,可以用下面的方法:#ifdef _X86#pragma message("_X86 macro activated!")#endif我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示"_86 macro activated!"。
我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。
(2)另一个使用得比较多的pragma参数是code_seg格式如:#pragma code_seg( ["section-name" [,"section-class"] ] )它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。
(3)#pragma once (比较常用)只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
windows下系统dll文件大全注释
windows下系统dll文件大全注释它是Dynamic Link Library 的缩写形式,DLL 是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。
动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。
函数的可执行代码位于一个DLL 中,该DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。
DLL 还有助于共享数据和资源。
多个应用程序可同时访问内存中单个DLL 副本的内容。
DLL 是一个包含可由多个程序同时使用的代码和数据的库。
例如,在Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。
因此,每个程序都可以使用该DLL 中包含的功能来实现“打开”对话框。
这有助于促进代码重用和内存的有效使用。
通过使用DLL,程序可以实现模块化,由相对独立的组件组成。
例如,一个计帐程序可以按模块来销售。
可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。
因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。
此外,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。
例如,您可能具有一个工资计算程序,而税率每年都会更改。
当这些更改被隔离到DLL 中以后,您无需重新生成或安装整个程序就可以应用更新。
下表说明了Windows 操作系统中的一些作为DLL 实现的文件:• ActiveX 控件(.o cx) 文件ActiveX 控件的一个示例是日历控件,它使您可以从日历中选择日期。
• 控制面板(.cpl) 文件.cpl 文件的一个示例是位于控制面板中的项。
每个项都是一个专用DLL。
• 设备驱动程序(.drv) 文件设备驱动程序的一个示例是控制打印到打印机的打印机驱动程序。
DLL 的优点1、扩展了应用程序的特性;2、可以用许多种编程语言来编写;3、简化了软件项目的管理;4、有助于节省内存;5、有助于资源共享;6、有助于应用程序的本地化;7、有助于解决平台差异;8、可以用于一些特殊的目的。
c++中--declspec的用法详解
c++中--declspec的用法详解c++ 中--declspec 的用法详解c++ 中__declspec 的用法是怎样的呢?如下是为大家整理的c++ 中__declspec 的用法详解,想要了解的继续往下看吧。
语法说明:__declspec ( extended-decl-modifier-seq )扩展修饰符:1:align(#)用__declspec(align(#))精确控制用户自定数据的对齐方式,#是对齐值。
e.g__declspec(align(32))struct Str1{int a, b, c, d, e;};它与#pragma pack()是一对兄弟,前者规定了对齐的最小值,后者规定了对齐的最大值。
同时出现时,前者优先级高。
__declspec(align())的一个特点是,它仅仅规定了数据对齐的位置,而没有规定数据实际占用的内存长度,当指定的数据被放置在确定的位置之后,其后的数据填充仍然是按照#pragma pack规定的方式填充的,这时候类/结构的实际大小和内存格局的规则是这样的:在__declspec(align())之前,数据按照#pragma pack规定的方式填充,如前所述。
当遇到__declspec(align())的时候,首先寻找距离当前偏移向后最近的对齐点(满足对齐长度为max(数据自身长度,指定值)),然后把被指定的数据类型从这个点开始填充,其后的数据类型从它的后面开始,仍然按照#pragma pack填充,直到遇到下一个__declspec(align())。
当所有数据填充完毕,把结构的整体对齐数值和__declspec(align())规定的值做比较,取其中较大的作为整个结构的对齐长度。
特别的,当__declspec(align())指定的数值比对应类型长度小的时候,这个指定不起作用。
2: allocate("segname")用__declspec(allocate("segname")) 声明一个已经分配了数据段的'一个数据项。
动态链接库
节省磁盘空间
更新产品更为容易
支持多语言程序
提供了扩展MFC类库的机制
隐藏实现的细节
拓展开发工具的功能
8.1.2 动态链接库的加载
应用程序调用动态链接库有两种方法:静态调用和 动态调用。
在静态调用时,使用DLL的可执行文件链接到此DLL提供 的导入库(.lib文件),可执行文件运行时就加载DLL。因 此,静态调用也称为隐式链接、静态加载或加载时动态链接。 在动态调用时,使用DLL的可执行文件必须进行函数调用, 显式地加载和卸载此DLL,并访问此DLL的导出函数。可执 行文件必须通过函数指针调用导出函数。因此,动态链接也 称为显式链接、动态加载或运行时动态链接。
8.1.1 动态链接库与静态链接库
静态链接库与动态链接库的最大区别是库代码 的链接时机。
动态链接库是在被应用程序调用的时候才同程 序相链接,链接操作由Windows操作系统来完成。 静态链接库是在应用程序被执行时就同程序相 链接,链接操作由链接器来完成。
使用动态链接库具有以下优点:
共享代码、资源和数据
DLLExample.def
DLL模块定义文件,这个文件在编译期 间使用。它包含DLL的名称,对于在 DLL中那些将要导出的项,可以选择在 此声明。
DLL项目的debug文件夹包含的主要文件:
引入库(.LIB)文件与DLL文件
引入库(.LIB)文件:引入库文件包含被DLL导出 的函数的名称和位置; DLL文件:DLL包含实际的函数和数据; 应用程序使用LIB文件链接到所需要使用的DLL文件, 库中的函数和数据并不复制到可执行文件中,因此 在应用程序的可执行文件中,存放的不是被调用的 函数代码,而是DLL中所要调用的函数的内存地址, 这样当一个或多个应用程序运行是再把程序代码和 被调用的函数代码链接起来,从而节省了内存资源。
DLL和LIB
DLL和LIB什么事dll和lib文件动态链接库(Dynamic Link Library,缩写为DLL)是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。
动态链接库文件的扩展名一般是dll,也有可能是drv、sys和fon,它和可执行文件(exe)非常类似,区别在于DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用程序直接或间接调用。
动态链接是相对于静态链接而言的。
所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。
换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。
当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。
而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。
仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。
当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应的函数代码。
一般情况下,如果一个应用程序使用了动态链接库,Win32系统保证内存中只有DLL的一份复制品,这是通过内存映射文件实现的。
DLL 首先被调入Win32系统的全局堆栈,然后映射到调用这个DLL的进程地址空间。
在Win32系统中,每个进程拥有自己的32位线性地址空间,如果一个DLL被多个进程调用,每个进程都会收到该DLL的一份映像。
与16位Windows不同,在Win32中DLL可以看作是每个进程自己的代码。
dll和lib文件的区别和联系.dll是在你的程序运行的时候才连接的文件,因此它是一种比较小的可执行文件格式,.dll还有其他的文件格式如.ocx等,所有的.dll文件都是可执行。
.lib是在你的程序编译连接的时候就连接的文件,因此你必须告知编译器连接的lib文件在那里。
DLL编写教程(绝对经典之作)
DLL编写教程(绝对经典之作)DLL编写教程半年不能上⽹,最近⽹络终于通了,终于可以更新博客了,写点什么呢?决定最近写⼀个编程技术系列,其内容是⼀些通⽤的编程技术。
例如DLL,COM,Socket,多线程等等。
这些技术的特点就是使⽤⼴泛,但是误解很多;⽹上教程很多,但是⼏乎没有什么优质良品。
我以近⼏个⽉来的编程经验发现,很有必要好好的总结⼀下这些编程技术了。
⼀来对⾃⼰是总结提⾼,⼆来可以⽅便光顾我博客的朋友。
好了,废话少说,⾔归正传。
第⼀篇就是《DLL编写教程》,为什么起这么⼟的名字呢?为什么不叫《轻轻松松写DLL》或者《DLL⼀⽇通》呢?或者更nb的《深⼊简出DLL》呢?呵呵,常常上⽹搜索资料的弟兄⾃然知道。
本⽂对通⽤的DLL技术做了⼀个总结,并提供了源代码打包下载,下载地址为:DLL的优点简单的说,dll有以下⼏个优点:1)节省内存。
同⼀个软件模块,若是以源代码的形式重⽤,则会被编译到不同的可执⾏程序中,同时运⾏这些exe时这些模块的⼆进制码会被重复加载到内存中。
如果使⽤dll,则只在内存中加载⼀次,所有使⽤该dll的进程会共享此块内存(当然,像dll中的全局变量这种东西是会被每个进程复制⼀份的)。
2)不需编译的软件系统升级,若⼀个软件系统使⽤了dll,则该dll被改变(函数名不变)时,系统升级只需要更换此dll即可,不需要重新编译整个系统。
事实上,很多软件都是以这种⽅式升级的。
例如我们经常玩的星际、魔兽等游戏也是这样进⾏版本升级的。
3)Dll库可以供多种编程语⾔使⽤,例如⽤c编写的dll可以在vb中调⽤。
这⼀点上DLL还做得很不够,因此在dll的基础上发明了COM技术,更好的解决了⼀系列问题。
最简单的dll开始写dll之前,你需要⼀个c/c++编译器和链接器,并关闭你的IDE。
是的,把你的VC和C++ BUILDER之类的东东都关掉,并打开你以往只⽤来记电话的记事本程序。
不这样做的话,你可能⼀辈⼦也不明⽩dll的真谛。
dll导出函数的两种方式的比较
dll导出函数的两种⽅式的⽐较最初的⽹页链接已经挂了, 在此贴⼀个中间的转载链接⼀概要 vs中导出 dll的⽅法有两种: ⼀种是使⽤__declspec(dllexport), 另⼀种就是使⽤.def⽂件⽅式, 这两种⽅式的最主要区别是在导出函数的名字上, 其次还有⼀些操作的灵活性上以及功能的强弱⼆⼀个具体的例⼦1 __declspec(dllexport) ⽅式⾸先对C和C++编译(extern "C")与调⽤约定(__cdecl、__stdcall、__fastcall)进⾏组合测试:<1> C++编译__declspec(dllexport) int add(int, int);__declspec(dllexport) int __cdecl add(int, int);__declspec(dllexport) int __stdcall add(int, int);__declspec(dllexport) int __fastcall add(int, int);对于C++编译器的函数名修饰规则:不管__cdecl, __fastcall还是__stdcall调⽤⽅式,函数修饰名都是以"?"开始,后⾯是函数在名字,再后⾯是函数返回类型和参数类型按照代号拼出的参数表。
对于__stdcall⽅式,参数表的开始标⽰是"@@YG”,对于__cdecl⽅式则是"@@YA”,对于__fastcall⽅式则是"@@YI”.参数表后以"@Z”标⽰整个名字的结束,如果该函数⽆参数,则以"Z”标识结束。
<2> C编译extern "C" __declspec(dllexport) int add(int, int);extern "C" __declspec(dllexport) int __cdecl add(int, int);extern "C" __declspec(dllexport) int __stdcall add(int, int);extern "C" __declspec(dllexport) int __fastcall add(int, int);<3> 备注__declspec(dllexport)的位置:To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified.For example:__declspec(dllexport) void __cdecl Function1(void);To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:class __declspec(dllexport) CExampleExport : public CObject{ class definition };2 def⽂件导出⽅式(项⽬中添加⼀个def后缀的⽂件, 然后在项⽬属性->连接器->所有选项->模块定义⽂件)具体到测试实例,我们的def⽂件内容如下:LIBRARY "win"EXPORTSadd @1其中LIBRARY指定dll的模块名称,即dll名字,EXPORTS后的每⼀⾏指定⼀个导出函数名字,这个名字和头⽂件中的声明⼀致,后⾯可以跟@序号指定该函数的序号(这个是可选的,后⾯按序号导⼊函数的时候再详细说)。
C 语言下的跨平台软件开发
C++语言下的跨平台软件开发作者:罗云青来源:《电子技术与软件工程》2015年第09期摘要本文通过归纳总结目前C++程序设计语言下跨平台软件开发的相关技术,介绍了C++语言在计算机编程设计领域的优势和跨平台设计思想的提出与实现,运用几个实例说明跨平台软件开发在实践中的广泛应用。
C++语言的可移植性和跨平台开发的项目部署,在当下主流的编程软件中已经被广泛采用,最后结合笔者见解对跨平台软件开发提出新的展望。
【关键词】C++ 开发跨平台软件1 C++语言的优势领域C++语言在某些领域有着很高的地位,像科学数值计算中的数据挖掘,游戏开发里面的图形图像设计,以及在高级系统设计中的电子邮件系统,数据库系统等等都有C++语言的身影。
同时,混合系统的设计和通用系统的设计问题都是C++所要解决的高层次的程序设计问题。
更重要的是,Microsoft公司的很多产品都是用C++程序设计语言设计出来的,像Windows XP,Windows NT,Internet Explorer 和Visual Studio版本下的Visual C++,Visual Basic,.NET Framework等等。
这些产品在不同程度上都奠基了C++程序设计语言在程序开发中的不可磨灭的地位。
2 跨平台开发跨平台开发是程序设计领域在近些年提出的新的要求,它源自于现代软件工程的发展。
跨平台的主要目的就是要让所开发的应用程序可以在不同类型的平台上顺利运行,跨平台项目的软件在开发的时候,必然要想到软件的移植性。
在实际的软件开发过程中,C++语言的跨平台开发项目,与具有可移植性的代码,他们的核心都是高度一致的。
只需要一次编写,多次编译,这样就实现了既可以在不同的设备和产品上顺利运行,又不会产生功能损失的现象。
因此,跨平台软件开发几乎可以运行在不同的平台上而不需要做出其他任何的调整和修改。
目前在市面上流行的几大系统软件的厂家,像Windows,Linux,Unix等在应用程序接口的实现中存在着较大的差异,同时,它们实现的细节和原理也存在着较大的差别。
declspec(dllexport)与_declspec(dllimport)
declspec(dllexport)与_declspec(dllimport)(转)2010-12-21 10:46:05| 分类:默认分类 | 标签:导出 dllimport __declspec dllexport 函数 |字号大中小订阅一部分:使用 __declspec(dllexport) 从 DLL 导出Microsoft 在 Visual C++ 的 16 位编译器版本中引入了__export,使编译器得以自动生成导出名并将它们放到一个 .lib 文件中。
然后,此 .lib 文件就可以像静态 .lib 那样用于与 DLL 链接。
在 32 位编译器版本中,可以使用__declspec(dllexport)关键字从 DLL 导出数据、函数、类或类成员函数。
__declspec(dllexport)会将导出指令添加到对象文件中,因此您不需要使用 .def 文件。
当试图导出 C++ 修饰函数名时,这种便利最明显。
由于对名称修饰没有标准规范,因此导出函数的名称在不同的编译器版本中可能有所变化。
如果使用__declspec(dllexport),仅当解决任何命名约定更改时才必须重新编译 DLL 和依赖 .exe 文件。
许多导出指令(如序号、NONAME 和 PRIVATE)只能在 .def 文件中创建,并且必须使用 .def 文件来指定这些属性。
不过,在 .def 文件的基础上另外使用__declspec(dllexport)不会导致生成错误。
若要导出函数,__declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。
例如:__declspec(dllexport) void __cdecl Function1(void);若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:class __declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将__declspec(dllexport)添加到头文件中的声明中。
type = noload的用法
类型(type)是编程语言中的一个重要概念,它定义了数据的形式和可对数据进行的操作。
在一些编程语言中,类型限制了数据的存储方式和可执行的操作,而在其他语言中,类型可以隐式转换或者根据需要进行转换。
在本文中,我们将探讨一种特殊类型noload,以及它在编程中的用法。
1. noload的定义noload是一种不常见的类型,在一些特定的编程环境中才会出现。
通常来说,noload类型用于指示编译器在加载一个模块或者库时不要加载特定的函数或者变量。
这通常用于解决模块之间的依赖关系或者减少加载时间。
2. noload的使用场景noload类型常常在大型软件系统中出现,特别是当有多个模块互相依赖,而其中某些函数或者变量实际上并不需要被加载时。
在这种情况下,使用noload类型可以有效地减少系统的加载时间和内存占用。
3. noload的语法在大多数编程语言中,noload类型的语法通常比较简单。
在C语言中,可以使用关键字__declspec(noload)来标记一个函数或者变量,告诉编译器在加载时不要加载它。
在其他语言中,可能会有一些特定的语法来实现类似的功能,但基本原理是一样的。
4. noload的注意事项虽然noload类型可以在一些情况下带来性能上的提升,但它并不是一个被广泛使用的特性。
在使用noload类型时,需要慎重考虑其对系统整体的影响,特别是在模块间的依赖关系和程序的正确性方面。
noload类型是一种特殊的类型,它在编程中的用法主要是用于告诉编译器在加载模块或者库时不要加载特定的函数或者变量。
虽然它可以在一定程度上提升系统的性能,但它并不是一个被广泛使用的特性。
在使用noload类型时,需要根据具体情况慎重考虑其对系统整体的影响。
noload类型的使用虽然在一般情况下并不常见,但它在特定的编程环境中发挥着重要作用。
在实际的软件开发过程中,特别是在涉及大型软件系统或者复杂的模块间依赖关系时,合理地利用noload类型可以带来一些显著的好处。
当你想使用C++写自己的类库(1)
当你想使⽤C++写⾃⼰的类库(1)差不多花了⼀年时间,才终于对C++有了点感觉。
开始想要⽤它做⼀些事。
就在这时候,刚好看到了《COM本质论》,读完第⼀章,惊为神作。
在刚毕业那会⼉有个误区(也许误区都说不上,因为当时对这个职业根本就是没想法),喜欢追新,什么新跟着什么跑。
加上第⼀份⼯作是使⽤.net,花了两个⽉啃完那本红⽪的C#⼊门经典,后续任务基本上可以总结为“通过MSDN查找需要的API来完成对功能需求的堆砌”。
C#确实是⾮常⾼级的语⾔,.net库也⾮常了不起。
C#很成功,如它所期望的,让程序员真的摆脱了底层原理,也不关⼼内存效率,脑⼦⾥只有业务逻辑,开发过程中遇到任何困境,只要使⽤MS提供的功能词典(MSDN)去查找,总能找到⼀个神奇的类来解决问题,找不到的时候就会热切期待下⼀版本的升级。
这种情况不是绝对的,但就我的情况⽽⾔,使⽤c#没有让我过多地感受到编程这件事需要创造⼒。
但这对⽤户(只有⽤户没有客户)来说是仿佛是⼀件好事,当时我的精⼒除了完善功能,剩下的都在琢磨UI,甚⾄⾃⼰画图标,界⾯美观易⽤,⽤户体验很好,最后还做了⼀版参加⾏业软件展览。
不得不再说,MS这套东西商⽤的优势⾮常明显⾮常明显。
但C++就不⼀样了。
虽然C++也有许多成熟的类库,但没有⼀个像.net framework这样⼤包⼤揽的。
⾃⼰写⼀个类库或框架,这是很容易冒出来的念头。
这时候各种问题就出现了。
⽐如内存管理,⽐如跨编译器的调⽤。
同时,C++的开源库特别多,其维护者不可能像MS⼀样提供那么⼀本MSDN⼤辞典供你查阅,对开源库的理解最后都会变成对源码的理解,在这个过程中,最终都会遇到同样的问题。
这些问题,是⽤C++构建⼀个⾃⼰的类库所必须解决的,也是在1988年⾄1993年之间,COM的设计者们思考的问题,最终他们解决了,并且提出了COM的概念。
《COM本质论》的第⼀章就是对这些问题的⼀个汇总和⼀次思考过程的复盘。
以下是这⼀章的笔记。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
_declspec关键字__declspec(dllexport)声明一个导出函数,是说这个函数要从本DLL导出。
我要给别人用。
一般用于dll中省掉在DEF文件中手工定义导出哪些函数的一个方法。
当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类__declspec(dllimport)声明一个导入函数,是说这个函数是从别的DLL导入。
我要用。
一般用于使用某个dll的exe 中不使用__declspec(dllimport) 也能正确编译代码,但使用__declspec(dllimport) 使编译器可以生成更好的代码。
编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL 边界的函数调用中。
但是,必须使用__declspec(dllimport) 才能导入DLL 中使用的变量。
使用举例:// File: SimpleDLLClass.h#ifdef SIMPLEDLL_EXPORT#define DLL_EXPORT __declspec(dllexport)#else#define DLL_EXPORT#endifclass DLL_EXPORT SimpleDLLClass{public:SimpleDLLClass();virtual ~SimpleDLLClass();virtual getValue() { return m_nValue;};private:int m_nValue;};// File:SimpleDLLClass.cpp#include "SimpleDLLClass.h"SimpleDLLClass::SimpleDLLClass(){m_nValue=0;}SimpleDLLClass::~SimpleDLLClass(){}说明:1. 在你的APP中include SimpleDLLClass.h时,如果你的APP的项目不定义SIMPLEDLL_EXPORT,则DLL_EXPORT不存在。
此时APP仍可以正常运行。
// File: SimpleDLLClass.hstatic int m_nValue;// File:SimpleDLLClass.cppint SimpleDLLClass::m_nValue=0;说明:1. 如果你的APP的项目不定义SIMPLEDLL_EXPORT,则DLL_EXPORT不存在。
此时APP无法LINK。
原因是找不到m_nValue。
(原因:静态变量m_nValue已被DLL导出,但SimpleDLLClass 无法访问m_nValue)Workaround:#define DLL_EXPORT __declspec(dllimport)Conclusion:dllimport是为了更好的处理类中的静态成员变量(或者其他...)的,如果没有静态成员变量(或者其他...),那么这个__declspec(dllimport)无所谓./////////////////////////////////////////////////在Windows DLL编程时,可使用__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外的函数也可以这样做,从而提高空间和时间效率。
变量的导入与函数不同的是,在使用DLL中的变量时,需要显示地导入变量。
使用__declspec(dllimport)关键字导入变量。
若在DLL中使用.def导出变量,则应使用DATA修饰变量,而不是使用已经被遗弃的CONSTANT。
因为CONSTANT可能需要使用指针间接访问变量,不确定什么时候会出问题。
我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。
当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。
但是,MSDN 文档里面,对于__declspec(dllimport)的说明让人感觉有点奇怪,先来看看MSDN里面是怎么说的:不使用__declspec(dllimport) 也能正确编译代码,但使用__declspec(dllimport) 使编译器可以生成更好的代码。
编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL 边界的函数调用中。
但是,必须使用__declspec(dllimport) 才能导入DLL 中使用的变量。
初看起来,这段话前面的意思是,不用它也可以正常使用DLL的导出库,但最后一句话又说,必须使用__declspec(dllimport) 才能导入DLL 中使用的变量这个是什么意思??那我就来试验一下,假定,你在DLL里只导出一个简单的类,注意,我假定你已经在项目属性中定义了SIMPLEDLL_EXPORTSimpleDLLClass.h#ifdef SIMPLEDLL_EXPORT#define DLL_EXPORT __declspec(dllexport)#else#define DLL_EXPORT#endifclass DLL_EXPORT SimpleDLLClass{public: SimpleDLLClass();virtual ~SimpleDLLClass();virtual getValue() { return m_nValue;};private: int m_nValue;};SimpleDLLClass.cpp#include "SimpleDLLClass.h"SimpleDLLClass::SimpleDLLClass(){ m_nValue=0;}SimpleDLLClass::~SimpleDLLClass(){}然后你再使用这个DLL类,在你的APP中include SimpleDLLClass.h时,你的APP的项目不用定义SIMPLEDLL_EXPORT 所以,DLL_EXPORT 就不会存在了,这个时候,你在APP中,不会遇到问题。
这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。
但,我们也没有遇到变量不能正常使用呀。
那好,我们改一下SimpleDLLClass,把它的m_nValue 改成static,然后在cpp文件中加一行int SimpleDLLClass::m_nValue=0;如果你不知道为什么要加这一行,那就回去看看C++的基础。
改完之后,再去LINK一下,你的APP,看结果如何,结果是LINK告诉你找不到这个m_nValue。
明明已经定义了,为什么又没有了??肯定是因为我把m_nValue定义为static的原因。
但如果我一定要使用Singleton的Design Pattern的话,那这个类肯定是要有一个静态成员,每次LINK都没有,那不是完了?如果你有Platform SDK,用里面的Depend程序看一下,DLL中又的确是有这个m_nValue导出的呀。
再回去看看我引用MSDN的那段话的最后一句。
那我们再改一下SimpleDLLClass.h,把那段改成下面的样子:#ifdef SIMPLEDLL_EXPORT#define DLL_EXPORT __declspec(dllexport)#else#define DLL_EXPORT __declspec(dllimport)#endif再LINK,一切正常。
原来dllimport是为了更好的处理类中的静态成员变量的,如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。