Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Warum kann ich die Eingaben nicht wieder auslesen (https://www.delphipraxis.net/205864-warum-kann-ich-die-eingaben-nicht-wieder-auslesen.html)

delphifan2004 24. Okt 2020 20:09

Warum kann ich die Eingaben nicht wieder auslesen
 
Hallo!

Ich habe folgende Unit erstellt, will wissen wie Windows intern Registrydaten speichert. Ob es Windows ganz genau so macht, weiß ich natürlich nicht, aber ich versuche mir vorzustellen, wie das Windows intern machen könnte.

Delphi-Quellcode:
unit entries;

interface

uses
  System.SysUtils, Classes, Windows, Contnrs;

type
  PNode = ^TNode; //Ein voerheriger Versuch
  TNode = record
    Data: Pointer;
    next,
    prev: PNode;
  end;

//So könnte Windows intern Registrydaten speichern
  TEntry = class(TObject)
  private
    FSubkey: AnsiString;   //Unterschlüssel
    FSubkeyW: WideString;
    FKeyClass: AnsiString; //Schlüsselklasse
    FKeyClassW: WideString;
    FKeyValue: AnsiString; //Schlüsselwert
    FKeyValueW: WideString;
    FdwOptions: DWORD;     //Optionen zur Erzeugung
    FsamDesired: REGSAM;   //Optionen zum Zugriff auf den Schlüssel
    FDataType: LPDWORD;    //Typ der Daten im Schlüsseleintrag
    FDataLen: DWORD;       //Länge dieser Daten
    FData: LPBYTE;         //Die Daten selber
    function GetData: LPBYTE;
    procedure SetData(const Value: LPBYTE);
    function GetNode: PNode;
    procedure SetNode(const Value: PNode);
  public
    constructor Create;
    constructor CreateAndInit(
      lpSubKey: AnsiString;
      lpClass: AnsiString;
      dwOptions: DWORD;
      samDesired: REGSAM;
      aDataType: LPDWORD=nil;
      aDataLen: DWORD=0;
      aData: LPBYTE=nil
    );
    constructor CreateAndInitW(
      lpwSubKey: WideString;
      lpwClass: WideString;
      dwOptions: DWORD;
      samDesired: REGSAM;
      aDataType: LPDWORD=nil;
      aDataLen: DWORD=0;
      aData: LPBYTE=nil
    );
    destructor Destroy; override;
    property Subkey: AnsiString read FSubKey write FSubkey;
    property KeyClass: AnsiString read FKeyClass write FKeyClass;
    property KeyValue: AnsiString read FKeyValue write FKeyValue;
    property dwOptions: DWORD read FdwOptions write FdwOptions;
    property samDesired: REGSAM read FSamDesired write FsamDesired;
    property DataType: LPDWORD read FDataType write FDataType;
    property DataLen: DWORD read FDataLen write FDataLen;
    property Data: LPBYTE read GetData write SetData;
  end;

//Für jeden Subkey dann einen Registryeintrag
  TEntries = class(TObjectList) //Subkeys
  private
    function GetEntries(Index: Integer): TEntry;
    procedure SetEntries(Index: Integer; const Value: TEntry);
  public
    function FindSubKey(aSubKey: AnsiString; var Entry: TEntry): Integer;
    function FindClass(aClass: AnsiString; var Entry: TEntry): Integer;
    function FindValue(aValueName: AnsiString; var Entry: TEntry): Integer;
    property Entries[Index: Integer]: TEntry read GetEntries write SetEntries; default;
  end;

//Wegen der vielen Subkeys diese Klasse
  TKey = class(TObject)
  private
    FKey: HKEY;                 //Key
    FKeys: TEntries;
    function GetEntries: TEntries;
    procedure SetEntries(const Value: TEntries);
    function GetKeys(Index: Integer): TEntry;
    procedure SetKeys(Index: Integer; const Value: TEntry);      //Subkeys
  public
    constructor Create;
    destructor Destroy; override;
    property SubKeys[Index: Integer]: TEntry read GetKeys write SetKeys;
    property InThe: TEntries read FKeys write FKeys;
    property Key: HKEY read FKey write FKey;
  end;

//Und endlich alle Keys uns Subkeys in einer Liste
  TKeys = class(TObjectList)
  private
    function GetKeys(Index: Integer): TKey;
    procedure SetKeys(Index: Integer; Value: TKey);
  public
    constructor Create;
    destructor Destroy; override;
    function AddEntry(Key: HKey; Entry: TEntry): Integer; //Neuen Key
    function AddKey(Key: TKey): Integer; //Subkey
    function AddSubKey(Key: HKey; Entry: TEntry): Integer; //wie AddEntry

    property Keys[Index: Integer]: TKey read GetKeys write SetKeys;

  end;


implementation

constructor TEntry.Create;
begin
  inherited Create;
end;

constructor TEntry.CreateAndInit(lpSubKey, lpClass: AnsiString;
  dwOptions: DWORD; samDesired: REGSAM; aDataType: LPDWORD; aDataLen: DWORD;
  aData: LPBYTE);
begin
  inherited Create;
  FSubkey    := lpSubKey;
  FKeyClass  := lpClass;
  FdwOptions := dwOptions;
  FsamDesired := samDesired;
  FDataType  := aDataType;
  FDataLen   := aDataLen;
  FData      := aData;

end;

constructor TEntry.CreateAndInitW(lpwSubKey, lpwClass: WideString;
  dwOptions: DWORD; samDesired: REGSAM; aDataType: LPDWORD; aDataLen: DWORD;
  aData: LPBYTE);
begin
  inherited Create;
  FSubkey    := lpwSubKey;
  FKeyClass  := lpwClass;
  FdwOptions := dwOptions;
  FsamDesired := samDesired;
  FDataType  := aDataType;
  FDataLen   := aDataLen;
  FData      := aData;

end;

destructor TEntry.Destroy;
begin
  freemem(FData,FDataLen);
  inherited;
end;

function TEntry.GetData: LPBYTE;
begin
  Result := nil;
  {
  if FData <> nil then
    Result := FData
  else Result := nil;
  }
end;

function TEntry.GetNode: PNode;
begin
  Result := nil;
end;

procedure TEntry.SetData(const Value: LPBYTE);
begin
  FData := Value;
end;

procedure TEntry.SetNode(const Value: PNode);
begin
  //War ein vorheriger Ansatz mit Nodeslist,
  //den ich aber verworfen habe
end;

{ TEntries }

function TEntries.FindClass(aClass: AnsiString; var Entry: TEntry): Integer;
var Index: Integer;
begin
  Index := 0; Result := -1;
  while Index < self.Count do
  begin
    if TEntry(Items[Index]).KeyClass = aClass then
    begin
      Entry := TEntry(Items[Index]);
      Result := Index;
      //Index := self.Count;
      break;                      //wieder break statt Index auf Count
    end;                          //(auch in meinem Delphi Code geändert)
    inc(Index);
  end;
end;

function TEntries.FindSubKey(aSubKey: AnsiString; var Entry: TEntry): Integer;
var Index: Integer;
begin
  Index := 0; Result := -1;
  while Index < self.Count do
  begin
    if TEntry(Items[Index]).Subkey = aSubKey then
    begin
      Entry := TEntry(Items[Index]);
      Result := Index;
      //Index := self.Count;
      break;                   //wieder break statt Index auf Count
    end;                       //(auch in meinem Delphi Code geändert)
    inc(Index);
  end;
end;

function TEntries.FindValue(aValueName: AnsiString; var Entry: TEntry): Integer;
var Index: Integer;
begin
  Index := 0; Result := -1;
  while Index < self.Count do
  begin
    if TEntry(Items[Index]).KeyValue = aValueName then
    begin
      Entry := TEntry(Items[Index]);
      Result := Index;
      //Index := self.Count;
      break;                         //wieder break statt Index auf Count
    end;                             //(auch in meinem Delphi Code geändert)
    inc(Index);
  end;
end;

function TEntries.GetEntries(Index: Integer): TEntry;
begin
  if (Index >= 0) and (Index < Count)
    then Result := TEntry(Items[Index])
  else Result := nil;
end;

procedure TEntries.SetEntries(Index: Integer; const Value: TEntry);
begin
  Delete(Index);
  Insert(Index,Value);
end;


{ TKeys }

function TKeys.GetKeys(Index: Integer): TKey;
begin
  Result := TKey(Items[Index]);
end;

procedure TKeys.SetKeys(Index: Integer; Value: TKey);
begin
  Keys[Index] := Value;
end;

function TKeys.AddEntry(Key: HKEY; Entry: TEntry): Integer;
begin
  Result := AddSubKey(Key, Entry);
end;

function TKeys.AddKey(Key: TKey): Integer;
begin
  Result := inherited Add(Key);
end;

function TKeys.AddSubKey(Key: HKEY; Entry: TEntry): Integer;
var Index,subix: Integer;
begin
  Index := 0; Result := -1; //so jetzt ist Result auf jeden Fall definiert (auch in meinem Delphi Code geändert)
  while Index < Count do
  begin
    if TKey(Items[Index]).FKey = Key then
    begin
      TKey(Items[Index]).inThe.Add(Entry);
      Result := Index;
      Index := Count;
      break;
    end;
    Inc(Index);
  end;
end;

constructor TKeys.Create;
begin
  inherited Create;
end;

destructor TKeys.Destroy;
begin

  inherited;
end;

{ TKey }

constructor TKey.Create;
begin
  inherited Create;
end;

destructor TKey.Destroy;
begin

  inherited;
end;

function TKey.GetEntries: TEntries;
begin
  Result := FKeys;
end;

function TKey.GetKeys(Index: Integer): TEntry;
begin
  Result := FKeys.GetEntries(Index);
end;

procedure TKey.SetEntries(const Value: TEntries);
begin
  FKeys.Assign(Value);
end;

procedure TKey.SetKeys(Index: Integer; const Value: TEntry);
begin
  FKeys.SetEntries(Index,Value);
end;

end.
Ich kann aber die Werte nach Füllen der Liste nicht wieder auslesen.

Warum geht das nicht, ich sehr den Fehler nicht.

Mein Testprogramm sieht so aus:

Delphi-Quellcode:
program EntryTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Windows, Entries;

var
  AKey: TKey;
  Keys: TKeys;
  Entr: TEntry;

begin
  try
    { TODO -oUser -cConsole Main : Code hier einfügen }

    Entr := TEntry.Create;
    Entr.Subkey := 'Erster Testschlüssle';
    AKey := TKey.Create;
    AKey.Key := 1111;
    Keys := TKeys.Create;
    Keys.AddKey(AKey);
    Keys.AddEntry(1111,Entr);

    Writeln('Mein Ergebnis der Eingabe:');

    TKey(Keys.Keys[0])..inThe.FindSubKey(Entr.Subkey, Entr);

    if Entr <> nil then Writeln('Gefundener Key: ', Entr.Subkey);

    Writeln('Zurück mit Enter ... ');
    Readln;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Bei der Ausgabe erhalte ich eine EAccessviolation, wohl wird mein Key nicht wiedergefunden, Entr hat den Wert NIL!

Der Delphi Debugger hält danach bei TList.Add() an

Warum?

.

himitsu 24. Okt 2020 22:42

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Entr kann nicht nil sein, da du niemals Nil setzt.

Es wird ausschließlich das Result gesetzt, also ist deine Prüfung falsch,
Delphi-Quellcode:
X := TKey(Keys.Keys[0]).inThe.FindSubKey(Entr.Subkey, Entr);
//if X >= 0 then ... ja, nun rächt es sich, dass hier ein total unpraktisches Result "Count" rausgegeben wird, wenn nichts gefunden wurde
if X < TKey(Keys.Keys[0]).inThe.Count then ... oder sowas
oder in FindSubKey muß Entr auch auf Nil gesetzt werden.

Auf den ersten Blick seh ich auch nichts,
aber rate mal wozu der Debugger da ist.

delphifan2004 24. Okt 2020 23:01

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Danke erst mal für die Antwort. Ja, ich weiß, wozu ein Debugger gut ist. Da bin ich jetzt gerade drüber, habe aber noch keine Idee, woran es liegen könnte. Der Debugger sagt mit aber dass diese Anweisung in der TKeys.AddSubKey Methode nicht in Ordnung ist.

Delphi-Quellcode:
TKey(Items[Index]).inThe.Add(Entry);
Mit Entr will ich meinen Subkey haben. Result gibt den Index in die KeyListe zurück, also der wievielte Key den Subkey enthält.

TEntries enthlt meine Subkeys vom Typ TEntry

TKeys enthält meine Keys vom Typ TKey, bestened aus dem numerischen Key und der TEntries Liste mit den zugehörigen Subkeys.

Mit Result := Count will ich die Schleife beenden, Break hat in einem anderen Kontext wo ich die Unit getestet hatte das gesamte Programm verlassen. Obwohl break nur die aktuelle Schleife verlassen sollte. Kann aber break noch mal in diesem Kontext hier testen.

himitsu 24. Okt 2020 23:14

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Bei AddSubKey seh ich grade, dass Result garnicht zugewiesen wird, wenn der Key nicht existiert.
Da sollte der Compiler eigentlich auch eine Warnung werfen und es wäre besser, wenn du diese Fehler erstmal beseitigst.

Ich bin mir auch fast sicher, dass AddEntry/AddSubKey garnicht macht, weswegen man natürlich auch nichts finden kann und durch die fehlenden Indexprüfungen die nachfolgenden Zugriffe auch schön knallen dürfen.


PS: In einem etwas aktuelleren Delphi (maximal 10 statt 18 Jahre alt), würden durch die Generics eventuelle Fehler durch falsche Casts entfallen.

delphifan2004 24. Okt 2020 23:52

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Da guck ich dann morgen. Jetzt schlaf ich erst mal darüber, vielleicht kommt mir dann morgen noch eine Idee. Soweit erst mal Danke für die Tipps. Da geh ich den Result Zuweisungsfehler noch an und überlege mir morgen ein besseres Design. Leider habe ich mit Generics noch gar keine Erfahrung. Mein Delphi ist inzwischen auch die brandneue Delphi 10.3.3 Community Edition, also weit unter 10 Jahre alt. Die letzte vorherige war Turbo Delphi.

freimatz 26. Okt 2020 08:12

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Zitat:

Zitat von delphifan2004 (Beitrag 1476078)
Danke erst mal für die Antwort. Ja, ich weiß, wozu ein Debugger gut ist. Da bin ich jetzt gerade drüber, habe aber noch keine Idee, woran es liegen könnte. Der Debugger sagt mit aber dass diese Anweisung in der TKeys.AddSubKey Methode nicht in Ordnung ist.

Delphi-Quellcode:
TKey(Items[Index]).inThe.Add(Entry);

Offensichtlich weisst du nur teilweise wozu ein Debugger da ist. :-D
Vielleicht auch ich, habe keine Ahnung wie der Debugger sagen kann, dass eine Methode nicht in Ordnung sei.
Wenn das Problem bei "TKey(Items[Index]).inThe.Add(Entry);" liegt dann
a) lass Dir doch die Werte anzeigen. Z.B. Zuerst von "Index", dann von "Items[Index])", dann "TKey(Items[Index])" usw.
b) Zerlege den komplizierten Ausdruck in einfachere.

delphifan2004 26. Okt 2020 10:58

AW: Warum kann ich die Eingaben nicht wieder auslesen
 
Hab ich jetzt auch gemacht, die Zeile lautet jetzt

TKey(Items[Index]).AddEntry(Entry);

Wobei ich diese Methode in TKey hinzugefügt habe.

Delphi-Quellcode:
function TKey.AddEntry(AEntry): Integer;
begin
  Result := -1;
  if Assigned(FKeys) then Result := FKeys.Add(AEntry);
end;
So funktioniert nun auch das Einfügen von Keys.

Uns so lese ich aus

Delphi-Quellcode:
    for KeyIdx := 0 to Keys.Count-1 do
    for SubIdx := 0 to Keys.Keys[KeyIdx].InThe.Count-1 do
    begin
      Entr := nil;
      Entr := Keys.Keys[KeyIdx].SubKeys[SubIdx];
      //Keys.Keys[KeyIdx].InThe.FindSubKey('Zweiter Testschlüssel',Entr);
      if Entr <> nil then Writeln('Gefundener Key: ', Entr.Subkey);
    end;


Alle Zeitangaben in WEZ +2. Es ist jetzt 00:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf