《设计“网络聊天”程序(dll实现)》由会员分享,可在线阅读,更多相关《设计“网络聊天”程序(dll实现)(47页珍藏版)》请在金锄头文库上搜索。
1、7.17.27.37.4实现功能及设计思路主要知识点程序实现过程实例小结及扩展7.1.1 功能描述 在列表控件中选择用户,或在“发送给”组合框中选择接收人后,输入发送 的消息内容,然后单击“发送信息”按钮将发送消息,如图7.1所示。如果选中“ 所有人”复选框后,那么消息内容或文件将被发送给局域网中的所有用户。单击窗口上的“发送文件”按钮,将弹出一个文件“打开”对话框以选择需要发 送的文件,如图7.2所示。当接收到文件后,弹出一个消息提示框并询问是否接收文件,如图7.3所示 ,如果单击“是”按钮则开始接收文件。在创建套接字类动态链接库时,使用MFC创建常规的动态链接库,并在应用程序中隐式加载该动
2、态链接库;在创建多线程动态链接库时,使用MFC创建扩展的动态链接库,并以动态显示的方式加载该动态链接库。v7.2.1 动态链接库概述 1DLL入口函数 创建DLL时,可以有选择地指定DLL的入口函数DllMain。DllMain函数负责加 载DLL的初始化和释放DLL的结束工作。每当一个新的进程或者该进程的新的线 程访问DLL时,或访问DLL的每一个进程或者线程不再使用DLL或结束时,都会调 用DllMain函数。但需要注意的是,使用TerminateProcess或TerminateThread函数 终止进程或者线程时,不会调用DllMain函数。典型的DllMain函数代码如下: exte
3、rn “C“ int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) if (dwReason = DLL_PROCESS_ATTACH) / Extension DLL one-time initializationelse if (dwReason = DLL_PROCESS_DETACH) / Terminate the library before destructors are calledTRACE0(“DLLEXAMPLE.DLL Terminating!n“);return 1;
4、/ ok 2导出、导入函数 模块定义(.def)文件为链接器提供有关被链接程序的导出、属性及其他方 面的信息。通常,在模块定义文件中,需要声明DLL的LIBRARY语句和EXPORTS语 句。例如: ; DllExample.def : Declares the module parameters for the DLL. LIBRARY “DllExample“ DESCRIPTION DllExample Windows Dynamic Link Library EXPORTS; Explicit exports can go hereSendFileProc ; 导出SendFilePr
5、oc函数使用_declspec(dllexport)修饰名可以显示地导出某个函数。通常,该修饰 名被添加在函数声明前以说明导出该函数。例如: extern “C” _declspec(dllexport) UINT SendFileProc(LPVOID lParam); /声明导 出SendFileProc 为了能够在程序中使用DLL的导出函数,同样需要使用_declspec(dllimport) 修饰名来说明需要导入的DLL函数。例如: extern “C“ _declspec(dllimport) UINT SendFileProc(LPVOID lParam); /声明导 入SendF
6、ileProc 在MFC中,为了能够方便地导入、导出函数、类,MFC也定义了相应的导入 、导出宏。根据导入、导出的不同类型,这些宏分为三类,分别用于C+类、 API函数和数据变量的导入、导出声明。这些宏定义见表7.1。3extern “C”修饰名 在直接使用_declspec(dllimport)或_declspec(dllexport)修饰名导入、导出C 函数时,需要添加extern“C”函数修饰名。extern是C/C+语言中表明函数和全局 变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变 量可以在本模块或其他模块中使用。通常,在C语言的头文件中经常可以看到类 似下面这
7、种形式的代码: #ifdef _cplusplus extern “C“ #endif /* some declaration or so */ #ifdef _cplusplus #endif /* end of _cplusplus */4函数调用约定 函数的调用约定指定了函数在被调用时,其函数参数入栈的顺序和产生函数 修饰名的方法,以及指定由调用者还被调用者管理堆栈。常见的调用约定见表 7.2。调 用 约 定说 明_cdecl函数参数从右至左入栈,由调用者将参数弹出栈_stdcall函数参数从右至左入栈,由被调用者将参数弹出栈_fastcall函数的头两个DWORD类型或占更少字节的参数
8、被放入ECX和 EDX寄存器,其他参数从右至左入栈,由被调用者将参数弹出栈在Windows中提供这些调用方式定义相应的宏以方便在程序中使用,这些 宏都定义在windef.h头文件中。常见的Windows调用约定宏见表7.3。调用约定宏说 明CALLBACK_stdcall调用方式,窗口过程回调函数WINAPI_stdcall调用方式,Win32 API函数声 明 WINAPIV_cdecl调用方式APIENTRY_stdcall调用方式,API入口函数APIPRIVATE_stdcall调用方式PASCAL_stdcall调用方式1创建非MFC动态链接库 选择“文件”“新建”菜单命令,弹出“新
9、建项目”对话框。在对话框中的“项 目类型”窗格中选择“Visual C+”项下的“Win32”,然后在“模板”窗格中选择 “Win32”项目。指定项目名称及保存路径后,单击“确定”按钮并通过“Win32应用 程序向导”选择创建DLL项目,如图7.4所示。2创建常规动态链接库 在“新建项目”对话框中,选择“Visual C+”项下的“MFC”项目类型,然后在“ 模板”窗格中选择“MFC DLL”,指定项目的名称及保存路径并单击“确定”按钮。在 弹出的“MFC DLL向导”对话框页面中选择“使用共享MFC DLL的规则DLL”单选按钮 ,创建常规动态链接库项目,如图7.5所示。常规动态链接库的源文
10、件中定义了一个与工程名对应的应用程序类,在该 类中封装了DLL的入口函数。在DLL的源文件中,可以直接添加导出的函数。例 如: / / The one and only CDllExample2App object CDllExample2App theApp; / extern “C“ _declspec(dllexport) UINT SendFileProc(LPVOID lParam) AFX_MANAGE_STATE(AfxGetStaticModuleState(); / 用于模块切换时的状 态保护/ return 0; 3创建扩展动态链接库同样在“MFC DLL向导”对话框中,选
11、择“MFC扩展DLL”可以创建MFC扩展动态链接库项目,如图7.5所示。创建的MFC扩展动态链接库项目中仅包含一个DLL入口函数DllMain。然后,选择“项目”“添加类”菜单命令向项目中添加导出的类,并在类名前添加AFX_EXT_CLASS宏来声明该类可以被导出动态链接库。1隐式链接 有两种方法可以将lib文件添加到工程中。一种方法是:在解决方案资源管 理器中选择项目名称并右击,在弹出的快捷菜单中选择“属性”菜单命令,或者 选择“项目”“属性”菜单命令,弹出该项目的属性页对话框,然后选择“配置属 性”“链接器”“输入”菜单命令,在“附加依赖项”属性栏中指定需要导入的lib库 文件的全路径名,
12、如图7.6所示。另一种方式是在源文件中通过预处理指令pragma来导入lib文件。在这种方式下可以将lib文件复制到工程目录下,并在pragma预处理指令中以该文件的相对路径名来导入lib文件。例如: / stdafx.h #pragma comment(lib, “chatsock.lib“)2显式链接 显式链接方式是指在应用程序中调用Win32 API函数LoadLibrary或者MFC提供 的AfxLoadLibrary函数来显式地加载动态连接库。它们的函数声明如下:HMODULE WINAPI LoadLibrary( LPCTSTR lpszLibFileName ); / Win3
13、2 API库加载函数 HINSTANCE AFXAPI AfxLoadLibrary( LPCTSTR lpszModuleName );/ MFC库加载函数 通过LoadLibrary和AfxLoadLibrary函数取得DLL实例后,调用GetProcAddress函 数来取得函数的入口地址。例如: typedef UINT (SENDFILEPROC)(LPVOID); / 定义函数指针 HINSTANCE hInstance; SENDFILEPROC *SendFileProc; hInstance = :LoadLibrary(“FileThread.dll“); / 加载DLL
14、SendFileProc = (SENDFILEPROC*):GetProcAddress(hInstance, “SendFileProc“); / 取得入口 UINT nRes = SendFileProc(NULL); / 调用DLL函数GetProcAddress函数用于查找指定的动态链接库中的输出库函数地址,并将符号名或标识号转换为DLL内部的地址。该函数的声明如下: FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );在使用完DLL后或者在应用程序退出之前,应该用FreeLibrary函数或MFC提供的AfxFr
15、eeLibrary函数释放动态链接库。它们的函数声明如下: BOOL WINAPI FreeLibrary( HMODULE hLibModule ); BOOL AFXAPI AfxFreeLibrary( HINSTANCE hInstLib );在使用显式链接方式调用DLL时,操作系统在加载应用程序时并不会将该应用程序所有引用的DLL都加载到内存中,而是在使用某个DLL时再将其载入。在对DLL加载的过程中,Windows将遵循下面的搜索顺序来查找DLL:(1)包含可执行文件(exe)的目录;(2)进程的当前目录;(3)Windows系统目录;(4)系统中Windows目录;(5)PATH环境变量中的目录。v7.3.1 创建NetChat项目(1)选择“文件”“新建”“项目”菜单命令,弹出“新建项目”对话框。在对话框中选择“MFC”项目类型,并在模板窗格中选择“MFC应用程序”。指定新项目的名称为NetChat及该项目保存的位置,然后选中“创建解决方案的目录”复选框。单击“确定”按钮创建一个基于对话框的应用程序,并取消“使用Unicode库”及允许“使用Windows套接字”功能。(2)向对话框模板中添加相应的控件,并