原文地址:亲自动手~用VC++做DLL作者:__one_day__

一:Win32 Dynamic-Link Library 方式创建 Non-MFC DLL动态链接库

首先,打开VC++,选择File->New创建工程,使用Win32 Dynamic-Link Library方式,Project名为Win32Dll :

新建工程具有基本代码:

Finish之后得到新工程如下:

只有个简单的DllMain入口函数。

使用导出函数关键字_declspec(dllexport)创建DLL(对这个关键字的介绍参看下一遍博文吧)。因此,新生成Win32Dll.h文件,并在其中用关键字_declspec(dllexport)对要导出的函数进行声明。

在Win32Dll.cpp对其进行实现:

如上所示,我们想要导出的2个函数分别为JustSoSo和Max,他们都用关键字_declspec(dllexport)进行了修饰,但是不同的是JustSoSo还有用extern “C”进行修饰。有什么不同吗?extern “C”的修饰时必须的吗?我们具体来试验一下:

我们使用显示连接来调用这个DLL。

在工程文件中,首先要定义下我们需要从DLL中调用的函数的函数指针。

其中,FunctionFunc是JustSoSo的函数指针,而pMax是Max的函数指针。

然后就是进行调用:

对JustSoSo的调用:

调试结果,调用JustSoSo()成功!

对Max的调用:

调试结果,调用Max失败!原因是GetProcAddress返回的函数指针为0x00000000.

这是为什么呢?是extern “C”导致的吗?

在Win32Dll.h中修改Max的的声明为:

extern “C” _declspec(dllexport) int Max(int a,int b);

调试结果:调用Max成功!

那么,这个extern “C” 是个什么功效呢?如何理解这个状况呢?

答:在DLL的设计中,如果使用C++开发,通常在导出函数的定义中使用extern ”C“,为什么呢?其实是因为,当用户使用“运行时动态链接”的时候需要使用GetProcAddress函数来得到导出函数的地址,该函数是通过导出函数的函数名定位导出函数的,而C++编译器因为函数重载的原因会对开发者定义的函数名进行修饰,导致导出表中的函数名通常不是开发者使用的函数名,比如函数Max可能被修饰成??Max@QAEX.所以使用extern “C”通知编译器按照C的格式进行编译,而不是使用C++的方式进行编译。(使用VS提供的一个工具Dependency Walker可以查看DLL的导出函数)

我们试试使用隐式连接来调用这个DLL。

首先,将DLL和LIB文件放置于调用者同一目录下。

包含入lib文件:

方式一:

#pragma comment (lib,“Win32Dll.lib”)

方式二:

Project->setting->link->Object/library modules 添加 Win32Dll.lib

声明导出函数:

extern “C” _declspec(dllexport) int Max(int a,int b);

使用:

int temp = Max(5,8);

得到 temp 为 8,使用正确,调试成功~!

二:MFC AppWizard[dll]方式生成常规DLL

首先,打开VC++,选择File->New创建工程,选择MFC AppWizard[dll]方式,设置Project Name为MFCdll:

点击“OK”按钮,选择我们要生成的DLL类型:

如上图所示,对于“What type of DLL would you like to create?”提示,我们可以选择要创建的DLL为:

A.常规DLL静态链接到MFC

B.常规DLL动态链接到MFC

C.MFC扩展DLL

在此我们选择第二个选项。

不选择任何选项来回应“What features would you like in your DLL?”

然后点击“Finish”按钮。到此,我们的工程创建就完毕了。

现在我们想把一个add函数作为在DLL外部可以调用的导出函数,这次我们采用.def的方式来创建DLL。

那么首先在.def中田间add函数名:

然后,在类中添加add方法:

注意:在函数定义的起始需要此语句用来正确地切换MFC模块状态

创建的是动态DLL:

AFX_MANAGE_STATE(AfxGetAppModuleState());
创建的是静态DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

现在我们用显示连接来调用这个DLL:

先进行指针函数的定义,然后进行寻址等操作。


调试结果:失败了!!在dlladd(2,3)这一步!!这是为什么呢??

报错如下:

查询资料,有解决办法如下:

1.
要将导出函数声明为WINAPI,如:
void WINAPI AutoChess(BOOL, BOOL, BOOL);

使用时,函数指针的定义也需要注为WINAPI:

typedef void (WINAPI*AutoChess)(BOOL, BOOL, BOOL);

2.
是由于调用的接口与原接口参数不一致导致的,比如参数不符合或少参数输入导致.

但是,我按照提示进行修改声明及函数指针的定义

函数声明.h

函数指针定义:

依然是报错,这是为什么啊??

继续查询错误原因资料:

网络上搜索,出现此错误的原因如下:(和调用约定相关)

1、dll调用时,调用了dll中不存在的一个方法。出现此种情况,一般是在使用dll时没有把版本搞清楚。

2、由于调用的接口与原接口参数不一致导致的,比如参数不符合或少参数输入导致。这种错误方式比较常见

3、在dll中导出函数必须通过def文件来设定(__declspec(dllexport)这样的方式是为用.LIB连接准备的),且要声明为WINAPI,如:

void WINAPI AutoChess(char board[][15], char color, int &x, int &y);

4、Dll导出函数声明导出方法,与主模块中声明的导入方法不一致。使得调用时参数的传递中,破坏了调用堆栈,出现错误。

解决方法:请确定导出方(Dll等)与导入方(Exe等)的声明保持一致。

5、Dll导出函数本身破坏了调用堆栈。编码中最一般的错误比如:对象(如CString)等。

解决方法:保证产生的对象都被安全的释放。

进行调用的单步调试,发现确实是在传递调用参数时出现问题:

调用时,我传入的参数为整数2和3:

F11单步调试进入DLL函数中,传入的实参发生变化:

这是怎么回事呢?

参数类型和个数没有误差,那是哪里出问题了?聪明的你一定发现了,在DLL中我对all函数的声明进行了修改,但是定义没有修改,依然是:

这就是问题所在,定义的时候我依然让他带有"CMFCdll::”,因此,进行修改如下(或是 int add(int a ,int b)也可):

进行调试,完全正确~~!!!

关于WINAPI:

WINAPI 含义:

WINAPI见windef.h这个头文件

#define WINAPI __stdcall

默认情况下,我们的函数调用都是遵循__stdcall这个规则的。当然,也有诸如__cdecl、__pascal等规则。

使用__stdcall还是__cdecl或__pascal,在纯Windows编程下并非特别需要。

__stdcall:

1、进行函数调用,函数参数的入栈方式是最右边先入栈。

2、同时__stdcall规定,子函数负责栈的回收(调用者只负责压栈). 题外话:__pascal的调用规则是从左到右,正好与__stdcall相反。

3、C调用约定(即用__cdecl关键字说明)(The C default calling convention)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。

MFC的缺省调用:

在函数调用过程中,会使用栈。__stdcall与__cdecl是两种不同的函数调用约定,定义了函数参数入栈的顺序,由调用函数还是被调用函数将参数弹出栈,以及产生函数修饰名的方法。

对于参数个数可变的函数,例如printf,使用的是__cdecl调用约定,Win32的API函数都遵循__stdcall调用约定。在VC++开发环境中,默认的编译选项是__cdecl,对于那些需要__stdcall调用约定的函数,在声明时必须显式地加上__stdcall。

DLL与WINAPI:

在一些地方windows要求必须使用winapi标准,比如说在dll中的输出函数(

制作dll 是为了 让其他的语言可以调用, 但是呢, 有的语言 如delphe 的参数调用方法就是 _stadcall……所以,为了dll 有更好的通用性, 一般 都用 WINAPI

)。

现在试试用隐式方式来调用DLL:

首先将DLL和LIB文件放到与调用DLL的EXE同级目录下。

在调用中引入lib库:

#pragma comment (lib,“MFCdll.lib”)

或者 Project->setting->link->Object/library modules 添加MFCdll.lib

声明导出函数:

extern int add(int a,int b);

使用:

int temp = add(2,3);

结果得出:temp为5,正确~!

亲自动手~用VC++做DLL相关推荐

  1. VC++动态链接库(DLL)编程深入浅出(zz)

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了" ...

  2. [转]C++学习:VC++动态链接库(DLL)编程深入浅出(zz)

    转自:http://www.cnblogs.com/chio/archive/2007/11/03/948480.html 1.概论 先来阐述一下DLL(Dynamic Linkable Librar ...

  3. VC++动态链接库(DLL)编程深入浅出

    深度好文作为入门理解非常不错 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在 ...

  4. VC-基础:VC++动态链接库(DLL)编程深入浅出

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了" ...

  5. VC++动态链接库(DLL)编程(一)――理解库

    VC++动态链接库(DLL)编程(一) ――理解库 作者:宋宝华  e-mail:21cnbao@21cn.com 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概 ...

  6. php get your hands dirty,BBC地道英语:To Get your Hands Dirty 亲自动手

    Neil: Hello, I'm Neil. Li: What a miserable day it is today! Hey, I think that's Li! Neil: What on e ...

  7. php get your hands dirty,地道英语: To Get your Hands Dirty 亲自动手

    The script of this programme 本节目台词 Neil: Hello, I'm Neil.Audio: Get your hands dirty 亲自动手 Li: What a ...

  8. VC++动态链接库(DLL)编程(四)――MFC扩展 DLL

    VC++动态链接库(DLL)编程(四) ――MFC扩展 DLL 作者:宋宝华  e-mail:21cnbao@21cn.com   前文我们对非MFC DLL和MFC规则DLL进行了介绍,现在开始详细 ...

  9. Delphi 调用VC的DLL

    Delphi 调用VC的DLL VC中DLL声名格式: Extern "C" void __declspec(dllexport) __stdcall ShowMess(HWND ...

最新文章

  1. 公共端接正极还是负极_【动力电池大事记】现代摩比斯启动首批模组工厂,松下拟挪威建厂,200名车主起诉现代,密歇根大学开发锂金属固态电池及“无负极”工艺...
  2. mysql性能调优与架构设计_了解架构设计远远不够!一文拆解 Tomcat 高并发原理与性能调优
  3. 浏览器时间久了重新登录_注意!今日开始打印一建准考证,附各地时间及常见问题汇总...
  4. 计算机二级报名可以报两个地方吗,同学们注意了!!这4个地区计算机二级还可以报名!!...
  5. POJ1269 直线相交
  6. Android开发之判断APP前后台的方法
  7. 北航 2012 秋季 现代软件工程 两人结对 作业要求
  8. QQ红包源码 大转盘抽奖源码下载 微信红包源码
  9. java面试编程面试题_完美的编程面试问题
  10. ROS仿真-记一次错误 gazebo-2 process has died exit code 2
  11. SCU 4437 Carries(二分乱搞)题解
  12. 现代语音信号处理之倒谱分析与同态滤波
  13. 普鸥知识产权|如何申请美国外观专利?申请费用、时间、流程?
  14. java gc 命令_Java 查看系统GC命令介绍
  15. springcloud整合openfeign启动报错,Error creating bean with name ‘feignTargeter‘
  16. Chrome手势插件
  17. 个人第1次作业:阅读与准备作业
  18. Linux的memory日志,Linux:日志,cpu,memory,mount,load等系统信息查看
  19. 详细浮点型数据的存储讲解
  20. python实现kd树以及最近邻查找算法

热门文章

  1. antd vue 越过登录直接跳静态页面
  2. 暴力推荐:MiniTool Partition Wizard Home Edition
  3. 芭蕉芋淀粉加工设备和薯类机械的区别
  4. AUTOCAD 常用操作
  5. L1-007. 念数字
  6. java web入门经典 pdf_Java Web入门经典 (王国辉陈英) PDF
  7. 计算机打字测试标准,拼音打字考试标准练习题200字
  8. 创业企业家是一个职业头衔
  9. 阿贝云服务器是智商税?
  10. SVM学习(五):松弛变量与惩罚因子