| 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;implementationuses  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     EBPend;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.
 |