Auteur : Zou Fei
E-mail : [email protected]
Page d'accueil : http://www.atechsoft.com/people/zouf/ Lorsque vous utilisez Delphi, vous rencontrerez inévitablement de nombreux problèmes étranges, et la documentation de Delphi est étonnamment peu nombreuse, je ne peux donc la résumer que lentement par moi-même, il y en a donc (puisque ce ne sont que des détails épars, je n'ai pas fait beaucoup d'efforts sur l'écriture, c'est peut-être un peu brouillon, mais ça devrait être compréhensible ;-)). Si : 1. Si vous avez une meilleure solution au problème suivant, dites-le-moi ainsi qu'à mes amis sur csdn. 2. Si vous avez d'autres questions, veuillez énumérer les problèmes et vos réponses et dites-le-moi et à mes amis sur csdn. La communication crée tout !
Texte : Q : Si un formulaire créé dans Delphi DLL est ShowModal dans Exe, deux icônes apparaîtront sur la barre des tâches. Pourquoi ? Comment résoudre ce problème ? R : Ce qui suit est une méthode typique pour placer un formulaire dans une DLL : DLL : function ShowFrm: TModalResult; stdcall;beginForm1 := TForm1.Create(Nil); finalementForm1.Free;end;end; fonction ShowFrm : TModalResult ; 'TestDLL.dll';…begin…ShowFrm;…end. Le formulaire dans la DLL créée de cette manière affichera une autre icône avec l'application principale. La raison est qu'une autre application sera créée pour la DLL dans Delphi, et chacune. L'application affichera une icône dans la barre des tâches. Solution : transmettez l'application de l'EXE principal dans la DLL de l'application principale, comme suit : 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; external 'TestDLL.dll';…begin…ShowFrm(Application);…end Remarque : Application dans DLL et Application dans EXE. encore quelques différences, regardez le code dans Forms.pas : constructeur TApplication.Create(AOwner : TComponent);begin… if not IsLibrary then CreateHandle;…end;On peut savoir que l'application dans la DLL n'a pas de handle, donc le traitement de la boucle de message ne sera pas effectué, ce qui est également correct. Q : Des problèmes surviennent souvent avec les DLL dans Delphi ! R : La raison pour laquelle le problème se produit est due au mécanisme de gestion de la mémoire propre à Delphi. Par exemple : Créez un objet dans une DLL : x := TClass.Create(Application); À ce moment, Delphi libérera automatiquement L'espace d'adressage peut avoir expiré (les différents systèmes d'exploitation seront différents), donc l'opération de libération de x sera provoquer une exception. Autre exemple : créez un objet dans EXE et transmettez la DLL en tant que variable locale dans la DLL. Lorsque la DLL est détruite, Delphi libère automatiquement toutes les variables hors de portée, donc si vous utilisez à nouveau cet objet dans EXE, un une exception sera levée. D'une manière générale, le problème est dû au mécanisme de gestion de la mémoire du compilateur Delphi "intelligent" et au mécanisme d'ajout/déchargement de DLL de Windows, ce qui entraîne des conflits d'accès mémoire dans les DLL et EXE. Solution : (La plupart des problèmes peuvent être évités tant que vous suivez les principes suivants) 1. Entre DLL et EXE, essayez de ne pas utiliser le mécanisme de gestion automatique de la mémoire de Delphi. Le programmeur est responsable du cycle de vie de l'objet. Par exemple : pour ce qui précède, x := TClass.Create(Application); TClass.Create(nil); De cette façon, l'application ne le libérera plus. Bien entendu, le programmeur doit le libérer lui-même. 2. Essayez d'éviter d'avoir des pointeurs différents pointant vers le même objet entre la DLL et l'EXE. Par exemple, dans la DLL, x pointe vers l'objet TClass et dans l'EXE, y pointe vers l'objet TClass. De cette manière, la libération de mémoire d'un côté ou de l'autre entraînera l'invalidité de la mémoire de l'autre côté. 3. Autres... Q : Un thread qui exécute des tâches périodiques doit faire une pause pendant un moment puis continuer à s'exécuter. Mais que se passe-t-il si le thread doit être arrêté à ce moment-là (par exemple, le processus est terminé) ? R : Solution 1 : effectuez une boucle périodique via Sleep dans le thread. (Si le fil est mis en pause via Sleep, il ne peut pas être ressuscité via Resume et d'autres méthodes.) Terminez le fil via KillThread. C'est la méthode la plus simple, mais elle est trop grossière et peut poser des problèmes (KillThread est une API non recommandée pour Windows) Solution 2 : suspendre le thread, passer un minuteur en dehors du thread et reprendre de temps en temps. Le code est le suivant : // ThreadPRocedure Execute;beginwhile not Terended dobegin... // Traitement du code Suspend;end;end;// Outside // Timer procédure OnTimer(Sender: Tobject);beginthd.Resume;end;// Pour terminer le fil de discussion Place...thd.Resume;thd.Terminate;thd.WaitFor; Généralement, après avoir terminé le fil de discussion, vous devez utiliser WaitFor pour confirmer que le fil de discussion est réellement terminé. ...Problème : Le couplage entre le filetage et l'extérieur est trop fort, et même le cycle de fonctionnement du filetage doit être déterminé via une minuterie externe. Troisième solution (c'est la meilleure façon à laquelle j'ai pensé) : faites une pause dans le fil via un sémaphore. // ThreadTMyThread = class(TThread)private Event: TEvent;procédure protégée Execute;override;public constructor Create(loginInfo: TLoginInfo override;procédure SetEvent;end;{ TMyThread }constructor TMyThread.Create(loginInfo): TLoginInfo);begin Event := TEvent.Create(nil, True, True, 'EventName');end;destructeur TMyThread.Destroy;begin Event.Free; hérité;end;procédure TMyThread.Execute;begin hérité;do begin // ... Event.ResetEvent; end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;Pour les programmes qui doivent interrompre les threads, le code suivant suffit : start …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;