--------------------------------------------------------------------------------
  一、动态连接库的用途 
   动态连接库,dynamic-link libraries(DLL),是微软公司提供的一项软件技术。 它实质上是包含了一些函数和数据的可执行模块,它可以被应用程序(.EXE)或其它DLL
调用。这种技术有以下好处:共享资源、节省内存、支持多语种、可重复利用、便于大
项目的开发等。这样说是不是有点老套,也是,教科书都有的嘛。咳,就当复习一下功课了....    下面说一下我的理解。    没有总结,就没有进步。这话好象听谁说过的。作为一种载体,用来对过去经验作 个总结,动态库得天独厚。比方说你在以往的项目开发或编程中积累下了很多的经验、
技巧、想法(?)和专业资料,而且它们在特定的领域很有价值。但是随着开发工具的
发展、执行平台的升级,已往的这些经验、技巧和资料可能就会被丢弃。其实将它们作
为对以前劳动成果的一种总结,汇集到特定的动态库中,不失为一种两全其美的方法。
由于动态库与编程语言无关,如此得到的资源可以得到更广泛地应用。作为一种长远
考虑,资源的重复利用不但没有使以往的劳动浪费,而且使原来的劳动增值,使工作
更有效。尤其是资源的重复利用问题,如果系统地考虑软件复用则是解决软件开发中
重复劳动问题的一种方案,动态库则是一种途径和方法。以已有的工作为基础,充分
利用过去应用系统开发中积累的知识和经验,将开发的重点集中于应用的特有构成成
分上,消除重复劳动,避免重新开发可能引入的错误,从而提高软件开发的效率和质量。    另外,作为混合编程的一种特例,动态库当仁不让。由于动态库与具体的编程语言 无关,只要这种语言支持动态库技术,则这种语言就能拿来用,目的只有一个“取长补
短”。各类编程语言的存在是由于它们各有所长。我们可以通过动态库将一个大的任务
分割成一个个子任务,这些子任务可以分别由不同的语言来实现。    还有一个最成功的例子:微软的应用程序接口API。    二、动态连接库的有关约定    关于动态库输出函数的约定有两种:调用约定和名字修饰约定。    调用约定决定着函数参数传送时入栈和出栈的顺序,以及编译器用来识别函数名字 的修饰约定。名字修饰约定随调用约定和编译种类(C或C++)的不同而变化。为了让不
同的编程语言共享动态库带来的方便,函数输出时必须使用正确的调用约定,并且最好
不带有任何由编译器生成的名字修饰。 下面就以VC5和VB5为例,结合具体情况来说明如何实现这些要求。    (一)调用约定     VC++5.0支持的函数调用约定有多种,在这里仅讨论以下三种:__stdcall调用约定 、C调用约定和__fastcall调用约定。    __stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC+ +5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,
__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上
是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的
内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。    C调用约定(即用__cdecl关键字说明)和__stdcall调用约定有所不同,虽然参数传 送方面是一样的,但对于传送参数的内存栈却是由调用者来维护的(也正因为如此,实
现可变参数的函数只能使用该调用约定),另外,在函数名修饰约定方面也有所不同。    __fastcall调用约定是“人”如其名,它的主要特点就是快,因为它是通过寄存器 来传送参数的(实际上,它用ECX和EDX传送前两个双字或更小的参数,剩下的参数仍旧
自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定
方面,它和前两者均不同。    关键字 __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前,也可以在 编译环境的Setting...\C/C++ \Code Generation项选择。当加在输出函数前的关键字与编
译环境中的选择不同时,直接加在输出函数前的关键字有效。它们对应的命令行参数分别
为/Gz、/Gd和/Gr。缺省状态为/Gd,即__cdecl。    顺便说明一下,要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定,至于 函数名修饰约定,可以通过其它方法模仿。还有一个值得一提的是WINAPI宏,Windows.h支
持该宏,它可以将输出函数翻译成适当的调用约定,在WIN32中,它被定义为__stdcall。    建议:使用WINAPI宏,这样你就可以创建自己的APIs了。   (二)函数名修饰约定    函数名修饰约定随编译种类和调用约定的不同而不同,下面分别说明。    对于C编译,__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一 个“@”符号和其参数的字节数,格式为_functionname@number。__cdecl调用约定仅在
输出函数名前加上一个下划线前缀,格式为_functionname。__fastcall调用约定在输出
函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为
@functionname@number。它们均不改变输出函数名中的自符大小写,这和PASCAL调用约定
不同,PASCAL约定输出的函数名无任何修饰且全部大写。说到这里,我给出一种完全模仿
PASCAL调用约定的方法,在.DEF文件的EXPORTS段通过别名来实现。例如:           int  __stdcall MyFunc (int a, double b);           void __stdcall InitCode (void); 在 .DEF 文件中:          EXPORTS              MYFUNC=_MyFunc@12              INITCODE=_InitCode@0    C++编译输出的函数名修饰较为复杂,VC++5.0的随机文档中也没有给出说明。经过 一些实验和摸索, 我发现了C++编译时函数名修饰约定规则,现在说明如下。    __stdcall调用约定:          1、以“?”标识函数名的开始,后跟函数名;          2、函数名后面以“@@YG”标识参数表的开始,后跟参数表;          3、参数表以代号表示:             X--void ,             D--char,             E--unsigned char,             F--short,             H--int,             I--unsigned int,             J--long,             K--unsigned long,             M--float,             N--double,             _N--bool,             ....             PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现 ,以“0”代替,                 一个“0”代表一次重复;          4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型;          5、参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z” 标识结束。 其格式为“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如          int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”          void Test2()                       -----“?Test2@@YGXXZ”    __cdecl调用约定:    规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“ @@YA”。    __fastcall调用约定   规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“@ @YI”。