静态链接库和动态链接库

静态链接库

WIN32 Static Library

//lib.h #ifndef __LIB_H_ #define __LIB_H_ extern "C" int _declspec(dllexport)add(int x, int y); #endif

 

//lib.cpp #include "stdafx.h" #include "lib.h" int add(int x, int y) { return x + y; }

调用libtest.lib:

//libCall.cpp #include <iostream> #include "lib.h" using namespace std; #pragma comment(lib, "LibTest.lib") int main(int argc, char *argv[]) { cout<< "2 + 3 = " << add(2,3) <<endl; return 1; }

 

动态DLL

WIN32 DYNAMIC-LINK LIBRARY

代码跟LIBREST的生成是一样的

动态调用:

//dllcall.cpp #include <iostream> #include <windows.h> using namespace std; typedef int(*lpFunAdd)(int, int); int main(int argc, char *argv[]) { HINSTANCE hDll; lpFunAdd addFun; hDll = LoadLibrary("TestDll.dll"); if(hDll != NULL) { addFun = (lpFunAdd)GetProcAddress(hDll, "add"); if(addFun != NULL) { int result = addFun(2, 3); cout<< "2 + 3 = " << result <<endl; } } FreeLibrary(hDll); return 0; }

下面我们来看看静态调用的例子(单击此处下载本工程附件),将编译dllTest 工程所生

成的.lib 和.dll 文件拷入dllCall 工程所在的路径,dllCall 执行下列代码:

#include <iostream> //#include <windows.h> using namespace std; #pragma comment(lib, "TestDll.lib") extern "C" int _declspec(dllexport)add(int x, int y); int main(int argc, char *argv[]) { cout<< "2 + 3 = " << add(2, 3) <<endl; return 0; }

 

DLL  中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明;另外一种方式是采用模块定义(.def)文件声明,.def 文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

下面的代码演示了怎样同.def 文件将函数add 声明为DLL 导出函数(需在dllTest 工程

中添加lib.def 文件):

 

 ; lib.def :  导出DLL 函数

 

 LIBRARY dllTest

 

 EXPORTS

 

 add @ 1

 

.def 文件的规则为:

 

    (1)LIBRARY 语句说明.def 文件相应的DLL;

 

    (2)EXPORTS 语句后列出要导出函数的名称。可以在.def 文件中的导出函数名后加@n,

表示要导出函数的序号为n            (在进行函数调用时,这个序号将发挥其作用);

 

    (3).def 文件中的注释由每个注释行开始处的分号 (;)               指定,且注释不能与语句共享一

行。

 

    由此可以看出,例子中lib.def 文件的含义为生成名为“dllTest”的动态链接库,导出其

中的add 函数,并指定add 函数的序号为1。

 

带DllMain的DLL:

 

 Windows 在加载DLL 的时候,需要一个入口函数,就如同控制台或DOS 程序需要main

函数、WIN32 程序需要WinMain 函数一样。在前面的例子中,DLL 并没有提供DllMain 函

数,应用工程也能成功引用DLL,这是因为Windows 在找不到DllMain  的时候,系统会从

其它运行库中引入一个不做任何操作的缺省DllMain  函数版本,并不意味着DLL 可以放弃

DllMain 函数。

 

    根据编写规范,Windows 必须查找并执行DLL 里的DllMain 函数作为加载DLL 的依据,

它使得DLL 得以保留在内存里。这个函数并不属于导出函数,而是DLL 的内部函数。这意

味着不能直接在应用工程中引用DllMain 函数,DllMain 是自动被调用的。

 

 //dllmaindll.h #ifndef __DLLMAINDLL_H_ #define __DLLMAINDLL_H_ extern "C" int _declspec(dllexport)add(int x, int y); #endif

//dllmaindll.cpp #include "dllmaindll.h" int add(int x, int y) { return x + y; }

 

//dllmain.cpp #include <iostream> #include <windows.h> using namespace std; BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: cout<< "DLL_PROCESS_ATTACH" <<endl; break; case DLL_THREAD_ATTACH: cout<< "DLL_THREAD_ATTACH" <<endl; break; case DLL_THREAD_DETACH: cout<< "DLL_THREAD_DETACH" <<endl; break; case DLL_PROCESS_DETACH: cout<< "DLL_PROCESS_DETACH" <<endl; break; } return true; }

调用就跟其他DLL调用是一样的!

 如果通过VC++编写的DLL  欲被其他语言编写的程序调用,应将函数的调用方式声明

为__stdcall 方式,WINAPI 都采用这种方式,而C/C++缺省的调用方式却为__cdecl 。__stdcall

方式与__cdecl 对函数名最终生成符号的方式不同。若采用C 编译方式(在C++中需将函数声

明为extern "C"),__stdcall 调用约定在输出函数名前面加下划线,后面加“@”符号和参数

的字节数,形如_functionname@number ;而__cdecl 调用约定仅在输出函数名前面加下划线,

形如_functionname 。

 

    Windows 编程中常见的几种函数类型声明宏都是与__stdcall  和__cdecl  有关的(节选自

windef.h ):

 

 #define CALLBACK __stdcall //这就是传说中的回调函数

 

 #define WINAPI __stdcall //这就是传说中的WINAPI

 

 #define WINAPIV __cdecl

 

 #define APIENTRY WINAPI //DllMain 的入口就在这里

 

 #define APIPRIVATE __stdcall

 

 #define PASCAL __stdcall

 

在lib.h 中,应这样声明add 函数:

 

 int __stdcall add(int x, int y);

 

在应用工程中函数指针类型应定义为:

 

 typedef int(__stdcall *lpAddFun)(int, int);

 

     若在 lib.h   中将函数声明为__stdcall          调用,而应用工程中仍使用 typedef                  int  (*

lpAddFun)(int,int),运行时将发生错误(因为类型不匹配,在应用工程中仍然是缺省的__cdecl

调用),弹出错误对话框。

 

 

 

对于MFC规则库和MFC扩展库都一样啦,只是在Regular DLL using shared MFC DLL 序最后一行代码"CDLLApp theApp;"后面输入函数,并在函数中输入AFX_MANAGE_STATE(AfxGetStaticModuleState());

你可能感兴趣的:(thread,windows,mfc,dll,library,winapi)