![]() |
Alle User eines Rechners auflisten
Hi,
welche Win32-API-Funktion erlaubt es mir alle User, die auf dem Rechner registriert sind aufzulisten? Chris |
NetUserEnum
|
Super!
Habe aber das Problem, dass das MSDN/PSDK mir nicht sagen will, in welcher Unit das ganze zu finden ist. Das wüsste ich gerne und kannst du mir mal sagen, was da zurückgegeben wird??? Chris |
PSDK sagt der header ist Lm.h. Ich weiß nicht, ob borland dafür eien Unit zur Verfügung stellt. Aber bei den Jedis müßtest du fündig werden. Näheres kann ich dir dazu auch nicht sagen, da ich damit noch nicht gearbeitet habe.
|
Nur ist das Problem, dass die Jedis immer noch offline sind (inzwischen vermute ich für immer... :-? )
Chris |
Es gibt bestimmt Referenz-seiten, die (sicher nicht ganz legal) die Inhalte kopiert haben. Vielleicht hast du Glück und du findest bei Google was
|
Liste der Anhänge anzeigen (Anzahl: 1)
Im Anhang mal die Header-Überrsetzungen von den Jedis.
|
oder so :mrgreen:
|
Moin Chris,
Zitat:
Oft entspricht der Name der Headerdatei der dort angegeben wird, dem Namen der Unit in der Du die Funktion o.ä. findest. Meist wirst Du keine direkte Delphi Implementierung von Funktionen finden, wenn diese für 9x und NT ff unterschiedlich sind. (Wie z.B. die Netxxx Funktionen). |
So, Jedi-Headers gefunden, heruntergeladen und installiert.
Nun stellt sich aber folgendes Problem: Wenn ich folgendes Aufrufe (eigentlich nutze ich nonVCL, aber das mache ich später):
Delphi-Quellcode:
Wie bereits als Comment geschrieben: Welchen Typ soll aBuffer haben? Normalerweise ist das ja array[0..MAX_LENGTH+1] of Char, aber es müssen ja mehrere User rein!
if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, aBuffer, MAX_LENGTH, iUsers, iUsers{2}, nil) = NERR_SUCCESS then begin
{... hier stellt sich das Problem: wie lese ich Buffer aus? } end; Wie werden die User voneinander getrennt? Chris |
Ich vermute mal durch #0 und abgeschlossen wird die Liste mit #0#0.
|
Würde ich ausprobieren, nur gibt obiges folgendes aus (Label1.Caption := aBuffer);
Zitat:
|
So, nachdem ich mir mal die Ausgabestruktur angesehen habe (_USER_INFO_0). Kommt nun raus (Label1.Caption := Buffer.usri0_name):
Zitat:
|
Moin Chris,
kleine Gemeinheit der Netxxx Funktionen. Da die Funktionen den erforderlichen Platz für die Daten selber reservieren, wird als Buffer kein Pointer, sondern die Adresse eines Pointers übergeben. Der Aufruf muss also
Delphi-Quellcode:
lauten.
if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, [color=red]@[/color]aBuffer, MAX_LENGTH, iUsers, iUsers{2}, nil) = NERR_SUCCESS then
Ganz wichtig: Nachdem der Buffer abgearbeitet wurde muss er mit NetApiBufferFree wieder freigegeben werden. Um den Buffer abzuarbeiten empfiehlt es sich eine zweite Variable des Typs anzulegen, und diesem dann den Wert in aBuffer nach Aufruf der Funktion zu übergeben. Wenn man als Parameter prefmaxlen den Wert MAX_PREFERRED_LENGTH angibt erhält man ja alle Einträge, und kann diese dann in einer for Schleife abarbeiten, wobei ein inc(aBuffer) genügt, um auf den nächsten Eintrag zu kommen (wenn man aBuffer vom richtigen Typ her angelegt hat!) Da ich den Zahlenwert der Konstanten MAX_LENGTH nicht kenne: Tausch die lieber mal gegen MAX_PREFERRED_LENGTH aus. |
Hi,
also, ich habe nun 2 Buffer vom Typ _USER_INFO_0 (so steht es auch im PSDK). Nun habe ich folgenden Source:
Delphi-Quellcode:
Allerdings gibt es an der Stelle, wo der Pfeil ist folgenden Fehler:
procedure TMainFrm.FormCreate(Sender: TObject);
var aBuffer1, aBuffer2: _USER_INFO_0; iUsers: Cardinal; begin if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, @aBuffer1,{<-} MAX_PATH+1, iUsers, iUsers{2}, nil) = NERR_SUCCESS then begin aBuffer2 := aBuffer1; NetApiBufferFree(@aBuffer1); Label1.Caption := aBuffer2.usri0_name; end; end; Zitat:
Chris |
Zitat:
Wenn aBuffer vom Typ Pointer ist kann ich ja mit Inc(aBuffer) an den nächsten Eintrag ran. Aber wie bekomme ich jetzt das ganze im Klartext? |
Wenn du den Typ _USER_INFO_0 meinst, dann ist das ganze ein record. Du kannst darauf zugreifen. Wie, steht in irgendeinem der vorangegangenen Sources.
Chris |
Dass das Ding ein Record ist, ist klar. Den kenne ich ja auch. Nur ist es ja nicht ein Record, sondern jeder User hat ja einen Record. Irgendwie so stelle ich mir das vor:
Delphi-Quellcode:
s := aBuffer[0].UserName; // 1. gefundene User
s := aBuffer[1].Username; // 2. gefundene User |
Moin Zusammen,
also ich gehe da von der PSDK Deklaration aus, so dass der Typ von aBuffer ein Pointer auf eine USER_INFO_x Struktur ist. Wie in Delphi sonst üblich einen Record zu übergeben kann ja eigentlich deshalb schon nicht klappen, da man sich ja eine beliebige Anzahl an Einträgen zurückgeben lassen kann, ohne vorher zu Wissen, wieviele es sind. Ein Witz an diesen Netxxx Funktionen ist ja, dass sie den erforderlichen Speicher selber reservieren. aBuffer wäre dann also als
Delphi-Quellcode:
deklariert, so dass man auf diesem Wege das Ergebnis verarbeiten kann
var
aBuffer : PUSER_INFO_1;
Delphi-Quellcode:
Deshalb auch das Sichern von aBuffer in einer Variablen gleichen Typs, da man ja an NetApiBufferFree die Startadresse des Ergebnisbuffers zurückliefern muss, damit der Speicher wieder freigegeben werden kann.
for i := 1 to dwEntriesRead do
begin //... was auch immer mit aBuffer geschehen soll inc(aBuffer); // auf den nächsten Eintrag adressieren end; Als Pointer ist aBuffer in der Funktion nur deshalb deklariert, da es sich um einen Pointer auf verschiedene Datenstrukturen (USER_INF0_x) handeln kann, so dass eine feste Typangabe nicht möglich ist. |
Hi Christian,
ich hatte mir heute auch mal was ausgedacht, werde das nachher mal prüfen, aber nun zu deinem Source: woher kommt dwReadEntries? Chris |
Hi Christian,
also, ich gehe davon aus, dass PUSER_INFO_0 (bzw. _1) ein Pointer auf _USER_INFO_0 ist (
Delphi-Quellcode:
).(Der Typ selber existiert in der JwaLM-Unit nämlich nicht)
type PUSER_INFO_0 = ^_USER_INFO_0
Dann habe ich den Source wie folgt geschrieben:
Delphi-Quellcode:
Da kommt folgender Fehler.
{33} if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, aBuffer, MAX_PREFERRED_LENGTH, iUser, iUser, nil) = NERR_SUCCESS then begin
{34} while aBuffer <> nil do begin {35} ListBox1.Items.Add(aBuffer.usri0_name); {36} inc(aBuffer); {37} end; {38} end; Zitat:
Chris |
Hi,
so, nun ist es soweit, dass das Programm läuft (obwohl ich mich ehrlich frage, warum er das so macht). Allerdings wirft er mir beim Starten eine kräftige Access Violation gegen den Kopf. :freak: Hat jemand eine Ahnung warum? Chris |
Schon nach einer halben Stunde habe ich das Problem einigermaßen behoben. Jetzt ist mir auch klar woher "dwEntriesRead" herkommt... ;)
Aber zurück zum Thema: Anstatt irgendeiner AV oder Exception wird einfach das CPU-Fenster geöffnet, sonst nix. CPU-Fenster beenden, F9 und schon geht's weiter. Aber warum geht das CPU-Fenster überhaupt auf? Chris |
Poste doch mal, wie dein bisheriger Code aussieht. Ich beschäftige mich auch gerade damit.
|
So, ich habe es jetzt so weit:
Delphi-Quellcode:
Beim Abarbeiten der Schleife bekomme ich eine AccessViolation. Könnte sich dessen mal bitte jemand annehmen?
procedure TForm1.Button1Click(Sender: TObject);
var dwEntriesRead, dwEntriesTotal: DWORD; ui1, ui2 : Pointer; i : Integer; begin if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, ui1, MAX_PREFERRED_LENGTH, dwEntriesRead, dwEntriesTotal, nil) = NERR_SUCCESS then begin ui2 := ui1; for i := 0 to dwEntriesRead-1 do begin Listbox1.Items.Add(PUserInfo1(ui1)^.usri1_name); Inc(Integer(ui1)); // <-- So nicht! end; end; NetAPIBufferFree(ui2); end; |
Problem gelöst. War etwas blöd:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var dwEntriesRead, dwEntriesTotal: DWORD; ui1, ui2 : Pointer; i : Integer; begin if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, ui1, MAX_PREFERRED_LENGTH, dwEntriesRead, dwEntriesTotal, nil) = NERR_SUCCESS then begin ui2 := ui1; for i := 0 to dwEntriesRead-1 do begin Listbox1.Items.Add(PUserInfo1(ui1)^.usri1_name); Inc(Integer(ui1), SizeOf(Pointer)); end; end; NetAPIBufferFree(ui2); end; |
Hi,
super! Werde mal sehen, was sich da machen lässt. Das Problem ist nur, dass unter nonVCL sich das CPU-Fenster nicht öffnet, aber wenn ich mit der VCL programmiere schon. Chris PS: Source ist auf dem Laptop; Laptop steht irgendwo anders; Source kommt später |
Das ist VCL Code. Hier ist das nonVCL Pendant:
Delphi-Quellcode:
Geht beides ohne Probleme.
procedure GetUsers;
var dwEntriesRead, dwEntriesTotal: DWORD; ui1, ui2 : Pointer; i : Integer; s : String; begin ui2 := nil; SendDlgItemMessage(hTabDlgs[0], IDC_CB, CB_RESETCONTENT, 0, 0); if NetUserEnum(nil, 0, FILTER_NORMAL_ACCOUNT, ui1, MAX_PREFERRED_LENGTH, dwEntriesRead, dwEntriesTotal, nil) = NERR_SUCCESS then begin ui2 := ui1; for i := 0 to dwEntriesRead-1 do begin s := PUserInfo1(ui1)^.usri1_name; SendDlgItemMessage(hTabDlgs[0], IDC_CB, CB_ADDSTRING, 0, Integer(@s[1])); Inc(Integer(ui1), SizeOf(Pointer)); end; end; NetAPIBufferFree(ui2); SendDlgItemMessage(hTabDlgs[0], IDC_CB, CB_SETCURSEL, 0, 0); s := Format('Anzahl der Benutzer: %d', [dwEntriesRead]); SendDlgItemMessage(hApp, IDC_STATUSBAR, SB_SETTEXT, 1, Integer(@s[1])); end; |
Moin Zusammen,
nur um mal zu verdeutlichen, wie's so bei mir aussieht (speziell wegen des @pBuffer)
Delphi-Quellcode:
Unter Verwendung dieser Deklarationen:
procedure TfrmMAIN.Button1Click(Sender: TObject);
var pBuffer : PUSER_INFO_0; pWork : PUSER_INFO_0; dwEntriesRead : DWORD; dwTotalEntries : DWORD; i : integer; begin if NetUserEnum(nil,0,FILTER_NORMAL_ACCOUNT,@pBuffer,MAX_PREFERRED_LENGTH,@dwEntriesRead,@dwTotalEntries,nil) = NERR_Success then begin try ListBox1.Items.Clear; pWork := pBuffer; for i := 1 to dwEntriesRead do begin ListBox1.Items.Add(pWork.usri0_name); inc(pWork); end; finally NetApiBufferFree(pBuffer); end; end; end;
Delphi-Quellcode:
type
// LMCons.h NET_API_STATUS = DWORD; // aus LMACCESS.H PUSER_INFO_0 = ^USER_INFO_0; USER_INFO_0 = packed record usri0_name : PWChar; end; PUSER_INFO_1 = ^USER_INFO_1; USER_INFO_1 = packed record usri1_name : PWChar; usri1_password : PWChar; usri1_password_age : DWord; usri1_priv : DWord; usri1_home_dir : PWChar; usri1_comment : PWChar; usri1_flags : DWord; usri1_script_path : PWChar; end; const MAX_PREFERRED_LENGTH = DWORD(-1); FILTER_NORMAL_ACCOUNT = $0002; // LMERR.H NERR_Success = 0; // Success // aus LMACCESS.H function NetUserEnum( const servername : PWChar; const level : DWord; const filter : DWord; const bufptr : Pointer; const prefmaxlen : DWord; const entriesread : PDWord; const totalentries : PDWord; const resume_handle : PDWord ) : NET_API_STATUS; stdcall; external 'netapi32.dll'; // aus LMAPIbuf.h function NetApiBufferFree( const Buffer : Pointer ) : NET_API_STATUS; stdcall; external 'netapi32.dll'; |
Hi Christian,
aufgrund der Tatsache, dass neuerdings beim Starten des Programmes wieder einfach nur das CPU-Fenster aufpoppt, werde ich mal deinen Source testen. Problem ist nur, dass der Typ "PUSER_INFO_0" bei mir nicht in der JwaLM (bzw. JwaLmAccess) steht. Habe aber bereits den Typ angelegt. Problem ist bei mir, dass ich nicht einfach @aBuffer schreiben kann. Bei mir akzeptiert er nur Pointer(aBuffer). Daran liegt vermutlich auch der Fehler. Werde in den nächsten Stunden mal rein schauen... Chris |
Moin Chris,
deshalb hatte ich auch meine Deklarationen mit angegeben. In die Jedi Sourcen habe ich noch nicht reingeschaut, deshalb weiss ich nicht, welche "Philosophie" dort vertreten wird, was die Deklaration der APIs angeht. Ich halte mich nur möglichst an die Vorgaben aus dem PSDK, damit ich auch die Samples möglichst einfach nutzen kann. Borland selber deklariert an den Stellen, an denen Werte von der Funktion geschrieben werden sollen die Parameter als var, was dann u.a. zur Folge hat, dass man sich gelegentlich Dummy Variablen anlegen muss, wenn man einen Parameter nicht nutzen will (also auf 0 oder nil setzen muss), was bei einem var Parameter ja nur geht, wenn eine entsprechende Variable angegeben wird. Wichtig: Wenn das Programm auch unter 9x/ME gestartet werden soll, müssen die Funktionen dynamisch importiert werden, und nicht, wie angegeben, statisch, damit sie ggf. weggelassen werden können. |
Was meinst du mit "dynamisch" import? Meinst du Compilerschalter?
Chris |
Zitat:
![]() |
Moin Chris,
nein, ich meine Damit, dass Du einen Typ deklarierst, der der Funktionsdeklaration entspricht, dann eine Variable diese Typs, die entsprechende DLL aus der die Funktion stammt mittels LoadLibrary/LoadLibraryEx lädst, und dann die Adresse der Funktion mit GetProcAddress der Variablen zuweist. NetUserEnum (und die Netapi32.dll) gibt's auf der 9x Schiene nicht, so dass bei statischem Import das Programm beim Starten sonst gleich mit einer Fehlermeldung abbricht, wenn die, statisch importierte, Funktion irgendwo angesprochen wird. So könnte das Ganze dann mit dynamischem Import der Funktionen aussehen:
Delphi-Quellcode:
Wobei man natürlich den Import, bzw. Freigabe der DLL auch im initialization/finalization Abschnitt erledigen kann (sollte), und das dann in Abhängigkeit des Betriebssystemes, auf dem das Programm läuft.
const
MAX_PREFERRED_LENGTH = DWORD(-1); FILTER_NORMAL_ACCOUNT = $0002; NERR_Success = 0; type NET_API_STATUS = DWORD; TcsNetUserEnum = function( const servername : PWChar; const level : DWord; const filter : DWord; const bufptr : Pointer; const prefmaxlen : DWord; const entriesread : PDWord; const totalentries : PDWord; const resume_handle : PDWord ) : NET_API_STATUS; stdcall; TcsNetApiBufferFree = function( const Buffer : Pointer ) : NET_API_STATUS; stdcall; PUSER_INFO_0 = ^USER_INFO_0; USER_INFO_0 = packed record usri0_name : PWChar; end; var NetUserEnum : TcsNetUserEnum; NetApiBufferFree : TcsNetApiBufferFree; hDLL : DWORD; pBuffer : PUSER_INFO_0; pWork : PUSER_INFO_0; dwEntriesRead : DWORD; dwTotalEntries : DWORD; i : integer; begin hDLL := LoadLibrary('netapi32.dll'); if hDLL = 0 then begin exit; end; try NetUserEnum := GetProcAddress(hDLL,'NetUserEnum'); if @NetUserEnum = nil then begin exit; end; NetApiBufferFree := GetProcAddress(hDLL,'NetApiBufferFree'); if @NetApiBufferFree = nil then begin exit; end; // Nutzen der Funktion if NetUserEnum(nil,0,FILTER_NORMAL_ACCOUNT,@pBuffer,MAX_PREFERRED_LENGTH,@dwEntriesRead,@dwTotalEntries,nil) = NERR_Success then begin try ListBox1.Items.Clear; pWork := pBuffer; for i := 1 to dwEntriesRead do begin ListBox1.Items.Add(pWork.usri0_name); inc(pWork); end; finally NetApiBufferFree(pBuffer); end; end; finally FreeLibrary(hDLL); end; end; Was, gerade bei den Netxxx Funktionen, oft eine Beschränkung bedeutet, da nicht alle dieser Funktionen unter 9x zur Verfügung stehen. (z.B. NetUserEnum) Für 9x muss man sich dann ggf. noch eine Unterscheidung der Datenstrukturen einfallen lassen, da die MS Deklarationen sich nur in der Gross-/Kleinschreibung unterscheiden, was in Pascal ja nicht funktioniert. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:58 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