C# 使用远程桌面连接本机 您所在的位置:网站首页 利用电脑本机远程控制 C# 使用远程桌面连接本机

C# 使用远程桌面连接本机

2023-08-08 15:08| 来源: 网络整理| 查看: 265

前言

最近由于项目需求,需要实现 远程桌面连接当前本机(自己连接自己) 当程序完成操作之后,注销远程桌面(确保每次打开的,都是新的桌面)

注意事项: 此功能只能在专业版系统上使用,我测试过家庭版、教育版等,均不能连接上远程桌面

白屏问题

最近看到不少朋友都反馈有白屏问题,请检查:

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 实验室设备网 版权所有