首页 > 代码库 > DLL-动态链接库(导入导出符/调用约定)

DLL-动态链接库(导入导出符/调用约定)

1. DLLs in Visual C++

1.1 __declspec(llexport) and __declspec(dllimport)

首先,如题,这是VC的东西。*nix下不需要。

在VC中使用DLL的过程如下

1)新建一个Win32项目,右键项目→属性→常规,把配置属性改为dll,如图

技术分享

2)在要导出(本工程外使用)的类、方法、变量之前,加上导出符号 __declspec(dllexport) [必须]

  这就引出了本节的主角,先看微软的定义

  You can import public symbols into an application or export functions from a DLL using two methods:

  • Use a module definition (.def) file when building the DLL

  • Use the keywords __declspec(dllimport) or __declspec(dllexport) in a function definition in the main application

  You do not need to use __declspec(dllimport) for your code to compile correctly, but doing so allows the compiler to generate better code. The compiler is able to generate better code because it can determine whether a function exists in a DLL or not, which allows the compiler to produce code that skips a level of indirection that would normally be present in a function call that crossed a DLL boundary. However, you must use __declspec(dllimport) to import variables used in a DLL.

  微软说了,__declspec(dllimport)不是必须,但是加了会使编译器产生更好的代码,通过减少对跨越DLL调用的函数调用的间接寻址过程。一种比较优雅的实现方式是

#ifdef __WIN32

#ifdef EXPORT
#define MYAPI __declspec(dllexport)
#else
#define MYAPI __declspec(dllimport)
#endif

#else
#define MYAPI //非windows平台 该宏为空
#endif

---我是分隔符---

在DLL工程编译之后,我们会得到一个dll文件和lib文件。好,下边进入另外一个工程,要使用我们的DLL的工程。

---我是分隔符---

3) 为编译器包含头文件。

  右键工程→属性→C/C++→包含附加目录

  有了头文件,编译器才能知道有哪些函数的声明,IDE也是在包含头文件之后可以进行函数补全等智能提示(有这功能的话)。

4) 为链接器指定导入库文件

  右键工程→属性→链接器→附加库目录

  先说一下定义,这里的导入库lib文件,虽然后缀和静态链接库lib文件的后缀一样,但除此之外没有任何关系!本文的lib指的都是导入库文件。lib中一般是一些函数入口地址之类的索引信息,用于定位符号在dll中的位置。所以lib是链接器用到的东西(这也是为什么VC中,在链接器设置页面包含导入库),链接器可以根据lib文件,链接出本工程的可执行文件或其它目标文件。也就是说,即使没有DLL文件,只要做了以上两步,链接过程是可以成功的!当然,如此运行当然会报错:dll丢失。

5) 把DLL和可执行文件放在同一目录

  这样,可执行文件在运行时,会且能,找到需要的符号。注意这里是运行时加载的dll中的文件,这也是为什么叫“动态”链接。

1.2 调用约定

  首先来看微软怎么说

  Calling Conventions

  The Visual C/C++ compiler provides several different conventions for calling internal and external functions. Understanding these different approaches can help you debug your program and link your code with assembly-language routines.

  The topics on this subject explain the differences between the calling conventions, how arguments are passed, and how values are returned by functions. They also discuss naked function calls, an advanced feature that enables you to write your own prolog and epilog code.

  

Keyword Stack cleanupParameter passing
__cdecl Caller Pushes parameters on the stack, in reverse order (right to left)
__clrcall n/a Load parameters onto CLR expression stack in order (left to right).
__stdcall Callee Pushes parameters on the stack, in reverse order (right to left)
__fastcall Callee Stored in registers, then pushed on stack
__thiscall Callee Pushed on stack; this pointer stored in ECX
__vectorcall Callee Stored in registers, then pushed on stack in reverse order (right to left)

  调用约定用在很多API中,会做兼容性定义,这里就不展开了。注意,这里是x86 & Windows平台的东西。

  有关的小知识点

  1.   调用参数从右至左入栈,是实现可变参数的基础。
  2.   windef.h中有如下定义 #define WINAPI_INLINE  __clrcall

2.DLLs in Linux

  事情简单了很多,没有导入导入符,用就是了 :)

 

DLL-动态链接库(导入导出符/调用约定)