我有一个 Windows 服务,可以通过调用“CreateProcessAsUser”函数在用户 Windows 会话中创建可执行文件。只要那里已经有一个 Windows 会话,它就可以正常工作。如果还没有,我希望能够以编程方式创建一个。这是可能的吗?似乎无法找到执行此操作的功能。
4 回答
这不是我提出的问题的完全解决方案,但是如果您明白我的意思,那么通过提出这个问题来帮助实现我想要实现的目标的解决方案。
您可以将 Windows 配置为在启动时自动登录,而不是让 Windows 服务创建服务器会话。这仍然意味着有人可能会意外注销,但可以解决会话消失的主要原因:服务器正在重新启动。使用以下步骤激活自动登录:
- 按键盘上的 Windows 键 + R 启动“运行”对话框。
- 输入 regedit 并按回车键打开注册表编辑器
- 然后浏览到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\
- 设置 AutoAdminLogon = 1 (如果不存在它的字符串变量,则创建它)
- 设置 DefaultUserName = 你的用户名(如果不存在它的字符串变量,则创建它)
- 设置 DefaultPassword = 你的密码(如果不存在它的字符串变量,则创建它)
说明取自这篇文章: http ://channel9.msdn.com/Blogs/coolstuff/Tip-Auto-Login-Your-Windows-7-User-Account
您不能从服务创建新会话。会话由操作系统管理。当用户以交互方式登录时会创建新的。
LogonUser 函数呢?
@Robert,我知道这是一个老问题,你已经找到了适合你的东西,但就我而言,我正在寻找与你原来的问题类似的东西,我终于弄明白了,所以我想我会分享. 我的解决方案仅使用 .NET 和 COM 引用,而不是您标题中提到的 Win32 API,但我猜这对您来说并不是真正的要求。
我编写了一个简单的实用程序来使用远程桌面 ActiveX 控件(COM 参考)。如果您将此代码粘贴到类库中,您可以通过简单地传递服务器、用户名、域和密码来调用它,并且一切都为您完成,无需任何其他交互。一旦方法完成,您就可以调用您的“CreateProcessAsUser”代码。我以某种方式编写了此实用程序,以便您每次都可以调用它,但启动 RDP 会话需要几秒钟,所以为了性能起见,我建议您编写另一种方法来枚举会话并查看您的用户是否已登录和仅当您确定您的用户未登录时才调用此实用程序(这就是我在实际项目中所做的)。如果你觉得你在评论中的那篇文章需要帮助,我
这是一个返回我的问题的链接,它比这个问题有更多的要求/细节。
从控制台或 Windows 服务以编程方式创建 Windows 会话
这是我的 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);
}
}
}