AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Zugriffsverletzung beim Zerstören der TIniFile-Instanz
Thema durchsuchen
Ansicht
Themen-Optionen

Zugriffsverletzung beim Zerstören der TIniFile-Instanz

Ein Thema von TheSledgeHammer · begonnen am 26. Jan 2021 · letzter Beitrag vom 3. Feb 2021
Antwort Antwort
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#1

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 12:58
2.
Wenn in der DLL TForm verwendet wird, enthält die DLL eine komplett eigenständige Kopie der VCL.
Die VCL verwendet ebenfalls globale Variablen, insbesondere "Application".
"Application.Handle" muss vor der Verwendung der VCL in der DLL einmalig gesetzt werden.
Delphi-Quellcode:
{in der DLL, Handle der Anwendung übernehmen}
procedure InitVCL(AHandle: THandle); stdcall;
begin
  Application.Handle := AHandle;
end;
{in der Anwendung, Handle der Anwendung übergeben}
...
InitVCL(Application.Handle);
Ich hab mir das mal zu Gemüte geführt. Hab das meiner Meinung nach auch korrekt umgesetzt, allerdings kommt jetzt irgendwann im Erstellungsprozess die Exception
Exception-Klasse EOSError mit Meldung
System Error. Code 1400. Ungültiges Fensterhandle.

Application war auch zu Beginn nicht verfügbar, da die Unit Vcl.Forms nicht eingebunden war. Ich möchte jetzt sicher gehen, dass ich das korrekt verstanden hab: das soll schon in der DLL gesetzt werden, richtig? Nicht erst "während" des Konstruktors des eigentlichen TForm-Objekts? Da wäre es meiner Meinung nach nämlich zu spät, aber ich will da lieber nochmal nachfragen. Das sieht jetzt ungefähr so aus:
Delphi-Quellcode:
// In der DLL
procedure CreateSearch({... ;} AHnd: THandle); cdecl;
begin
  Application.Handle := AHnd; // hier ist das ja korrekt oder?
  FDynamicSearchDlg := TFormDynamicSearchDialog.Create({...}); // hier als Parameter wäre zu spät, richtig?
  // usw.
end;

// Im DLL-Interface (-> außerhalb der DLL, in der EXE drinnen sozusagen)
CreateSearch({...;}, Application.Handle);
Tobias
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.493 Beiträge
 
Delphi 12 Athens
 
#2

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 15:03
Application war auch zu Beginn nicht verfügbar, da die Unit Vcl.Forms nicht eingebunden war. Ich möchte jetzt sicher gehen, dass ich das korrekt verstanden hab: das soll schon in der DLL gesetzt werden, richtig? Nicht erst "während" des Konstruktors des eigentlichen TForm-Objekts? Da wäre es meiner Meinung nach nämlich zu spät, aber ich will da lieber nochmal nachfragen. Das sieht jetzt ungefähr so aus:
Delphi-Quellcode:
// In der DLL
procedure CreateSearch({... ;} AHnd: THandle); cdecl;
begin
  Application.Handle := AHnd; // hier ist das ja korrekt oder?
  FDynamicSearchDlg := TFormDynamicSearchDialog.Create({...}); // hier als Parameter wäre zu spät, richtig?
  // usw.
end;

// Im DLL-Interface (-> außerhalb der DLL, in der EXE drinnen sozusagen)
CreateSearch({...;}, Application.Handle);
Ja im Prinzip hab ich das so gedacht. Die Initialisierung kann aber erst erfolgen, wenn die Applikarion schon läuft (Hauptfenster erzeugt ist).
Da dein Formular von TForm abgeleitet ist, muss die Unit Forms zumindest da schon eingebunden sein.
http://docwiki.embarcadero.com/Libra...ication.Handle

Modale Formulare vorher zu erzeugen und nur bei Bedarf anzuzeigen ist in der Regel nicht sinnvoll.
Diese werden häufig nach diesem Schema benutzt:
Delphi-Quellcode:
procedure ShowMyDialogForm(var AMyData: TMyData): Boolean;
var
  F: TMyDialogForm; // globale Variable ist für Dialoge nicht erforderlich
begin
  F := TMyDialogForm.Create(nil); // Owner = nil, wir übernehmen selbst die Freigabe des Dialogs
  try
    {Daten übergeben zur Anzeige/Bearbeitung z.B.}
    F.Data := Copy(AMyData);

    Result := (F.ShowModal = mrOk);

    {geänderte Daten übernehmen}
    if Result then
      AMyData := Copy(F.Data);
  finally
    F.Free;
  end;
end;
Wenn tatsächlich im Contructor ein Fehler auftreten kann, sollte man das zusätzllich mit try..except absichern.
F wird dann nicht zugewiesen und der Resourcenschutzblock try..finally komplett nicht durchlaufen.
Man solllte Objekte immer auf der Ebene freigeben, wo diese auch erzeigt wurden, insbesondere aber nur an einer Stelle.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.493 Beiträge
 
Delphi 12 Athens
 
#3

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 15:32
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.

Rückgabewerte aus der DLL als PChar sind problematisch. Solange der Rückgabewert auf eine Constante oder einen Resourcestring verweist, ist das ok.
Delphi-Quellcode:
function MyDLLFunction(): PChar;
const
  sc = 'ConstText';
var
  s: string;
begin
  s := MyInternFunction;
  Result := PChar(s); // unzulässig da "s" nach verlassen der Funktion eventuell nicht mehr existiert
  // <- wenn Referenzzähler von s auf 0 fällt, wird der String freigegeben, Result enthält einen ungültiger Zeiger

  s := sc;
  Result := PChar(s); // zulässig da "s" auf eine Konstante verweist
  // Referenzzähler von String-Konstanten ist immer -1
end;
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.734 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 27. Jan 2021, 17:36
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.
Doch. Ein "auf String casten" erzeugt eine Kopie des Inhalts.

Man muss nur darauf achten, dass auf beiden Seiten das gleiche PChar verwendet wird, oder besser gleich auf beiden Seiten PAnsiChar oder PWideChar, dann ist es eindeutig.
Thomas Mueller
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.493 Beiträge
 
Delphi 12 Athens
 
#5

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 29. Jan 2021, 09:34
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.
Doch. Ein "auf String casten" erzeugt eine Kopie des Inhalts.

Man muss nur darauf achten, dass auf beiden Seiten das gleiche PChar verwendet wird, oder besser gleich auf beiden Seiten PAnsiChar oder PWideChar, dann ist es eindeutig.
Das ist richtig, die Kopie kann man natürlich verändern. Delphi behandelt PChar, PAnsiChar, PWideChar anders wie normale Pointer.
  Mit Zitat antworten Zitat
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 28. Jan 2021, 07:03
Parameter als PChar sind problemlos verwendbar, solange die übergebenen Zeichenketten in der DLL nicht verändert werden.
Wieder auf String casten und dann verändern ist nicht zulässig.

Rückgabewerte aus der DLL als PChar sind problematisch. Solange der Rückgabewert auf eine Constante oder einen Resourcestring verweist, ist das ok.
Delphi-Quellcode:
function MyDLLFunction(): PChar;
const
  sc = 'ConstText';
var
  s: string;
begin
  s := MyInternFunction;
  Result := PChar(s); // unzulässig da "s" nach verlassen der Funktion eventuell nicht mehr existiert
  // <- wenn Referenzzähler von s auf 0 fällt, wird der String freigegeben, Result enthält einen ungültiger Zeiger

  s := sc;
  Result := PChar(s); // zulässig da "s" auf eine Konstante verweist
  // Referenzzähler von String-Konstanten ist immer -1
end;
Also hier gibt es keine Probleme. Ich caste alles entsprechend, so wie dummzeuch es ja beschrieben hat. I.d.R. werden aber die PChar-Variablen unverändert einfach durch gereicht, von daher gibt es hier auch keine Veränderungen. Aber sollte es in einem anderen Fall dazu kommen, wird natürlich eine lokale Kopie erzeugt und mit der weiter gearbeitet.
Tobias
  Mit Zitat antworten Zitat
TheSledgeHammer

Registriert seit: 22. Mai 2019
Ort: Mulfingen
43 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz

  Alt 28. Jan 2021, 07:00
Ja im Prinzip hab ich das so gedacht. Die Initialisierung kann aber erst erfolgen, wenn die Applikarion schon läuft (Hauptfenster erzeugt ist).
Da dein Formular von TForm abgeleitet ist, muss die Unit Forms zumindest da schon eingebunden sein.
http://docwiki.embarcadero.com/Libra...ication.Handle
Also nur, damit ich das klarstelle: wenn ich den Erben einer TForm-Klasse (hier das Objekt TFormDynamicSearchDialog) erzeuge, brauche ich keine Unit Vcl.Forms einbinden; das geht auch ohne. In derjenigen Unit, wo ich die Klasse TFormDynamicSearchDialog allerdings implementiere, da brauche ich das natürlich, sonst kennt Delphi ja den Typ TForm nicht.

Ich hab jetzt aber dort, wo ich den Erben von TForm instanziiere, das Obkekt Application verwenden sollen und da brauchte ich bisher die Unit Vcl.Forms noch nicht. Daher hab ich sie jetzt erst eingebunden. Aber wie ich ja sagte: ich erhalte eine invalid handle value Exception. Und das während der Konstruktion des Objekts TFormDynamicSearchDialog. Ich glaub es war bei der Erzeugung des PageControl-Components, bin mir aber nicht mehr sicher. Was mache ich denn jetzt damit? Die Hauptapplikation ist ja die EXE-Anwendung und die läuft natürlich schon. Oder hast du damit gemeint, dass ich das Handle-Value nach der Erzeugung des Objekts TFormDynamicSearchDialog erst setzen soll?

Modale Formulare vorher zu erzeugen und nur bei Bedarf anzuzeigen ist in der Regel nicht sinnvoll.
Diese werden häufig nach diesem Schema benutzt:
Delphi-Quellcode:
procedure ShowMyDialogForm(var AMyData: TMyData): Boolean;
var
  F: TMyDialogForm; // globale Variable ist für Dialoge nicht erforderlich
begin
  F := TMyDialogForm.Create(nil); // Owner = nil, wir übernehmen selbst die Freigabe des Dialogs
  try
    {Daten übergeben zur Anzeige/Bearbeitung z.B.}
    F.Data := Copy(AMyData);

    Result := (F.ShowModal = mrOk);

    {geänderte Daten übernehmen}
    if Result then
      AMyData := Copy(F.Data);
  finally
    F.Free;
  end;
end;
Exakt! Und dieses Schema bilde ich heute schon in der EXE-Anwendung nach. Dort steht es exakt so, wie du es im Beispiel gezeigt hast. Jetzt wurde aber das Objekt in eine DLL verlagert und da ich ja nicht wollte, dass meine Kollegen zu viel Code anpassen müssen, hab ich die einzelnen Methoden in der DLL abgebildet. D.h. um in deinem Beispiel zu bleiben gibt es einen Konstruktor, einen Destruktor, ein ShowModal und eine Property; letztere gibt es natürlich nur im Interface zur DLL, die DLL selbst exportiert dann natürlich eine Setter- und Getter-Methode. Daher steht das "Create" getrennt von dem "ShowModal", was die DLL angeht. Aber das ist ja nichts, was man jetzt nicht machen darf. Eine neue Komponente würde ich so natürlich nicht programmieren, da gäbe es dann eine Art "CreateAndShow"-Methode oder so.
Tobias
  Mit Zitat antworten Zitat
Antwort Antwort


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 14:14 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