【问题标题】:Create a Windows Session from a service via the Win32 API通过 Win32 API 从服务创建 Windows 会话
【发布时间】:2012-12-21 08:08:22
【问题描述】:

我有一个 Windows 服务,可以通过调用“CreateProcessAsUser”函​​数在用户 Windows 会话中创建可执行文件。只要那里已经有一个 Windows 会话,它就可以正常工作。如果还没有,我希望能够以编程方式创建一个。这是可能的吗?似乎找不到执行此操作的功能。

【问题讨论】:

    标签: windows winapi


    【解决方案1】:

    这不是我提出的问题的完全解决方案,但如果您明白我的意思,那么通过提出这个问题来帮助实现我想要实现的目标的解决方案。

    您可以将 Windows 配置为在启动时自动登录,而不是让 Windows 服务创建服务器会话。这仍然意味着有人可能会意外注销,但可以解决会话消失的主要原因:服务器正在重新启动。使用以下步骤激活自动登录:

    1. 按键盘上的 Windows 键 + R 以启动“运行”对话框。
    2. 输入 regedit 并回车以打开注册表编辑器
    3. 然后浏览到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\
    4. 设置 AutoAdminLogon = 1(如果它的字符串变量不存在则创建它)
    5. 设置 DefaultUserName = 您的用户名(如果不存在它的字符串变量,则创建它)
    6. 设置 DefaultPassword = 您的密码(如果不存在它的字符串变量,则创建它)

    说明取自这篇文章: http://channel9.msdn.com/Blogs/coolstuff/Tip-Auto-Login-Your-Windows-7-User-Account

    【讨论】:

      【解决方案2】:

      您不能从服务创建新会话。会话由操作系统管理。当用户以交互方式登录时会创建新的。

      【讨论】:

      • 您可以在调用CreateProcessAsUser()之前使用WTS API,例如WTSGetActiveSessionId()WTSEnumerateSessions()来确定用户会话是否存在。
      • 备案:Windows Server 2012 支持远程桌面协议提供程序 API,您可以使用它以编程方式创建会话。此外,至少在理论上,您可以编写自己的远程桌面客户端(或修改其中一个开源客户端)以在任何受支持的 Windows 版本上创建新会话 - 当然前提是启用了远程桌面。
      • @RemyLebeau 这是我已经在做的,我正在努力避免会话意外关闭的问题。
      • @HarryJohnston 谢谢,这听起来像是解决方案,但不得不承认我希望有更简单的东西。
      • @Robert:你和我都是。如果您确实设法获得了一个可行的解决方案,并且能够分享它,您能告诉我吗? (我的个人资料包括我的电子邮件地址。)
      【解决方案3】:

      【讨论】:

      • 不幸的是,“会话”在 Windows 中是一个重载的术语。在这种情况下,我认为 OP 是在谈论远程桌面(又名 Windows 终端服务)会话而不是登录会话。罗伯特,你能澄清一下吗?
      • 我不确定我是否理解这里的区别,它本身不需要是远程桌面会话,但它确实需要一个 sessionid > 0 以便它可以执行程序一个gui。
      • 远程桌面服务是 Windows 的一部分,它允许用户切换和会话零隔离,以及实际的远程桌面连接。您肯定在这里谈论远程桌面会话 ID,因此 LogonUser 不会解决您的问题。
      【解决方案4】:

      @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);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-10
        • 2010-09-20
        • 1970-01-01
        • 2021-09-19
        • 1970-01-01
        相关资源
        最近更新 更多