【问题标题】:c# - How to get active session/user on local machine (Windows 10)c# - 如何在本地机器上获取活动会话/用户(Windows 10)
【发布时间】:2020-03-23 14:15:28
【问题描述】:

Windows 10 在启动时自动登录多个(本地)用户和程序。 所以我可能有一些“幽灵”用户登录一次,此时只有 1 个用户“活跃”

我需要在我的应用程序中识别用户是否真正处于活动状态(在会话中工作),而不仅仅是 Windows 在后台登录。

在 .NET 中有什么方法可以做到这一点吗? (来自非管理员帐户) 谷歌了很多,但数找到可靠的东西

附言。我发现 cmd 行命令 (qwinsta) 似乎在做我需要的事情 - 但我不知道如何从 C# 代码运行它并读取输出 (我正在接收未找到的 qwinsta)

请指教...

* 编辑 *

澄清:我不需要找到活动用户名(这很容易) 我希望获取有关本地计算机上所有会话的信息并检查哪些当前处于活动状态(请参见下面的命令行输出 qwinsta.exe)。

想象一下,所有本地用户都在启动我的应用程序 - 应用程序需要做某事,但只有当用户已解锁会话时,此时正在计算机前做某事(我个人不会通过这种 Windows-10 机制自动登录讨厌...)

qwinsta.exe 将为我完成工作,但如果我从 .NET 启动此过程,它总是说找不到 qwinsta.exe。即使我给出完整路径: c:\Windows\system32\qwinsta.exe

 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
>console           carl                    1  Active
 rdp-tcp                                 65536  Listen

【问题讨论】:

  • 你能分享一些代码吗?
  • stackoverflow.com/questions/2017705/… 可能与您的要求有关...一些很好的说明您的意思是“活跃”会很好...
  • 旁注:如果您对bing.com/search?q=c%23+process+start+read+output 上的现有答案有疑问,您应该发布需要minimal reproducible example 的调试问题...
  • 如果您有一个 32 位应用程序在 WOW64 下的 64 位 Windows 中运行,则路径为“%SystemRoot%\SysNative\qwinsta.exe”。你应该知道在WOW64下运行时访问“System32”目录会重定向到“SysWOW64”。在这种情况下,您首先应该检查的是,您想要的文件是否实际上是作为“SysWOW64”中的 32 位程序分发的,方法是从 64 位进程(如 Explorer 或 CMD)检查它。您会发现它仅作为本机 64 位二进制文​​件分发,位于真正的“System32”目录中。这可以在 WOW64 下作为“SysNative”访问。

标签: c# windows session-state


【解决方案1】:

对于系统级应用程序

    [DllImport("Wtsapi32.dll")]
    public static extern bool WTSQuerySessionInformationW(
          IntPtr hServer,
          int SessionId,
          int WTSInfoClass,
          out IntPtr ppBuffer,
          out IntPtr pBytesReturned);

public static void AddArray<xArray>(ref xArray[] array, dynamic deger)
    {
        try
        {
            int diziboyu;
            if (array == null)
            {
                diziboyu = 0;
            }
            else
                diziboyu = array.Length;
            diziboyu++;
            System.Array.Resize(ref array, diziboyu);
            array[diziboyu - 1] = deger;
        }
        catch (Exception)
        {

        }
    }

public static string[] Online_userNames = null;

Process[] pname = Process.GetProcessesByName("explorer");
foreach (Process proc in pname)
            {
                IntPtr AnswerBytes;
                IntPtr AnswerCount;
                WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE,
                                                    proc.SessionId,
                                                    WTS_UserName,
                                                    out AnswerBytes,
                                                    out AnswerCount);

                AddArray(ref Online_userNames, Marshal.PtrToStringUni(AnswerBytes));
            }

            pname = null;

【讨论】:

    【解决方案2】:

    这是我的代码示例。我正在编写代码以使用 x86 进程而不是 x64,因为 W10 是 x64。

    IntPtr ptr = new IntPtr();
    Wow64DisableWow64FsRedirection(ref ptr);
    var p = Process.Start(
             new ProcessStartInfo("qwinsta", $"/server:")
             {
                 CreateNoWindow = true,
                 UseShellExecute = false,
                 RedirectStandardError = true,
                 RedirectStandardOutput = true,
                 WorkingDirectory = Environment.CurrentDirectory
             }
         );
    
    p.WaitForExit();
    string output = p.StandardOutput.ReadToEnd().TrimEnd();
    string errorInfoIfAny = p.StandardError.ReadToEnd().TrimEnd();
    
    Wow64RevertWow64FsRedirection(ptr);
    

    添加这两种导入方法。

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
    

    【讨论】:

      【解决方案3】:

      有一个更好的解决方案,它使用了 qwinsta 可能使用的 winapi。
      我不能将实施归功于 - 这是 github 链接:
      https://github.com/murrayju/CreateProcessAsUser

      这样做是使用 winapi 枚举机器中的所有会话。对于每个会话,它都会调用另一个 winapi,以获取有关此会话的详细信息,这就是您获取此会话是否处于活动状态的指示的方式。

      看看我链接的那个项目,它是一个更好的解决方案,可以解析不同应用程序的输出

      【讨论】:

      • 获取活动会话并从中获取用户名的更短方法是调用“WTSGetActiveConsoleSessionId”,它也在我链接的项目中。
      【解决方案4】:

      这是我的代码示例,它终于可以工作了(感谢 @Eryk Sun)——也许有人会觉得它有用。 PS。正确指出 - 我可能应该提到我的应用是 x86 但 W10 是 x64 ...

      public static bool IsUserActive(string userName) {
          Process p = new Process();
          p.StartInfo.UseShellExecute         = false;
          p.StartInfo.RedirectStandardOutput  = true;
          p.StartInfo.FileName                =  "c:\\Windows\\SysNative\\qwinsta.exe";
          p.StartInfo.Arguments               = userName;
          p.Start();
          string output = p.StandardOutput.ReadToEnd();
          p.WaitForExit();
      
          return output.Contains("  Active");
      }
      

      【讨论】:

        【解决方案5】:

        在 c# 中我使用这个

        private string MyUser = System.Environment.UserName;
        

        【讨论】:

        • 抱歉,我不需要获取当前用户名...正如我之前写的那样,我希望获取所有用户名/会话并找到哪些是活动的
        【解决方案6】:

        使用这个。几年前我做过一次,效果很好。

        string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
        

        这里是原文post

        【讨论】:

        • 您能否说明当前用户名(始终存在)如何帮助确定用户是否“活跃”(无论 OP 是什么意思)?
        • 我想他想知道用户是否已登录并且是活跃的 - 我觉得登录是活跃的。这是来自 MS 的直接涂料:docs.microsoft.com/en-us/dotnet/api/…
        • 抱歉,我不需要获取当前用户名...正如我之前写的,我希望获取所有用户名/会话并找到哪些是活动的
        猜你喜欢
        • 1970-01-01
        • 2023-03-30
        • 2015-12-28
        • 2016-06-29
        • 1970-01-01
        • 1970-01-01
        • 2019-08-26
        • 1970-01-01
        • 2017-02-27
        相关资源
        最近更新 更多