《计算机语言C++》 windows下的库文件

来源:互联网 发布:连接助理软件 编辑:程序博客网 时间:2024/06/06 13:05
</pre><p><span style="font-size:18px;">windows下的库文件一.window下的库文件可以分为静态库文件、动态库文件、MFC规则动态库文件、MFC扩展动态库文件。</span></p><p><span style="font-size:18px;color:#ff0000;BACKGROUND-COLOR: #ffffff">1.静态库文件</span></p><p><span style="font-size:18px;">1) 函数和数据被编译进一个二进制文件扩展名(.lib),运行时不需要存在,编译时会被嵌入到可执行文件中去(exe,dll);  也可利用vc的命令行工具经行生成 cl -c *.obj -I“path”,通过这个对源文件进行  编译,然后利用link -lib -libpath“libpath”,来连接生成.lib库文件的生成;</span></p><p><span style="font-size:18px;">2) 静态库的使用,如果生成的静态库没有在当前工程的目录下,可以有两种的解决方式,一 一种是通过对工程进行设置库文件的搜索路径,或者可以使用     #pragma comment(lib,"name.lib")经行静态库的引入;当然在使用的时候需要包含对应的头文件进行函数的声明;</span></p><p><span style="font-size:18px;"> </span></p><p><span style="font-size:18px;">3)注意情况,当在C++的文件中使用C的静态库的时候需要在函数的声明的前面加上extern "C",原因是,当用C的编译器进行生成静态库的时候,采用的编译方式是c的编译方式,那么在.lib文件中的函数名称是C方式的函数名称,那么在C++的文件中在函数的声明前面不加上extern "C",就会按照C++的编译方式进行编译,会有名字改遍存在,这样当进行连接的时候,就在对应的.lib文件中找不到对应的函数,产生连接错误;</span></p><p><span style="font-size:18px;">因此C的库文件中都有:</span></p><p><span style="font-size:18px;"> #ifdef __cplusplus</span></p><p><span style="font-size:18px;"> extern "C" {            /* Assume C declarations for C++ */</span></p><p><span style="font-size:18px;"><span style="font-size:18px;">#endif </span></span></p><p><span style="font-size:18px;"></span> </p><p><span style="font-size:18px;">#ifdef __cplusplus</span></p><p><span style="font-size:18px;">}</span></p><p><span style="font-size:18px;">#endif  /* __cplusplus */</span></p><p><span style="font-size:18px;"> </span></p><p><span style="font-size:18px;color:#ff0000;">2.window下的动态库;</span></p><p><span style="font-size:18px;">1)windows下动态库会有两个文件,一个是引入库文件(.lib),一个.dll文件,动态库的.lib文件和静态库的.lib文件有着本质的区别,引入库文件中成放的是dll导出函数和变量的符号名称,而dll文件中包含dll的实际函数和数据;</span></p><p><span style="font-size:18px;">dll 在连接的时候不需要,在运行的时候会需要,程序会去系统指定的目录下,和path变量中指定的目录下去查找;包括windows目录,以及windows/system32,windows/system;</span></p><p><span style="font-size:18px;">在连接时需要的文件是引入库文件(.lib),引用方式同静态库的引入方式;</span></p><p><span style="font-size:18px;">当程序运行的时候,将dll映射到进程的地址空间去,然后访问dll的导出函数</span></p><p><span style="font-size:18px;">2)函数的导出方式有两种,一种是.def文件,</span></p><p><span style="font-size:18px;">LIBRARY TEST</span></p><p><span style="font-size:18px;">EXPORTS</span></p><p><span style="font-size:18px;">add @1</span></p><p><span style="font-size:18px;">mul @2</span></p><p><span style="font-size:18px;">注:此种方式导出的函数名称,就是add、mul,也不会因为函数的调用方式发生改变而改变</span></p><p><span style="font-size:18px;">另外的一种方式是使用,__declspec(dllexport) 、__declspec(dllimport),一般在头文件中对他用宏变量进行控制;</span></p><p><span style="font-size:18px;">#ifdefine FLAG</span></p><p><span style="font-size:18px;">#define DLL-FLAG  __declspec(dllexport)</span></p><p><span style="font-size:18px;">#else</span></p><p><span style="font-size:18px;">#define DLL-FLAG  __declspec(dllimport)</span></p><p><span style="font-size:18px;">extern "C" DLL-FLAG  void show(){}</span></p><p><span style="font-size:18px;">#endif</span></p><p><span style="font-size:18px;">当用这么方式导出函数的时候,当调用约定是__cdecl,并且编译方式为extern “C”的时候,函数导出的名称不会发生改变;</span></p><p><span style="font-size:18px;">函数的调用约定在函数声明和定义的时候都需要指出</span></p><p><span style="font-size:18px;">可以使用vc工具,dumpbin -exports dll1.dll 来查看dll的导出函数;</span></p><p><span style="font-size:18px;">3)动态库的加载方式分为:隐式加载和显示加载</span></p><p><span style="font-size:18px;">   隐式加载就是,在程序开始运行的时候加载对应的动态库,使用方法就是,包含头文件,#pragma comment(lib,"")包含引入库文件</span></p><p><span style="font-size:18px;"> </span></p><p><span style="font-size:18px;"> 动态加载,就是在程序需要使用动态库中的函数的时候进行加载,动态加载不需要头文件,和引入库文件,需要三个函数</span></p><span style="font-size:18px;"></span><pre class="cpp" name="code">HINSTANCE LoadLibrary( LPCTSTR lpLibFileName); 
FARPROC GetProcAddress( HMODULE hModule, LPCWSTR lpProcName); 
BOOL FreeLibrary( HMODULE hLibModule); 
</pre><p><span style="font-size:18px">显示加载动态库的时候需要定义对应的函数指针:extern "C"typedef void(/*__stdcall*/ *SHOW)();</span></p><p><span style="font-size:18px">两者之间的区别:隐式加载动态库,在程序连接的时候,在函数调用处会被记住导出函数的偏移地址,当动态库发生变化的时候,应用程序需要重新编译才能使用;</span></p><p><span style="font-size:18px">而显示加载,是通过函数的名称去dll中查找对应的函数,顾当dll发生变化的时候不需要重新编译客户程序;</span></p><p><span style="font-size:18px"> </span></p><p><span style="font-size:18px">4)动态库中的导出类;</span></p><p><span style="font-size:18px">//test.h</span></p><p><span style="font-size:18px">#ifdefine FLAG</span></p><p><span style="font-size:18px">#define DLL-FLAG  __declspec(dllexport)</span></p><p><span style="font-size:18px">#else</span></p><p><span style="font-size:18px">#define DLL-FLAG  __declspec(dllimport)</span></p><p><span style="font-size:18px">class DLL-FLAG  A</span></p><p><span style="font-size:18px">{</span></p><p><span style="font-size:18px"> </span></p><p><span style="font-size:18px">};</span></p><p><span style="font-size:18px">#endif</span></p><p><span style="font-size:18px">//.test.cpp</span></p><p><span style="font-size:18px">#define FLAG</span></p><p><span style="font-size:18px">#include "test.h" </span></p><h4><span style="font-size:18px">5)动态库的入口函数,DllMain该函数是可选的,在编写dll程序的时候可以提供DllMain函数也可以不提供,如果提供了这个函数,当程序加载动态库的时候就会调用这个函数,在此函数中不要进行太复杂的调用,因为在加载该动态库的时候可能还有一些核心的动态库没有加载</span></h4><p><span style="font-size:18px">3.MFC规则库,和MFC扩展库</span></p><p><span style="font-size:18px">1)创建一个常规的动态链接库,该dll使用MFC的静态链接,提供时只需提供该dll即可(只能导出自己写的C++类,不能导出MFC类)</span></p><p><span style="font-size:18px">2) 创建一个常规的动态库,该dll使用MFC的动态链接库,提供时该dll,和MFC动态库</span></p><p><span style="font-size:18px">3)创建一个扩展的MFC动态库,(可以导出MFC类)</span></p><p><span style="font-size:18px"></span> </p><p><span style="font-size:18px"></span> </p><p><span style="font-size:18px">代码:</span></p><pre class="cpp" name="code"><span style="font-size:18px;">// dll_test.cpp : 定义 DLL 应用程序的导出函数。//#include "stdafx.h"#include "stdio.h"#include "iostream"using namespace std;//用__declspec(dllexport),__cdecl,导出函数,此种导出函数,会产生名字改编问题extern "C"__declspec(dllexport)void __stdcall show(){printf("this is dll export\n");cout<<"cout this"<<endl;}</span>


 

// dll_use.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "windows.h"#include "stdio.h"//静态链接//void show();//#pragma comment(lib,"../debug/dll_test.lib")extern "C"typedef void(__stdcall *SHOW)();int _tmain(int argc, _TCHAR* argv[]){HINSTANCE hInstance;hInstance= LoadLibrary(L"dll_test.dll");SHOW show=(SHOW)GetProcAddress(hInstance,"_show@0");show();FreeLibrary(hInstance);getchar();return 0;}


导出类

//class.h#ifndef _CLASS_H_#define _CLASS_H_#include "stdio.h"#ifdef EXPORT_FLAG#define CLASS_FALG __declspec(dllexport)#else #define CLASS_FALG __declspec(dllimport)#endif#define REGISTER(NUM)\extern "C" __declspec(dllexport) void Show##NUM()\{\int *p =new NUM();\printf("%d\n",*p);\}class CLASS_FALG test{private:int a;public:test(int b);void show(void);};#endif


 

// export-class.cpp : 定义 DLL 应用程序的导出函数。//#include "stdafx.h"#include "stdio.h"#define EXPORT_FLAG#include "class.h"test::test(int b):a(b){}void test::show(void){printf("%d\n",a);}REGISTER(int)


使用该类:

// use_class.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "../export-class/class.h"#pragma comment(lib,"../Debug/export-class.lib")extern "C"void Showint();int _tmain(int argc, _TCHAR* argv[]){test a(5);a.show();Showint();getchar();return 0;}

原创粉丝点击