declspec关键字

合集下载

如何编写dll文件

如何编写dll文件
生成一个Dll工程,然后将你的类和函数都添加进去,然后将要输出的函数在该工程下的Translate.def文件中将名字列出(注意,只要名字,不要括号、参数等);实际上和你的Exe工程没有很大的区别。
如果你要用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

【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++是一种面向对象编程语言,同时也可以用作系统级编程语言。

在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关键字详细用法

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用法

__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原理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导出函数

__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)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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)无所谓。

相关文档
最新文档