2008-12-15 45 views
2

使用標準win32 api,檢測多個用戶的最佳方法是登錄?我有一個升級到我們的軟件產品,當多個用戶登錄時無法運行。(我知道這是因爲惱人的因素需要避免的,但是產品非常複雜,您必須相信我,當我說真的沒有其他解決方案時。)謝謝。通過win32檢測多個登錄用戶

+0

那麼,我認爲你希望這可以在Windows 2000,XP,Vista和Windows 7上工作。你有興趣知道人們是否通過終端服務登錄? – Mick 2008-12-15 15:41:06

回答

3

爲了讓多個用戶立即登錄,必須啓用終端服務或快速用戶切換。由於使用終端服務實現了快速用戶切換,因此首先需要確定操作系統是否啓用了該功能。您可以使用GetVersionExOSVERSIONINFOEX。檢查VER_SUITE_SINGLEUSERTS和VER_SUITE_TERMINAL標誌。

如果啓用了TS,則可以使用WTSEnumerateSessions來確定有多少用戶已登錄。這僅在「終端服務」服務啓動時纔有效。

如果機器不支持終端服務(或者服務未啓動),那麼您只能有一個用戶登錄。

+0

這是不正確的,通過快速用戶切換,> 1個用戶可以同時運行進程。 – 2008-12-15 16:08:41

+0

@Paul Betts:如果您使用快速用戶切換,則WTSEnumerateSessions將返回所有當前登錄的會話,無論它們是否處於活動狀態。 – 2008-12-15 16:10:09

0

這可能是一種迂迴的方式,但是運行流程列表並查看流程所有者是誰。

+0

這實際上是一個很好的方法。枚舉所有進程:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682623%28v=vs.85%29.aspx然後從每個進程獲取用戶名:http:// stackoverflow。 com/questions/2686096/c-get-username-from-process/2686150#2686150 – Itaypk 2014-02-02 11:53:32

2

這是一個適用於XP,Server 2003,Vista和Server 2008的解決方案。請注意,這不適用於Windows 2000,因爲「LsaEnumerateLogonSessions」在Windows 2000上不可用。此代碼從Delphi-PRAXIS post

爲了編譯這個,在窗體上創建一個帶有TButton和TMemo的新VCL應用程序。然後複製並粘貼這段代碼,它應該編譯。我在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.