123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- unit CompThread;
- interface
- {$WARN SYMBOL_DEPRECATED OFF}
- {$WARN SYMBOL_PLATFORM OFF}
- uses
- Classes, Windows;
- type
- { TCompThread }
- TCompThread = class
- private
- FHandle: THandle;
- FThreadID: TThreadID;
- FTerminated: Boolean;
- FSuspended: Boolean;
- FFreeOnTerminate: Boolean;
- FFinished: Boolean;
- FReturnValue: Integer;
- FOnTerminate: TNotifyEvent;
- FMethod: TThreadMethod;
- FSynchronizeException: TObject;
- procedure CallOnTerminate;
- function GetPriority: TThreadPriority;
- procedure SetPriority(Value: TThreadPriority);
- procedure SetSuspended(Value: Boolean);
- protected
- procedure DoTerminate; virtual;
- procedure Execute; virtual; abstract;
- procedure Synchronize(Method: TThreadMethod);
- property ReturnValue: Integer read FReturnValue write FReturnValue;
- property Terminated: Boolean read FTerminated;
- public
- constructor Create(CreateSuspended: Boolean);
- destructor Destroy; override;
- procedure Resume;
- procedure Suspend;
- procedure Terminate; virtual;
- function WaitFor(Milliseconds: Cardinal = INFINITE): Boolean;
- property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
- property Handle: THandle read FHandle;
- property Priority: TThreadPriority read GetPriority write SetPriority;
- property Suspended: Boolean read FSuspended write SetSuspended;
- property ThreadID: TThreadID read FThreadID;
- property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
- end;
- implementation
- uses
- SysUtils, DateUtils;
- const
- CM_EXECPROC = $8FFF;
- CM_DESTROYWINDOW = $8FFE;
- type
- PRaiseFrame = ^TRaiseFrame;
- TRaiseFrame = record
- NextRaise: PRaiseFrame;
- ExceptAddr: Pointer;
- ExceptObject: TObject;
- ExceptionRecord: PExceptionRecord;
- end;
- var
- ThreadLock: TRTLCriticalSection;
- ThreadWindow: HWND;
- ThreadCount: Integer;
- procedure FreeThreadWindow;
- begin
- if ThreadWindow <> 0 then
- begin
- DestroyWindow(ThreadWindow);
- ThreadWindow := 0;
- end;
- end;
- function ThreadWndProc(Window: HWND; Message, wParam, lParam: Longint): Longint; stdcall;
- begin
- case Message of
- CM_EXECPROC:
- with TCompThread(lParam) do
- begin
- Result := 0;
- try
- FSynchronizeException := nil;
- FMethod;
- except
- FSynchronizeException := AcquireExceptionObject;
- end;
- end;
- CM_DESTROYWINDOW:
- begin
- EnterCriticalSection(ThreadLock);
- try
- Dec(ThreadCount);
- if ThreadCount = 0 then
- FreeThreadWindow;
- finally
- LeaveCriticalSection(ThreadLock);
- end;
- Result := 0;
- end;
- else
- Result := DefWindowProc(Window, Message, wParam, lParam);
- end;
- end;
- var
- ThreadWindowClass: TWndClass = (
- style: 0;
- lpfnWndProc: @ThreadWndProc;
- cbClsExtra: 0;
- cbWndExtra: 0;
- hInstance: 0;
- hIcon: 0;
- hCursor: 0;
- hbrBackground: 0;
- lpszMenuName: nil;
- lpszClassName: 'TThreadWindow');
- procedure AddThread;
- function AllocateWindow: HWND;
- var
- TempClass: TWndClass;
- ClassRegistered: Boolean;
- begin
- ThreadWindowClass.hInstance := HInstance;
- ClassRegistered := GetClassInfo(HInstance, ThreadWindowClass.lpszClassName,
- TempClass);
- if not ClassRegistered or (TempClass.lpfnWndProc <> @ThreadWndProc) then
- begin
- if ClassRegistered then
- Windows.UnregisterClass(ThreadWindowClass.lpszClassName, HInstance);
- Windows.RegisterClass(ThreadWindowClass);
- end;
- Result := CreateWindow(ThreadWindowClass.lpszClassName, '', 0,
- 0, 0, 0, 0, 0, 0, HInstance, nil);
- end;
- begin
- EnterCriticalSection(ThreadLock);
- try
- if ThreadCount = 0 then
- ThreadWindow := AllocateWindow;
- Inc(ThreadCount);
- finally
- LeaveCriticalSection(ThreadLock);
- end;
- end;
- procedure RemoveThread;
- begin
- EnterCriticalSection(ThreadLock);
- try
- if ThreadCount = 1 then
- PostMessage(ThreadWindow, CM_DESTROYWINDOW, 0, 0);
- finally
- LeaveCriticalSection(ThreadLock);
- end;
- end;
- {type
- PThreadRec = ^TThreadRec;
- TThreadRec = record
- Func: TThreadFunc;
- Parameter: Pointer;
- end;
- function ThreadWrapper(Parameter: Pointer): Integer; stdcall;
- asm
- CALL _FpuInit
- XOR ECX,ECX
- PUSH EBP
- PUSH offset _ExceptionHandler
- MOV EDX,FS:[ECX]
- PUSH EDX
- MOV EAX,Parameter
- MOV FS:[ECX],ESP
- MOV ECX,[EAX].TThreadRec.Parameter
- MOV EDX,[EAX].TThreadRec.Func
- PUSH ECX
- PUSH EDX
- CALL _FreeMem
- POP EDX
- POP EAX
- CALL EDX
- XOR EDX,EDX
- POP ECX
- MOV FS:[EDX],ECX
- POP ECX
- POP EBP
- end;
- function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
- ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
- var ThreadId: LongWord): Integer;
- var
- P: PThreadRec;
- begin
- New(P);
- P.Func := ThreadFunc;
- P.Parameter := Parameter;
- IsMultiThread := TRUE;
- Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P,
- CreationFlags, ThreadID);
- end;
- procedure EndThread(ExitCode: Integer);
- begin
- ExitThread(ExitCode);
- end;
- }
- { TCompThread }
- function ThreadProc(Thread: TCompThread): Integer;
- var
- FreeThread: Boolean;
- begin
- try
- Thread.Execute;
- finally
- FreeThread := Thread.FFreeOnTerminate;
- Result := Thread.FReturnValue;
- Thread.FFinished := True;
- Thread.DoTerminate;
- if FreeThread then
- begin
- Thread.Free;
- end;
- EndThread(Result);
- // it should not get past EndThread
- end;
- end;
- constructor TCompThread.Create(CreateSuspended: Boolean);
- var
- Flags: Cardinal; //DWORD;
- begin
- inherited Create;
- AddThread;
- FSuspended := CreateSuspended;
- Flags := 0;
- if CreateSuspended then Flags := CREATE_SUSPENDED;
- FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
- end;
- destructor TCompThread.Destroy;
- begin
- if not FFinished and not Suspended then
- begin
- Terminate;
- WaitFor;
- end;
- if FHandle <> 0 then CloseHandle(FHandle);
- inherited Destroy;
- RemoveThread;
- end;
- procedure TCompThread.CallOnTerminate;
- begin
- if Assigned(FOnTerminate) then FOnTerminate(Self);
- end;
- procedure TCompThread.DoTerminate;
- begin
- if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
- end;
- const
- Priorities: array [TThreadPriority] of Integer =
- (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
- THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
- THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL);
- function TCompThread.GetPriority: TThreadPriority;
- var
- P: Integer;
- I: TThreadPriority;
- begin
- P := GetThreadPriority(FHandle);
- Result := tpNormal;
- for I := Low(TThreadPriority) to High(TThreadPriority) do
- if Priorities[I] = P then Result := I;
- end;
- procedure TCompThread.SetPriority(Value: TThreadPriority);
- begin
- SetThreadPriority(FHandle, Priorities[Value]);
- end;
- procedure TCompThread.Synchronize(Method: TThreadMethod);
- begin
- FSynchronizeException := nil;
- FMethod := Method;
- SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
- if Assigned(FSynchronizeException) then raise FSynchronizeException;
- end;
- procedure TCompThread.SetSuspended(Value: Boolean);
- begin
- if Value <> FSuspended then
- if Value then
- Suspend else
- Resume;
- end;
- procedure TCompThread.Suspend;
- begin
- FSuspended := True;
- SuspendThread(FHandle);
- end;
- procedure TCompThread.Resume;
- begin
- if ResumeThread(FHandle) = 1 then FSuspended := False;
- end;
- procedure TCompThread.Terminate;
- begin
- FTerminated := True;
- end;
- function TCompThread.WaitFor(Milliseconds: Cardinal): Boolean;
- var
- Msg: TMsg;
- H: THandle;
- Start: TDateTime;
- R: DWORD;
- begin
- H := FHandle;
- if GetCurrentThreadID = MainThreadID then
- begin
- Start := Now;
- repeat
- R := MsgWaitForMultipleObjects(1, H, False, Milliseconds, QS_SENDMESSAGE);
- if R = WAIT_OBJECT_0 + 1 then PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
- until (R <> WAIT_OBJECT_0 + 1) or ((Milliseconds <> INFINITE) and (MilliSecondsBetween(Now, Start) >= Milliseconds));
- end
- else
- begin
- R := WaitForSingleObject(H, Milliseconds);
- end;
- Result := (R = WAIT_OBJECT_0);
- end;
- initialization
- InitializeCriticalSection(ThreadLock);
- finalization
- DeleteCriticalSection(ThreadLock);
- end.
|