




已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1 VS2005创建DLL使用VS2005创建自己的动态链接库,这样就不用看到DLL文件有抵触情感了。一、打开VS2005软件,创建DLL工程。起名ceshi1.1) 2) 点击下一步,应用程序类型为DLL,空工程。3) 完成,一个新的DLL工程设置完毕,接下来编辑源码添加头文件,命名为ceshi1.h,编辑内容:#ifndef CESHI1_H#define CESHI1_H /防止重复定义#include /头文件引用#if defined DLL_EXPORT /源文件需引用下一函数#define DECLDIR _declspec(dllexport)/就是这个#else#define DECLDIR _declspec(dllimport)#endifextern CDECLDIR int add(int a, int b); /函数声明DECLDIR void function(void);#endif解释:VC中有两种方式导出DLL文件中的函数1) 使用 _declspec关键字。2) 创建模板定义文件(Module_Definithion File)即.def文件。在此使用第一种方法:_declspec(dllexport)作用是导出函数符号到DLL的一个存储类中。在头文件中定义#define DECLDIR _declspec(dllexport)宏来运行这个函数。使用条件编译,在源文件中宏定义 #define DLL_EXPORT 来运行这个函数。/*创建源文件 ceshi1.cpp#include #define DLL_EXPORT#include ceshi1.hextern C/定义Dll中的所有函数DECLDIR int add(int a, int b)return a+b;DECLDIR void function(void)std:coutDLL calledstd:endl;编译工程,生成ceshi1.dll文件和ceshi1.lib文件(注:找到工程目录,这两个文件在外面的debug文件夹下)。二、使用创建好的DLL库文件创建一个控制台应用程序1) 隐式链接:连接到.lib文件,首先将ceshi1.h头文件,ceshi1.dll动态库文件,ceshi1.lib静态库文件放在控制台应用程序工程的目录中,即源文件所在的文件夹里。添加源文件ceshi2.cpp,编码:#pragma comment(lib,ceshi1.lib)/链接.lib文件#include ceshi1.h /包含dll的头文件#include int main()function();std:coutadd(25,25)std:endl;getchar();return 0;/*2) 显式链接只加载.dll文件,但需用到函数指针和Windows 函数,不需要.lib文件和.h头文件。#include #include typedef int (*AddFunc)(int, int);typedef void (*FunctionFunc)(void);/函数指针int main()AddFunc _AddFunc;FunctionFunc _FunctionFunc;/HINSTANCE实例句柄(即一个历程的入口地址)HINSTANCE hInstLibrary = LoadLibraryA(ceshi1.dll); /注意,此时的LoadLibraryA()窄字符集和LoadLibraryW()宽字符集的区别,后有介绍。if(hInstLibrary = NULL)FreeLibrary(hInstLibrary);/释放DLL获得的内存,若句柄无效 /获得函数的入口地址,还需类型转换_AddFunc = (AddFunc)GetProcAddress(hInstLibrary,add);_FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary,function);if(_AddFunc=NULL | _FunctionFunc =NULL)/确定是否成功。FreeLibrary(hInstLibrary);std:cout_AddFunc(25,25)std:endl;_FunctionFunc();getchar();FreeLibrary(hInstLibrary);return 0;/* Windows 的执行文件可以划分为两种形式:程序和动态连接库(DLLs)。一般程序运行是用.EXE文件,但应用程序有时需要调用存储在DLL 中的函数。 当我们调用Windows 中的API 函数的时候,实际上就是调用存储在DLL 中的函数。 在如下几种情况下,调用DLL 是合理的: 1) 不同的程序使用相同的DLL ,这样只需要将DLL 在内存中装载一次,节省了内存的开销。 2) 当某些内容需要升级的时候,如果使用DLL 只需要改变DLL 就可以了,而不需要把整个程序都进行变动。 3) 由于DLL 是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的时候,使用DLL 便于程序系统的交流,当然,Delphi开发的DLL 也可以在诸如Visual BASIC,C+ 等系统中使用。2 C语言创建DLL只是要在公开的接口函数声明前面加上几个特定的修饰符。/*example1.h*#ifndef EXAMPLE1_H#define EXAMPLE1_H#define DLLIMPORT _declspec(dllexport)DLLIMPORT void HelloWorld(void);#endif/*example1.c*#include example1.h#include #include #include DLLIMPORT void HelloWorld(void)MessageBox(0,TEXT(Hello World from DLL!n),TEXT(Hi),MB_ICONINFORMATION);BOOL APIENTRY DllMain(HINSTANCE hInst,DWORD reason,LPVOID reserved)switch(reason)case DLL_PROCESS_ATTACH:break;case DLL_PROCESS_DETACH:break;case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;return true;_declspec(dllexport)标志着后面这个函数将成为对外的接口,使用包含在DLL中的函数,必须将其导入,导入操作通过dllimport来完成,dllexport和dllimport都是VC和BC所支持的关键字,但不能被自身格式所使用,通用格式为_declspec(dllexport)和_declspec(dllimport),为了简化,用宏名代替,若程序被编译成C+程序,同时希望C程序亦可使用,需要增加”C”的链接说明,#define DLLEXPORT extern “C” _declspec(dllexport),就避免了标准C+命名损坏。、有错。BOOL APIENTRY DllMain()说明:1、每个DLL必须有一个入口点,DllMain()是入口函数,负责初始化(initialization)和结束(termination)工作,每当一个新的进程或该进程的新的线程访问DLL时,或者不再使用DLL时,或结束时,都将调用DllMain。但是使用terminate Process或terminate Thread结束进程和线程,不会调用DllMain。DllMain()函数的原型:BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_resong_for_call, LPVOID lpreserved)switch(ul_reason_for_call)case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_PROCESS_DETTACH:case DLL_THREAD_DETTACH:return true;参数:hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);HINSTANCEul_reason_for_call:是一个说明动态库被调原因的标志。当进程或线程装入或卸载动态连接库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用;DLL_THREAD_ATTACH: 线程被调用;DLL_PROCESS_DETACH: 进程被停止;DLL_THREAD_DETACH: 线程被停止;lpReserved:是一个被系统所保留的参数。/问题:如何使用上面的DLL库文件?资料:动态链接库调用有两种函数:导出函数(export function)和内部函数(internal function)。导出函数可被其他模块调用,内部函数只在定义的DLL中内部使用。其他模块使用导出函数的用法:1) 传统方法在模块定义文件的EXPORT部分指定需要的函数或变量,语法格式如下:entryname=internalname ordinalNONAME DATE PRIVATE其中:entryname是导出函数或数据被引用的名称。internalname 同entryname.ordinal 表示在输出表中的顺序号NONAME仅仅在按顺序号输出时被使用,(不使用entryname)DATA表示输出的是数据项,使用DLL输出数据的程序必须声明该数据项为_declspec(dllimport).以上各项中,只有entryname是必须的,其他可以省略。对于“C”函数来说,entryname可以等同于函数名;但是对“C+”函数(成员函数、非成员函数)来说,entryname是修饰名。可以从.map映像文件中得到要输出函数的修饰名,或者使用DUMPBIN /SYMBOLS得到,然后把它们写在.def文件的输出模块。DUMPBIN是VC提供的一个工具。如果要输出一个“C+”类,则把要输出的数据和成员的修饰名都写入.def模块定义文件。2) 命令行输出对链接程序LINK指定/EXPORT命令行参数。3) 使用MFC提供的修饰符号 _declspec(dllexport)在要导出的函数、类、数据的声明前加上 _declspec(dllexport) 修饰符,表示导出。extern “C”使在C+中使用C编译方式,在C+中定义C函数,需加extern “C”关键字,用extern “C”来指明该函数使用C编译方式,导出的C函数可在C代码中调用。例如:在一个C+文件中,有如下函数extern “C” void _declspec(dllexport) _cdecl Test(int var);其输出函数名为 Test (非C+方式)MFC提供了一些宏,就有这样的作用。省略 #defineAFX_CLASS_IMPORT:_declspec(dllexport)AFX_API_IMPORT:_declspec(dllexport)AFX_DATA_IMPORT:_declspec(dllexport)AFX_CLASS_EXPORT:_declspec(dllexport)AFX_API_EXPORT:_declspec(dllexport)AFX_DATA_EXPORT:_declspec(dllexport)AFX_EXT_CLASS: #ifdef _AFX_EXT AFX_CLASS_EXPORT#elseAFX_CLASS_IMPORTAFX_EXT_API:#ifdef _AFX_EXTAFX_API_EXPORT#elseAFX_API_IMPORTAFX_EXT_DATA:#ifdef _AFX_EXTAFX_DATA_EXPORT#elseAFX_DATA_IMPORT像AFX_EXT_CLASS这样的宏,如果用于DLL应用程序的实现中,则表示输出(因为_AFX_EXT被定义,通常是在编译器的标识参数中指定该选项/D_AFX_EXT);如果用于使用DLL的应用程序中,则表示输入(_AFX_EXT没有定义)。要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。如:class AFX_EXT_CLASS CTextDoc : public CDocumentextern C AFX_EXT_API void WINAPI InitMYDLL();这几种方法中,最好采用第三种,方便好用;其次是第一种,如果按顺序号输出,调用效率会高些;最次是第二种。3 动态链接库的实现一、创建DLL文件1) 使用VS2005创建DLL空工程。2) 新建头文件 builder1.h,程序:/*#ifndef BUILDER1_H#define BUILDER1_H#ifdef BUILDER1_DLL#define DLL_API _declspec(dllexport)#else #define DLL_API _declspec(dllimport)#endif/注意#endif的位置extern C /原样编译/_stdcall 使非C/C+语言能够调用APIDLL_API int _stdcall Max(int a, int b); #endif/*3) 新建源文件 builder1.cpp /*#define BUILDER1_DLL#include builder1.hDLL_API int _stdcall Max(int a,int b)return ab ? a:b;/*4) 用.def文件创建动态链接库 build1.dlla、删除build1工程中的builder1.h文件b、在builder1.cpp中删除#include ”builder1.h”语句。内容:int _stdcall Max(int a,int b)return ab ? a:b;c、向该工程中加入一个文本文件,命名为builder1.def,内容:错误LIBRARY build1 /标准格式 LIBRARY “build1”EXPORTSMax 1 /注意:一定要有空格,语法的格式d、编译生出dll文件二、调用动态链接库DLL1、隐式调用:1) 创建控制台工程build22) 将build1.dll, build1.lib, builder1.h拷贝到工程所在目录,(主程序cpp所在的文件夹下)三个文件必须全要。3) 新建源文件 build2.cpp/*#include builder1.h#pragma comment(lib,build1.lib)#include int main()int value;value = Max(100,250);std:cout Value=valuestd:endl;getchar();return 0;/*成功*2、显式调用1) 建立控制台工程2) 将close1.dll拷贝到工程目录(close1.dll是由.def文件生成)3) 用vc/bin下的Dumpbin.exe的小程序,查看DLL文件(DllDemo.dll)中的函数结构。4) 使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针。typedef int(_stdcall *lpMax)(int a, int b); /一定要和dll中头文件声明一致5) 通过LoadLibrary()将DLL加载到当前的应用程序中,并返回当前DLL文件的句柄:HINSTANCE hDLL; /声明一个DLL文件实例句柄hDLL = LoadLibrary(close1.dll); /导入动态链接库6) 通过GetProcAddress()函数获得导入到应用程序的函数指针。lpMax Max;Max = (lpMax)GetProcAddress(hDll,” Max”);int value;value = Max(250, 500);std:cout ”Value = ” valuestd:endl;7) 函数调用完毕后,使用FreeLibrary(),释放DLL文件FreeLibrary(hDll);8) 编译生成exe文件。4 C+Builder 创建和使用DLL一、创建1) File-New建立一个新的DLL工程,生成一个DLL的工程框架。入口函数:int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) return 1;DllEntryPoint()函数为一个入口方法,如果使用者在DLL被系统初始化或者注销时被调用,用来写入对DLL的初始化程序和卸载程序;参数:hinst用来指示DLL的基地址;reason用来指示DLL的调用方式,用于区别多线程单线程对DLL的调用、创建、卸载DLL;lpReaerved为保留参数;#pragma argsusedextern C _declspec(dllexport) int _stdcall test(void); /函数声明 int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) return 1;/-int _stdcall test(void) /函数定义 std:cout My first BCB DLL projectstd:endl; return 250;/Make project 生成DLL库文件二、调用DLL1、静态调用法控制台应用程序,工程添加输入接口库(import library),在project manager中添加。/-#include #pragma hdrstop/-#pragma argsusedextern C _declspec(dllimport) int _stdcall test(void); /接口声明int main(int argc, char* argv) std:cout test()std:endl; std:coutfirst dllstd:endl; getchar(); return 0;/-注意: (1)动态链接库调用过程、函数时CALL方式 与创建时方式一样不写为_cdecl,其它需要声明。 (2)BCB创建的DLL有对应的输入接口库(import library),如只有DLL而无库时,可用BCB的implib工具产生:implib xxx.lib xxx.dll;另外可用:tlibxxx.lib,xxx.lst 产生DLL的内部函数列表,许多Windows的未公开技术就是用这种方法发现的。 2、动态调用法动态调用法要用Windows API 中的LoadLibrary()和GetProcAddress()来调入DLL库,指出库中函数位置,这种方法较常见。先设置Project Options:Packages标签:去除Builder with runtime packages检查框。(在框下面) Linker标签:去除Use dynamic RTL检查框。 右下角否则创建的DLL需要Runtime packages or Runtime library。 #include #include #pragma hdrstop/-#pragma argsusedtypedef int (_stdcall *TEST)(void);int main(int argc, char* argv) HINSTANCE hDll; hDll = LoadLibrary(Project2.dll); TEST ddd; ddd = GetProcAddress(hDll,test); std:coutddd()=ddd()std:endl; FreeLibrary(hDll); getchar(); return 0;/-成功-1 利用VC6.0创建静态链接库一、创建New-projects-Win32 Static Libaray,空的工程。创建一个.h文件 staticLib.h/*#ifndef _STATIC_LIB_H#define _STATIC_LIB_Hclass staticLibTestprivate:int m_value;public:staticLibTest();void SetVal(int para=0);int GetVal();void Display();#endif/*创建对应的cpp文件 fighting.cpp/*#include #include staticLib.hstaticLibTest:staticLibTest()m_value = 8;void staticLibTest:SetVal(int para)m_value = para;int staticLibTest:GetVal()return m_value;void staticLibTest:Display()std:cout output value is: m_valuestd:endl;/*Ctrl+F7编译,F7生成LIB*二、创建中间层(用外部函数来引用静态对象中的数据(数据由对象公有函数传递))。以便C+类中的成员函数能够在C中被调用(通过中间层),将中间层做成静态库。新建一个静态链接库工程如上,建好工程wrap后,新建头文件wrap.h/*#ifndef WRAP_H#define WRAP_H#ifdef _cplusplusextern C#endifvoid ExtcSetVal(int para);int ExtcGetVal(void);void ExtcDisplay(void);#ifdef _cplusplus#endif#endif/*对应的.cpp文件 wrap.cpp/*#include wrap.h#include staticLib.h#pragma comment(lib,view1.lib);staticLibTest staticLibObj;void ExtcSetVal(int para)staticLibObj.SetVal(para);int ExtcGetVal()return staticLibObj.GetVal();void ExtcDisplay()staticLibObj.Display();注意:在编译这个工程之前要把1中的头文件staticLib.h和静态库staticLib.lib拷到当前目录下,编译工程,生成wrap.lib。三、编写测试工程新建一个Win32 Console Application工程,test1。新建test.cpp/*#include #include wrap.h#pragma comment(lib,wrap.lib)int main()ExtcSetVal(250);ExtcDisplay();return 0;/*将之前生成的两个静态库staticLib.lib和wrap.lib还有头文件wrap.h拷到当前目录下,编译运行即可2 MFC 动态链接库1.制作的步骤:(1)新建MFC AppWizard(dll)工程,工程名为MFCDll,选择空工程 类型。(2)在生成的MFCDll.cpp文件后面增加下面函数代码:int sum(int a, int b) return a+b; (3)在生成的MFCDll.def文件后面增加如下:sum 1 ;表示第一个函数是sum(4)编译后会产生两个文件MFCDll.lib,MFCDll.dll 2、调用(1)隐式调用法: 将MFCDll.lib拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:/注意这里没有在MFCDll.h中声明函数,所以不能直接包含MFCDll.h来声明函数。以下是引用片段:#pragma comment(lib,MFCDll); int sum(int a, int b);/当然如果你的DLL中有很多函数,那可以另外写个MFCDll.h,包含所有的函数声明,然后直接将头文件包含进去(2)显示调用法:与Win32的调用方法一样,不需要#pragma comment(lib,MFCDll);,但是需要在Project-Setting-Link-Object/library modules的框中增加MFCDll.lib这个库。(研究中)*DLL(Dynamic
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 海南省陵水黎族自治县2025年上半年公开招聘城市协管员试题含答案分析
- 2025年二手房交易佣金支付标准协议
- 2025年度高科技企业采购法务与合同管理综合服务合同
- 2025房地产无底薪业务员营销服务及佣金分配合同
- 2025年度大型活动专用场馆租赁服务合同
- 2025年医疗设备采购与售后服务合同
- 2025版商铺租赁委托与市场拓展合作合同
- 2025年出租车行业新能源技术研发合作协议
- 2025版建筑废弃物填土处理工程合同
- 2025年度图书出版翻译与校对服务合同
- 数据安全管理员职业技能竞赛考试题库(含答案)
- 院科两级对核心制度执行率的持续改进案例-儿科I病区运用PDCA循环持续改进三级医师查房制度
- 新概念一册Lesson1-12-测试题(附答案)
- 彩钢瓦围挡施工方案
- 一年级新生家长会课件
- DB64-T 1972-2024 风积沙路基填筑(干压法)施工技术规范
- 质量信得过班组申报材料
- TSG+23-2021气瓶安全技术规程
- 酒店代运营合同范本
- 基于SCALANCE W774W734无线通信网络构建与运行(无线通信模块) (1)讲解
- 家庭医生签约服务培训
评论
0/150
提交评论