从控制台或 Windows 服务以编程方式创建 Windows 会话
Create Windows Session programmatically from Console or Windows Service
如何以编程方式登录 windows 以创建 Windows 登录会话?
我需要一种适用于 WinForms 应用程序、控制台应用程序和(最重要的)Windows 服务的方法。
另一个要求是我需要它在 program/service 是 运行 的本地系统上工作,也需要它在远程系统上工作。
如果有办法使用 pInvoke/Win32 API 我也愿意。
我在研究中发现了这些相似的questions/answers:
Programmatically create and launch and RDP session (without gui)
这里的答案说这是可能的,但给出了 link 但是 link 中的示例代码不起作用
Create a Windows Session from a service via the Win32 API
所问问题无解
Create Windows session programmatically
没有解决方案,但 OP 在评论中提到 http://freerdp.com 对他有用。
我创建了一个简单的实用程序,我相信它可以满足问题中的所有要求。您需要添加对 Microsoft 终端服务活动客户端 1.0 类型库 (ActiveX) 的 COM 引用。
我认为它可能无法在本地计算机上创建会话,但我在 2012R2 运行 作为服务进行了测试,它实际上可以。可以从 WinForms 应用程序或控制台应用程序调用完全相同的方法。从 WinForms 或控制台应用程序启动时,表单会显示几秒钟,因此我确保将控件设置为 enabled = false,这样它就无法与之交互。
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
namespace Utility.RemoteDesktop
{
public class Client
{
private int LogonErrorCode { get; set; }
public void CreateRdpConnection(string server, string user, string domain, string password)
{
void ProcessTaskThread()
{
var form = new Form();
form.Load += (sender, args) =>
{
var rdpConnection = new AxMSTSCLib.AxMsRdpClient9NotSafeForScripting();
form.Controls.Add(rdpConnection);
rdpConnection.Server = server;
rdpConnection.Domain = domain;
rdpConnection.UserName = user;
rdpConnection.AdvancedSettings9.ClearTextPassword = password;
rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
if (true)
{
rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
}
rdpConnection.Connect();
rdpConnection.Enabled = false;
rdpConnection.Dock = DockStyle.Fill;
Application.Run(form);
};
form.Show();
}
var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
rdpClientThread.SetApartmentState(ApartmentState.STA);
rdpClientThread.Start();
while (rdpClientThread.IsAlive)
{
Task.Delay(500).GetAwaiter().GetResult();
}
}
private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
{
LogonErrorCode = e.lError;
}
private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
{
if (LogonErrorCode == -2)
{
Debug.WriteLine($" ## New Session Detected ##");
Task.Delay(10000).GetAwaiter().GetResult();
}
var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
rdpSession.Disconnect();
}
private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
Environment.Exit(0);
}
}
}
在旁注中,我发现这个问题说可能有一种方法可以在根本不使用 windows 表单的情况下使用 ActiveX 控件(用于 RDP)。我看到了他们给出的例子,但我不确定是否可以在这种情况下使用他们的代码。
ActiveX control without a form
如果有人知道如何在不在表单上托管 ActiveX 控件的情况下执行此操作,请post举个例子。
如何以编程方式登录 windows 以创建 Windows 登录会话? 我需要一种适用于 WinForms 应用程序、控制台应用程序和(最重要的)Windows 服务的方法。
另一个要求是我需要它在 program/service 是 运行 的本地系统上工作,也需要它在远程系统上工作。
如果有办法使用 pInvoke/Win32 API 我也愿意。
我在研究中发现了这些相似的questions/answers:
Programmatically create and launch and RDP session (without gui)
这里的答案说这是可能的,但给出了 link 但是 link 中的示例代码不起作用
Create a Windows Session from a service via the Win32 API
所问问题无解
Create Windows session programmatically
没有解决方案,但 OP 在评论中提到 http://freerdp.com 对他有用。
我创建了一个简单的实用程序,我相信它可以满足问题中的所有要求。您需要添加对 Microsoft 终端服务活动客户端 1.0 类型库 (ActiveX) 的 COM 引用。
我认为它可能无法在本地计算机上创建会话,但我在 2012R2 运行 作为服务进行了测试,它实际上可以。可以从 WinForms 应用程序或控制台应用程序调用完全相同的方法。从 WinForms 或控制台应用程序启动时,表单会显示几秒钟,因此我确保将控件设置为 enabled = false,这样它就无法与之交互。
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
namespace Utility.RemoteDesktop
{
public class Client
{
private int LogonErrorCode { get; set; }
public void CreateRdpConnection(string server, string user, string domain, string password)
{
void ProcessTaskThread()
{
var form = new Form();
form.Load += (sender, args) =>
{
var rdpConnection = new AxMSTSCLib.AxMsRdpClient9NotSafeForScripting();
form.Controls.Add(rdpConnection);
rdpConnection.Server = server;
rdpConnection.Domain = domain;
rdpConnection.UserName = user;
rdpConnection.AdvancedSettings9.ClearTextPassword = password;
rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
if (true)
{
rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
}
rdpConnection.Connect();
rdpConnection.Enabled = false;
rdpConnection.Dock = DockStyle.Fill;
Application.Run(form);
};
form.Show();
}
var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
rdpClientThread.SetApartmentState(ApartmentState.STA);
rdpClientThread.Start();
while (rdpClientThread.IsAlive)
{
Task.Delay(500).GetAwaiter().GetResult();
}
}
private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
{
LogonErrorCode = e.lError;
}
private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
{
if (LogonErrorCode == -2)
{
Debug.WriteLine($" ## New Session Detected ##");
Task.Delay(10000).GetAwaiter().GetResult();
}
var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
rdpSession.Disconnect();
}
private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
Environment.Exit(0);
}
}
}
在旁注中,我发现这个问题说可能有一种方法可以在根本不使用 windows 表单的情况下使用 ActiveX 控件(用于 RDP)。我看到了他们给出的例子,但我不确定是否可以在这种情况下使用他们的代码。
ActiveX control without a form
如果有人知道如何在不在表单上托管 ActiveX 控件的情况下执行此操作,请post举个例子。