![]() |
Den aktiven Benutzer bzw Status des Benutzers bekommen
Hallo Leute!
Hab in diesem Forum leider noch nichts zu diesem Thema gefunden. In mühevoller Kleinarbeit hab ich mir den Code selber zusammen gebaut:
Delphi-Quellcode:
Vielleicht entdeckt noch irgend jemand einen Fehler bzw kennt eine bessere Methode.
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 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'; implementation {$R *.dfm} function GetActiveUserName: string; 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; begin result:= nil; //Auflisten der LogOnSessions i1:= lsaNtStatusToWinError(LsaEnumerateLogonSessions(@Count, @List)); if i1 = 0 then begin i1:= -1; if Count > 0 then begin repeat inc(i1); LsaGetLogonSessionData(List, sessionData); //Wenn es sich um einen interaktive LogOnSession handelt if sessionData.LogonType = Interactive then begin //Prufen ob es sich um einen Benutzer handelt SizeNeeded := MAX_PATH; SizeNeeded2:= MAX_PATH; GetMem(OwnerName, MAX_PATH); GetMem(DomainName, MAX_PATH); if LookupAccountSID(nil, sessionData.SID, OwnerName, SizeNeeded, DomainName, SizeNeeded2, OwnerType) then begin if OwnerType = 1 then begin //Wenn Benutzer verbunden if WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, sessionData.Session, WTSConnectState, pBuffer, pBytesreturned) then begin if WTS_CONNECTSTATE_CLASS(pBuffer^) = WTSActive then result:= sessionData.UserName.Buffer; end; end; end; end; inc(List); until (i1 = Count-1) or (result <> nil); end; end; end; Ich hoff ich kann jemandem damit helfen! Mfg Scorpion 3000 |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Moin Scorpion,
hast Du Dir schon mal die Funktion GetUserName angeschaut? Zitat:
|
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Sorry! Hab noch etwas vergessen: Diese Quelltext ist nur für Multi-User Betriebssysteme (Win Xp aufwärts).
Die genannte Methode "GetUserName" von Christian Seehase ist unter Win Xp anwendbar. Allerdings liefert die Funktion "GetUserName" nur den Benutzernamen, der mit dem aufrufend Thread/Process verbunden ist bzw unter dem das Prog läuft. Dieser Benutzer muss NICHT automatisch jener Benutzer sein der aktiv ist. (zB. Werft einmal einen Blick in den Taskmanager unter Benutzer. In der Spalte "Status" kann man feststellen, dass (wenn ein oder mehrere Benutzer angemeldet sind) nur einer aktiv ist (sofern kein Benutzer sich Remote anmeldet). Ihr könnt ja kurz einmal ein kleines Prog schreiben, das in einem gewissen Intervall mittels "GetUserName" den momentanen Benutzernamen in einer Listbox ausgibt. Wechselt (nicht ausloggen) dann den Benutzer für kurze Zeit zu einem anderen Benutzer. Dann wieder zurück zu dem Benutzer unter dem ihr das Prog gestartet habt. Das Programm hat brav den Benutzernamen ausgegeben, allerdings halt den, unter dem das Programm läuft und nicht den, zu dem ihr kurz gewechselt habt!) Interessant ist der obige Quelltext vor allem für Dienste, die Programme unter dem gerade aktiven Benutzer ausführen wollen (Falls jemand interesse hat kann ich bei Zeiten einmal den Quelltext posten). Mfg Scorpion3000 |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Zitat:
Zitat:
Also stimmt entweder am Code etwas nicht, oder du machst Annahmen, die nicht gerechtfertigt sind (i.e. nur einer kann aktiv sein). |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Hallo Olli!
Zitat:
Zitat:
Habe einen sehr wichtige Abfrage vergessen! Hier ist die neue Funktion mit der Abfrage:
Delphi-Quellcode:
Danke für dein Feedback. Hätte das fast übersehen. So sollte es passen.
function WTSGetActiveConsoleSessionId: DWORD; external 'Kernel32.dll';
function GetActiveUserName: string; 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; begin result:= nil; //Auflisten der LogOnSessions i1:= lsaNtStatusToWinError(LsaEnumerateLogonSessions(@Count, @List)); if i1 = 0 then begin i1:= -1; if Count > 0 then begin repeat inc(i1); LsaGetLogonSessionData(List, sessionData); //Wenn es sich um einen interaktive LogOnSession handelt if sessionData.LogonType = Interactive then begin //Prufen ob es sich um einen Benutzer handelt SizeNeeded := MAX_PATH; SizeNeeded2:= MAX_PATH; GetMem(OwnerName, MAX_PATH); GetMem(DomainName, MAX_PATH); if LookupAccountSID(nil, sessionData.SID, OwnerName, SizeNeeded, DomainName, SizeNeeded2, OwnerType) then begin if OwnerType = 1 then begin //Wenn Benutzer an lokaler console angemeldet //unter Windows NT 4.0 und Windows 2000 ist die SessionID der Konsole immer "0" dh.: //if sessionData.Session = 0 then if sessionData.Session = WTSGetActiveConsoleSessionId then //<- Hab ich vergessen begin //Wenn Benutzer aktiv if WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, sessionData.Session, WTSConnectState, pBuffer, pBytesreturned) then begin if WTS_CONNECTSTATE_CLASS(pBuffer^) = WTSActive then result:= sessionData.UserName.Buffer; end; end; end; end; FreeMem(OwnerName); FreeMem(DomainName); end; inc(List); until (i1 = Count-1) or (result <> nil); end; end; end; Mfg Scorpion3000 |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Stimmt, so sollte es funktionieren. Wenn man keine TS hat, ist man leicht gelackmeiert. Das Problem ist dabei, daß man "verbundene" Benutzer oder Benutzer die "interaktiv" über eine Konsole (zB über SSH oder PSEXEC von Sysinternals) laufen nicht vom Rest unterscheiden kann. Die einzige Unterscheidung sind die laufenden Prozesse. Und genau dabei kann es zu ziemlichen Ungenauigkeiten kommen.
Ach ja, die TS sind ab XP Home dabei (deswegen ja "schnelle Benutzerumschaltung"). |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Hi!
Ich schreibe grade einen Dienst, der den obigen Quelltest verwendet. Leider steigt der Speicherbedarf meines Dienstes pro Aufruf der Prozedur um 8KB. Da er die Funktion jede Sekunde aufruft, ist der Speicher schnell voll! An welcher Stelle muss gegebenenfalls Speicher wieder freigegeben werden? |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Hallo,
ein try finally um das GetMem wäre das eine. Ich denke aber sessionData wird nicht freigegeben (ist doch nen Pointer ?), Freigabe erfolgt über LSAFreeReturnBuffer Dazu fällt mir das noch ein ![]() Heiko |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Hallo hoika,
Danke erstmal für Deine Hilfe! Die Freigabe für sessionData habe ich eingebaut, aber nach dem folgenden if Aufruf steigt der Speicher um 4KB und wird nicht mehr freigegeben:
Delphi-Quellcode:
Den Teil im if-Block habe ich probehalber auskommentiert, daran kann es nicht liegen. Auch habe ich alle optionalen Parameter mit nil angegeben, trotzdem ändert sich nichts!
if LookupAccountSID(nil, sessionData.SID, OwnerName,
SizeNeeded, DomainName, SizeNeeded2, OwnerType) then begin ... end; Woran kann das liegen? |
Re: Den aktiven Benutzer bzw Status des Benutzers bekommen
Hallo,
dann schau dir mal per msdn die einzelnen Aurufe an. Das mit der Freigabe habe ich auch nur dort gefunden. werden jetzt pro Aufruf 4 kB verbraten oder einmalig ? Ich würde jetzt mal memcheck (google) druaf ansetzen. Heiko |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:03 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz