2009. július 9., csütörtök

Synchronize TThreads

Problem/Question/Abstract:

I am using a thread that does some system checks and outputs the results to a TRichEdit, so I need to use a Syncronize(AMethod) to update the interface and the TRichEdit mentioned before. But I cannot do this if AMethod accepts parameters. I would like to pass some parameters to AMethod, but have not been able to do this. Is this possible?

Answer:

Below is the complete code to do this, using the function:

function ExecuteInMainThread(Proc: MainThreadProcType; var Parameter): boolean;

It will call Proc in the main Windows thread and wait for the procedure to finish before returning. Proc takes one untyped variable. If you want to pass more than one variable, put the data into a record and pass the record. You don't really have to code anything. Just copy this code to a unit, use the unit in your code, and call the function. There is no TThread method that does this.

unit ThreadLib;

interface

uses
Windows, Messages, ExtCtrls, Classes, Forms, SyncObjs;

type
MainThreadProcType = procedure(var Parameter) of object;

function ExecuteInMainThread(Proc: MainThreadProcType; var Parameter): boolean;

implementation

uses
SysUtils;

const
UM_EXECMAIN = WM_USER + 590;

type
WindowProcType = function(hWnd: HWND; Msg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;

ProcInfoType = record
Method: MainThreadProcType;
Param: pointer;
end;

ProcInfoPtrType = ^ProcInfoType;

var
OrigThreadWndProc: WindowProcType;

function ExecuteInMainThread(Proc: MainThreadProcType; var Parameter): boolean;
var
ProcInfo: ProcInfoType;
begin
if GetCurrentThreadID = MainThreadID then
try
Proc(Parameter);
Result := true;
except
Result := false;
end
else
begin
ProcInfo.Method := Proc;
ProcInfo.Param := @Parameter;
Result := SendMessage(Application.Handle, UM_EXECMAIN, 0, longint(@ProcInfo)) =
ord(true);
{To send a message without waiting for it to return (PostMessage),
make sure that the message parameters do not include pointers. Otherwise,
the functions will return before the receiving thread has had a chance to
process the message and the sender will free the memory before it is used.}
end;
end;

function ParamThreadWndProc(Window: HWND; Message, wParam, lParam: longint):
longint; stdcall;
begin
if Message = UM_EXECMAIN then
try
with ProcInfoPtrType(pointer(lParam))^ do
Method(Param^);
Result := ord(true);
except
Result := ord(false);
end
else
Result := OrigThreadWndProc(Window, Message, wParam, lParam);
end;

begin
OrigThreadWndProc := WindowProcType(SetWindowLong(Application.Handle,
GWL_WNDPROC, longint(@ParamThreadWndProc)));
end.



Nincsenek megjegyzések:

Megjegyzés küldése