《动态链接库DLL编程》由会员分享,可在线阅读,更多相关《动态链接库DLL编程(61页珍藏版)》请在金锄头文库上搜索。
1、VC+动态链接库动态链接库(DLL)编程编程仪砧丫壮她照乐辨脓遁课街醛位验尺尘嘴泉辗脐阮弯淖伦吗七幻趁剁柒亏动态链接库DLL编程动态链接库DLL编程1.概论概论先来阐述一下先来阐述一下DLL(DynamicLinkableLibrary)的概念,你可以简单的把的概念,你可以简单的把DLL看看成一种仓库,它提供给你一些可以直接成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。拿来用的变量、函数或类。在仓库的发展史上经历了在仓库的发展史上经历了“无库静态无库静态链接库动态链接库链接库动态链接库”的时代。的时代。对动态链接库,需建立如下概念:对动态链接库,需建立如下概念:孜恳日亡揣信瘁聂坍抛
2、擒正嫩说惑花纵潍牢陋吐垂蔬瘸埃棠肋陕魄剥乙榷动态链接库DLL编程动态链接库DLL编程(1)与具体的编程语言及编译器无关)与具体的编程语言及编译器无关只要遵循约定的只要遵循约定的DLL接口规范和调用方接口规范和调用方式,用各种语言编写的式,用各种语言编写的DLL都可以相互都可以相互调用。调用。譬如譬如Windows提供的系统提供的系统DLL(其中包(其中包括了括了Windows的的API),在任何开发环境),在任何开发环境中都能被调用,不在乎其是中都能被调用,不在乎其是VisualBasic、VisualC+还是还是Delphi。庸陋遣瞪钓糙倚阳前泄挤橙壁畏直蓑泪仗骨坠粒宿青弥殴镀蝇绒顶颤栗命动
3、态链接库DLL编程动态链接库DLL编程(2)动态链接库随处可见)动态链接库随处可见在在Windows目录下的目录下的system32文件夹中会文件夹中会看到看到kernel32.dll、user32.dll和和gdi32.dll,windows的大多数的大多数API都包含在这些都包含在这些DLL中。中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面(MessageBox函数);gdi32.dll中的函数则负责图形方面的操作。勾覆悄杀队屑攀崖闯题盎缀澈怀剑以佩琅陆桩三沽伎翠搞叶冯助各唇乘旬动态链接库DLL编程动态链接库DLL编程(3)VC
4、动态链接库的分类动态链接库的分类VisualC+支持三种支持三种DLL,它们分别是非,它们分别是非MFC动动态库、态库、MFC规则规则DLL、MFCExtensionDLL。非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。屎晚笔禹刚常草卒蹲踪盾剧翁队羔舶胆胜墙碎肖佰贴幼章敌鲁证轧闭宦妊动态链接库DLL编程动态链接库DLL编程明狱助夫拥循孺憋曝瑞胖所窜底涵盟列店缠三坊确攫腊值纵舞昨给依奄
5、如动态链接库DLL编程动态链接库DLL编程湍太裙诬鬃矢炙坪耕趣奠踢诺片埠蹲黍宁稻漆谅谁充珠矩打子洒摔桥剔其动态链接库DLL编程动态链接库DLL编程2.静态链接库静态链接库在在VC+6.0中中new一个名称为一个名称为libTest的的staticlibrary工程工程,并新建并新建lib.h和和lib.cpp两个文件,两个文件,lib.h和和lib.cpp的源代码的源代码如下:如下:/文件:lib.h#ifndefLIB_H#defineLIB_HexternCintadd(intx,inty);/声明为C编译、连接方式的外部函数#endif/文件:lib.cpp#includelib.hin
6、tadd(intx,inty)returnx+y;陋签兆吊盔顷凑旗弘瓮导仟贺吉捅诅宵塔凋验露楼纂蝎麻调萤漂猛蚜海兜动态链接库DLL编程动态链接库DLL编程#include#include.lib.h#pragmacomment(lib,.debuglibTest.lib)/指定与静态库指定与静态库一起连接一起连接intmain(intargc,char*argv)printf(2+3=%d,add(2,3);侦篆又逝铸镑颜登洗牲钵遭烙倪蔽纳哺潮燕刽存瞩侈靳救僻坎扼蛹土猖疚动态链接库DLL编程动态链接库DLL编程选择选择tools、options、directories、libraryfiles
7、菜单菜单或选项,填入库文件路径或选项,填入库文件路径米易满偏宙揖储如刚假允斌车辉挣蝎就老乡闷沂齿捡昔庶笛髓皮劈梅盛锭动态链接库DLL编程动态链接库DLL编程4.非非MFCDLL澡辙黔痔出屯狡贫屡欲谓磊耘诸悍惋海椭垣辉班灵癌水篮匣档稼嚼痛翻革动态链接库DLL编程动态链接库DLL编程在建立的工程中添加在建立的工程中添加lib.h及及lib.cpp文件,源代码文件,源代码如下:如下:/*文件名:文件名:lib.h*/#ifndefLIB_H#defineLIB_HexternCint_declspec(dllexport)add(intx,inty);#endif/*文件名:文件名:lib.cpp*
8、/#includelib.hintadd(intx,inty)returnx+y;灾叹奏储孔魄爹疼仰液柔诧兆悉症惹绎雷裤邻彪瘸夯疼祖净也讯尿救诈猜动态链接库DLL编程动态链接库DLL编程dllCall#include#includetypedefint(*lpAddFun)(int,int);/宏定义函数指针类型宏定义函数指针类型intmain(intargc,char*argv)HINSTANCEhDll;/DLL句柄句柄lpAddFunaddFun;/函数指针函数指针hDll=LoadLibrary(.DebugdllTest.dll);if(hDll!=NULL)addFun=(lpAd
9、dFun)GetProcAddress(hDll,add);if(addFun!=NULL)intresult=addFun(2,3);printf(%d,result);FreeLibrary(hDll);return0;扶妇数悸蠢诈逸琼遂例率苔瞳怪鲸爵沦谦幽蒙丈缝捍歪网拿痰挎府钦午注动态链接库DLL编程动态链接库DLL编程DLL的调用和静态链接库的调用有较大差异的调用和静态链接库的调用有较大差异首先,语句首先,语句typedefint(*lpAddFun)(int,int)定义了一个与定义了一个与add函数接受参数类型和返回值均相同的函数指针类型。随函数接受参数类型和返回值均相同的函数指针
10、类型。随后,在后,在main函数中定义了函数中定义了lpAddFun的实例的实例addFun;其次,在函数其次,在函数main中定义了一个中定义了一个DLLHINSTANCE句柄实句柄实例例hDll,通过,通过Win32Api函数函数LoadLibrary动态加载了动态加载了DLL模块并将模块并将DLL模块句柄赋给了模块句柄赋给了hDll;再次,在函数再次,在函数main中通过中通过Win32Api函数函数GetProcAddress得得到了所加载到了所加载DLL模块中函数模块中函数add的地址并赋给了的地址并赋给了addFun。经。经由函数指针由函数指针addFun进行了对进行了对DLL中中
11、add函数的调用;函数的调用;最后,应用工程使用完最后,应用工程使用完DLL后,在函数后,在函数main中通过中通过Win32Api函数函数FreeLibrary释放了已经加载的释放了已经加载的DLL模块。模块。芝珊参钥烬保乎涎居焉掐斗格早削食涟讯峭筛俺辨妨陆鲸返灾曼遗背潜徘动态链接库DLL编程动态链接库DLL编程声明导出函数声明导出函数DLL中导出函数的声明有两种方式:中导出函数的声明有两种方式:一种为给出的在函数声明中加上一种为给出的在函数声明中加上_declspec(dllexport);一种方式是采用模块定义一种方式是采用模块定义(.def)文件声文件声明明;拣仟舱蒸宰烂稚搀抠裤趟惑恬
12、境辽署受亮蚊轨稻祭订笆桨悬项笋其看峰峦动态链接库DLL编程动态链接库DLL编程在在DLL中想要中想要export的函数和数据定义前的函数和数据定义前添加添加_declspec(dllexport)关键字(对)关键字(对于函数和变量定义,加在最前面;对于于函数和变量定义,加在最前面;对于class定义,加在定义,加在class关键字后)关键字后);_declspec(dllexport)voidShowDlg(void)class_declspec(dllexport)class_name/导出类这样该函数和数据就会被添加到这样该函数和数据就会被添加到ET中。中。使用这种方法函数将按名字使用这种
13、方法函数将按名字export。_declspec(dllexport)桩啪沫弓赂割绸沁野辈士凄撞残剑他透斧推绸欧匈症缔汇砰彬剔球伎叉仙动态链接库DLL编程动态链接库DLL编程(.def)文件声明文件声明为为DLL创建一个创建一个.DEF文件(模块定义文文件(模块定义文件),并在件),并在build该该DLL时使用这个时使用这个.DEF文件。使用这种方法使你可以将函文件。使用这种方法使你可以将函数按序号数按序号export。在LINK选项卡中假如:/def:lib.def将lib.def加入到工程中。乒仇赏胀脖是您帖采杠明则胖尿抽须僚扁占邦唯舔讣递堵很虐洲径户枝考动态链接库DLL编程动态链接库D
14、LL编程lib.def;lib.def:导出导出DLL函数函数LIBRARYdllTestEXPORTSadd1.def文件的规则为:文件的规则为:(1)LIBRARY语句说明语句说明.def文件相应的文件相应的DLL;(2)EXPORTS语句后列出要导出函数的名称。可以在语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加文件中的导出函数名后加n,表示要导出函数的序号,表示要导出函数的序号为为n(在进行函数调用时,这个序号将发挥其作用);(在进行函数调用时,这个序号将发挥其作用);(3).def文件中的注释由每个注释行开始处的分号文件中的注释由每个注释行开始处的分号(;)指定,且
15、注释不能与语句共享一行。指定,且注释不能与语句共享一行。狂肢寓遍琅仪袱筛莉体陌夯聊姐柞毅饲妹激铜枷府荚辆钎嫂竭洗氢擞世翁动态链接库DLL编程动态链接库DLL编程库的调试与查看库的调试与查看动态链接库中的导出接口可以使用动态链接库中的导出接口可以使用VisualC+的的Depends工具进行查看,工具进行查看,用用Depends打开系统目录中的打开系统目录中的MouseHook.dll.襄渴云碌松逊裴拣靶饭鄂世逼拧峦沟腕馒徊痕畔厅哑洋嘲琢铰掺拨姥彝痛动态链接库DLL编程动态链接库DLL编程汾棉概祁棺踢糕能七越抿优凶拥乡唯拖蔚员殊前电汕寺崎詹扑汤太演牧蓖动态链接库DLL编程动态链接库DLL编程寞天
16、呕张底馈宅罪栅碟缄劲然羡匠慢顽莎休谓垂骤弘核屉擒割跺香饭镁兵动态链接库DLL编程动态链接库DLL编程DLL的调用方式的调用方式1.隐式调用隐式调用:1.将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在*.cpp文件(的顶部添加:2.#pragmacomment(lib,RegularDll.lib)OR疤甫歌憎称指勘颇仰馏淮譬走音冰矛贸蓟酚抠蓬踊踩样闭审貌添荧蚕英影动态链接库DLL编程动态链接库DLL编程动态调用动态调用特点特点:是完全由编程者用是完全由编程者用API函数加载和函数加载和卸载卸载DLL,程序员可以决定,程序员可以决定DLL文件文件何时加载或不加载,显式链
17、接在运行时何时加载或不加载,显式链接在运行时决定加载哪个决定加载哪个DLL文件。文件。责纬一方硼教蓟弊吟盐毁删眯咯麦逃珍敬瘦宠苛捷迅蜜澄塞镀铱杆搪元艳动态链接库DLL编程动态链接库DLL编程dllTest.dll在建立的工程中添加在建立的工程中添加lib.h及及lib.cpp文件,源代码如下:文件,源代码如下:/*文件名:文件名:lib.h*/#ifndefLIB_H#defineLIB_HexternCint_declspec(dllexport)add(intx,inty);#endif/*文件名:文件名:lib.cpp*/#includelib.hintadd(intx,inty)ret
18、urnx+y;惦馁灶远穴殆湖赂拌褒虹居谣暗斟一尼摩挑谈婆穿鉴驳咨疆绸琅笼万秀猾动态链接库DLL编程动态链接库DLL编程调用调用dllTest.dll#include#includetypedefint(*lpAddFun)(int,int);/宏定义函数指针类型宏定义函数指针类型intmain(intargc,char*argv)HINSTANCEhDll;/DLL句柄句柄lpAddFunaddFun;/函数指针函数指针hDll=LoadLibrary(.DebugdllTest.dll);if(hDll!=NULL)addFun=(lpAddFun)GetProcAddress(hDll,a
19、dd);if(addFun!=NULL)intresult=addFun(2,3);printf(%d,result);FreeLibrary(hDll);割磷们默茬莉群棍祖刮夸愤画涉碉硫尝油梦妥盏忱劣委晤婴庙滔砷宦想状动态链接库DLL编程动态链接库DLL编程DLL的的Export和和ImportDLL的的export是指将是指将DLL中的函数和数据输出中的函数和数据输出到其它程式中,以供其使用。到其它程式中,以供其使用。DLL的的import是是指使用指使用DLL的程式引入的程式引入DLL中的函数和数据。中的函数和数据。DLL的的exportDLL中包含有一个表,称为中包含有一个表,称为ex
20、porttable(以下简称(以下简称ET),其中包含了),其中包含了DLL中可以被外部程式使用的所有函数和数据中可以被外部程式使用的所有函数和数据的名字。的名字。只有记录在只有记录在ET中的函数和数据才可以被外部程中的函数和数据才可以被外部程式所使用(如果没有式所使用(如果没有.DEF文件的话),其它所文件的话),其它所有没有记录在有没有记录在ET中的函数和数据都被视为是中的函数和数据都被视为是DLL私有的。私有的。休糟栈膛暗炭彤纹右盛凶慕问渺舰犯催政命篮闭妨推茸舅妄耍识蹿瘴削昌动态链接库DLL编程动态链接库DLL编程DllMain函数函数Windows在加载在加载DLL的时候,需要一个入口
21、函的时候,需要一个入口函数,就如同控制台或数,就如同控制台或DOS程序需要程序需要main函数、函数、WIN32程序需要程序需要WinMain函数一样。函数一样。在前面的例子中,在前面的例子中,DLL并没有提供并没有提供DllMain函函数,应用工程也能成功引用数,应用工程也能成功引用DLL,这是因为,这是因为Windows在找不到在找不到DllMain的时候,系统会从的时候,系统会从其它运行库中引入一个不做任何操作的缺省其它运行库中引入一个不做任何操作的缺省DllMain函数版本,并不意味着函数版本,并不意味着DLL可以放弃可以放弃DllMain函数。函数。瓷徊妙布侯靴奄晤翱栽蕊熙酋精滦须福
22、暑抹拄徒灸撰圆彰拱牢胶誓秦满宴动态链接库DLL编程动态链接库DLL编程BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_reason_for_call,LPVOIDlpReserved)DllMain函数在函数在DLL被加载和卸载时被调用,在单个线程启动被加载和卸载时被调用,在单个线程启动和终止时,和终止时,DLLMain函数也被调用函数也被调用;ul_reason_for_call指明了被调用的原因。原因共有指明了被调用的原因。原因共有4种,即种,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和和THREAD_DET
23、ACH,以,以switch语句列语句列出。出。唉鸯狰鉴劲薪屡酝妆订狠惧四董妹陵纶绝华耿本掀盛泻颅腔乡媚霜粗尾窿动态链接库DLL编程动态链接库DLL编程DLL导出变量导出变量/*文件名:文件名:lib.h*/#ifndefLIB_H#defineLIB_HexternintdllGlobalVar;#endif/*文件名:文件名:lib.cpp*/#includelib.h#includeintdllGlobalVar;BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_reason_for_call,LPVOIDlpReserved)dllGlobalVar=1
24、00;/在在dll被加载时,赋全局变量为被加载时,赋全局变量为100returnTRUE;文件名:文件名:lib.def;在在DLL中导出变量中导出变量LIBRARYdllTestEXPORTSdllGlobalVarDATA扦荫剥孵寨柄腰册契事萎扳逮钩总跪异熊儿雇这杰逃陪比最末故悲亭妄踊动态链接库DLL编程动态链接库DLL编程在主函数中引用在主函数中引用DLL中定义的全局变量:中定义的全局变量:#include#pragmacomment(lib,dllTest.lib)externint_declspec(dllimport)dllGlobalVar;/用用_declspec(dllimp
25、ort)导入导入intmain(intargc,char*argv)printf(%d,dllGlobalVar);dllGlobalVar=1;printf(%d,dllGlobalVar);return0;员偿渡能沙困忻渍掠蹲拭鹃泼娶复望啸逃廖炮悦咕睡蛇动拼芽仍芽码行朗动态链接库DLL编程动态链接库DLL编程特别要注意特别要注意用用externintdllGlobalVar声明所导入的并不是声明所导入的并不是DLL中全局变量本身,而是其地址,应用程序中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用必须通过强制指针转换来使用DLL中的全局变中的全局变量。这一点,从量。这一点,从
26、*(int*)dllGlobalVar可以看可以看出。因此在采用这种方式引用出。因此在采用这种方式引用DLL全局变量时,全局变量时,千万不要进行这样的赋值操作:千万不要进行这样的赋值操作:dllGlobalVar=1;率鸿仕谍籽始丹橙往薛梢滴帘态扮掀针逊芋般柏富煽离攻搀拭销茧纪廷指动态链接库DLL编程动态链接库DLL编程MFC规则规则DLLMFC规则规则DLL的概念体现在两方面:的概念体现在两方面:它是它是MFC的的“是MFC的”意味着可以在这种DLL的内部使用MFC;它是规则的它是规则的“是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的
27、接口不能是MFC。而MFC扩展DLL与应用程序的接口可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。RegularDLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。位搅凤篷债饱拣勋西欲缩妥尊诈朴帧塞拿芝瞧拇昭肩赏执田怠岂砰窘运计动态链接库DLL编程动态链接库DLL编程RegularDLL分为两类:分为两类:(1)静态链接到)静态链接到MFC的规则的规则DLL静态链接到MFC的规则DLL与MFC库(包括MFC扩展DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用DLL的资源。因此,在静态链接到M
28、FC的规则DLL中不需要进行模块状态的切换。使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。(2)动态链接到)动态链接到MFC的规则的规则DLL动态链接到MFC的规则DLL可以和使用它的可执行文件同时动态链接到MFCDLL和任何MFC扩展DLL。在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共享MFCDLL的规则DLL,必须进行模块切换以使得MFC能够找到正确的资源模板。筏谅继典嘉廖侄焊禾盗循于窟汛私忙釉交蓟迪昌妮屁咏墨彼见痞俄洲声
29、雹动态链接库DLL编程动态链接库DLL编程MFC规则规则DLL的创建的创建automation(自动化)技术(自动化)技术是否支持是否支持WindowsSockets酌乔狱正驾火确簿我俗氦网趾葱枷椰窒砂梦酪伐掂隋柳屋营故嘻赊鳞胰暑动态链接库DLL编程动态链接库DLL编程在在MFC应用程序中应用程序中CWinApp取代了取代了SDK程序中程序中WinMain的地位,的地位,SDK程序程序WinMain所完成的工作由所完成的工作由CWinApp的三的三个函数完成:个函数完成:virtualBOOLInitApplication();virtualBOOLInitInstance();virtual
30、BOOLRun();/传说中传说中MFC程程序的序的“活水源头活水源头”兢瑟抚芦赔叉方或顷歧穿裹建医皑猴似哩前猴滩芋截挤第瓦李蓟修萎赴程动态链接库DLL编程动态链接库DLL编程MFC规则规则DLL接口函数接口函数#includeStdAfx.h#includeDllDialog.h_declspec(dllexport)voidShowDlg(void)或或externC_declspec(dllexport)voidShowDlg(void)CDllDialogdllDialog;dllDialog.DoModal();分析:分析:这个接口并不使用这个接口并不使用MFC,但是在其中却可以调用
31、,但是在其中却可以调用MFC扩展类扩展类CdllDialog的函数,这体现了的函数,这体现了“规则规则”的概类。的概类。与非与非MFCDLL完全相同,可以使用完全相同,可以使用_declspec(dllexport)声明或在声明或在.def中引出的方式导出中引出的方式导出MFC规则规则DLL中的接口。中的接口。炼碴页喝配兵嘎社污肚节榴朝基阔稍城卢庞岿骄滇厦彩雹控扳淀铣虽钥叭动态链接库DLL编程动态链接库DLL编程MFC规则规则DLL的调用的调用澄央孕傅沟并苗插筹耘庭牌卉剂疫薄笺墙藕乓习诫瑟渐蝶扫累摔帐暮敷咀动态链接库DLL编程动态链接库DLL编程#pragmacomment(lib,Regul
32、arDll.lib)_declspec(dllexport)voidShowDlg(void)voidShowDlg(void);或或externC_declspec(dllexport)voidShowDlg(void)externCvoidShowDlg(void);voidCRegularDllCallDlg:OnCalldllButton()ShowDlg();乏剃佃缝荒侵嚏尾己铬冰轻罢鲸魏谨翔戎空悦晤悉爆匠士嘱侍聘拢呜阔堡动态链接库DLL编程动态链接库DLL编程MFC扩展扩展DLLMFC扩展扩展DLL与与MFC规则规则DLL的相同点在于在两种的相同点在于在两种DLL的内部都可以使用的
33、内部都可以使用MFC类库,其不同点在于类库,其不同点在于MFC扩展扩展DLL与应用程序的接口可以是与应用程序的接口可以是MFC的。的。MFC扩展扩展DLL的含义在于它是的含义在于它是MFC的扩展,其主要功的扩展,其主要功能是实现从现有能是实现从现有MFC库类中派生出可重用的类。库类中派生出可重用的类。MFC扩展扩展DLL使用使用MFC动态链接库版本,动态链接库版本,因此只有因此只有用共享用共享MFC版本生成的版本生成的MFC可执行文件(应用程序可执行文件(应用程序或规则或规则DLL)才能使用)才能使用MFC扩展扩展DLL。一般使用一般使用MFC扩展扩展DLL来包含一些来包含一些MFC的增强功能
34、,的增强功能,譬如扩展譬如扩展MFC的的CStatic、CButton等类使之具备更强等类使之具备更强大的能力。大的能力。编矽荡乡攫荡对鼠腐浪簧豪嘎陈暇洲乡桌酒蔡亩彭搅橱爵靖俗挖朗碗词枝动态链接库DLL编程动态链接库DLL编程三种三种DLL对对DllMain入口函数的不同处理方式:入口函数的不同处理方式:DLLDLL类型类型 入口函数入口函数 非非 MFC DLL MFC DLL 编程者提供编程者提供DllMainDllMain函数函数 MFCMFC规则规则 DLL DLL CWinAppCWinApp对象的对象的InitInstance InitInstance 和和 ExitInstanc
35、e ExitInstance MFCMFC扩展扩展 DLL DLL MFC DLLMFC DLL向导生成向导生成DllMain DllMain 函数函数 游狼平蓬殆乍邮榜罕尊浙执芭睁使京和诊锗晶驹电蔬帖馏霹搂幢诺堪聚娥动态链接库DLL编程动态链接库DLL编程宏宏宏为宏为DLL和应用程序的编写提供了方便。像和应用程序的编写提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA在在DLL和应用程序中将具有不同的定义,这取和应用程序中将具有不同的定义,这取决于决于_AFXEXT宏宏是否被定义。这使得在是否被定义。这使得在DLL和和应用程序中,使用统一的一个宏就可以
36、表示出应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思。输出和输入的不同意思。在DLL中,表示输出(因为_AFXEXT被定义,通常是在编译器的标识参数中指定/D_AFXEXT);在应用程序中,则表示输入(_AFXEXT没有定义)。丘星陌肇婿牌瞥帕数码腿刹剧讳淮替拷俄揖梁争涤配攘圣哪的幢港茶业假动态链接库DLL编程动态链接库DLL编程AFX_CLASS_IMPORT_declspec(dllexport)AFX_API_IMPORT_declspec(dllexport)AFX_DATA_IMPORT_declspec(dllexport)AFX_CLASS_EXPORT_decls
37、pec(dllexport)AFX_API_EXPORT_declspec(dllexport)AFX_DATA_EXPORT_declspec(dllexport)鸽肮卞寐糯殃哗瘦蝶倍死取服榷横厘捎界寺践漂样爬荧制撒订则发播垂仇动态链接库DLL编程动态链接库DLL编程AFX_EXT_CLASS #ifdef _AFXEXT AFX_CLASS_EXPORT #else AFX_CLASS_IMPORT AFX_EXT_API #ifdef _AFXEXT AFX_API_EXPORT #else AFX_API_IMPORT AFX_EXT_DATA #ifdef _AFXEXT AFX_D
38、ATA_EXPORT #else AFX_DATA_IMPORT 犀剁熙株诗试眠灭聪厚蚕朴赏凄还屑猖灯翻晶琉害缆疽哦哲胺辖期椿交门动态链接库DLL编程动态链接库DLL编程classAFX_EXT_CLASSCExtDialog:publicCDialog*#include.ExtDialog.h#pragmacomment(lib,ExtDll.lib)而而“调用调用DLL”按钮的单击事件的消息处理函数为:按钮的单击事件的消息处理函数为:voidCLoadExtDllDlg:OnDllcallButton()CExtDialogextDialog;extDialog.DoModal();荒眯抹
39、庶党来瓜春常郸讲活佛阎哀瘫掘韦域疤汽庙炎波民肪瞪搏侈监躬支动态链接库DLL编程动态链接库DLL编程Win32系统钩子技术系统钩子技术APIHOOK技术应用广泛,常用于屏幕取技术应用广泛,常用于屏幕取词、网络防火墙、病毒木马、加壳软件、词、网络防火墙、病毒木马、加壳软件、串口红外通信、游戏外挂、串口红外通信、游戏外挂、Internet通信通信等领域。等领域。HOOK的中文意思就是钩子,的中文意思就是钩子,APIHOOK就是钩住就是钩住API,对,对API进行预进行预处理,先执行我们的函数。处理,先执行我们的函数。哈害梁捌伪朝磊赃探姻宁辗伎讶豹私泅滤腹祭慌哼去唱洱沉卖胺菠酮磷巨动态链接库DLL编程
40、动态链接库DLL编程APIHOOK技术技术钩子的本质是一段用以处理系统消息的程序,钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。通过系统调用,把它挂入系统。钩子的种类很多,每种钩子可以截获并处理相钩子的种类很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时钩子函数可以对截获的此消息的控制权。此时钩子函数可以对截获的消息进行加工处理,甚至可以强制结束消息的消息进行加工处理,甚至可以强制结束消息的传递。传递。这有点类似
41、与这有点类似与MFC中的中的PreTranslateMessage函函数,所不同的是该函数只能用于拦截本进程中数,所不同的是该函数只能用于拦截本进程中的消息,而对系统消息则无能为力。的消息,而对系统消息则无能为力。路夷台慷班妹送棕乡嘲忧摈限盏评柑浊截锑厩满惶这邻梳酉办乏根铅蛋枢动态链接库DLL编程动态链接库DLL编程Win32系统钩子的实现系统钩子的实现每种类型的钩子均由系统来维护一个钩每种类型的钩子均由系统来维护一个钩子链,最近安装的钩子位于链的开始,子链,最近安装的钩子位于链的开始,拥有最高的优先级,而最先安装的钩子拥有最高的优先级,而最先安装的钩子则处在链的末尾。则处在链的末尾。要实现要
42、实现Win32的系统钩子,首先要调用的系统钩子,首先要调用SDK中的中的API函数函数SetWindowsHookEx来来安装这个钩子函数,其原型是:安装这个钩子函数,其原型是:陇竟登元窟索粗砖估启铃脸够筷臣杭慧磅桨酶详陈垂哲治鸯汝瑰潜梆艾蔼动态链接库DLL编程动态链接库DLL编程HHOOKSetWindowsHookEx(intidHook,HOOKPROClpfn,HINSTANCEhMod,DWORDdwThreadId);其中:其中:第一个参数是钩子的类型,常用的有第一个参数是钩子的类型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等;等;第二个参数是钩
43、子函数的地址,当钩子钩到任何消息后便第二个参数是钩子函数的地址,当钩子钩到任何消息后便调用这个函数;调用这个函数;第三个参数是钩子函数所在模块的句柄;第三个参数是钩子函数所在模块的句柄;第四个参数是钩子相关函数的第四个参数是钩子相关函数的ID用以指定想让钩子去钩用以指定想让钩子去钩哪个线程,为哪个线程,为0时则拦截整个系统的消息此时为全局钩子。时则拦截整个系统的消息此时为全局钩子。如果指定确定的线程,即为线程专用钩子。如果指定确定的线程,即为线程专用钩子。科上屁围呀催扫除界奄峦搜炕及遁惯牺肘伤豺烷纸酥逞长暮磺慎态椿县源动态链接库DLL编程动态链接库DLL编程全局钩子函数必须包含在全局钩子函数必
44、须包含在DLL(动态链(动态链接库)中,而线程专用钩子则可包含在接库)中,而线程专用钩子则可包含在可执行文件中。可执行文件中。得到控制权的钩子函数在处理完消息后,得到控制权的钩子函数在处理完消息后,可以调用另外一个可以调用另外一个SDK中的中的API函数函数CallNextHookEx来继续传递该消息。也来继续传递该消息。也可以通过直接返回可以通过直接返回TRUE来丢弃该消息,来丢弃该消息,阻止该消息的传递。阻止该消息的传递。彩虞磁紧塌逾呐杨冯倡蝶久兢孜诫抄溢阜仕库粟抢砒揽换除撵搏惨憨里鹏动态链接库DLL编程动态链接库DLL编程使用全局钩子函数时需要以使用全局钩子函数时需要以DLL为载体,为载
45、体,VC6中有三种形式的中有三种形式的MFCDLL可供选择,即标准可供选择,即标准静态链接静态链接MFCDLL、标准动态链接、标准动态链接MFCDLL以及扩展以及扩展MFCDLL)。)。第一种DLL在编译时把使用的MFC代码链接到DLL中,执行程序时不需要其他MFC动态链接类库的支持,但体积较大;第二种DLL在运行时动态链接到MFC类库,因而体积较小,但却依赖于MFC动态链接类库的支持;这两种DLL均可被MFC程序和Win32程序使用。第三种DLL的也是动态连接,但做为MFC类库的扩展,只能被MFC程序使用。益验顿跺颗酪茎焉蛇功霜圈双懂方获层码耻夺得乾驹停损骆任疯措偿馈篇动态链接库DLL编程动
46、态链接库DLL编程Win32DLLBOOLWINAPIDllMain(HINSTANCEhinstDLL,DWORDfdwReason,LPVOIDlpvReserved);其中:其中:第一个参数表示DLL的实例句柄;第三个参数系统保留;第二个参数指明了当前调用该动态连接库的状态,它有四个可能的值:DLL_PROCESS_ATTACH(进程载入)、DLL_THREAD_ATTACH(线程载入)、DLL_THREAD_DETACH(线程卸载)、DLL_PROCESS_DETACH(进程卸载)。持逻钎浸挠湛男爽警吕言关你始奴含邢膘敞凛锰功朋冠袋撕拼涸简厄茎屡动态链接库DLL编程动态链接库DLL编程
47、DLL的共享问题的共享问题由于在由于在Win32环境下,所有进程的空间都是相互独立的,环境下,所有进程的空间都是相互独立的,这减少了应用程序间的相互影响,但大大增加了编程这减少了应用程序间的相互影响,但大大增加了编程的难度。的难度。当进程在动态加载当进程在动态加载DLL时,系统自动把时,系统自动把DLL地址映射地址映射到该进程的私有空间到该进程的私有空间;而且也复制该而且也复制该DLL的全局数据的一份拷贝到该进程空的全局数据的一份拷贝到该进程空间,每个进程所拥有的相同的间,每个进程所拥有的相同的DLL的全局数据其值却的全局数据其值却并不一定是相同的。并不一定是相同的。当当DLL内存被映射到进程
48、空间中,每个进程都有自己内存被映射到进程空间中,每个进程都有自己的全局内存拷贝,加载的全局内存拷贝,加载DLL的每一个新的进程都重新的每一个新的进程都重新初始化这一内存区域,也就是说进程不能再共享初始化这一内存区域,也就是说进程不能再共享DLL。牌刻澜憾扎丧李姑沽壳饵签酉梦庐循笆更藐鸵罕况瑚胰是违利终屑砌虚祥动态链接库DLL编程动态链接库DLL编程全局共享数据的实现全局共享数据的实现在在Win32环境下要想在多个进程中共享数环境下要想在多个进程中共享数据,就必须进行必要的设置。据,就必须进行必要的设置。一种方法便是把这些需要共享的数据单一种方法便是把这些需要共享的数据单独分离出来,放置在一个独
49、立的数据段独分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,建立里,并把该段的属性设置为共享,建立一个内存共享的一个内存共享的DLL。豁蘑麦奔天涯疾避娄氛窿期雇枚兆皇嘴湘慷刀张歧掘弓岩谰阴旨辊晓快粳动态链接库DLL编程动态链接库DLL编程#pragmadata_seg用用#pragmadata_seg建立一个新的数据段并定义建立一个新的数据段并定义共享数据,其具体格式为:共享数据,其具体格式为:#pragmadata_seg(shareddata)HWNDsharedwnd=NULL;/共享数据#pragmadata_seg()所有在所有在data_segpragmas语句之间声
50、明的变量都语句之间声明的变量都将在将在shareddata段中。仅定义一个数据段还不能段中。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的(其效果是相同性,有两种方法可以实现该目的(其效果是相同的),的),聪饼呛铀闰叠沁悬扫靴筷胎眠党割拖扣详芋信慕猎邀桩沦哄斟坷淆镍瘁龟动态链接库DLL编程动态链接库DLL编程一种方法是在一种方法是在.DEF文件中加入如下语句:文件中加入如下语句:SETCTIONSshareddataREADWRITESHARED另一种方法是在项目设置链接选项中加入如下另一种方法是在项目设置
51、链接选项中加入如下语句:语句:/SECTION:shareddata,rws加上一条指令#pragmacomment(linker,/section:.shareddata,rws),递曲婴崇菏浓奖寡塔唾啤培顾蚌爵侯草啦荆荷难滦肪字锡含州弓橱躺北棵动态链接库DLL编程动态链接库DLL编程程序只能启动一次程序只能启动一次#includewindows.h#pragmadata_seg(flag_data)intcount=0;#pragmadata_seg()#pragmacomment(linker,/SECTION:flag_data,RWS)intmain(intargc,char*arg
52、v)if(count0)MessageBox(NULL,已经启动了一个应用程序已经启动了一个应用程序,Warning,MB_OK);return0;count+;system(pause);return0;枫扳违缔徒长扭脉缕杜僧胰篮呈硷坷氮较换雁沿窟瞥圈马州炳亭奄幌肘觉动态链接库DLL编程动态链接库DLL编程程序示例程序示例鼠标钩子鼠标钩子鼠标鼠标-键盘键盘-密码密码早由厅缺剖皮未业剩滋溢集炯殊傲苇瓜晚急酵冯池菱卉艇续舔卑羚睬槛返动态链接库DLL编程动态链接库DLL编程挂接挂接ExitWindowsEx随着安全意识的不断提高,许多软件都增强的自我保随着安全意识的不断提高,许多软件都增强的自我保
53、护性,结束其进程时将会调用护性,结束其进程时将会调用ExitWindowsEx函数关函数关机或者重启。这种技术在收费管理系统、病毒木马、机或者重启。这种技术在收费管理系统、病毒木马、加壳软件、反破解领域里很常见,因而采用加壳软件、反破解领域里很常见,因而采用APIHOOK技术挂接技术挂接ExitWindowsEx函数使其失效,对函数使其失效,对与我们查杀病毒以及软件破解是很有用的。与我们查杀病毒以及软件破解是很有用的。当然还能运用它免费上网呢!现在许多收费软件都采当然还能运用它免费上网呢!现在许多收费软件都采取会员制,下机时点结帐下机按钮后,客户端就发送取会员制,下机时点结帐下机按钮后,客户端
54、就发送数据报给主机,告知用户已下机从而停止记费,同时数据报给主机,告知用户已下机从而停止记费,同时重新启动或关闭计算机。挂接重新启动或关闭计算机。挂接ExitWindowsEx后就可后就可以让机子不重启,免费上网?以让机子不重启,免费上网?饲泄楼韵搜户输踢埃著捻聊伦菊带逗锐樱英封悼翰汽娩逼考址梭灼畜寺挎动态链接库DLL编程动态链接库DLL编程改写改写IAT(引入表)法(引入表)法这种方法的优点是较稳定,不要担心线程同步的这种方法的优点是较稳定,不要担心线程同步的问题。问题。思路如下:思路如下:根据PE文件格式穷举模块中的image_impot_desciptor引入函数数组,检查进程空间里是否
55、有要HOOK的API的所在的DLL,如果有则通过WiteProcessMemory、VirtualProtect等函数改写IAT中的目标API函数地址,将其改为我们自定义函数的地址。由于地址不能跨进程引用,所以我们可以使用Windows消息钩子将APIHOOK所在的所在的DLL注入到其他进程里注入到其他进程里,为了取得较好的效果,推荐使用WH_GETMESSAGE类性的钩子。荆马嗅稀压铣聘行侈你膨寄叮碧附半招杏尼恿扰零孪兼冉希厌赶台孰删嫌动态链接库DLL编程动态链接库DLL编程席蝇囚鸦窗来缨垢巡袜如友袜娘彪疏烤佑丫襟汹拽痹沧莱相数袱荒况峻箍动态链接库DLL编程动态链接库DLL编程密凶枫姥洋隐戊鲁腮鲤剥称绸核丈念具乔滔夸虾须炊和圆既瞧枷湃每龙侨动态链接库DLL编程动态链接库DLL编程