DLLResearch on Internal Thread Synchronization main thread (subthreadCodePut it in the main thread for execution)
We often use multi-thread programming in actual projects, such as socket programming. to synchronize the main thread within the created thread, we generally use the synchronize method to implement Sub-thread operations and put them in the main thread for execution, synchronize is very convenient to use, and anonymous methods can be used in versions 2009 and later, which brings great convenience to multithreading. However, it turns out that synchronize isProgram. If the requirements for running the synchronize method in the DLL program loaded by the main program are harsh, the DLL program must be copied to the main program, at the same time, The dll must have a form status of modal or the form in the main program must not be displayed. For details, see:
Main Program:
Unit mainfrm;
Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs, stdctrls;
Type
Tmainform = Class (tform)
Btn1: tbutton;
Procedure btn1click (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
End;
VaR
Mainform: tmainform;
Implementation
{$ R *. DFM}
Procedure tmainform. btn1click (Sender: tobject );
VaR
Fhandle: thandle;
Opendllwindow: Procedure (amainhandle: integer); stdcall;
Begin
Fhandle: = loadlibrary (pchar ('dlprj. dll '));
If fhandle> 0 then
Begin
Opendllwindow: = getprocaddress (fhandle, pchar ('opendllwindow '));
If assigned (opendllwindow) then
Begin
Opendllwindow (application. Handle );
End;
End
Else
Showmessage ('dll loading failed! ');
End;
End.
DLLProgram:
Unit dllfrm;
Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs;
Type
Tdllform = Class (tform)
Procedure formshow (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
End;
Type
Tdllthread = Class (tthread)
Protected
Procedure execute; override;
End;
VaR
Dllform: tdllform;
Implementation
{$ R *. DFM}
Procedure tdllthread. Execute;
VaR
Count: integer;
TP: tthreadprocedure;
Begin
Count: = 0;
While true do
Begin
Try
Synchronize (
Procedure
Begin
Showmessage (inttostr (count ));
Count: = count + 2000;
End
);
Except
// Ignore Error
End;
Sleep (2000); // pause for two seconds
End;
End;
Procedure opendllwindow (amainhandle: integer); stdcall;
Begin
If dllform = nil then
Dllform: = tdllform. Create (application );
// Copy to the main program
Application. Handle: = amainhandle;
Dllform. showmodal;
// Dllform. show;
End;
Exports opendllwindow;
Procedure tdllform. formshow (Sender: tobject );
VaR
Dllthread: tdllthread;
Begin
Dllthread: = tdllthread. Create (false );
End;
End.
The above Code uses the synchronize method to synchronize the master thread and can run normally. However, if we remove application. Handle: = amainhandle from the opendllwindow method in the DLL project, or change the code dllform. showmodal; To dllform. Show, the thread will be blocked when synchronizing data to the main thread.
In this case, if the form display mode is not modal after the main program is loaded in the DLL project, we will not be able to use the convenient synchronize method. In this way, it is necessary to use sendmessage to send messages to the main thread. For example, we need to change the code in the DLL project as follows:
Unit dllfrm;
Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs;
Type
Tdllform = Class (tform)
Procedure formshow (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
Procedure wmrefreshform (var msg: tmessage); message wm_user + 100;
End;
Type
Tdllthread = Class (tthread)
Protected
Procedure execute; override;
End;
VaR
Dllform: tdllform;
Implementation
{$ R *. DFM}
Procedure tdllthread. Execute;
VaR
Count: integer;
TP: tthreadprocedure;
Begin
Count: = 0;
While true do
Begin
Try
Sendmessage (dllform. Handle, wm_user+ 100, Count, 0 );
Count: = count + 2000;
Except
// Ignore Error
End;
Sleep (2000 );
End;
End;
Procedure opendllwindow (amainhandle: integer); stdcall;
Begin
If dllform = nil then
Dllform: = tdllform. Create (application );
// Copy to the main program
// Application. Handle: = amainhandle;
// Dllform. showmodal;
Dllform. show;
End;
Exports opendllwindow;
Procedure tdllform. formshow (Sender: tobject );
VaR
Dllthread: tdllthread;
Begin
Dllthread: = tdllthread. Create (false );
End;
Procedure tdllform. wmrefreshform (var msg: tmessage );
Begin
If msg. MSG = wm_user + 100 then
Begin
Showmessage (inttostr (msg. wparam ));
End;
End;
End.
In this way, our DLL program will work normally, which is also a common method. However, if we have frequent synchronization operations in the thread, or these synchronization operations will use a large number of internal variables in the thread, sendmessage will be troublesome and difficult. If we can customize the anonymous method in the thread execution method, just like using synchronize, the amount of code will be greatly reduced and the programming process will be greatly simplified, in this way, we think of passing the pointer of the anonymous method as a parameter of sendmessage to a custom message, and then executing this anonymous method in the custom message. We are glad that this is okay. Modify the code in the DLL project as follows:
Unit dllfrm;
Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs;
Type
Tdllform = Class (tform)
Procedure formshow (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
Procedure wmrefreshform (var msg: tmessage); message wm_user + 100;
End;
Type
Tdllthread = Class (tthread)
Protected
Procedure execute; override;
End;
VaR
Dllform: tdllform;
Implementation
{$ R *. DFM}
Procedure tdllthread. Execute;
VaR
Count: integer;
TP: tthreadprocedure;
Begin
Count: = 0;
While true do
Begin
Try
Sendmessage (dllform. Handle, wm_user + 100, INTEGER (
@ Procedure
Begin
Showmessage (inttostr (count ));
Count: = count + 2000;
End), 0
);
// TP: = procedure
// Begin
// Showmessage (inttostr (count ));
// Count: = count + 2000;
// End;
// Sendmessage (dllform. Handle, wm_user + 100, INTEGER (@ TP), 0 );
Except
// Ignore Error
End;
Sleep (2000 );
End;
End;
Procedure opendllwindow (amainhandle: integer); stdcall;
Begin
If dllform = nil then
Dllform: = tdllform. Create (application );
// Copy to the main program
// Application. Handle: = amainhandle;
// Dllform. showmodal;
Dllform. show;
End;
Exports opendllwindow;
Procedure tdllform. formshow (Sender: tobject );
VaR
Dllthread: tdllthread;
Begin
Dllthread: = tdllthread. Create (false );
End;
Procedure tdllform. wmrefreshform (var msg: tmessage );
Begin
If msg. MSG = wm_user + 100 then
Begin
Tthreadprocedure (pointer (msg. wparam). Invoke;
End;
End;
End.
If the tdllthread. Execute method is changed
Procedure tdllthread. Execute;
VaR
Count: integer;
TP: tthreadprocedure;
Begin
Count: = 0;
While true do
Begin
Try
TP: = procedure
Begin
Showmessage (inttostr (count ));
Count: = count + 2000;
End;
Sendmessage (dllform. Handle, wm_user + 100, INTEGER (@ TP), 0 );
Except
// Ignore Error
End;
Sleep (2000 );
End;
End;
The tdllform. wmrefreshform method should be changed:
Procedure tdllform. wmrefreshform (var msg: tmessage );
Begin
If msg. MSG = wm_user + 100 then
Begin
Tthreadprocedure (pointer (msg. wparam) ^). Invoke;
End;
End;
Note This.
In this way, we can achieve the same effect of synchronize with just a slight modification in the DLL program, and enjoy the convenience of using the anonymous method. The above code is debugged in delphi2010, I would like to share with you some suggestions on the shortcomings.
Author: Zhang Hao
2010-7-30