C# 使用远程桌面连接本机 | 您所在的位置:网站首页 › 利用电脑本机远程控制 › C# 使用远程桌面连接本机 |
前言
最近由于项目需求,需要实现 远程桌面连接当前本机(自己连接自己) 当程序完成操作之后,注销远程桌面(确保每次打开的,都是新的桌面) 注意事项: 此功能只能在专业版系统上使用,我测试过家庭版、教育版等,均不能连接上远程桌面 白屏问题最近看到不少朋友都反馈有白屏问题,请检查: 1 当前操作系统是否为Windows专业版,此功能只能在专业版系统上使用。 2 调用WTSEnableChildSessions时是否返回True,如果返回False,用管理员权限启动程序即可解决。 引用DLL需要引用AxInterop.MSTSCLib.dll和MSTSCLib.dll Dll下载地址 提取码 egqq 代码实现WPF项目,使用 WindowsFormsHost来展示远程桌面画面,需要引用WindowsFormsIntegration 引用命名空间 using AxMSTSCLib; using MSTSCLib; 初始化 /// /// 全局RDP对象 /// private AxMsRdpClient9NotSafeForScripting rdp; public PictureInPictureForm() { InitializeComponent(); //实例化对象 rdp = new AxMsRdpClient9NotSafeForScripting(); //远程桌面的内容显示在窗体中 formhost.Child = rdp; } 连接方法 /// /// 连接方法 /// public void Connect() { //连接本机,不会把自己挤掉线 rdp.Server = "localhost"; var settings = (rdp.GetOcx() as IMsRdpExtendedSettings); object otrue = true; //设置连接自己,必须要加这一行,加了这一行后,会自动定位到LocalHost settings.set_Property("ConnectToChildSession", ref otrue); //设置账号密码,我这里因为不知道用户的账号密码,暂时屏蔽掉 //rdp.UserName = ""; //rdp.AdvancedSettings2.ClearTextPassword="" //启用CredSSupSupport //一定要把EnableCredSspSupport属性置为ture 否则连接上去就是一片空白 rdp.AdvancedSettings7.EnableCredSspSupport = true; //自动尺寸 rdp.AdvancedSettings7.SmartSizing = true; //显示连接栏 rdp.AdvancedSettings7.DisplayConnectionBar = false; //重新定向 rdp.AdvancedSettings7.RedirectSmartCards = true; //远程桌面登录完成事件 rdp.OnLoginComplete += (_, __) => { //如有需要,编写代码 }; //远程桌面警告事件 rdp.OnWarning += (_, e) => { //如有需要,编写代码 }; //正在连接远程桌面事件 rdp.OnConnecting += (_, e) => { //如有需要,编写代码 }; //连接成功后触发事件 rdp.OnConnected += (_, e) =>{ //如有需要,编写代码 }; //断开连接回调事件 rdp.OnDisconnected += OnDisconnected; //登录远程桌面事件 rdp.OnLogonError += delegate (object _, IMsTscAxEvents_OnLogonErrorEvent e) { if (e.lError != -2) { //如有需要 this.Close(); } }; //远程桌面发生致命错误事件 rdp.OnFatalError += delegate (object _, IMsTscAxEvents_OnFatalErrorEvent e) { //如有需要 this.Close(); }; //连接 rdp.Connect(); } 断开连接 /// /// 窗体关闭的时候,断开连接 /// /// /// private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (rdp == null) { return; } //减去事件 rdp.OnDisconnected -= OnDisconnected; //查看连接数,断开连接 if (rdp.Connected != 0) { rdp.Disconnect(); } } } OnDisconnected事件 /// /// 断开连接 /// /// /// private void OnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e) { this.Close(); } 效果注销远程桌面 由于连接远程桌面的类库并没有提供此功能,先自己实现,思路是开启远程桌面之前,设置一个自己开发的程序为开机启动,并且不可见,程序执行完相应的功能之后,取消设置开机启动,注销掉远程桌面 //注销 Process.Start("shutdown.exe", "-l"); //设置开机启动项 ,Path开机启动程序的地址 using (var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true)) { key.SetValue("Program", Path); } //删除开机启动 using (var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true)) { key.DeleteValue("Program", false); }2021/3/18 今天测试的时候发现一个问题,同事的机器上连接远程桌面的时候白屏后闪退,我的机器正常,为了解决这个问题,翻阅了一下微软官方文档 https://docs.microsoft.com/zh-cn/windows/win32/termserv/child-sessions 微软的官方文档上写让我调用WTSEnableChildSessions函数启用子会话功能,还可以通过使用WTSIsChildSessionsEnabled函数来判断是否已启用子会话 解决方法: /// /// 注销使用 /// public unsafe static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = (IntPtr)(void*)null; /// /// 打开子会话功能 /// /// /// [DllImport("Wtsapi32.dll")] private static extern bool WTSEnableChildSessions(bool enable); /// /// 判断用户是否打开了子会话功能 /// /// /// [DllImport("Wtsapi32.dll")] private static extern bool WTSIsChildSessionsEnabled(out bool isEnabled); /// /// 获取子会话的SessionID /// /// /// [DllImport("Wtsapi32.dll")] private static extern bool WTSGetChildSessionId(out uint SessionId); /// /// 注销子会话 /// /// /// [DllImport("Wtsapi32.dll", SetLastError = true)] private static extern bool WTSLogoffSession(IntPtr hServer, uint SessionId, bool bWait);调用WTSEnableChildSessions即可 /// /// 连接方法 /// public void Connect() { //打开子会话功能 if (!WTSEnableChildSessions(true)) { throw new InvalidOperationException("启用画中画功能失败"); } //连接本机,不会把自己挤掉线 rdp.Server = "localhost"; var settings = (rdp.GetOcx() as IMsRdpExtendedSettings); object otrue = true; //设置连接自己,必须要加这一行,加了这一行后,会自动定位到LocalHost settings.set_Property("ConnectToChildSession", ref otrue); //设置账号密码,我这里因为不知道用户的账号密码,暂时屏蔽掉 //rdp.UserName = ""; //rdp.AdvancedSettings2.ClearTextPassword="" //启用CredSSupSupport //一定要把EnableCredSspSupport属性置为ture 否则连接上去就是一片空白 rdp.AdvancedSettings7.EnableCredSspSupport = true; //自动尺寸 rdp.AdvancedSettings7.SmartSizing = true; //显示连接栏 rdp.AdvancedSettings7.DisplayConnectionBar = false; //重新定向 rdp.AdvancedSettings7.RedirectSmartCards = true; //远程桌面登录完成事件 rdp.OnLoginComplete += (_, __) => { //如有需要,编写代码 }; //远程桌面警告事件 rdp.OnWarning += (_, e) => { //如有需要,编写代码 }; //正在连接远程桌面事件 rdp.OnConnecting += (_, e) => { //如有需要,编写代码 }; //连接成功后触发事件 rdp.OnConnected += (_, e) =>{ //如有需要,编写代码 }; //断开连接回调事件 rdp.OnDisconnected += OnDisconnected; //登录远程桌面事件 rdp.OnLogonError += delegate (object _, IMsTscAxEvents_OnLogonErrorEvent e) { if (e.lError != -2) { //如有需要 this.Close(); } }; //远程桌面发生致命错误事件 rdp.OnFatalError += delegate (object _, IMsTscAxEvents_OnFatalErrorEvent e) { //如有需要 this.Close(); }; //连接 rdp.Connect(); }另外,发现了注销远程桌面的函数,原来并不是没有方法,只是我没有仔细查阅官方文档 private void Window_Closed(object sender, EventArgs e) { if (WTSGetChildSessionId(out var SessionId) && !WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, SessionId, bWait: true)) { Trace.TraceError($"注销子会话 {SessionId},失败,错误信息: {Marshal.GetLastWin32Error()}"); } }然后打包在同事的电脑和虚拟机上测试,问题解决。 2022/1/19 今天发现了一个新的问题,专业版电脑上调用WTSEnableChildSessions失败,返回了False,解决此问题需要用管理员权限启用程序,再次打开子会话界面即可解决。 另外调用WTSEnableChildSessions之前应该判断功能是否已经开启,代码如下。 /// /// 判断是否已经打开了画中画功能 /// /// public static bool IsChildSessionEnabled() { try { WTSIsChildSessionsEnabled(out var isEnabled); return isEnabled; } catch (Exception innerException) { throw new InvalidOperationException(innerException.Message); } }应该先调用WTSIsChildSessionsEnabled,如果没有开启子会话功能,再去调用WTSEnableChildSessions。 |
CopyRight 2018-2019 实验室设备网 版权所有 |