【发布时间】:2012-12-21 08:08:22
【问题描述】:
我有一个 Windows 服务,可以通过调用“CreateProcessAsUser”函数在用户 Windows 会话中创建可执行文件。只要那里已经有一个 Windows 会话,它就可以正常工作。如果还没有,我希望能够以编程方式创建一个。这是可能的吗?似乎找不到执行此操作的功能。
【问题讨论】:
我有一个 Windows 服务,可以通过调用“CreateProcessAsUser”函数在用户 Windows 会话中创建可执行文件。只要那里已经有一个 Windows 会话,它就可以正常工作。如果还没有,我希望能够以编程方式创建一个。这是可能的吗?似乎找不到执行此操作的功能。
【问题讨论】:
这不是我提出的问题的完全解决方案,但如果您明白我的意思,那么通过提出这个问题来帮助实现我想要实现的目标的解决方案。
您可以将 Windows 配置为在启动时自动登录,而不是让 Windows 服务创建服务器会话。这仍然意味着有人可能会意外注销,但可以解决会话消失的主要原因:服务器正在重新启动。使用以下步骤激活自动登录:
说明取自这篇文章: http://channel9.msdn.com/Blogs/coolstuff/Tip-Auto-Login-Your-Windows-7-User-Account
【讨论】:
您不能从服务创建新会话。会话由操作系统管理。当用户以交互方式登录时会创建新的。
【讨论】:
CreateProcessAsUser()之前使用WTS API,例如WTSGetActiveSessionId()和WTSEnumerateSessions()来确定用户会话是否存在。
LogonUser 函数呢?
【讨论】:
@Robert,我知道这是一个老问题,你已经找到了适合你的东西,但就我而言,我正在寻找与你原来的问题类似的东西,我终于弄明白了,所以我想我会分享。我的解决方案仅使用 .NET 和 COM 引用,而不是您标题中提到的 Win32 API,但我猜这对您来说并不是真正的要求。
我编写了一个简单的实用程序来使用远程桌面 ActiveX 控件(COM 参考)。如果将此代码粘贴到类库中,则只需传入服务器、用户名、域和密码即可调用它,一切都为您完成,无需任何其他交互。一旦方法完成,您就可以调用您的“CreateProcessAsUser”代码。我以某种方式编写了此实用程序,以便您每次都可以调用它,但启动 RDP 会话需要几秒钟,所以为了性能起见,我建议您编写另一种方法来枚举会话并查看您的用户是否已登录和仅当您确定您的用户未登录时才调用此实用程序(这就是我在实际项目中所做的)。如果您觉得在 cmets 中的该帖子需要帮助,我将分享我是如何做到的,但这并不是这个问题的一部分,所以现在我将其排除在外。
这是我的问题的链接,它比这个问题有更多的要求/细节。
Create Windows Session programmatically from Console or Windows Service
这是我的 RDP 实用程序。将此代码放入类库后,您可以从控制台应用程序、winForms 应用程序或运行在同一台计算机或远程计算机上的 Windows 服务调用它。
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);
}
}
}
【讨论】: