VS创建自己的DLL库.docx
- 文档编号:18149835
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:26
- 大小:111.39KB
VS创建自己的DLL库.docx
《VS创建自己的DLL库.docx》由会员分享,可在线阅读,更多相关《VS创建自己的DLL库.docx(26页珍藏版)》请在冰点文库上搜索。
VS创建自己的DLL库
1VS2005创建DLL
使用VS2005创建自己的动态链接库,这样就不用看到DLL文件有抵触情感了。
一、打开VS2005软件,创建DLL工程。
起名ceshi1.
1)
2)点击下一步,应用程序类型为DLL,空工程。
3)完成,一个新的DLL工程设置完毕,接下来编辑源码
添加头文件,命名为ceshi1.h,编辑内容:
#ifndefCESHI1_H
#defineCESHI1_H//防止重复定义
#include
#ifdefinedDLL_EXPORT//源文件需引用下一函数
#defineDECLDIR__declspec(dllexport)//就是这个
#else
#defineDECLDIR__declspec(dllimport)
#endif
extern"C"
{
DECLDIRintadd(inta,intb);//函数声明
DECLDIRvoidfunction(void);
}
#endif
解释:
VC中有两种方式导出DLL文件中的函数
1)使用__declspec关键字。
2)创建模板定义文件(Module_DefinithionFile)即.def文件。
在此使用第一种方法:
__declspec(dllexport)作用是导出函数符号到DLL的一个存储类中。
在头文件中定义#defineDECLDIR__declspec(dllexport)宏来运行这个函数。
使用条件编译,在源文件中宏定义#defineDLL_EXPORT来运行这个函数。
//******************************************************************************
创建源文件ceshi1.cpp
#include
#defineDLL_EXPORT
#include"ceshi1.h"
extern"C"
{
//定义Dll中的所有函数
DECLDIRintadd(inta,intb)
{
returna+b;
}
DECLDIRvoidfunction(void)
{
std:
:
cout<<"DLLcalled"< : endl; } } 编译工程,生成ceshi1.dll文件和ceshi1.lib文件(注: 找到工程目录,这两个文件在外面的debug文件夹下)。 二、使用创建好的DLL库文件 创建一个控制台应用程序 1)隐式链接: 连接到.lib文件,首先将ceshi1.h头文件,ceshi1.dll动态库文件,ceshi1.lib静态库文件放在控制台应用程序工程的目录中,即源文件所在的文件夹里。 添加源文件ceshi2.cpp,编码: #pragmacomment(lib,"ceshi1.lib")//链接.lib文件 #include"ceshi1.h"//包含dll的头文件 #include intmain() { function(); std: : cout< : endl; getchar(); return0; } //****************************************************************************** 2)显式链接 只加载.dll文件,但需用到函数指针和Windows函数,不需要.lib文件和.h头文件。 #include #include typedefint(*AddFunc)(int,int); typedefvoid(*FunctionFunc)(void);//函数指针 intmain() { AddFunc_AddFunc; FunctionFunc_FunctionFunc; //HINSTANCE实例句柄(即一个历程的入口地址) HINSTANCEhInstLibrary=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)< : endl; _FunctionFunc(); getchar(); FreeLibrary(hInstLibrary); return0; } //****************************************************************************** Windows的执行文件可以划分为两种形式: 程序和动态连接库(DLLs)。 一般程序运行是用.EXE文件,但应用程序有时需要调用存储在DLL中的函数。 当我们调用Windows中的API函数的时候,实际上就是调用存储在DLL中的函数。 在如下几种情况下,调用DLL是合理的: 1)不同的程序使用相同的DLL,这样只需要将DLL在内存中装载一次,节省了内存的开销。 2)当某些内容需要升级的时候,如果使用DLL只需要改变DLL就可以了,而不需要把整个程序都进行变动。 3)由于DLL是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的时候,使用DLL便于程序系统的交流,当然,Delphi开发的DLL也可以在诸如VisualBASIC,C++等系统中使用。 2C语言创建DLL 只是要在公开的接口函数声明前面加上几个特定的修饰符。 //**********example1.h*********************************************************** #ifndefEXAMPLE1_H #defineEXAMPLE1_H #defineDLLIMPORT__declspec(dllexport) DLLIMPORTvoidHelloWorld(void); #endif //******example1.c*************************************************************** #include"example1.h" #include #include #include DLLIMPORTvoidHelloWorld(void) { MessageBox(0,TEXT("HelloWorldfromDLL! \n"),TEXT("Hi"),MB_ICONINFORMATION); } BOOLAPIENTRYDllMain(HINSTANCEhInst,DWORDreason,LPVOIDreserved) { switch(reason){ caseDLL_PROCESS_ATTACH: break; caseDLL_PROCESS_DETACH: break; caseDLL_THREAD_ATTACH: break; caseDLL_THREAD_DETACH: break; } returntrue; } __declspec(dllexport)标志着后面这个函数将成为对外的接口,使用包含在DLL中的函数,必须将其导入,导入操作通过dllimport来完成,dllexport和dllimport都是VC和BC所支持的关键字,但不能被自身格式所使用,通用格式为__declspec(dllexport)和__declspec(dllimport),为了简化,用宏名代替,若程序被编译成C++程序,同时希望C程序亦可使用,需要增加”C”的链接说明, #defineDLLEXPORTextern“C”__declspec(dllexport),就避免了标准C++命名损坏。 、、有错。 BOOLAPIENTRYDllMain()说明: 1、每个DLL必须有一个入口点,DllMain()是入口函数,负责初始化(initialization)和结束(termination)工作,每当一个新的进程或该进程的新的线程访问DLL时,或者不再使用DLL时,或结束时,都将调用DllMain。 但是使用terminateProcess或terminateThread结束进程和线程,不会调用DllMain。 DllMain()函数的原型: BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_resong_for_call,LPVOIDlpreserved) { switch(ul_reason_for_call){ caseDLL_PROCESS_ATTACH: … caseDLL_THREAD_ATTACH: … caseDLL_PROCESS_DETTACH: … caseDLL_THREAD_DETTACH: … } returntrue; } 参数: hMoudle: 是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);HINSTANCE ul_reason_for_call: 是一个说明动态库被调原因的标志。 当进程或线程装入或卸载动态连接库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。 它所有的可能值为: DLL_PROCESS_ATTACH: 进程被调用; DLL_THREAD_ATTACH: 线程被调用; DLL_PROCESS_DETACH: 进程被停止; DLL_THREAD_DETACH: 线程被停止; lpReserved: 是一个被系统所保留的参数。 //问题: 如何使用上面的DLL库文件? 资料: 动态链接库调用有两种函数: 导出函数(exportfunction)和内部函数(internalfunction)。 导出函数可被其他模块调用,内部函数只在定义的DLL中内部使用。 其他模块使用导出函数的用法: 1)传统方法 在模块定义文件的EXPORT部分指定需要的函数或变量,语法格式如下: entryname[=internalname][@ordinal[NONAME]][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)__cdeclTest(intvar);} 其输出函数名为Test(非C++方式) MFC提供了一些宏,就有这样的作用。 省略#define AFX_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 #else AFX_CLASS_IMPORT AFX_EXT_API: #ifdef_AFX_EXT AFX_API_EXPORT #else AFX_API_IMPORT AFX_EXT_DATA: #ifdef_AFX_EXT AFX_DATA_EXPORT #else AFX_DATA_IMPORT 像AFX_EXT_CLASS这样的宏,如果用于DLL应用程序的实现中,则表示输出(因为_AFX_EXT被定义,通常是在编译器的标识参数中指定该选项/D_AFX_EXT);如果用于使用DLL的应用程序中,则表示输入(_AFX_EXT没有定义)。 要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。 如: classAFX_EXT_CLASSCTextDoc: publicCDocument { … } extern"C"AFX_EXT_APIvoidWINAPIInitMYDLL(); 这几种方法中,最好采用第三种,方便好用;其次是第一种,如果按顺序号输出,调用效率会高些;最次是第二种。 3动态链接库的实现 一、创建DLL文件 1)使用VS2005创建DLL空工程。 2)新建头文件builder1.h,程序: //************************************************************************* #ifndefBUILDER1_H #defineBUILDER1_H #ifdefBUILDER1_DLL #defineDLL_API__declspec(dllexport) #else #defineDLL_API__declspec(dllimport) #endif //注意#endif的位置 extern"C"{//原样编译 //__stdcall使非C/C++语言能够调用API DLL_APIint__stdcallMax(inta,intb); } #endif //****************************************************************************** 3)新建源文件builder1.cpp //****************************************************************************** #defineBUILDER1_DLL #include"builder1.h" DLL_APIint__stdcallMax(inta,intb) { returna>b? a: b; } //***************************************************************************** 4)用.def文件创建动态链接库build1.dll a、删除build1工程中的builder1.h文件 b、在builder1.cpp中删除#include”builder1.h”语句。 内容: int__stdcallMax(inta,intb) { returna>b? a: b; } c、向该工程中加入一个文本文件,命名为builder1.def,内容: 错误 LIBRARYbuild1//标准格式LIBRARY“build1” EXPORTS Max@1//注意: 一定要有空格,语法的格式 d、编译生出dll文件 二、调用动态链接库DLL 1、隐式调用: 1)创建控制台工程build2 2)将build1.dll,build1.lib,builder1.h拷贝到工程所在目录,(主程序cpp所在的文件夹下) 三个文件必须全要。 3)新建源文件build2.cpp //*********************************************************************** #include"builder1.h" #pragmacomment(lib,"build1.lib") #include intmain() { intvalue; value=Max(100,250); std: : cout<<"Value="< : endl; getchar(); return0; } //************************成功************************************************** 2、显式调用 1)建立控制台工程 2)将close1.dll拷贝到工程目录(close1.dll是由.def文件生成) 3)用vc/bin下的Dumpbin.exe的小程序,查看DLL文件(DllDemo.dll)中的函数结构。 4)使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针。 typedefint(__stdcall*lpMax)(inta,intb);//一定要和dll中头文件声明一致 5)通过LoadLibrary()将DLL加载到当前的应用程序中,并返回当前DLL文件的句柄: HINSTANCEhDLL;//声明一个DLL文件实例句柄 hDLL=LoadLibrary(close1.dll);//导入动态链接库 6)通过GetProcAddress()函数获得导入到应用程序的函数指针。 lpMaxMax; Max=(lpMax)GetProcAddress(hDll,”Max”); intvalue; value=Max(250,500); std: : cout<<”Value=”< : endl; 7)函数调用完毕后,使用FreeLibrary(),释放DLL文件 FreeLibrary(hDll); 8)编译生成exe文件。 4C++Builder创建和使用DLL 一、创建 1)File----New建立一个新的DLL工程,生成一个DLL的工程框架。 入口函数: intWINAPIDllEntryPoint(HINSTANCEhinst,unsignedlongreason, void*lpReserved) { return1; } DllEntryPoint()函数为一个入口方法,如果使用者在DLL被系统初始化或者注销时被调用,用来写入对DLL的初始化程序和卸载程序;参数: hinst用来指示DLL的基地址;reason用来指示DLL的调用方式,用于区别多线程单线程对DLL的调用、创建、卸载DLL;lpReaerved为保留参数; #pragmaargsused extern"C"{ __declspec(dllexport)int__stdcalltest(void);//函数声明 } intWINAPIDllEntryPoint(HINSTANCEhinst,unsignedlongreason,void*lpReserved) { return1; } //--------------------------------------------------------------------------- int__stdcalltest(void)//函数定义 { std: : cout<<"MyfirstBCBDLLproject"< : endl; return250; } //……………………………Makeproject生成DLL库文件………………………………………………………… 二、调用DLL 1、静态调用法 控制台应用程序,工程添加输入接口库(importlibrary),在projectmanager中添加。 //--------------------------------------------------------------------------- #include #pragmahdrstop //--------------------------------------------------------------------------- #pragmaargsused extern"C"__declspec(dllimport)int__stdcalltest(void);//接口声明 intmain(intargc,char*argv[]) { std: : cout< : endl; std: : cout<<"firstdll"< : endl; getchar(); return0; } //--
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VS 创建 自己 DLL