【VC编程技巧】动态链接库☞1.2用模块导出接口
来源:互联网 发布:粮库远程监控软件 编辑:程序博客网 时间:2024/06/01 09:19
为什么要用模块(def文件)导出接口呢?
第一步,我先从函数调用方式说起,大家都知道函数调用有几种常见的方式,分别是__cdecl,__stdcall(pascall),__fastcall,和thiscall。下面我说一下这几种方式会在那些场合出现和它们的差异:
- __cdecl :(C和C++缺省调用方式)参数压栈顺序,从右到左;栈的清除,由调用者完成;
- __stdcall:(Win32 API的调用方式,并且WINAPI、CALLBACK和__stdcall都一样)参数压栈顺序,从右到左;栈的清除,由被调者完成;通过第一点和第二点我们知道每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的exe模块要比__stdcall大。因为Win32 API采用这种调用方式,所以目前这种方式调用支持大多数语言。而__cdecl约定调用只适合C语言,另外如果接口函数有可变参数必须用__cdecl约定调用,__stdcall约定不行。
- __fastcall:(C++Builder默认的调用方式)它的主要特点就是快,因为它是通过寄存器来传送参数的。
- thiscall:(C++类成员函数调用方式)仅仅应用于 "C++" 成员函数。this 指针存放于 CX 寄存器,参数从右到左压。thiscall 不是关键词,因此不能被程序员指定。
综上 ,我们知道Dll要有良好的共性接口的调用约定应该是__stdcall,而如果只是C来用的话可以约定为__cdecl;
第二步,当我们编写__stdcall形式的接口时,大家都知道C++编译器会对函数名做修改,使我们Dll的共性降低(只能在同一种编译器生成的模块之间调用)。
而通过关键字extern "C" __declspec(dllexport)可以保证__cdecl约定方式的函数名称不被改变,却不能保证__stdcall约定方式的函数。这样我们会因为__stdcall函数名称被修改,不能通过函数名来调用接口函数;
第三步,现在可以回答文章开头的问题了,因为向Dll中引入模块的正好解决了上面的问题(保证__stdcall约定方式的函数名称不变),同时它使接口形式更加清晰,为程序员带来了很大帮助。
第四步,我举个例子验证一下这个结论:关键字extern "C" __declspec(dllexport)可以保证__cdecl约定方式的函数名称不被改变,却不能保证__stdcall约定方式的函数。
- 创建Win32DLL工程,工程名:DllCall
- 添加求和函数add和求差函数subtract接口,如下:
// DllCall.cpp : Defines the entry point for the DLL application.//#include "stdafx.h"BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ return TRUE;}extern "C" __declspec(dllexport) int __stdcall add (int a, int b){return a+b;}extern "C" __declspec(dllexport) int __cdecl subtract(int a, int b){return a-b;}
- 编译生成动态链接库DllCalldll,然后用VC6自带的depends工具查看DLL的借口,我们发现:add变成了_add@8,subtract还是subtract。
第五步,我们来证明向DLL中引入模块是可以解决这个问题的。
- 先创建Win32DLL工程,工程名:DllCall1
- 添加求和函数add和求差函数subtract接口,如下:
// DllCall1.cpp : Defines the entry point for the DLL application.//#include "stdafx.h"BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ return TRUE;}int __stdcall add (int a, int b){return a+b;}int __cdecl subtract(int a ,int b){return a-b;}
- 添加模块文件DllCall1.def,各标签的内容都有注释:
;LIBRARY 指DLL的名称,必须和生成dll文件名称一直;DESCRIPTION 指DLL的说明;EXPORTS语法格式entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE];EXPORTS 指要导出的接口LIBRARY DllCall1DESCRIPTIONEXPORTSaddsubtract
- 编译生成动态链接库DllCall1.dll,然后用depends工具查看add是add,subtract还是subtract:
总的来说,编写动态库函数调用方式推荐__stdcall,接口导出时采用模块导出。
- 【VC编程技巧】动态链接库☞1.2用模块导出接口
- 【VC编程技巧】动态链接库☞1.3MFC扩展类的导出
- 【VC编程技巧】动态链接库☞1.1调用Dll中的一个图标
- 【VC编程技巧】动态链接库☞1.4进程间共享数据
- 【VC编程技巧】动态链接库☞1.5设计支持多国语言应用程序
- 【VC编程技巧】动态链接库☞1.6设计应用程序界面换肤
- VC++动态链接库编程
- vc 动态链接库编程
- VC++动态链接库编程
- VC++动态链接库编程
- VC++ 动态链接库编程
- VC动态链接库DLL 开发技巧
- VC++动态链接库(DLL)编程深入浅出
- VC++动态链接库(DLL)编程深入浅出
- VC++动态链接库(DLL)编程深入浅出
- VC++动态链接库(DLL)编程深入浅出
- VC++动态链接库(DLL)编程深入浅出
- VC++动态链接库(DLL)编程深入浅出
- VIM自动缩进等格式设置方法
- Makefile常见错误
- 灰度计算方法
- Windows 7定时关机命令shutdown
- 浅谈服务器编程
- 【VC编程技巧】动态链接库☞1.2用模块导出接口
- 软核,硬核、固核的区别!(整理总结)
- POJ 3013 Big Christmas Tree 最短路
- Google发布了一款名为J2ObjC的源代码语言转换工具
- 《Description of CWnd derived MFC objects and multithreaded applications in Visual C++》译文
- EL表达式详解
- Servlet中Writer和Cookie共同使用的注意事项
- linux下usb转串口设置
- 解决win7英文版下中文显示乱码问题