Author: Zou Fei
E-mail: [email protected]
Homepage: http://www.atechsoft.com/people/zouf/ When using Delphi, you will inevitably encounter many strange problems, and Delphi’s documentation is surprisingly few, so I can only summarize it slowly by myself, so there are (Since it’s just scattered details, I didn’t spend much effort on the writing, it may be a bit messy, but it should be understandable;-)). If: 1. If you have a better solution to the following problem, please tell me and my friends on csdn. 2. If you have other questions, please list the problems and your answers and tell me and my friends on csdn. Communication creates everything!
Text: Q: If a Form made in Delphi DLL is ShowModal in Exe, two icons will appear on the taskbar. Why? How to solve this problem? A: The following is a typical method of placing a Form in a DLL: DLL: function ShowFrm: TModalResult; stdcall;beginForm1 := TForm1.Create(Nil); tryForm1.ShowModal; finallyForm1.Free;end;end; main EXE: function ShowFrm: TModalResult; stdcall; external 'TestDLL.dll';…begin…ShowFrm;…end. The Form in the DLL created in this way will display another Icon with the main application. The reason is that another application will be created for the DLL in Delphi. , and each Application will display a taskbar icon. Solution: Pass the Application of the main EXE into the DLL in the main application, as follows: 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. Note: Application in DLL and Application in EXE There are still some differences, look at the code in Forms.pas: constructor TApplication.Create(AOwner: TComponent);begin…if not IsLibrary then CreateHandle;…end;It can be known that the Application in the DLL does not have a Handle, so the message loop processing will not be performed, which is also correct. Q: Problems often occur with DLLs in Delphi! A: The reason why the problem occurs is because of Delphi's own memory management mechanism. For example: Create an object in a DLL: x := TClass.Create(Application); At this time, Delphi will automatically Free The address space may have expired (different operating systems will be different), so the release operation of x will cause an exception. Another example: Create an object in EXE, and pass in DLL as a local variable in the DLL. When the DLL is destroyed, Delphi will automatically release all variables that are out of scope, so if you use this in EXE again object, an exception will be thrown. Generally speaking, the problem is due to the memory management mechanism of the "smart" Delphi compiler and the DLL add/unload mechanism of Windows, which leads to memory access conflicts in the DLL and EXE. Solution: (Most problems can be avoided as long as you follow the following principles) 1. Between DLL and EXE, try not to use Delphi's automatic memory management mechanism. The programmer is responsible for the life cycle of the object. For example: for the above x := TClass.Create(Application); change it to: x : = TClass.Create(nil); In this way, Application will no longer Free it. Of course, the programmer must free it himself. 2. Try to avoid having different pointers pointing to the same object between the DLL and the EXE. For example, in the DLL, x points to the TClass object, and in the EXE, y points to the TClass object. In this way, memory release on either side will cause the memory on the other side to be invalid. 3. Others... Q: A thread that performs periodic tasks needs to pause for a moment and then continue running. But what if the thread needs to be stopped at this time (for example, the process has ended)? A: Solution 1: Perform periodic looping through Sleep in the thread. (If the thread is paused through Sleep, the thread cannot be resurrected through Resume and other methods.) End the thread through KillThread. This is the simplest method, but it is too crude and may cause problems (KillThread is an API not recommended for Windows) Solution 2: Suspend in the thread, pass a timer outside the thread, and Resume every once in a while. The code is as follows: // ThreadPRocedure Execute;beginwhile not Terminated dobegin... // Processing code Suspend;end;end;// Outside // Timer procedure OnTimer(Sender: Tobject);beginthd.Resume;end;// To end the thread Place...thd.Resume;thd.Terminate;thd.WaitFor; // Generally, after ending the thread, you have to use WaitFor to confirm that the thread has really ended. ...Problem: The coupling between the thread and the outside is too strong, and even the operation cycle of the thread must be determined through an external timer. Solution three (this is the best way I thought of): Pause in the thread through a semaphore. // ThreadTMyThread = class(TThread)private Event: TEvent;protected procedure Execute; override;public constructor Create(loginInfo: TLoginInfo); overload; destructor Destroy; override; procedure SetEvent;end;{ TMyThread }constructor TMyThread.Create(loginInfo: 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; Event.WaitFor(10000); end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;For programs that need to interrupt threads, just the following code is enough: begin …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;