代码之家  ›  专栏  ›  技术社区  ›  Charles

通过win32检测多个登录用户

  •  2
  • Charles  · 技术社区  · 17 年前

    使用标准win32 api,检测多个用户登录的最佳方法是什么?我有一个升级到我们的软件产品,当多个用户登录时无法运行。(我知道这是一件需要避免的事情,因为它的麻烦因素,但是产品非常复杂。当我说真的没有其他解决方案时,你必须相信我。)谢谢。

    3 回复  |  直到 17 年前
        1
  •  4
  •   Roger Lipscombe    17 年前

    GetVersionEx 带着 OSVERSIONINFOEX

    如果启用了TS,则可以使用 WTSEnumerateSessions 以了解有多少用户登录。这仅在“终端服务”服务启动时有效。

    如果机器不支持终端服务(或服务未启动),则只能有一个用户登录。

        2
  •  3
  •   Mick    17 年前

    这是一个适用于XP、Server2003、Vista和Server2008的解决方案。注意,这在Windows 2000上不起作用,因为“ LsaEnumerateLogonSessions “在Windows 2000上不可用。此代码是从 Delphi-PRAXIS post

    要编译它,请在表单上创建一个新的VCL应用程序,其中包含一个TButton和一个TMemo。然后复制并粘贴这段代码,它就可以编译了。我在XP和Vista上进行了测试,效果很好。它将返回交互式和远程用户。

    unit main;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    const
      WTS_CURRENT_SERVER_HANDLE = 0;
    
    type
      PTOKEN_USER = ^TOKEN_USER;
      _TOKEN_USER = record
        User: TSidAndAttributes;
      end;
      TOKEN_USER = _TOKEN_USER;
    
      USHORT = word;
    
      _LSA_UNICODE_STRING = record
        Length: USHORT;
        MaximumLength: USHORT;
        Buffer: LPWSTR;
      end;
      LSA_UNICODE_STRING = _LSA_UNICODE_STRING;
    
      PLuid = ^LUID;
      _LUID = record
        LowPart: DWORD;
        HighPart: LongInt;
      end;
      LUID = _LUID;
    
      _SECURITY_LOGON_TYPE = (
        seltFiller0, seltFiller1,
        Interactive,
        Network,
        Batch,
        Service,
        Proxy,
        Unlock,
        NetworkCleartext,
        NewCredentials,
        RemoteInteractive,
        CachedInteractive,
        CachedRemoteInteractive);
      SECURITY_LOGON_TYPE = _SECURITY_LOGON_TYPE;
    
      PSECURITY_LOGON_SESSION_DATA = ^SECURITY_LOGON_SESSION_DATA;
      _SECURITY_LOGON_SESSION_DATA = record
        Size: ULONG;
        LogonId: LUID;
        UserName: LSA_UNICODE_STRING;
        LogonDomain: LSA_UNICODE_STRING;
        AuthenticationPackage: LSA_UNICODE_STRING;
        LogonType: SECURITY_LOGON_TYPE;
        Session: ULONG;
        Sid: PSID;
        LogonTime: LARGE_INTEGER;
        LogonServer: LSA_UNICODE_STRING;
        DnsDomainName: LSA_UNICODE_STRING;
        Upn: LSA_UNICODE_STRING;
      end;
      SECURITY_LOGON_SESSION_DATA = _SECURITY_LOGON_SESSION_DATA;
    
      _WTS_INFO_CLASS = (
        WTSInitialProgram,
        WTSApplicationName,
        WTSWorkingDirectory,
        WTSOEMId,
        WTSSessionId,
        WTSUserName,
        WTSWinStationName,
        WTSDomainName,
        WTSConnectState,
        WTSClientBuildNumber,
        WTSClientName,
        WTSClientDirectory,
        WTSClientProductId,
        WTSClientHardwareId,
        WTSClientAddress,
        WTSClientDisplay,
        WTSClientProtocolType);
      WTS_INFO_CLASS = _WTS_INFO_CLASS;
    
      _WTS_CONNECTSTATE_CLASS = (
        WTSActive,              // User logged on to WinStation
        WTSConnected,           // WinStation connected to client
        WTSConnectQuery,        // In the process of connecting to client
        WTSShadow,              // Shadowing another WinStation
        WTSDisconnected,        // WinStation logged on without client
        WTSIdle,                // Waiting for client to connect
        WTSListen,              // WinStation is listening for connection
        WTSReset,               // WinStation is being reset
        WTSDown,                // WinStation is down due to error
        WTSInit);               // WinStation in initialization
      WTS_CONNECTSTATE_CLASS = _WTS_CONNECTSTATE_CLASS;
    
      function LsaFreeReturnBuffer(Buffer: pointer): Integer; stdcall;
    
      function WTSGetActiveConsoleSessionId: DWORD; external 'Kernel32.dll';
    
      function LsaGetLogonSessionData(LogonId: PLUID;
         var ppLogonSessionData: PSECURITY_LOGON_SESSION_DATA): LongInt; stdcall;
         external 'Secur32.dll';
    
      function LsaNtStatusToWinError(Status: cardinal): ULONG; stdcall;
         external 'Advapi32.dll';
    
      function LsaEnumerateLogonSessions(Count: PULONG; List: PLUID): LongInt;
         stdcall; external 'Secur32.dll';
    
      function WTSQuerySessionInformationA(hServer: THandle; SessionId: DWORD;
         WTSInfoClass: WTS_INFO_CLASS; var pBuffer: Pointer;
         var pBytesReturned: DWORD): BOOL; stdcall; external 'Wtsapi32.dll';
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    function LsaFreeReturnBuffer; external 'secur32.dll' name 'LsaFreeReturnBuffer';
    
    procedure GetActiveUserNames(var slUserList : TStringList);
    var
       Count: cardinal;
       List: PLUID;
       sessionData: PSECURITY_LOGON_SESSION_DATA;
       i1: integer;
       SizeNeeded, SizeNeeded2: DWORD;
       OwnerName, DomainName: PChar;
       OwnerType: SID_NAME_USE;
       pBuffer: Pointer;
       pBytesreturned: DWord;
       sUser : string;
    begin
       //result:= '';
       //Listing LogOnSessions
       i1:= lsaNtStatusToWinError(LsaEnumerateLogonSessions(@Count, @List));
       try
          if i1 = 0 then
          begin
              i1:= -1;
              if Count > 0 then
              begin
                  repeat
                    inc(i1);
                    LsaGetLogonSessionData(List, sessionData);
                    //Checks if it is an interactive session
                    sUser := sessionData.UserName.Buffer;
                    if (sessionData.LogonType = Interactive)
                      or (sessionData.LogonType = RemoteInteractive)
                      or (sessionData.LogonType = CachedInteractive)
                      or (sessionData.LogonType = CachedRemoteInteractive) then
                    begin
                        //
                        SizeNeeded := MAX_PATH;
                        SizeNeeded2:= MAX_PATH;
                        GetMem(OwnerName, MAX_PATH);
                        GetMem(DomainName, MAX_PATH);
                        try
                        if LookupAccountSID(nil, sessionData.SID, OwnerName,
                                           SizeNeeded, DomainName,SizeNeeded2,
                                           OwnerType) then
                        begin
                          if OwnerType = 1 then  //This is a USER account SID (SidTypeUser=1)
                          begin
                            sUser := AnsiUpperCase(sessionData.LogonDomain.Buffer);
                            sUser := sUser + '\';
                            sUser := sUser + AnsiUpperCase(sessionData.UserName.Buffer);
                            slUserList.Add(sUser);
    //                          if sessionData.Session = WTSGetActiveConsoleSessionId then
    //                          begin
    //                            //Wenn Benutzer aktiv
    //                            try
    //                                if WTSQuerySessionInformationA
    //                                   (WTS_CURRENT_SERVER_HANDLE,
    //                                    sessionData.Session, WTSConnectState,
    //                                    pBuffer,
    //                                    pBytesreturned) then
    //                                begin
    //                                    if WTS_CONNECTSTATE_CLASS(pBuffer^) = WTSActive then
    //                                    begin
    //                                      //result:= sessionData.UserName.Buffer;
    //                                      slUserList.Add(sessionData.UserName.Buffer);
    //                                    end;
    //                                end;
    //                            finally
    //                              LSAFreeReturnBuffer(pBuffer);
    //                            end;
                              //end;
                          end;
                        end;
                        finally
                        FreeMem(OwnerName);
                        FreeMem(DomainName);
                        end;
                    end;
                    inc(List);
                    try
                        LSAFreeReturnBuffer(sessionData);
                    except
                    end;
                until (i1 = Count-1);// or (result <> '');
              end;
          end;
       finally
          LSAFreeReturnBuffer(List);
       end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      slUsers : TStringList;
    begin
      slUsers := TStringList.Create;
      slUsers.Duplicates := dupIgnore;
      slUsers.Sorted := True;
    
      try
        GetActiveUserNames(slUsers);
        Memo1.Lines.AddStrings(slUsers);
      finally
        FreeAndNil(slUsers)
      end;
    end;
    
    end.
    
        3
  •  0
  •   Ana Betts    17 年前

    这可能是一种迂回的方式,但请仔细查看流程列表,看看流程所有者是谁。