设计“网络聊天”程序(DLL实现).ppt_第1页
设计“网络聊天”程序(DLL实现).ppt_第2页
设计“网络聊天”程序(DLL实现).ppt_第3页
设计“网络聊天”程序(DLL实现).ppt_第4页
设计“网络聊天”程序(DLL实现).ppt_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第7章设计 网络聊天 程序 DLL实现 实现功能及设计思路 主要知识点 程序实现过程 实例小结及扩展 7 1实现功能及设计思路 7 1 1功能描述在列表控件中选择用户 或在 发送给 组合框中选择接收人后 输入发送的消息内容 然后单击 发送信息 按钮将发送消息 如图7 1所示 如果选中 所有人 复选框后 那么消息内容或文件将被发送给局域网中的所有用户 7 1 1功能描述 单击窗口上的 发送文件 按钮 将弹出一个文件 打开 对话框以选择需要发送的文件 如图7 2所示 7 1 1功能描述 当接收到文件后 弹出一个消息提示框并询问是否接收文件 如图7 3所示 如果单击 是 按钮则开始接收文件 7 1 2设计思路 在创建套接字类动态链接库时 使用MFC创建常规的动态链接库 并在应用程序中隐式加载该动态链接库 在创建多线程动态链接库时 使用MFC创建扩展的动态链接库 并以动态显示的方式加载该动态链接库 7 2主要知识点 7 2 1动态链接库概述1 DLL入口函数创建DLL时 可以有选择地指定DLL的入口函数DllMain DllMain函数负责加载DLL的初始化和释放DLL的结束工作 每当一个新的进程或者该进程的新的线程访问DLL时 或访问DLL的每一个进程或者线程不再使用DLL或结束时 都会调用DllMain函数 但需要注意的是 使用TerminateProcess或TerminateThread函数终止进程或者线程时 不会调用DllMain函数 典型的DllMain函数代码如下 extern C intAPIENTRYDllMain HINSTANCEhInstance DWORDdwReason LPVOIDlpReserved if dwReason DLL PROCESS ATTACH ExtensionDLLone timeinitialization elseif dwReason DLL PROCESS DETACH TerminatethelibrarybeforedestructorsarecalledTRACE0 DLLEXAMPLE DLLTerminating n return1 ok 7 2 1动态链接库概述 2 导出 导入函数模块定义 def 文件为链接器提供有关被链接程序的导出 属性及其他方面的信息 通常 在模块定义文件中 需要声明DLL的LIBRARY语句和EXPORTS语句 例如 DllExample def DeclaresthemoduleparametersfortheDLL LIBRARY DllExample DESCRIPTION DllExampleWindowsDynamicLinkLibrary EXPORTS ExplicitexportscangohereSendFileProc 导出SendFileProc函数 7 2 1动态链接库概述 使用 declspec dllexport 修饰名可以显示地导出某个函数 通常 该修饰名被添加在函数声明前以说明导出该函数 例如 extern C declspec dllexport UINTSendFileProc LPVOIDlParam 声明导出SendFileProc为了能够在程序中使用DLL的导出函数 同样需要使用 declspec dllimport 修饰名来说明需要导入的DLL函数 例如 extern C declspec dllimport UINTSendFileProc LPVOIDlParam 声明导入SendFileProc 在MFC中 为了能够方便地导入 导出函数 类 MFC也定义了相应的导入 导出宏 根据导入 导出的不同类型 这些宏分为三类 分别用于C 类 API函数和数据变量的导入 导出声明 这些宏定义见表7 1 7 2 1动态链接库概述 3 extern C 修饰名在直接使用 declspec dllimport 或 declspec dllexport 修饰名导入 导出C函数时 需要添加extern C 函数修饰名 extern是C C 语言中表明函数和全局变量作用范围 可见性 的关键字 该关键字告诉编译器 其声明的函数和变量可以在本模块或其他模块中使用 通常 在C语言的头文件中经常可以看到类似下面这种形式的代码 ifdef cplusplusextern C endif somedeclarationorso ifdef cplusplus endif endof cplusplus 7 2 1动态链接库概述 4 函数调用约定函数的调用约定指定了函数在被调用时 其函数参数入栈的顺序和产生函数修饰名的方法 以及指定由调用者还被调用者管理堆栈 常见的调用约定见表7 2 7 2 1动态链接库概述 在Windows中提供这些调用方式定义相应的宏以方便在程序中使用 这些宏都定义在windef h头文件中 常见的Windows调用约定宏见表7 3 7 2 2创建动态链接库 1 创建非MFC动态链接库选择 文件 新建 菜单命令 弹出 新建项目 对话框 在对话框中的 项目类型 窗格中选择 VisualC 项下的 Win32 然后在 模板 窗格中选择 Win32 项目 指定项目名称及保存路径后 单击 确定 按钮并通过 Win32应用程序向导 选择创建DLL项目 如图7 4所示 7 2 2创建动态链接库 2 创建常规动态链接库在 新建项目 对话框中 选择 VisualC 项下的 MFC 项目类型 然后在 模板 窗格中选择 MFCDLL 指定项目的名称及保存路径并单击 确定 按钮 在弹出的 MFCDLL向导 对话框页面中选择 使用共享MFCDLL的规则DLL 单选按钮 创建常规动态链接库项目 如图7 5所示 7 2 2创建动态链接库 常规动态链接库的源文件中定义了一个与工程名对应的应用程序类 在该类中封装了DLL的入口函数 在DLL的源文件中 可以直接添加导出的函数 例如 TheoneandonlyCDllExample2AppobjectCDllExample2ApptheApp extern C declspec dllexport UINTSendFileProc LPVOIDlParam AFX MANAGE STATE AfxGetStaticModuleState 用于模块切换时的状态保护 return0 7 2 2创建动态链接库 3 创建扩展动态链接库同样在 MFCDLL向导 对话框中 选择 MFC扩展DLL 可以创建MFC扩展动态链接库项目 如图7 5所示 创建的MFC扩展动态链接库项目中仅包含一个DLL入口函数DllMain 然后 选择 项目 添加类 菜单命令向项目中添加导出的类 并在类名前添加AFX EXT CLASS宏来声明该类可以被导出动态链接库 7 2 3访问动态链接库 1 隐式链接有两种方法可以将lib文件添加到工程中 一种方法是 在解决方案资源管理器中选择项目名称并右击 在弹出的快捷菜单中选择 属性 菜单命令 或者选择 项目 属性 菜单命令 弹出该项目的属性页对话框 然后选择 配置属性 链接器 输入 菜单命令 在 附加依赖项 属性栏中指定需要导入的lib库文件的全路径名 如图7 6所示 7 2 3访问动态链接库 另一种方式是在源文件中通过预处理指令pragma来导入lib文件 在这种方式下可以将lib文件复制到工程目录下 并在pragma预处理指令中以该文件的相对路径名来导入lib文件 例如 stdafx h pragmacomment lib chatsock lib 7 2 3访问动态链接库 2 显式链接显式链接方式是指在应用程序中调用Win32API函数LoadLibrary或者MFC提供的AfxLoadLibrary函数来显式地加载动态连接库 它们的函数声明如下 HMODULEWINAPILoadLibrary LPCTSTRlpszLibFileName Win32API库加载函数HINSTANCEAFXAPIAfxLoadLibrary LPCTSTRlpszModuleName MFC库加载函数通过LoadLibrary和AfxLoadLibrary函数取得DLL实例后 调用GetProcAddress函数来取得函数的入口地址 例如 typedefUINT SENDFILEPROC LPVOID 定义函数指针HINSTANCEhInstance SENDFILEPROC SendFileProc hInstance LoadLibrary FileThread dll 加载DLLSendFileProc SENDFILEPROC GetProcAddress hInstance SendFileProc 取得入口UINTnRes SendFileProc NULL 调用DLL函数 7 2 3访问动态链接库 GetProcAddress函数用于查找指定的动态链接库中的输出库函数地址 并将符号名或标识号转换为DLL内部的地址 该函数的声明如下 FARPROCGetProcAddress HMODULEhModule LPCSTRlpProcName 在使用完DLL后或者在应用程序退出之前 应该用FreeLibrary函数或MFC提供的AfxFreeLibrary函数释放动态链接库 它们的函数声明如下 BOOLWINAPIFreeLibrary HMODULEhLibModule BOOLAFXAPIAfxFreeLibrary HINSTANCEhInstLib 7 2 3访问动态链接库 在使用显式链接方式调用DLL时 操作系统在加载应用程序时并不会将该应用程序所有引用的DLL都加载到内存中 而是在使用某个DLL时再将其载入 在对DLL加载的过程中 Windows将遵循下面的搜索顺序来查找DLL 1 包含可执行文件 exe 的目录 2 进程的当前目录 3 Windows系统目录 4 系统中Windows目录 5 PATH环境变量中的目录 7 3程序实现过程 7 3 1创建NetChat项目 1 选择 文件 新建 项目 菜单命令 弹出 新建项目 对话框 在对话框中选择 MFC 项目类型 并在模板窗格中选择 MFC应用程序 指定新项目的名称为NetChat及该项目保存的位置 然后选中 创建解决方案的目录 复选框 单击 确定 按钮创建一个基于对话框的应用程序 并取消 使用Unicode库 及允许 使用Windows套接字 功能 2 向对话框模板中添加相应的控件 并为这些控件添加成员变量 同时 在CNetChatDlg类的OnInitDialog函数中初始化列表控件 7 3 1创建NetChat项目 3 在CNetChatDlg类的头文件中定义用户信息结构体USERINFO 数据传输结构体SENDDATA和文件信息结构体FILEINFO 以及相关的常量 代码如下 defineUDP PORTNR2000 UDP端口号 defineTCP PORTNR2001 TCP端口号structUSERINFO 用户信息结构体 参照第6章USERINFO结构体 defineUSER ONLINE0 用户在线状态 defineUSER LEAVE1 用户离开状态structSENDDATA 消息数据结构体 参照第6章USERINFO结构体 defineTYPE USERINFO1 用户信息 defineTYPE FILEINFO2 文件信息 defineTYPE CHATDATA3 消息数据 defineTYPE REQUFILE4 发送文件structFILEINFO 文件信息结构体 参照第6章USERINFO结构体 7 3 1创建NetChat项目 4 在CNetChatDlg类中添加两个成员变量m tLocalUsr和m lsUsrInfo分别用来保存本地用户信息和其他用户信息 代码如下 CNetChatDlg对话框classCNetChatDlg publicCDialog CListCtrlm ctrlUserList USERINFOm tLocalUsr 本地用户信息CPtrListm lsUsrInfo 其他用户信息 7 3 1创建NetChat项目 在CNetChatDlg的OnInitDialog函数中取得本地用户的信息 并保存到成员变量m tLocalUsr中 代码如下 BOOLCNetChatDlg OnInitDialog memset 除非将焦点设置到控件 否则返回TRUE 7 3 2创建套接字类DLL 1 选择 文件 新建 项目 菜单命令 弹出 新建项目 对话框并创建一个 MFCDLL 模板的项目ChatSock 然后指定该项目保存的路径 并在 解决方案 下拉列表中选择 添入解决方案 项 单击 确定 按钮 并弹出 MFCDLL向导 对话框 7 3 2创建套接字类DLL 2 在对话框中的 应用程序设置 向导页面中选择 DLL类型 为 MFC扩展DLL 并在 附加功能 项中选中 Windows套接字 复选框 如图7 7所示 然后 单击 完成 按钮新建ChatSock项目 7 3 2创建套接字类DLL 3 在解决方案资源管理器中选择ChatSock 并选择 项目 添加类 菜单命令 在弹出的 添加类 对话框中选择 MFC类 并单击 添加 按钮 然后 通过MFC类向导为项目添加CUDPSocket类 并指定该类的基类为CSocket 如图7 8所示 7 3 2创建套接字类DLL 4 在CUDPSocket类名前添加AFX EXT CLASS宏 并在该类的头文件中添加自定义消息 以及修改该类的构造函数 然后 在类视图中选中该类并右击 在弹出的快捷菜单中选择 添加函数 菜单命令以向该类添加CreateClient成员函数 代码如下 UDPSocket h headerfile defineWM UDPRECEIVE WM USER 1020 UDP接收数据消息 defineMAX UDPBUFFER65535 UDP数据缓冲大小classAFX EXT CLASSCUDPSocket publicCSocket public CUDPSocket CWnd pWnd virtual CUDPSocket 操作public BOOLCreateClient CStringstrAddr UINTnPort 创建UDP客户端 属性public CWnd m pWnd 主窗口指针 7 3 2创建套接字类DLL 在CUDPSocket类的源文件中修改构造函数 并在CreateClient函数中创建数据报式套接字 代码如下 在属性窗口中单击重写按钮为CUDPSocket类重写OnReceive函数 并在该函数中向主窗口发送接收数据的消息 代码如下 voidCUDPSocket OnReceive intnErrorCode ASSERT VALID m pWnd PostMessage m pWnd m hWnd WM UDPRECEIVE 0 LPARAM this 通知主窗口CSocket OnReceive nErrorCode 7 3 2创建套接字类DLL 5 首先在CTCPSocket类名前添加AFX EXT CLASS宏 并在该类的头文件中添加自定义消息 以及修改该类的构造函数 同时 向该类中添加CreateServer成员函数 并在该函数中创建流式套接字 代码如下 在属性窗口中为CTCPSocket类重写OnAccept函数 并在该函数中通知主窗口接收客户端连接请求 代码如下 voidCTCPSocket OnAccept intnErrorCode ASSERT VALID m pWnd PostMessage m pWnd m hWnd WM TCPACCEPT 0 LPARAM this 通知主窗口CSocket OnAccept nErrorCode 7 3 3创建文件传输DLL 1 选择 文件 新建 项目 菜单命令 弹出 新建项目 对话框创建 MFCDLL 项目FileThread 并在 解决方案 下拉列表中选择 添入解决方案 项 2 在对话框中的 应用程序设置 向导页面中选择 DLL类型 为 使用共享MFCDLL的规则DLL 并在 附加功能 项中选中 Windows套接字 复选框 如图7 9所示 然后 单击 确定 按钮新建FileThread项目 7 3 3创建文件传输DLL 3 在解决方案资源管理器中选择FileThread项目并右击 在弹出的快捷菜单中选择 属性 菜单命令 弹出 FileThread属性页 对话框 然后展开 配置属性 常规 项 并修改项目的字符集属性为 使用多字节字符集 如图7 10所示 7 3 3创建文件传输DLL 4 在FileThread cpp源文件中定义与CNetChatDlg类的头文件中相同的SENDDATA和FILEINFO结构体及常量 代码如下 defineUDP PORTNR2000 UDP端口号 defineTCP PORTNR2001 TCP端口号structSENDDATA 消息数据结构体 参照第6章SENDDATA结构体 defineTYPE USERINFO1 用户信息 defineTYPE FILEINFO2 文件信息 defineTYPE CHATDATA3 消息数据 defineTYPE REQUFILE4 发送文件structFILEINFO 文件信息结构体 参照第6章FILEINFO结构体 7 3 3创建文件传输DLL 5 添加导出函数SendFileProc和RecvFileProc 并用extern C 函数修饰名和 declspec dllexport 修饰名修饰这两个函数 然后根据第6章6 3 6节中的SendFileProc和RecvFileProc函数修改发送文件和接收文件的代码 代码如下 extern C declspec dllexport UINTSendFileProc LPVOIDlParam 发送文件线程 AFX MANAGE STATE AfxGetStaticModuleState 参考第6章SendFileProc函数 return0 extern C declspec dllexport UINTRecvFileProc LPVOIDlParam 接收文件线程 AFX MANAGE STATE AfxGetStaticModuleState 参考第6章RecvFileProc函数 return0 7 3 4导入套接字输出类 1 将ChatSock项目下的UDPSocket h和TCPSocket h头文件复制到NetChat项目的目录下 然后在解决方案资源管理中选择NetChat项目并右击 在弹出的快捷菜单中选择 属性 菜单命令 弹出 NetChat属性页 对话框 在对话框页面中展开 配置属性 链接器 输入 项 并在 附加依赖项 栏中指定ChatSock项目中的库文件全路径 如图7 11所示 7 3 4导入套接字输出类 2 在CNetChatDlg类中分别定义两个成员变量m pUDPClient和m pTCPServer分别用于创建UDP客户端和TCP服务端 代码如下 include UDPSocket h include TCPSocket h CNetChatDlg对话框classCNetChatDlg publicCDialog CPtrListm lsUsrInfo 其他用户信息CUDPSocket m pUDPClient 本地UDP客户端CTCPSocket m pTCPServer 本地TCP服务端 在OnInitDialog中分别创建UDP客户端和TCP服务端 在属性窗口中为CNetChatDlg类添加WM DESTROY消息的响应函数 并在该函数中关闭套接字及释放资源 代码如下 7 3 4导入套接字输出类 3 在类视图中选择NetChat项目下的CNetChatDlg 并在属性窗口中为IDC USER FRESHt添加BN CLICKED消息的响应函数 并在该函数中向局域网广播本地信息 代码如下 voidCNetChatDlg OnBnClickedUserFresh SENDDATAsd sd nType TYPE USERINFO lstrcpy sd szSend m tLocalUsr szAddr 发送方IP地址memcpy sd szData 广播本地信息 7 3 4导入套接字输出类 在CNetChatDlg类的OnInitDialog函数中调用OnBnClickedUserFresh函数通知局域网中的其他用户 代码如下 BOOLCNetChatDlg OnInitDialog OnBnClickedUserFresh 刷新用户信息returnTRUE 除非将焦点设置到控件 否则返回TRUE 7 3 4导入套接字输出类 4 在类视图中选择NetChat项下的CNetChatDlg并右击 在弹出的快捷菜单中选择 添加 添加函数 菜单命令为CNetChatDlg类添加SendToUser成员函数 然后在属性窗口中为IDC SEND MSG添加BN CLICKED消息的响应函数 代码如下 BOOLCNetChatDlg SendToUser SENDDATA ps ASSERT VALID m pUDPClient 同第6章SendToUser函数 returnTRUE voidCNetChatDlg OnBnClickedSendMsg UpdateData TRUE 取得控件数据 同第6章OnBnClickedSendMsg函数 7 3 4导入套接字输出类 为CNetChatDlg类中添加两个成员函数UpdateUserList和FindUser 这两个函数分别用于更新列表控件的显示及从链表中查找指定的用户信息 代码如下 voidCNetChatDlg UpdateUserList void m ctrlRecvUser ResetContent 清空接收人组合框中的内容m ctrlUserList DeleteAllItems 清空用户信息列表中的内容 同第6章ResetContent函数 USERINFO CNetChatDlg FindUser CStringstrAddr if strAddr IsEmpty IP地址为空 直接返回returnNULL 同第6章FindUser函数 returnNULL 未找到该用户 7 3 4导入套接字输出类 5 在CNetChatDlg类的头文件中添加OnUDPReceive和OnTCPAccept函数的声明 并在源文件中添加相应的消息映射宏 以及添加OnUDPReceive函数的实现代码 代码如下 7 3 5实现文件传输功能 1 将该FileThread工程中Debug目录下的FileThread dll文件复制到CNetChatDlg工程目录中 同时 在CNetChatDlg类中添加一个HINSTANCE类型的成员变量m hInstance 代码如下 CNetChatDlg对话框classCNetChatDlg publicCDialog CTCPSocket m pTCPServer 本地TCP服务端HINSTANCEm hInstance 7 3 5实现文件传输功能 在CNetChatDlg类的OnInitDialog函数中调用LoadLibrary函数加载FileThread dll动态链接库 并在OnDestroy函数中调用FreeLibrary函数释放该DLL 代码如下 BOOLCNetChat2Dlg OnInitDialog m hInstance LoadLibrary FileThread dll 加载DLLif m hInstance returnFALSE returnTRUE 除非将焦点设置到控件 否则返回TRUE voidCNetChatDlg OnDestroy FreeLibrary m hInstance 释放DLL 7 3 5实现文件传输功能 2 在类CNetChatDlg的头文件中定义一个用于保存文件信息的FILEINFO结构体 然后 在类视图中选择NetChat项下的CNetChatDlg 并在属性窗口中为按钮IDC

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论