动态库不能直接运行,也不能接受消息,他提供一些函数供执行他的程序或者动态库调用。

windows API中的所有函数都包含在DLL中,其中有几个最为重要:Kernel32.dll,用户管理内存、进程和线程的各个函数;User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;GDI32.dll,它包含用于画图和显示文本的各个函数。

静态库:函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)。

动态库:在使用动态库的时候,往往提供两个文件:一个引入库和一个DLL。引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。

动态链接库加载的两种方式
  预备知识
  ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  进程的虚拟地址空间:

  在32为系统中,系统为没个进程分配2^32的地址空间
  具体可参看《windows核心编程》
  预处理命令:
  没有什么可以说的了
  看看代码就明白了!!
  环境变量:(环境变量的概念我就不介绍了,具体的可以参看windows 核心编程,上面有很详细的说明)把DLL放到当前任意的环境变量中就可以加载
  定义函数指针
  格式:typedef int (*proc)(int a,int b);
  注意:proc是一个函数指针类型而不是一个变量
  然后我们可以用这个指针类型去定义变量
  Proc myproc;这里的myproc就是一个指针变量
  要是实在无聊内心空虚没事可做的话可以去这个网站看看函数的指针http://ufo.tyedu.com/study/programmer/language_C/200412/1472.html
  函数的调用约定(可以不必了解,但是理解后可以让你理解DLL的调用更为深刻)
  函数的调用约定:函数调用约定是函数调用者和被调用的函数体之间关于参数传递、返回值传递、堆栈清除、寄存器使用的一种约定 它是需要二进制级别兼容的强约定,函数调用者和函数体如果使用不同的调用约定,将可能造成程序执行错误,必须把它看作是函数声明的一部分
  常见的函数调用约定:
  VC6中的函数调用约定:
  调用约定 堆栈清除 参数传递 __cdecl 调用者 从右到左,通过堆栈传递 __stdcall 函数体 从右到左,通过堆栈传递 __fastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈 thiscall 函数体 this指针默认通过ECX传递,其它参数从右到左入栈
  __cdecl是C/C++的默认调用约定VC的调用约定中并没有thiscall这个关键字,它是类成员函数默认调用约定C/C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改
  默认调用约定一般能够通过编译器设置进行更改,如果你的代码依赖于调用约定,请明确指出需要使用的调用约定
  常见的函数调用约定中,只有cdecl约定需要调用者来清除堆栈C/C++中的函数支持参数数目不定的参数列表,比如printf函数由于函数体不知道调用者在堆栈中压入了多少参数, 所以函数体不能方便的知道应该怎样清除堆栈,那么最好的办法就是把清除堆栈的责任交给调用者
  这应该就是cdecl调用约定存在的原因吧
  VB一般使用的是stdcall调用约定(ps:有更强的保证吗)
  Windows的API中,一般使用的是stdcall约定(ps: 有更强的保证吗) 建议在不同语言间的调用中(如DLL)最好采用stdcall调用约定,因为它在语言间兼容性支持最好
  三:函数返回值传递方式 其实,返回值的传递从处理上也可以想象为函数调用的一个out形参数;函数返回值传递方式也是函数调用约定的一部分; 有返回值的函数返回时:一般int、指针等32bit数据值(包括32bit结构)通过eax传递,(bool,char通过al传递,short通过ax传递),特别的__int64等64bit结构(struct) 通过edx,eax两个寄存器来传递(同理:32bit整形在16bit环境中通过dx,ax传递); 其他大小的结构(struct)返回时把其地址通过eax返回;(所以返回值类型不是1,2,4,8byte时,效率可能比较差)
  参数和返回值传递中,引用方式的类型可以看作与传递指针方式相同; float/double(包括Delphi中的extended)都是通过浮点寄存器st(0)返回;
  
  具体的分析参看:http://blog.csdn.net/avalonbbs/archive/2004/12/25/229300.aspx
  :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  
  
  
  
  隐式链接
  本文现在对隐式链接不作具体的说明,只是做一个大概的介绍(下次再做具体的说明).当进程运行的时候,所有的相关的DLL都被加载到内存,然后映射到进程的地址空间,当一个进程要调用很多个DLL的时候,这种方法就显得特别浪费内存,所以在加载很多个DLL的时候,最好用显示加载的方式
  在调用DLL里面的函数时候
  要用extern 声明是外部变量
  比如extern int add(int num1,int num2);
  但是还应该注意的就是:在编译DLL时,要把编译的LIB文件放到执行文件的目录下,并且在编译执行文件的时候要连接LIB文件。
  在写DLL的时候要导出的函数也就是在能被外部程序调用的函数前面加上
  一般大型项目在开发DLL中,要进行预定义声明的
  
  ======================================

  在定义DLL的时候要定义导出函数就要在该函数前面加__declspec(DLLexport)时,C++编译器为了支持函数的重载会进行函数名字改编,当可执行模块执行该函数时由于找不到该函数的名字,于是调用就会出现错误!当使用extern “C”时就可以告诉编译器不必修改函数名和变量名。这样就可以用C++或C编译器程序调用该函数。
  以上操作只有在VC++创建的的可执行模块来调用该DLL,如果使用其他的编译器的模块来调用该DLL,就需要执行一些额外的操作。
  C编译在进行编译的时候也会进行名字的改编,当函数使用_stdcall(WINAPI)调用规则时,MS编译器就会改编函数的名称。
  比如:__declspec(DLLexport) LONG __stdcall Proc(int a ,int b);
  编译器会改编为__Proc@8
  因此当非C++或非C编译器调用该DLL中的函数Proc时,就会出现找不到函数的情况。
  这样我们就可以定义DEF文件来解决,并且在DEF文件加上下面的EXPORTS:
  EXPORTS
  Proc
  Def模块执行原理:当连接程序分析这个DEF文件时,它发现Proc和__Proc@8都被输出,由于这两个函数是相互匹配的,因此连接程序使用Proc来输出该函数,根本不使用__Proc@8来输出函数名
  =======================================
  
  
  
  
  
  
  下面是def的具体使用方法
  

  ----------------------------------------------------------------------------------------------------------------------模块定义文件(.DEF)是一个或多个用于描述DLL属性的模块语句组成的文本文件,每个DEF文件至少必须包含以下模块定义语句:
  * 第一个语句必须是LIBRARY语句,指出DLL的名字;
  * EXPORTS语句列出被导出函数的名字;将要输出的函数修饰名罗列在EXPORTS之下,这
  个名字必须与定义函数的名字完全一致,如此就得到一个没有任何修饰的函数名了。
  * 可以使用DESCRIPTION语句描述DLL的用途(此句可选);
  * ";"对一行进行注释(可选)。
  ----------------------------------------------------------------------------------------------------------------------
  
  
  dlltest.h
  #ifdefDLL1_API
  #else
  #defineDLL1_API extern"C" _declspec(dllimport)
  #endif
  
  DLL1_API int_stdcalladd(inta,intb);
  DLL1_API int_stdcallsubtract(inta,intb);
  //
  
  
  dlltest.cpp
  #defineDLL1_API extern"C" _declspec(dllexport)
  #include"Dll1.h"
  #include
  int_stdcalladd(inta,intb)
  {
  returna+b;
  }
  
  int_stdcallsubtract(inta,intb)
  {
  returna-b;
  }
  //
  
  
  // def文件
  LIBRARY dlltest
  EXPORTS
  add
  subtract
  
  
  有了上面的那些文件之后就可以在如何地方调用这些函数了
  
  voidCDllTestDlg::OnBtnSubtract()
  {
  // TODO: Add your control notification handler code here
  CString str;
  str.Format("5-3=%d",subtract(5,3));
  MessageBox(str);
  }
  
  voidCDllTestDlg::OnBtnOutput()
  {
  // TODO: Add your control notification handler code here
  Point pt;
  pt.output(5,3);
  }下面具体介绍显示加载
  显示加载
  VC++编译器在编译DLL的时候函数会发生名字改编;主要在非C++环境中就不能识别该函数了,所以这里应该定义模块文件类型DEF,主要就方便了非C++程序可以调用该DLL里面的函数
  再使用显示加载前必须要注意的是名字的改编问题,因为再动态加载中名字改编后在加载就得不原来的函数名字了,这样加载就会失败。但是可以用另外一种方法加载:MSDN上对GetProAddress中的第二个参数是这样说明的Pointer to a null-terminated string that specifies the function or variable name, or the function's ordinal value.也就是说可以使用函数的序号来调用该函数,具体使用方法是ProcAdd = (MYPROC) GetProcAddress(hinstLib, MakeIntResource(i)); (i代表函数在DLL中的序号,可以用DUMPBIN工具查看),但是一般的都不用这种转换序号的方式来取得函数的地址,因为这样非常的不直观!下面就用模块定义文件(DEF)来避免DLL中函数的名字的改编问题
  
  
  
  
  
  显示加载DLL
  //MSDN上的对DLL进程显示加载的DEMO
  Using Run-Time Dynamic Linking
  You can use the same DLL in both load-time and run-time dynamic linking. The following example uses the LoadLibraryfunction to get a handle to the Myputs DLL (see Creating a Simple Dynamic-Link Library). If LoadLibrary succeeds, the program uses the returned handle in the GetProcAddressfunction to get the address of the DLL's myPuts function. After calling the DLL function, the program calls the FreeLibraryfunction to unload the DLL.
  Because the program uses run-time dynamic linking, it is not necessary to link the module with an import library for the DLL.
  This example illustrates an important difference between run-time and load-time dynamic linking. If the DLL is not available, the application using load-time dynamic linking must simply terminate. The run-time dynamic linking example, however, can respond to the error.
  // A simple program that uses LoadLibrary and
  // GetProcAddress to access myPuts from Myputs.dll.
  
  #include
  #include
  typedef int (*MYPROC)(LPTSTR);
  VOID main(VOID)
  {
  HINSTANCE hinstLib;
  MYPROC ProcAdd;
  BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
  // Get a handle to the DLL module.
  hinstLib = LoadLibrary(TEXT("DllTest"));
  // If the handle is valid, try to get the function address.
  if (hinstLib != NULL)
  {
  ProcAdd = (MYPROC) GetProcAddress(hinstLib, TEXT("Proc"));
  // If the function address is valid, call the function.
  if (NULL != ProcAdd)
  {
  fRunTimeLinkSuccess = TRUE;
  (ProcAdd) (TEXT("Message via DLL function/n"));
  }
  // Free the DLL module.
  fFreeResult = FreeLibrary(hinstLib);
  }
  // If unable to call the DLL function, use an alternative.
  if (! fRunTimeLinkSuccess)
  printf("Message via alternative method/n");
  }
  
  对以上的几个函数作一些必要的说明:
  LoadLibrary:加载指定的DLL,加载方式是先在当前目录中查找,如果找不到再再环境变量目录下查找;
  还是看MSDN上的说明
  The LoadLibrary function maps the specified executable module into the address space of the calling process.
  HMODULE LoadLibrary(
  LPCTSTR lpFileName
  );
  Parameters
  lpFileName
  [in] Pointer to a null-terminated string that names the executable module (either a .dll or .exe file). The name specified is the file name of the module and is not related to the name stored in the library module itself, as specified by the LIBRARY keyword in the module-definition (.def) file.
  
  GetProcAddress:是取得已知的DLL中的函数,返回指定函数的地址
  MSDN上的说明
  This function returns the address of the specified exported DLL function.
  FARPROC GetProcAddress(
  HMODULE hModule,
  LPCWSTR lpProcName
  );
  Parameters
  hModule
  [in] Handle to the DLL module that contains the function.
  The LoadLibraryor GetModuleHandlefunction returns this handle.
  lpProcName
  [out] Pointer to a null-terminated string containing the function name, or specifies the function's ordinal value.
  If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.
  The lpProcName parameter must be in Unicode.
  Remark:
  The GetProcAddress function is used to retrieve addresses of exported functions in DLLs.
  The spelling and case of the function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL's module-definition (.def) file.
  The exported names of Win32 APIs might differ from the names you use when calling these functions in your code. This difference is hidden by macros used in the SDK header files.

学习编写测试桩之declspec (dllexport)篇相关推荐

  1. 为什么设计师应该学习编写代码

    通常,在完成了一件网页设计后,设计师的无知都会显露无遗而备受指责.他们把创建网页代码的繁重工作都留给了程序员们.这种现象不只出现在网络开发行业,在软件及游戏开发业也是如此(完整图文版).残酷的事实就是 ...

  2. react ui框架_Web开发 React 学习(二十)连载基础篇大结局

    系列文章: 测开技能--Web开发 React 学习(一) 测开技能--Web开发 React 学习(二)环境搭建 测开技能--Web开发 React 学习(三)元素的渲染 测开技能--Web开发 R ...

  3. 从零开始学习UCOSII操作系统13--系统移植理论篇

    从零开始学习UCOSII操作系统13--系统移植理论篇 1.什么是系统移植? (1)UCOSII移植到不同的处理器上,所谓的移植就是将一个实时的内核能在其他的微处理器或者微控制器上运行. 为了方便移植 ...

  4. 计算机新课标学习心得体会,【精品】新课标学习心得体会模板锦集10篇

    [精品]新课标学习心得体会模板锦集10篇 在平日里,心中难免会有一些新的想法,马上将其记录下来,这样可以记录我们的思想活动.很多人都十分头疼怎么写一篇精彩的心得体会,下面是小编收集整理的新课标学习心得 ...

  5. ROS2_Foxy学习9——多机激光SLAM先导篇

    ROS2_Foxy学习9--多机激光SLAM先导篇 1 环境准备 2 ROS1下测试SLAM 2.1 cartographer 源码测试 2.2 rplidar_ros 源码测试 2.3 rplida ...

  6. ROS2_Foxy学习10——多机激光SLAM准备篇

    ROS2_Foxy学习10--多机激光SLAM准备篇 1 安装Ubuntu20.04 mate 2 安装ROS noetic 3 安装cartographer 4 详细配置cartographer 5 ...

  7. lex编译dos命令_Lex与Yacc学习(一)之环境配置篇

    Abstract 在开发程序的过程中经常会遇到文本解析的问题,例如:解析 C 语言源程序,编写 脚本引擎等等,解决这种文本解析的方法有很多,一种方法就是自己手动用 C 或者 C++直接编写解析程序,这 ...

  8. 【学习笔记】 科目一之概念篇

    [学习笔记] 科目一之概念篇 概念题方法 1)抓重点:科目一设计知识范围太广,不要妄想所有知识点都复习到,这是不可能的,我们的目标是45分几个而不是考高分,复习时间有限,所以要学会抓重点,比如法律条文 ...

  9. [译]Mimic, 轻量级Web Service测试桩

    2019独角兽企业重金招聘Python工程师标准>>> 原文标题:Mimic, simple web service stubs for testing 原文: https://gi ...

最新文章

  1. 不连续子网掩码的魅力
  2. 阻止表中出现重复项——SQL UNIQUE 约束
  3. 日本“女机器人”畅销全球,有三个地方最吸引人,网友:想拥有
  4. 坚强生活(转)--To 小鱼,妹妹和傻女孩们
  5. 记录一次 Arthas 使用
  6. 26.Android Studio下Ndk开发(ffmpeg导入Android studio以cmake方式编译的过程)
  7. android EditText 控件中加入图片(非背景图片)
  8. QSerialport多线程方法
  9. Python1 关于安装
  10. 基础测绘数据分类标准
  11. druid数据源检测数据库连接有效性testOnBorrow、testOnReturn、testWhileIdle属性原理分析
  12. 解决mac 下蓝牙卡顿问题
  13. 三星Q990B全景声回音壁评测
  14. LSV软件不定时无法下载谷歌影像的原因
  15. 有了戴森HP04,空调和空气净化器都不用买了
  16. 关于iOS tableview自定义区头
  17. BTF社区不忘初心共筑未来通证新经济
  18. 科技和商业模式的发展真的会导致很多人失业吗?
  19. 阿里巴巴总裁马云经典语录。
  20. 2021年安全员-A证考试题库及安全员-A证新版试题

热门文章

  1. 阿里云重磅推出物联网设备身份认证Link ID²
  2. [net]ftp ssh http telnet https服务及端口
  3. 理解纯CSS画三角形
  4. 大型网站系统架构分析
  5. MySQL 数据库性能优化之SQL优化
  6. 从rpm包中提取文件的命令
  7. 培养创造性思维的20个技巧
  8. 判定是否过拟合、欠拟合的一种方式
  9. Android 隐藏、显示软键盘方法
  10. TCP Traffic Analyzer