AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Den aktiven Benutzer bzw Status des Benutzers bekommen
Thema durchsuchen
Ansicht
Themen-Optionen

Den aktiven Benutzer bzw Status des Benutzers bekommen

Ein Thema von Scorpion3000 · begonnen am 29. Nov 2005 · letzter Beitrag vom 7. Okt 2010
Antwort Antwort
Seite 1 von 2  1 2      
Scorpion3000

Registriert seit: 18. Apr 2004
47 Beiträge
 
Delphi 7 Enterprise
 
#1

Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 29. Nov 2005, 12:03
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:
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;
Vielleicht entdeckt noch irgend jemand einen Fehler bzw kennt eine bessere Methode.
Ich hoff ich kann jemandem damit helfen!

Mfg Scorpion 3000
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.117 Beiträge
 
Delphi 11 Alexandria
 
#2

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 29. Nov 2005, 16:25
Moin Scorpion,

hast Du Dir schon mal die Funktion GetUserName angeschaut?

Zitat von PSDK:
The GetUserName function retrieves the user name of the current thread. This is the name of the user currently logged onto the system.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Scorpion3000

Registriert seit: 18. Apr 2004
47 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 30. Nov 2005, 15:56
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
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#4

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 6. Dez 2005, 21:20
Zitat von Scorpion3000:
Sorry! Hab noch etwas vergessen: Diese Quelltext ist nur für Multi-User Betriebssysteme (Win Xp aufwärts).
Kleiner Tip: es heißt nicht "Multi-User Betriebssysteme", denn das sind NT 3.51 und 4.0 und Windows 2000 auch - was du meinst sind installierte und laufende Terminal Services (TS).

Zitat von Scorpion3000:
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).
Man kann es eben nicht ermitteln. 1.) es gibt auch für XP (Pro/Home) Erweiterungen, die TS voll freischalten und 2.) kann auf einem Server-OS (NT 4.0 - 2003 Server) mehr als ein Benutzer auf einmal an jeweils einem Terminal aktiv sein.

Also stimmt entweder am Code etwas nicht, oder du machst Annahmen, die nicht gerechtfertigt sind (i.e. nur einer kann aktiv sein).
  Mit Zitat antworten Zitat
Scorpion3000

Registriert seit: 18. Apr 2004
47 Beiträge
 
Delphi 7 Enterprise
 
#5

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 7. Dez 2005, 01:00
Hallo Olli!

Zitat:
Kleiner Tip: es heißt nicht "Multi-User Betriebssysteme", denn das sind NT 3.51 und 4.0 und Windows 2000 auch - was du meinst sind installierte und laufende Terminal Services (TS).
Das ist richtig. Es müssen Betriebssysteme mit installierten Terminal-Services sein. Dh NT 4.0 aufwärts mit installierten Terminal Services. Ab Windows Xp imho sind diese von Haus aus dabei.


Zitat:
2.) kann auf einem Server-OS (NT 4.0 - 2003 Server) mehr als ein Benutzer auf einmal an jeweils einem Terminal aktiv sein
Zuerst muss ich mal dazu sagen, dass ich unter "aktiv" den Benutzer meine, der gerade "lokal", also an der Konsole angemeldet ist.
Habe einen sehr wichtige Abfrage vergessen! Hier ist die neue Funktion mit der Abfrage:

Delphi-Quellcode:
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;
Danke für dein Feedback. Hätte das fast übersehen. So sollte es passen.

Mfg Scorpion3000
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#6

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 7. Dez 2005, 10:49
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").
  Mit Zitat antworten Zitat
Benutzerbild von Manzoni
Manzoni

Registriert seit: 15. Feb 2004
Ort: Berlin
120 Beiträge
 
Delphi 7 Enterprise
 
#7

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 11. Apr 2007, 17:41
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?
Bob
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#8

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 11. Apr 2007, 18:32
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

http://support.microsoft.com/kb/331970


Heiko
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Manzoni
Manzoni

Registriert seit: 15. Feb 2004
Ort: Berlin
120 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 11. Apr 2007, 22:55
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:
if LookupAccountSID(nil, sessionData.SID, OwnerName,
                   SizeNeeded, DomainName, SizeNeeded2, OwnerType) then
begin
...
end;
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!

Woran kann das liegen?
Bob
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#10

Re: Den aktiven Benutzer bzw Status des Benutzers bekommen

  Alt 12. Apr 2007, 08:24
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
Heiko
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz