65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 RDP API 和套接字进行桌面共享

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (18投票s)

2014年2月5日

CPOL

10分钟阅读

viewsIcon

82729

downloadIcon

6253

您可以使用此软件与任何其他人共享对等方的桌面,您可以想象以任何方式指定共享者和查看者。详细的开发文档和用户手册可在下载中找到。

引言

在电子教室的情况下,教师可能希望将一个指定学生的桌面与一组其他人共享,将另一个指定学生的桌面与另一组共享,或者将自己的桌面与一组指定学生共享,以便这组学生知道如何在学习过程中操作某些问题。

而且,教师可能还想测试某个学生是否真正理解如何操作,以便他/她可以指定该学生作为具有控制共享者桌面的特权的角色。

另一种情况是,教师希望确保学生正在执行他/她分配给他们的任务,因此他/她可以监视一组指定学生的桌面。

环境

开发环境:Windows 8 上的 VS2012

运行环境:Windows 7 或更高版本,Windows 2012 或更高版本。请注意,需要 VC++11 运行时。如果还没有,请先安装。

背景

该软件采用服务器-客户端模型,使用套接字在服务器和客户端之间进行控制和命令传输。在底层,桌面传输功能通过 Microsoft 的 WDS API(http://msdn.microsoft.com/zh-cn/library/windows/desktop/aa373871(v=vs.85).aspx)使用 RDP 实现。

事实上,对于 RDP 服务器,我参考了此链接,甚至直接引用了“CMyRDPSessionEvents”类来处理 RDP 事件。要理解代码,您需要具备 COM 的基本知识。对于 RDP 客户端,我参考了此链接。RDP 客户端应该是 ActiveX 控件,Microsoft 已经在 MFC 中提供了这样的控件。感谢这两篇文章的作者。

Using the Code

1. 简介

该桌面共享软件分为两部分:服务器端的控制中心和客户端的对等方。事实上,每个对等方都包含 RDP 服务器(作为共享者)和 RDP 客户端(作为查看者),这意味着它拥有共享桌面和查看他人桌面所需的一切。控制中心仅通过套接字命令控制对等方。

2. 控制中心

2.1 整体架构

“控制中心”是服务器端的名称。控制中心在逻辑上分为三个层次。底层包含两个派生自CSocket的类,它们分别是CDoorSocketCListenSock,分别与客户端和套接字通信。中间层只有一个服务类CService,提供基本的套接字服务,如发送和接收数据。该类为上层的 UI 类提供服务,在接收到套接字命令或状态字符串时向它们发送消息。它还包含一个列表和一个映射,用于存储对应于客户端的套接字。顶层包含许多 UI 类和一些相关的辅助类。UI 类主要是派生自CDialogEx的对话框类。

2.2 CService 详细信息

如上所述,CService类主要通过提供套接字服务来为 UI 类提供服务。

主要方法
  • SockSend:用于在需要时向客户端发送命令。
  • OnSockReceive:一旦套接字从客户端接收到命令或回复命令,将调用此方法。它将根据不同的接收字符串执行操作以更改映射中套接字的状态和/或向相应类发送自定义消息。此方法就像一个消息分发器。

该类还拥有列表和映射作为其属性。它们都用于存储连接到客户端的套接字。但为什么有两个容器呢?情况是当一个客户端连接到控制中心时,将在OnSockAccept方法中创建一个新的CDoorSocket实例,稍后当套接字发送一个带有标识客户端自身的名称的“logname”命令时,该名称-套接字对将被添加到映射中。之后,通常会使用映射中的实体,并以名称作为 ID。

就该类的功能而言,其实例应该是唯一的,即单例。因此,将其作为主对话框的属性远远不够,我将其作为CControlCenterApp的属性,以便任何类都可以通过单个“theApp”来使用它。

请注意,该类还包含一些指向CWnd的指针。它们用于在OnSockReceive方法中指示消息将发送到何处。显然,这不是一个好的设计。为了在发送消息时传递一些参数,我使用了SendMessage函数。这可能会对性能产生不良影响。

2.3 UI 设计

该软件是一个 MFC 对话框项目。因此,用户界面是对话框和它们上面的控件的集合。主窗口是一个对话框,其类为CControlCenterDlg,其中包含以下元素:选项卡控件客户端区域中的三个对话框,左下角的static控件和对应的隐藏“手动消息”对话框,最后是右下角代表在线客户端数量的static控件。

2.4 关于 CPeerTreeDlg

此类可能是最复杂的,即使它只是一个包含树控件的对话框。我想让它成为一个可移植的控件,所以我将对话框资源的边框设置为“none”。

其最基本的功能是显示一个包含按不同组划分的对等方的树。

请注意,有两种方法可以初始构建树。第一种方法是通过“BuildTree”方法,首先将内存中的一组文件内容读入内存,形式为map<CString, list<CString>* >,第一个元素是组名,第二个是指向对等方名称列表的指针。默认目录是“.\Group\”,其中的文件必须具有“.dat”扩展名。每个文件代表一个组,文件名就是组名,里面的内容是对等方名称。每个对等方名称占一行。数据加载到映射后,将根据映射创建树节点。最后释放映射的内存。在显示所有实际组之后,将添加一个“未知组”。这就是“管理组”面板中的树的构建方式。

第二种方法是通过“FilterTree”函数。它根据节点所代表的对等方是否在线来过滤现有树。如果对等方在线,则保留相应的节点,否则将其删除。创建广播会话或监视会话时显示的“创建新会话”对话框中的树就是通过这种方式构建的。

2.5 会话列表对话框

在“广播桌面”和“监视桌面”中,分别是CShareSessionDlgCMonitorSessionDlg。我发明了两种不同类型的会话,第一种是共享会话,用于CShareSessionDlg,意思是将对等方的桌面广播给同一会话中的其他人,第二种是监视会话,用于CMonitorSessionDlg,意思是监视一些对等方。类“CShareSession”和“CMonitorSession”分别对应它们。当你准备创建新的共享会话时,一个包含要选择的共享者和要从树中选择的查看者的对话框就是CShareSession的用户界面。在这里,在这种情况下,CShareSession似乎也是对话框的“托管 bean”,CMonitorSession也是如此。创建会话时显示的对话框是模态对话框,在调用DoModal之前,我传递一个CShareSessionCMonitorSession的实例,这样我就可以传入数据并让对话框显示,在DoModal返回后,我可以通过用户输入通过对话框填写的实例获取新数据。这是一个重要的概念。然而,在软件中,我没有使用这种方式来传递数据。请注意,在代码级别上,监视会话的概念与 UI 上的概念略有不同,在 UI 上,一个监视会话只有一个对等方被监视。

3. 对等方

3.1 架构

架构与控制中心类似。底层是CDoorSocket,中间层是CService类,顶层是CPeerDlgCViewerDlg。复杂程度大大降低。有些地方不同。与作为主对话框的CPeerDlg对应的对话框在软件运行时从不显示。然而,它处理由托盘图标菜单或套接字触发的事件。CService类提供三种服务:套接字服务、RDP 服务和系统管理服务。RDP 服务主要包括使用StartRDPService启动 RDP 服务和使用StopRDPService停止 RDP 服务。这里的系统管理服务只是使用SetHook安装全局鼠标钩子和键盘钩子。在SetHook函数中,我加载了一个名为“GlobalHook”的库,其中安装了全局鼠标钩子和键盘钩子。

3.2 RDP 服务

这是软件的核心。Microsoft 在此处提供了 API,我也参考了此链接此链接,这两篇文章对我帮助很大。我甚至直接引用了两个类“CMyRDPSessionEvents”来提供事件处理,以及“B”来将普通string转换为 BSTR。

4. 命令系统

回复 自定义消息
“共享者已启动” WM_MY_SHARERSTARTED CShareSessionDlg
“共享者未启动” WM_MY_SHARERNOTSTARTED CShareSessionDlg
“共享者已停止” WM_MY_SHARERSTOPPED CShareSessionDlg
“共享者未停止”    
“查看者已启动”    
“查看者未启动”    
“查看者已停止”    
“查看者未停止”    
“监视器已打开” WM_MY_MONITOROPENED CMonitorSessionDlg
“监视器未打开” WM_MY_MONITORNOTOPENED CMonitorSessionDlg
“监视器已关闭” WM_MY_MONITORCLOSED CMonitorSessionDlg
“监视器未关闭”    
客户端命令“logname” WM_MY_LOGNAME CPeerTreeDlg CControlCenterDlg
套接字关闭事件 WM_MY_SOCKCLOSE CPeerTreeDlg CShareSessionDlg CMonitorSessionDlg CControlCenterDlg
客户端命令“举手” WM_MY_HANDUP CControlCenterDlg CHandDlg

下面列出了从服务器发送的命令

功能 command 成功回复 失败回复
启动 RDP 服务 “启动共享者” 共享者已启动 ticket:+ticket string 共享者未启动
停止 RDP 服务 “停止共享者” 共享者已停止 共享者未停止
让 RDPViewer 连接 RDP 共享者,根据 ticket “启动查看者” + ticket string 查看者已启动 查看者未启动
断开 RDP 连接 “停止查看者” 查看者已停止 查看者未停止
与启动共享者相同 “打开监视器” 监视器已打开 ticket:+ticket string 监视器未打开
与停止共享者相同 “关闭监视器” 监视器已关闭 监视器未关闭
锁定查看者 “锁定”    
解锁查看者 “解锁”    
禁用客户端上的“退出程序”菜单项 “配置禁用退出”    
启用“退出程序”菜单项 “配置启用退出”    
disconnect      

从客户端发送的命令(不期望服务器回复)

功能 command
登录 “logname” + name
电子举手 “hand up”
disconnect  

注意:白色表示无。

5. 语言

为了使软件国际化,多语言是一个问题。要提供不同语言的版本,我将源代码中的每个string都转移到了资源脚本的string表中。因此,所有与语言相关的资源都在资源脚本中。默认资源脚本是中文。将资源收集到另一个 DLL 项目中,构建一个仅包含资源的 DLL 作为独立的语言包。更多信息可以在此处找到。

关注点

我需要为软件提供不同语言的版本。项目类型是使用 VC++11 的 MFC 对话框项目。最初,我将所有资源创建为中文版,后来我想要英文版,只需将所有与资源相关的文件(包括res目录,resource.htargetver.h)放入另一个 DLL 项目,编译并链接,您将获得一个仅包含资源的 DLL。系统可以根据仅包含资源的 DLL 的名称和系统配置来决定使用哪个资源。更多细节可以在此处此处找到。这真的很强大。

历史

这是于 2014 年 1 月 20 日完成的第三版。

结论

我在开发 MFC 软件方面是新手。尽管软件的技术可以归结为 RDP+Socket,但对我来说并不容易。它还包含许多其他东西,如配置文件、全局钩子、资源国际化、COM 事件、MFC DLL 等。如果您有任何问题或想与我交流,请发送电子邮件至 nuclear.sun@qq.com。

© . All rights reserved.