Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WTSEnumerateSessions挂起且永远不会返回_C#_Windows_Session_Service - Fatal编程技术网

C# WTSEnumerateSessions挂起且永远不会返回

C# WTSEnumerateSessions挂起且永远不会返回,c#,windows,session,service,C#,Windows,Session,Service,我有一个用c#编写的.Net服务。我正在pInvokingWTSEnumeratessions。会话检查由计时器每15分钟运行一次,它列出所有会话,并将用户名/域组合与预定义的用户集进行比较,以确定他们是否登录到服务器 问题在于有几个服务器对wtsenumeratessions的调用无限期挂起。它可以正常工作几次,然后突然停止,导致服务变得无响应 下面是我用来枚举会话的代码 [DllImport("wtsapi32.dll")] static extern IntPtr WTSOpenServe

我有一个用c#编写的.Net服务。我正在pInvoking
WTSEnumeratessions
。会话检查由计时器每15分钟运行一次,它列出所有会话,并将用户名/域组合与预定义的用户集进行比较,以确定他们是否登录到服务器

问题在于有几个服务器对
wtsenumeratessions
的调用无限期挂起。它可以正常工作几次,然后突然停止,导致服务变得无响应

下面是我用来枚举会话的代码

[DllImport("wtsapi32.dll")]
static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

[DllImport("wtsapi32.dll")]
static extern void WTSCloseServer(IntPtr hServer);

[DllImport("wtsapi32.dll")]
static extern Int32 WTSEnumerateSessions(
       IntPtr hServer,
       [MarshalAs(UnmanagedType.U4)] Int32 Reserved,
       [MarshalAs(UnmanagedType.U4)] Int32 Version,
       ref IntPtr ppSessionInfo,
       [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);

 [DllImport("wtsapi32.dll")]
 static extern void WTSFreeMemory(IntPtr pMemory);

 [DllImport("Wtsapi32.dll")]
 static extern bool WTSQuerySessionInformation(
        System.IntPtr hServer,
        int sessionId, 
        WTS_INFO_CLASS wtsInfoClass, 
        out System.IntPtr ppBuffer, 
        out uint pBytesReturned);

 [StructLayout(LayoutKind.Sequential)]
 private struct WTS_SESSION_INFO
 {
      public Int32 SessionID;

      [MarshalAs(UnmanagedType.LPStr)]
      public String pWinStationName;

      public WTS_CONNECTSTATE_CLASS State;
 }

 public enum WTS_INFO_CLASS
 {
      WTSInitialProgram,
      WTSApplicationName,
      WTSWorkingDirectory,
      WTSOEMId,
      WTSSessionId,
      WTSUserName,
      WTSWinStationName,
      WTSDomainName,
      WTSConnectState,
      WTSClientBuildNumber,
      WTSClientName,
      WTSClientDirectory,
      WTSClientProductId,
      WTSClientHardwareId,
      WTSClientAddress,
      WTSClientDisplay,
      WTSClientProtocolType
 }

 public enum WTS_CONNECTSTATE_CLASS
 {
      WTSActive,
      WTSConnected,
      WTSConnectQuery,
      WTSShadow,
      WTSDisconnected,
      WTSIdle,
      WTSListen,
      WTSReset,
      WTSDown,
      WTSInit
  }

 private void ListUsers_Elapsed()
 {
      IntPtr serverHandle = IntPtr.Zero;
      List<String> resultList = new List<string>();
      serverHandle = WTSOpenServer("");

      try
      {
        IntPtr SessionInfoPtr = IntPtr.Zero;
        IntPtr userPtr = IntPtr.Zero;
        IntPtr domainPtr = IntPtr.Zero;
        Int32 sessionCount = 0;
        Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref                     sessionCount);
        Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
        Int32 currentSession = (int)SessionInfoPtr;
        uint bytes = 0;

        if (retVal != 0)
        {
          for (int i = 0; i < sessionCount; i++)
          {
            WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO));
            currentSession += dataSize;

            WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes);
            WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes);

            //Then I compare the session information against a list of users to determine if they are still active

            WTSFreeMemory(userPtr); 
            WTSFreeMemory(domainPtr);
          }

          WTSFreeMemory(SessionInfoPtr);
        }
      }
      finally
      {
        CloseServer(serverHandle);
      }

    }
有人能解释一下为什么它会被挂起来,以及是否有更好的方法。我之所以依赖计时器而不是注册
OnSessionChange
事件,是因为过去我发现后者不可靠,因为它有时会触发虚假事件,或者在发生会话更改时根本不会触发

正如我所说的,除了几个服务器外,这在大多数服务器上都可以正常工作。即使对于那些受问题影响的人,它也会在计时器触发经过的事件4或5次后工作,然后它只挂起下一个引发的经过的事件,之后的每个连续经过的事件也是如此

另外,所有受影响的服务器都安装了Windows Server 2008 R2

编辑:

好吧,我发现了一些很奇怪的东西。我设法让WTSEnumerateSessions不用绞刑就能工作。问题是我所做的没有真正意义,在我的生活中,我不知道该怎么做才能阻止绞刑

下面是我所做的,出于沮丧,我正在寻找其他方法来获取会话列表。其中一种方法是使用
LsaEnumerateLogonSessions
来获取会话列表,而不是
WTSEnumerateSessions
。因此,我在调用
wtsenumeratessions
之前调用了以下函数

public static List<string> PopulateSessionsList()
        {
            var outList = new List<string>();
            System.Security.Principal.WindowsIdentity currentUser = System.Security.Principal.WindowsIdentity.GetCurrent();

            DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate

            UInt64 count;
            IntPtr luidPtr = IntPtr.Zero;
            CommonWin32.LsaEnumerateLogonSessions(out count, out luidPtr);  //gets an array of pointers to LUIDs

            IntPtr iter = luidPtr;      //set the pointer to the start of the array

            for (ulong i = 0; i < count; i++)   //for each pointer in the array
            {
                IntPtr sessionData;

                CommonWin32.LsaGetLogonSessionData(iter, out sessionData);
                CommonWin32.SECURITY_LOGON_SESSION_DATA data = (CommonWin32.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(CommonWin32.SECURITY_LOGON_SESSION_DATA));

                //if we have a valid logon
                if (data.PSiD != IntPtr.Zero)
                {
                    //get the security identifier for further use
                    System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD);

                    //extract some useful information from the session data struct
                    var ptrToStringUni = Marshal.PtrToStringUni(data.Username.buffer);
                    if (ptrToStringUni != null)
                    {
                        string username = ptrToStringUni.Trim();          //get the account username
                        var toStringUni = Marshal.PtrToStringUni(data.LoginDomain.buffer);
                        if (toStringUni != null)
                        {
                            string domain = toStringUni.Trim();        //domain for this account  
                            var stringUni = Marshal.PtrToStringUni(data.AuthenticationPackage.buffer);
                            if (stringUni != null)
                            {
                                string authpackage = stringUni.Trim();    //authentication package
                            }
                            string session = data.Session.ToString();
                            CommonWin32.SECURITY_LOGON_TYPE secType = (CommonWin32.SECURITY_LOGON_TYPE)data.LogonType;
                            DateTime time = systime.AddTicks((long)data.LoginTime);                              //get the datetime the session was logged in

                            outList.Add("Session: " + session + " User: " + username + " *** Domain: " + domain + " *** Login Type: (" + data.LogonType + ") " + secType.ToString() + " *** Login Time: " + time.ToLocalTime().ToString());
                        }
                    }
                }
                iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(CommonWin32.LUID)));  //move the pointer forward
                CommonWin32.LsaFreeReturnBuffer(sessionData);   //free the SECURITY_LOGON_SESSION_DATA memory in the struct
            }
            CommonWin32.LsaFreeReturnBuffer(luidPtr);   //free the array of LUIDs

            return outList;
        }
令我惊讶的是,打电话就停止了悬而未决的问题。我不知道它为什么那样做。不确定它是否调用某个内部/私有方法

在不调用新方法的情况下,只要连续调用不到10次,罪犯就会被绞死,我在几台机器上尝试的每次测试都是这样。添加代码后,它就可以正常工作了。不管你在一分钟内调用
wtsenumeratessions
1000次,它都不会挂断。一次也没有


有人能告诉我为什么调用
LsaEnumerateLogonSessions
LsaGetLogonSessionData
会神奇地停止挂起。有关于这些函数在内部执行什么操作的信息吗

WaitForLsmStart的谷歌点击率非常低。只有两个,其中一个描述了您的确切问题和解决方法。@HansPassant我看到了两个答案,一个是Firefox崩溃,另一个是打印机更新问题,我相信。它们都没有提供任何真正的解决办法。我不能要求用户不安装更新。我需要一个真正的解决办法。除了微软,你不会从任何人那里得到“真正的解决办法”。如果你不愿意打电话给他们,那么就把你的发现告诉你的客户。他们可以自己决定如何继续。@HansPassant最近,我能够在我的计算机上重现这个问题,并且我已经卸载了有问题的知识库。所以可能还有别的原因。这是隐私问题还是安全问题?我尝试了很多方法,但似乎都没有效果。@HansPassant我用一个新发现更新了我的问题,这是我在试图找到阻止我的服务挂起的方法时意外发现的。你知道为什么在调用
wtsenumeratessions
之前调用新方法会神奇地阻止后者挂起吗?
public static List<string> PopulateSessionsList()
        {
            var outList = new List<string>();
            System.Security.Principal.WindowsIdentity currentUser = System.Security.Principal.WindowsIdentity.GetCurrent();

            DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate

            UInt64 count;
            IntPtr luidPtr = IntPtr.Zero;
            CommonWin32.LsaEnumerateLogonSessions(out count, out luidPtr);  //gets an array of pointers to LUIDs

            IntPtr iter = luidPtr;      //set the pointer to the start of the array

            for (ulong i = 0; i < count; i++)   //for each pointer in the array
            {
                IntPtr sessionData;

                CommonWin32.LsaGetLogonSessionData(iter, out sessionData);
                CommonWin32.SECURITY_LOGON_SESSION_DATA data = (CommonWin32.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(CommonWin32.SECURITY_LOGON_SESSION_DATA));

                //if we have a valid logon
                if (data.PSiD != IntPtr.Zero)
                {
                    //get the security identifier for further use
                    System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD);

                    //extract some useful information from the session data struct
                    var ptrToStringUni = Marshal.PtrToStringUni(data.Username.buffer);
                    if (ptrToStringUni != null)
                    {
                        string username = ptrToStringUni.Trim();          //get the account username
                        var toStringUni = Marshal.PtrToStringUni(data.LoginDomain.buffer);
                        if (toStringUni != null)
                        {
                            string domain = toStringUni.Trim();        //domain for this account  
                            var stringUni = Marshal.PtrToStringUni(data.AuthenticationPackage.buffer);
                            if (stringUni != null)
                            {
                                string authpackage = stringUni.Trim();    //authentication package
                            }
                            string session = data.Session.ToString();
                            CommonWin32.SECURITY_LOGON_TYPE secType = (CommonWin32.SECURITY_LOGON_TYPE)data.LogonType;
                            DateTime time = systime.AddTicks((long)data.LoginTime);                              //get the datetime the session was logged in

                            outList.Add("Session: " + session + " User: " + username + " *** Domain: " + domain + " *** Login Type: (" + data.LogonType + ") " + secType.ToString() + " *** Login Time: " + time.ToLocalTime().ToString());
                        }
                    }
                }
                iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(CommonWin32.LUID)));  //move the pointer forward
                CommonWin32.LsaFreeReturnBuffer(sessionData);   //free the SECURITY_LOGON_SESSION_DATA memory in the struct
            }
            CommonWin32.LsaFreeReturnBuffer(luidPtr);   //free the array of LUIDs

            return outList;
        }
[DllImport("secur32.dll", SetLastError = false)]
public static extern uint LsaFreeReturnBuffer(IntPtr buffer);

[DllImport("Secur32.dll", SetLastError = false)]
public static extern uint LsaEnumerateLogonSessions(out UInt64 LogonSessionCount, out IntPtr LogonSessionList);

[DllImport("Secur32.dll", SetLastError = false)]
public static extern uint LsaGetLogonSessionData(IntPtr luid, out IntPtr ppLogonSessionData);