Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Falsche Speicherbereiche (https://www.delphipraxis.net/32340-falsche-speicherbereiche.html)

Luckie 21. Okt 2004 22:23


Falsche Speicherbereiche
 
Ich stehe vor einem Rätsel. Mit der API NetUserSetInfo versuche ich Details für einen Benutzer Account zu setzen. NetUserSetInfo erwartet unter anderem folgende Struktur:
Delphi-Quellcode:
type
  TUserInfo3 = record
    usri3_name: LPWSTR;
    usri3_password: LPWSTR;
    usri3_password_age: DWORD;
    usri3_priv: DWORD;
    usri3_home_dir: LPWSTR;
    usri3_comment: LPWSTR;
    usri3_flags: DWORD;
    usri3_script_path: LPWSTR;
    usri3_auth_flags: DWORD;
    usri3_full_name: LPWSTR;
    usri3_usr_comment: LPWSTR;
    usri3_parms: LPWSTR;
    usri3_workstations: LPWSTR;
    usri3_last_logon: DWORD;
    usri3_last_logoff: DWORD;
    usri3_acct_expires: DWORD;
    usri3_max_storage: DWORD;
    usri3_units_per_week: DWORD;
    usri3_logon_hours: PBYTE;
    usri3_bad_pw_count: DWORD;
    usri3_num_logons: DWORD;
    usri3_logon_server: LPWSTR;
    usri3_country_code: DWORD;
    usri3_code_page: DWORD;
    usri3_user_id: DWORD;
    usri3_primary_group_id: DWORD;
    usri3_profile: LPWSTR;
    usri3_home_dir_drive: LPWSTR;
    usri3_password_expired: DWORD;
  end;
  PUserInfo3 = ^TUserInfo3;
Diese fülle ich wie folgt:
Delphi-Quellcode:
function SetDetails: TUserInfo3;
begin
  ZeroMemory(@result, sizeof(result));
  result.usri3_name := PWideChar(WideString(GetText(ID_EDT_USER)));
  result.usri3_full_name := PWideChar(WideString(GetText(ID_EDT_FULLNAME)));
  result.usri3_comment := PWideChar(WideString(GetText(ID_EDT_DESCRIPTION)));
  result.usri3_home_dir := PWideChar(WideString(GetText(ID_EDT_HOMEDIR)));
  result.usri3_script_path :=
    PWideChar(WideString(GetText(ID_EDT_SCRIPT_PATH)));
  if GetCheck(ID_CHK_MUST_CHANGE_PW) then
    result.usri3_password_expired := 1
  else
    result.usri3_password_expired := 0;
  if GetCheck(ID_CHK_CANT_CHANGE_PW) then
    result.usri3_flags := result.usri3_flags or UF_PASSWD_CANT_CHANGE;
  if GetCheck(ID_CHK_PW_DONT_EXPIRE) then
    result.usri3_flags := result.usri3_flags or UF_DONT_EXPIRE_PASSWD;
  if GetCheck(ID_CHK_ACCOUNT_DISABLED) then
    result.usri3_flags := result.usri3_flags or UF_ACCOUNTDISABLE;
end;
Dann die eigentliche Funktion:
Delphi-Quellcode:
function SetUserInfo(Server, User: string; UserInfo: TUserInfo3):
  NET_API_STATUS;
var
  ui3: Pointer;
begin
  ui3 := nil;
  result := NERR_BASE;
  if User <> '' then
  begin
    if NetUserGetInfo(PWideChar(WideString(Server)),
      PWideChar(WideString(User)), 3, ui3) = NERR_SUCCESS then
    begin
      PUserInfo3(ui3)^.usri3_name := UserInfo.usri3_name;
      PUserInfo3(ui3)^.usri3_full_name := UserInfo.usri3_full_name;
      PUserInfo3(ui3)^.usri3_password := UserInfo.usri3_password;
      PUserInfo3(ui3)^.usri3_home_dir := UserInfo.usri3_home_dir;
      PUserInfo3(ui3)^.usri3_comment := UserInfo.usri3_comment;
      PUserInfo3(ui3)^.usri3_usr_comment := UserInfo.usri3_comment;
      PUserInfo3(ui3)^.usri3_priv := UserInfo.usri3_priv;
      PUserInfo3(ui3)^.usri3_script_path := UserInfo.usri3_script_path;
      PUserInfo3(ui3)^.usri3_auth_flags := UserInfo.usri3_auth_flags;
      PUserInfo3(ui3)^.usri3_parms := UserInfo.usri3_parms;
      PUserInfo3(ui3)^.usri3_workstations := UserInfo.usri3_workstations;
      PUserInfo3(ui3)^.usri3_acct_expires := UserInfo.usri3_acct_expires;
      PUserInfo3(ui3)^.usri3_max_storage := UserInfo.usri3_max_storage;
      PUserInfo3(ui3)^.usri3_home_dir_drive := UserInfo.usri3_home_dir_drive;
      PUserInfo3(ui3)^.usri3_profile := UserInfo.usri3_profile;
      PUserInfo3(ui3)^.usri3_password_expired := UserInfo.usri3_password_expired;
      PUserInfo3(ui3)^.usri3_flags := UserInfo.usri3_flags;
      result := NetUserSetInfo(PWideChar(WideString(Server)),
        PWideChar(WideString(User)), 3, ui3, nil);
    end;
  end;
end;
Es kommt alles richtig an. Stoppe ich hier: PUserInfo3(ui3)^.usri3_name := UserInfo.usri3_name; und schaue mir die Werte der felder der Struktur an, stimmen sie alle. Aber so bald der full_name zugewiesen wurde, stimmen die Werte der anderen Felder nicht mehr. Teilweise steht Schrott drinne teilweise sachen im Klartext, die irgendwo anders im Programm auftauchen, wie der Computername zum Beispiel.

Ich habe keinen blassen Schimmer, was da passiert und warum. :evil:

Luckie 22. Okt 2004 05:20

Re: Falsche Speicherbereiche
 
So. Motzi hat das ganze mal analysiert und festgestellt, das es bei den Casts von Server und User teilweise der Speicherbereich auf den der Pointer ui3 zeigt überschrieben wird. Lösung sieht so aus, dass man praktisch von Hand selber castet.

fkerber 22. Okt 2004 09:13

Re: Falsche Speicherbereiche
 
Hi!

Auch wenn ich eigentlich davon gar nix verstehe :drunken: , mal eine Frage dazu:

Heißt das, dass da ein Fehler in Delphi/Compiler ist oder was anderes?


Ciao Frederic

Luckie 22. Okt 2004 09:16

Re: Falsche Speicherbereiche
 
Da musst du mal auf Motzi warten, der kann dir das wohl besser erklären.

fkerber 22. Okt 2004 09:18

Re: Falsche Speicherbereiche
 
Hi!

Ok, dann warte ich mal gespannt :cyclops:

Ciao Frederic

Muetze1 22. Okt 2004 09:30

Re: Falsche Speicherbereiche
 
Moin!

Zitat:

Zitat von Luckie
..., stimmen die Werte der anderen Felder nicht mehr. Teilweise steht Schrott drinne teilweise sachen im Klartext, die irgendwo anders im Programm auftauchen, wie der Computername zum Beispiel.

Ich habe keinen blassen Schimmer, was da passiert und warum. :evil:

Für mich ist das denn eindeutig, dass der Speicherbereich auf den ui3 zeigt nicht ordentlich alloziiert wurde. Und daher würde ich vor allem erstmal in die Richtung forschen. Vor allem ist in der o.g. Funktion bisher auch noch keine Alloziierung zu erkennen (kann natürlich in den Sub-Routinen geschehen - sieht man aber nicht)...

MfG
Muetze1

shmia 22. Okt 2004 09:41

Re: Falsche Speicherbereiche
 
Obacht !
Sobald die Funktion SetDetails verlassen wird, zeigt result.usri3_name ins Nirvana (ungültiger Speicherbereich).
Delphi-Quellcode:
function SetDetails: TUserInfo3;
begin
  ZeroMemory(@result, sizeof(result));
  result.usri3_name := PWideChar(WideString(GetText(ID_EDT_USER)));
Mag sein, dass result.usri3_name noch auf sinnvolle Daten zeigt;
aber die Daten können jederzeit durch andere Daten überschrieben werden.
Du brauchst 2 Strukturen:
eine mit zeigerlosen Delphi-Datentypen und eine passend zu USER_INFO_3.

Im Betrag http://www.delphipraxis.net/internal...ct.php?t=31191 siehst wie das gemeint ist.

Übrigens: die MSDE sagt du sollst USER_INFO_4 nehmen:
The USER_INFO_3 structure contains information about a user account, including the account name, password data, privilege level, the path to the user's home directory, relative identifiers (RIDs), and other user-related network statistics.
It is recommended that you use the USER_INFO_4 structure instead.

Luckie 22. Okt 2004 10:19

Re: Falsche Speicherbereiche
 
Zitat:

Zitat von shmia
Obacht !
Sobald die Funktion SetDetails verlassen wird, zeigt result.usri3_name ins Nirvana (ungültiger Speicherbereich).

Nein. Das hat schon alles gestimmt. Nach verlassen der Prozedur, war noch alles da. Nur eine Interne Funktion zum Anfordern von Speicher für den String beim Cast hat den Speicher innerhalb des Speichers von ui3 reserviert.

Zitat:

It is recommended that you use the USER_INFO_4 structure instead.
Oh, das muss ich mir mal ankucken.

Hm, beim ir steht da aber auch:
Zitat:

Specifies level two information and additional attributes about the user account. This level is valid only on servers. The buf parameter points to a USER_INFO_4 structure.

Windows 2000/NT: This level is not supported.

Muetze1 22. Okt 2004 10:54

Re: Falsche Speicherbereiche
 
Moin!

Zitat:

Zitat von Luckie
Zitat:

Zitat von shmia
Obacht !
Sobald die Funktion SetDetails verlassen wird, zeigt result.usri3_name ins Nirvana (ungültiger Speicherbereich).

Nein. Das hat schon alles gestimmt. Nach verlassen der Prozedur, war noch alles da. Nur eine Interne Funktion zum Anfordern von Speicher für den String beim Cast hat den Speicher innerhalb des Speichers von ui3 reserviert.

Nein, shmia hat Recht, der Speicherbereich ist wieder frei verfügbar und genaus deshalb wird der Speicher für den String auch in dem Bereich alloziiert, weil der Bereich frei ist.

MfG
Muetze1

Motzi 22. Okt 2004 11:17

Re: Falsche Speicherbereiche
 
Nein, shmia hat nicht recht, der Compiler nimmt da alle nötigen Zwischenschritte vor.. ich hab am Anfang auch das als Fehlerursache im Aug gehabt und einiges entsprechend umgestellt, der Fehler blieb aber.

Inzwischen hab ich festgestellt, dass der Fehler wirklich bei den Typecasts lag, allerdings nicht auf Delphi-Seite, sondern auf API-Seite. In dem Prog wird recht oft von String auf WideString und PWideString gecastet. Bei jedem dieser Casts werden intern vom Compiler entsprechende Zwischenschritte durchgeführt die mit den APIs SysAllocStringLen und SysFreeString arbeiten. Ganz erklären kann ich es nicht, aber offensichtlich kommt mit den vielen Typecasts und damit verbundenem Speicher allozieren/deallozieren der Memory-Manager dieser APIs durcheinander, jedenfalls liefert beim 2ten Typecast die API-Funktion SysAllocStringLen als Ergebnis einen Zeiger auf dieselbe Adresse zurück auf die auch ein Feld von UserInfo zeigt. An genau dieser Stelle wurde zuvor bereits ein andrer WideString durch einen entsprechenden Typecast und Aufruf von SysAllocStringLen abgelegt. Offensichtlich versucht der Memory-Manager den Speicher wiederzuverwenden, nur dass in diesem Fall eben an dieser Stelle noch ein andrer String liegt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:04 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