Autor: Zou Fei
E-Mail: [email protected]
Homepage: http://www.atechsoft.com/people/zouf/ Bei der Verwendung von Delphi werden Sie unweigerlich auf viele seltsame Probleme stoßen, und die Dokumentation von Delphi ist auch überraschend gering, sodass ich sie nur langsam zusammenfassen kann , also gibt es sie (Da es sich nur um verstreute Details handelt, habe ich mir beim Schreiben nicht viel Mühe gegeben, es ist vielleicht etwas chaotisch, aber es sollte verständlich sein;-)). Wenn: 1. Wenn Sie eine bessere Lösung für das folgende Problem haben, sagen Sie es mir und meinen Freunden auf csdn. 2. Wenn Sie weitere Fragen haben, listen Sie bitte die Probleme und Ihre Antworten auf und sagen Sie es mir und meinen Freunden auf csdn. Kommunikation schafft alles!
Text: F: Wenn ein in der Delphi-DLL erstelltes Formular in Exe ShowModal ist, werden in der Taskleiste zwei Symbole angezeigt. Wie kann dieses Problem gelöst werden? A: Das Folgende ist eine typische Methode zum Platzieren eines Formulars in einer DLL: DLL: function ShowFrm: TModalResult;beginForm1 := TForm1.Create(Nil); tryForm1.Free;end;end; Funktion ShowFrm: TModalResult; stdcall; 'TestDLL.dll';…begin…ShowFrm;…end Das auf diese Weise erstellte Formular zeigt ein weiteres Symbol mit der Hauptanwendung an. Der Grund dafür ist, dass für die DLL eine andere Anwendung erstellt wird Die Anwendung zeigt ein Taskleistensymbol an. Lösung: Übergeben Sie die Anwendung der Haupt-EXE-Datei wie folgt an die DLL in der Hauptanwendung: DLL: function ShowFrm(app: TApplication): TModalResult; stdcall;varoldApp: TApplication;beginoldApp := Application;Application := app;Form1 : = TForm1.Create(Nil);tryForm1.ShowModal;finallyForm1.Free;end;Application := oldApp;end;Main EXE: function ShowFrm(app: TApplication): TModalResult; stdcall; external 'TestDLL.dll';…begin…ShowFrm(Application);…end Hinweis: Anwendung in DLL und Anwendung in EXE Es gibt immer noch einige Unterschiede, schauen Sie sich den Code in Forms.pas an: Konstruktor TApplication.Create(AOwner: TComponent);begin…if not IsLibrary then CreateHandle;…end;Es kann bekannt sein, dass die Anwendung in der DLL kein Handle hat, sodass die Nachrichtenschleifenverarbeitung nicht durchgeführt wird, was auch richtig ist. F: Mit DLLs in Delphi treten häufig Probleme auf! A: Der Grund, warum das Problem auftritt, liegt im Delphi-eigenen Speicherverwaltungsmechanismus. Beispiel: Erstellen Sie ein Objekt in einer DLL: x := TClass.Create(Application); Zu diesem Zeitpunkt wird Delphi automatisch freigeben. Der Adressraum ist möglicherweise abgelaufen (verschiedene Betriebssysteme sind unterschiedlich), daher wird der Freigabevorgang von x durchgeführt eine Ausnahme auslösen. Ein weiteres Beispiel: Erstellen Sie ein Objekt in EXE und übergeben Sie die DLL als lokale Variable in der DLL. Wenn die DLL zerstört wird, gibt Delphi automatisch alle Variablen frei, die außerhalb des Gültigkeitsbereichs liegen Es wird eine Ausnahme ausgelöst. Im Allgemeinen ist das Problem auf den Speicherverwaltungsmechanismus des „intelligenten“ Delphi-Compilers und den DLL-Hinzufügen/Entladen-Mechanismus von Windows zurückzuführen, was zu Speicherzugriffskonflikten in der DLL und EXE führt. Lösung: (Die meisten Probleme können vermieden werden, solange Sie die folgenden Grundsätze befolgen) 1. Versuchen Sie, zwischen DLL und EXE nicht den automatischen Speicherverwaltungsmechanismus zu verwenden. Der Programmierer ist für den Lebenszyklus des Objekts verantwortlich. Ändern Sie ihn beispielsweise in: x : = TClass.Create(nil); Auf diese Weise gibt die Anwendung es nicht mehr frei. Natürlich muss der Programmierer es selbst freigeben. 2. Versuchen Sie zu vermeiden, dass zwischen der DLL und der EXE-Datei unterschiedliche Zeiger auf dasselbe Objekt zeigen. Beispielsweise zeigt x in der DLL auf das TClass-Objekt und in der EXE-Datei y auf das TClass-Objekt. Auf diese Weise führt die Speicherfreigabe auf einer Seite dazu, dass der Speicher auf der anderen Seite ungültig wird. 3. Andere... F: Ein Thread, der periodische Aufgaben ausführt, muss einen Moment pausieren und dann weiterlaufen. Aber was ist, wenn der Thread zu diesem Zeitpunkt gestoppt werden muss (z. B. wenn der Prozess beendet ist)? A: Lösung 1: Führen Sie eine regelmäßige Schleife durch Sleep im Thread durch. (Wenn der Thread durch Sleep angehalten wird, kann er nicht durch Resume und andere Methoden wiederbelebt werden.) Beenden Sie den Thread durch KillThread. Dies ist die einfachste Methode, aber sie ist zu grob und kann Probleme verursachen (KillThread ist eine API, die für Windows nicht empfohlen wird). Lösung 2: Im Thread anhalten, einen Timer außerhalb des Threads übergeben und von Zeit zu Zeit fortfahren. Der Code lautet wie folgt: // ThreadPROcedure Execute;beginwhile not Terminated dobegin... // Verarbeitungscode Suspend;end;end;// Outside // Timer procedure OnTimer(Sender: Tobject);beginthd.Resume;end;// Um den Thread zu beenden: Place...thd.Resume;thd.Terminate;thd.WaitFor; Im Allgemeinen müssen Sie nach dem Beenden des Threads WaitFor verwenden, um zu bestätigen, dass der Thread tatsächlich beendet wurde. ...Problem: Die Kopplung zwischen dem Thread und der Außenseite ist zu stark und selbst der Betriebszyklus des Threads muss über einen externen Timer bestimmt werden. Lösung drei (das ist der beste Weg, den ich mir vorgestellt habe): Unterbrechen Sie den Thread durch ein Semaphor. // ThreadTMyThread = class(TMyThread)private Event: TEvent;protected procedure Execute;public constructionor Create(loginInfo: destructor); override; end TLoginInfo);begin Event := TEvent.Create(nil, True, True, 'EventName');end;destructor TMyThread.Destroy;begin Event.Free; inherited;end;procedure TMyThread.Execute;begin inherited; while not Terminated do begin // ... Event.ResetEvent; end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;Für Programme, die Threads unterbrechen müssen, reicht nur der folgende Code: begin …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;