AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Probleme mit Objektkopie und eigenem MessageDialog

Probleme mit Objektkopie und eigenem MessageDialog

Ein Thema von haentschman · begonnen am 19. Dez 2018 · letzter Beitrag vom 21. Dez 2018
Antwort Antwort
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.428 Beiträge
 
Delphi 12 Athens
 
#1

Probleme mit Objektkopie und eigenem MessageDialog

  Alt 19. Dez 2018, 18:45
Hallöle...

Ich stehe wieder mal vor einem Problem das ich nicht verstehe...

Gegeben:
* Klasse:
Delphi-Quellcode:
TDocumentProperties = class(TBaseObject)
  strict private
  {$REGION 'Fields'}
    FStoreLocation: string;
    FStoreStreet: string;
    FReceiptReciverName: string;
    FDocumentTypeString: string;
    FDocumentChoiceString: string;
    FDocumentLocation: TSEAMDocumentLocation;
    FStoreName: string;
    FCreateDate: TDateTime;
    FCreateName: string;
    FCreateYear: Integer;
    FModifiedName: string;
    FModifiedDate: TDateTime;
    FDocumentChoice: TSEAMDocumentChoice;
    FServiceDate: TDateTime;
    FNote: string;
    FStoreCountry: string;
    FReceiptDate: TDateTime;
    FStorePostCode: string;
    FReceiptReciverNumber: string;
    FServicePartnerNumber: string;
    FLocationNumber: string;
    FReceiptNumber: string;
    FStoreName_1: string;
    FDocumentCaption: string;
    FStoreNumber: string;
    FFileName: string;
    FFilePath: string;
    FExtension: string;
    FSendType: string;
    FFileNameContent: TStringList;
    procedure SetExtension(const Value: string);
    procedure SetFileName(const Value: string);
  {$ENDREGION}
  public
    constructor Create;
    destructor Destroy; override;
    property StoreNumber: string read FStoreNumber write FStoreNumber;
    property StoreName: string read FStoreName write FStoreName;
    property StoreName_1: string read FStoreName_1 write FStoreName_1;
    property StoreStreet: string read FStoreStreet write FStoreStreet;
    property StoreCountry: string read FStoreCountry write FStoreCountry;
    property StorePostCode: string read FStorePostCode write FStorePostCode;
    property StoreLocation: string read FStoreLocation write FStoreLocation;
    property Note: string read FNote write FNote;
    property CreateDate: TDateTime read FCreateDate write FCreateDate;
    property CreateName: string read FCreateName write FCreateName;
    property CreateYear: Integer read FCreateYear write FCreateYear;
    property ModifiedDate: TDateTime read FModifiedDate write FModifiedDate;
    property ModifiedName: string read FModifiedName write FModifiedName;
    property ReceiptDate: TDateTime read FReceiptDate write FReceiptDate;
    property ServiceDate: TDateTime read FServiceDate write FServiceDate;
    property DocumentChoice: TSEAMDocumentChoice read FDocumentChoice write FDocumentChoice;
    property DocumentLocation: TSEAMDocumentLocation read FDocumentLocation write FDocumentLocation;
    property DocumentChoiceString: string read FDocumentChoiceString write FDocumentChoiceString;
    property DocumentTypeString: string read FDocumentTypeString write FDocumentTypeString;
    property DocumentCaption: string read FDocumentCaption write FDocumentCaption;
    property SendType: string read FSendType write FSendType;
    property ReceiptNumber: string read FReceiptNumber write FReceiptNumber;
    property ReceiptReceiverNumber: string read FReceiptReciverNumber write FReceiptReciverNumber;
    property ReceiverReceiverName: string read FReceiptReciverName write FReceiptReciverName;
    property ServicePartnerNumber: string read FServicePartnerNumber write FServicePartnerNumber;
    property LocationNumber: string read FLocationNumber write FLocationNumber;
    property Extension: string read FExtension write SetExtension;
    property FileName: string read FFileName write SetFileName;
    property FilePath: string read FFilePath write FFilePath;
    procedure Assign(Source: TObject);
    function EncodeFileName: string;
    procedure DecodeFileName(FileName: string);
  end;
* GUI
Delphi-Quellcode:
procedure TfoDocuments.DoScrollDocuments(FocusedRecord: TcxCustomGridRecord);
var
  MessageList: TStringList;
  FileName: string;

  Test1, Test2: Pointer;
begin
  if FLogic.DocumentDatasource.Changed then
  begin
    MessageList := TStringList.Create;
    try
      FileName := FLogic.ModifiedDocument.FileName;
      MessageList.Add(Format(conTextConfirmationChangedDocument, [QuotedStr(FileName)]));
      MessageList.Add('');
      MessageList.Add(conTextConfirmationChangedDocument_1);
      if TMessageDialog.MessageDlg(MessageList, conTextSaveHeader, vmtQuestion, [buYes, buNo], clBlack, Self) = mrYes then
      begin
        FLogic.SaveDocument;
      end;
    finally
      MessageList.Free;
    end;
  end;

  FLogic.AfterScrollDocuments(FocusedRecord.RecordIndex); // Wechsel des Objekte in der Logic

  Test1 := Pointer(FLogic.OriginalDocument); // Kontrolle
  Test2 := Pointer(FLogic.ModifiedDocument); // Kontrolle

  if FLogic.ModifiedDocument.FileName.EndsWith('.pdf', True) then
  begin
    if FileExists(FLogic.ModifiedDocument.FileName) then
    begin
      WPViewPDF1.LoadFromFile(FLogic.ModifiedDocument.FileName);
    end
    else
    begin
      WPViewPDF1.Clear;
      TMessageDialog.MessageDlg(Format(conErrorFileNotPresent, [QuotedStr(FLogic.ModifiedDocument.FileName)]), conTextCheckHeader, vmtError, [buOk], clBlack, Self); // --> Zugriffsverletzung aus dem TReader im OnCreate der Dialog Form (siehe Unit)
    end;
  end;

  ShowDocument(FLogic.ModifiedDocument);
end;
* Logic
Delphi-Quellcode:
constructor TFormDocumentsLogic.Create(Preferences: TSEAMPreferences);
begin
  inherited Create(Preferences);
  FDocumentDatasource := TSEAMDocumentsDatasource.Create;
  FDocumentDatasource.OnChange := DoOnChange;
  FOriginalDocument := nil; // aus Liste
  FModifiedDocument := nil; // über Objektkopie
  FLastStoreName := '';
end;
...
procedure TFormDocumentsLogic.AfterScrollDocuments(FocusedRecordIndex: Integer);
begin
  FOriginalDocument := FDocumentDatasource.GetObject(FocusedRecordIndex); // Pointer aus Liste bleibt unangetastet
  if Assigned(FModifiedDocument) then // mit jedem Scroll die "Kopie" austauschen
  begin
    FModifiedDocument.Free;
  end;
  FModifiedDocument := TSEAMDocumentProperties(TSEAMToolsJson.ObjectCopy(FOriginalDocument)); // Kopie des Originals aus der Liste
  //wenn ich diese Zeile auskommentiere wird der Dialog angezeigt.
end;
* Objektkopie (funktioniert eigentlich immer)
Delphi-Quellcode:
class function TToolsJson.ObjectCopy(aValue: TObject): TObject;
var
  MarshalObj: TJSONMarshal;
  UnMarshalObj: TJSONUnMarshal;
  JSONValue: TJSONValue;
begin
  Result := nil;
  MarshalObj := TJSONMarshal.Create;
  try
    UnMarshalObj := TJSONUnMarshal.Create;
    try
      JSONValue := MarshalObj.Marshal(aValue);
      try
        if Assigned(JSONValue) then
          Result := UnMarshalObj.Unmarshal(JSONValue);
      finally
        JSONValue.Free;
      end;
    finally
      UnMarshalObj.Free;
    end;
  finally
    MarshalObj.Free;
  end;
end;

Problem:

1. Wenn ich ausschließlich das Originalobjekt oder ein leeres Objekt benutze (ohne FModifiedDocument Kopie), dann wird der Dialog angezeigt.
Delphi-Quellcode:
FModifiedDocument := TDocumentProperties.Create; //(TToolsJson.ObjectCopy(FOriginalDocument));
.
2. Wenn ich das Originalobjekt kopiere, auch bei der Benutzung von FOriginalDocument, kommt eine Zugriffsverletzung im OnCreate der Dialog Form.


Frage:

Was hat der Reader der Form damit zu tun? Der Code des MessageDialogs ist in Ordnung...


Danke...
Angehängte Grafiken
Dateityp: png Fehler.png (27,1 KB, 41x aufgerufen)
Dateityp: jpg Break.jpg (97,1 KB, 39x aufgerufen)
Dateityp: png Dialog.png (9,0 KB, 39x aufgerufen)

Geändert von haentschman (20. Dez 2018 um 07:24 Uhr)
  Mit Zitat antworten Zitat
CCRDude

Registriert seit: 9. Jun 2011
678 Beiträge
 
FreePascal / Lazarus
 
#2

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 07:53
Wie schön dass Du beurteilst dass der Code des MessageDialogs in Ordnung ist, aber offensichtlich spielt er ja doch mit rein, insofern wäre der constructor dort vermutlich hilfreich bei der Problemsuche
(oder anders ausgedrückt: mit solchen Ausschlüssen steht man sich selber gerne im Weg, schließlich ist man als Autor des Codes ja noch am ehesten betriebsblind)
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.490 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 08:09
Mein Vorschläge:
1. reduziere den Code so dass der Fehler gerade noch auftritt und dann weiter bis er nicht mehr auftritt. Dazwischen muss die Ursache liegen.
2. Baue den Code nach Clean Code Regeln um. Dann funktioniert er auch
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.428 Beiträge
 
Delphi 12 Athens
 
#4

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 09:26
Guten Morgen...

Danke für eure Anteilnahme.
Zitat:
Wie schön dass Du beurteilst dass der Code des MessageDialogs in Ordnung ist, aber offensichtlich spielt er ja doch mit rein, insofern wäre der constructor dort vermutlich hilfreich bei der Problemsuche
...das dumme ist nur, daß der Fehler im TReader beim Lesen des Formulars auftritt...in den constructor kommt er nicht!
Zitat:
reduziere den Code so dass der Fehler gerade noch auftritt und dann weiter bis er nicht mehr auftritt. Dazwischen muss die Ursache liegen.
Ich konnte die Ursache herausfinden. Nur verstehe ich es nicht! Ich mache nur eine Objektkopie (privat) aus einem Objekt in einer Objektliste. Ohne Kopie wird der Dialog angezeigt, mit Kopie wird der Dialog nicht angezeigt!
Zitat:
Baue den Code nach Clean Code Regeln um. Dann funktioniert er auch
Verstehe ich nicht. Was hast daran auszusetzen?
Angehängte Grafiken
Dateityp: png Callstack.png (44,7 KB, 22x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.599 Beiträge
 
Delphi 12 Athens
 
#5

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 09:40
Der Fehler tauch beim Lesen der DFM-Resource der Dialog-Forms aus. Wenn das plötzlich schief geht, ist das ein Zeichen für einen korrupten Speicher (die Resource stimmt offenbar nicht mehr).

Das deutet auf einen unerlaubten Speicher-Zugriff hin und hat vermutlich gar nichts mit deinem Code selbst zu tun. Eventuell passiert in ObjectCopy irgendwas Unanständiges.

Lass das Programm doch mal mit Range-Checking laufen. Wenn das keine Erkenntnisse bringt, würde ich den Einsatz von FastMM im FullDebugMode empfehlen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.428 Beiträge
 
Delphi 12 Athens
 
#6

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 09:53
Moin...
Zitat:
Das deutet auf einen unerlaubten Speicher-Zugriff hin und hat vermutlich gar nichts mit deinem Code selbst zu tun. Eventuell passiert in ObjectCopy irgendwas Unanständiges.
...das vermute ich auch. Die Objektkopiefunktion habe ich ständig in Gebrauch. Die macht nix anderes als TObject in JSON zu wandeln und das JSON wieder in ein TObject zu erzeugen.

Zitat:
Lass das Programm doch mal mit Range-Checking laufen. Wenn das keine Erkenntnisse bringt, würde ich den Einsatz von FastMM im FullDebugMode empfehlen
...mach ich.

Danke...
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.490 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Probleme mit Objektkopie und eigenem MessageDialog

  Alt 20. Dez 2018, 12:57
Ich habe da gar nichts auszusetzen. Meine Erfahrung ist oft wenn ich in altem Code Fehler suche, dass es mir hilft ihn erst mal nach diesen Regelnum zubauen.

Was mir konkret auffällt:

1. Warum hat TDocumentProperties so viele properties die nichts machen? Warum nicht gleich ein record? (KISS)
2. Warum hat die Klasse auch Methoden? (Auch ein record kann Methoden haben.) Vielleicht wäre es besser die Datenhaltung und die Verarbeitung zu trennen und ein DTO daraus zu machen (SoC)
3. "TMessageDialog.MessageDlg(Format(conErrorFileNotP resent, ...);" aufteilen. Die Zeile ist sehr lang. Einfach wäre es erst mal den string in einer lokalen Variablen zwischenzuspeichern dessen Namen auch sagt um was es geht.
4. "FModifiedDocument := TSEAMDocumentProperties(TSEAMToolsJson.ObjectCopy( FOriginalDocument));" - harte Typecasts vermeiden. Wenn dann erst prüfen ob das auch der gewünschte Typ ist.
  Mit Zitat antworten Zitat
Antwort Antwort

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 01:31 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 by Thomas Breitkreuz