thread.inc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. { Thread management routines }
  2. const
  3. CM_EXECPROC = $8FFF;
  4. CM_DESTROYWINDOW = $8FFE;
  5. type
  6. PRaiseFrame = ^TRaiseFrame;
  7. TRaiseFrame = record
  8. NextRaise: PRaiseFrame;
  9. ExceptAddr: Pointer;
  10. ExceptObject: TObject;
  11. ExceptionRecord: pointer; {PExceptionRecord}
  12. end;
  13. var
  14. ThreadWindow: HWND;
  15. ThreadCount: Integer;
  16. function ThreadWndProc(Window: HWND; Message, wParam, lParam: Longint): Longint;stdcall;
  17. begin
  18. case Message of
  19. CM_EXECPROC:
  20. with TThread(lParam) do
  21. begin
  22. Result := 0;
  23. try
  24. FSynchronizeException := nil;
  25. FMethod;
  26. except
  27. { if RaiseList <> nil then
  28. begin
  29. FSynchronizeException := PRaiseFrame(RaiseList)^.ExceptObject;
  30. PRaiseFrame(RaiseList)^.ExceptObject := nil;
  31. end; }
  32. end;
  33. end;
  34. CM_DESTROYWINDOW:
  35. begin
  36. DestroyWindow(Window);
  37. Result := 0;
  38. end;
  39. else
  40. Result := DefWindowProc(Window, Message, wParam, lParam);
  41. end;
  42. end;
  43. const
  44. ThreadWindowClass: TWndClass = (
  45. style: 0;
  46. lpfnWndProc: nil;
  47. cbClsExtra: 0;
  48. cbWndExtra: 0;
  49. hInstance: 0;
  50. hIcon: 0;
  51. hCursor: 0;
  52. hbrBackground: 0;
  53. lpszMenuName: nil;
  54. lpszClassName: 'TThreadWindow');
  55. procedure AddThread;
  56. function AllocateWindow: HWND;
  57. var
  58. TempClass: TWndClass;
  59. ClassRegistered: Boolean;
  60. begin
  61. ThreadWindowClass.hInstance := HInstance;
  62. ThreadWindowClass.lpfnWndProc:=WndProc(@ThreadWndProc);
  63. ClassRegistered := GetClassInfo(HInstance, ThreadWindowClass.lpszClassName,
  64. @TempClass);
  65. if not ClassRegistered or (TempClass.lpfnWndProc <> WndProc(@ThreadWndProc)) then
  66. begin
  67. if ClassRegistered then
  68. Windows.UnregisterClass(ThreadWindowClass.lpszClassName, HInstance);
  69. Windows.RegisterClass(ThreadWindowClass);
  70. end;
  71. Result := CreateWindow(ThreadWindowClass.lpszClassName, '', 0,
  72. 0, 0, 0, 0, 0, 0, HInstance, nil);
  73. end;
  74. begin
  75. if ThreadCount = 0 then
  76. ThreadWindow := AllocateWindow;
  77. Inc(ThreadCount);
  78. end;
  79. procedure RemoveThread;
  80. begin
  81. Dec(ThreadCount);
  82. if ThreadCount = 0 then
  83. PostMessage(ThreadWindow, CM_DESTROYWINDOW, 0, 0);
  84. end;
  85. { TThread }
  86. function ThreadProc(Thread: TThread): Integer;
  87. var
  88. FreeThread: Boolean;
  89. begin
  90. Thread.Execute;
  91. FreeThread := Thread.FFreeOnTerminate;
  92. Result := Thread.FReturnValue;
  93. Thread.FFinished := True;
  94. Thread.DoTerminate;
  95. if FreeThread then Thread.Free;
  96. ExitThread(Result);
  97. end;
  98. constructor TThread.Create(CreateSuspended: Boolean);
  99. var
  100. Flags: Integer;
  101. begin
  102. inherited Create;
  103. AddThread;
  104. FSuspended := CreateSuspended;
  105. Flags := 0;
  106. if CreateSuspended then Flags := CREATE_SUSPENDED;
  107. FHandle := CreateThread(nil, 0, @ThreadProc, Pointer(self), Flags, FThreadID);
  108. end;
  109. destructor TThread.Destroy;
  110. begin
  111. if not FFinished and not Suspended then
  112. begin
  113. Terminate;
  114. WaitFor;
  115. end;
  116. if FHandle <> 0 then CloseHandle(FHandle);
  117. inherited Destroy;
  118. RemoveThread;
  119. end;
  120. procedure TThread.CallOnTerminate;
  121. begin
  122. FOnTerminate(Self);
  123. end;
  124. procedure TThread.DoTerminate;
  125. begin
  126. if Assigned(FOnTerminate) then
  127. Synchronize(@CallOnTerminate);
  128. end;
  129. const
  130. Priorities: array [TThreadPriority] of Integer =
  131. (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
  132. THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
  133. THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL);
  134. function TThread.GetPriority: TThreadPriority;
  135. var
  136. P: Integer;
  137. I: TThreadPriority;
  138. begin
  139. P := GetThreadPriority(FHandle);
  140. Result := tpNormal;
  141. for I := Low(TThreadPriority) to High(TThreadPriority) do
  142. if Priorities[I] = P then Result := I;
  143. end;
  144. procedure TThread.SetPriority(Value: TThreadPriority);
  145. begin
  146. SetThreadPriority(FHandle, Priorities[Value]);
  147. end;
  148. procedure TThread.Synchronize(Method: TThreadMethod);
  149. begin
  150. FSynchronizeException := nil;
  151. FMethod := Method;
  152. SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
  153. if Assigned(FSynchronizeException) then raise FSynchronizeException;
  154. end;
  155. procedure TThread.SetSuspended(Value: Boolean);
  156. begin
  157. if Value <> FSuspended then
  158. if Value then
  159. Suspend else
  160. Resume;
  161. end;
  162. procedure TThread.Suspend;
  163. begin
  164. FSuspended := True;
  165. SuspendThread(FHandle);
  166. end;
  167. procedure TThread.Resume;
  168. begin
  169. if ResumeThread(FHandle) = 1 then FSuspended := False;
  170. end;
  171. procedure TThread.Terminate;
  172. begin
  173. FTerminated := True;
  174. end;
  175. function TThread.WaitFor: Integer;
  176. var
  177. Msg: TMsg;
  178. begin
  179. if GetCurrentThreadID = MainThreadID then
  180. while MsgWaitForMultipleObjects(1, FHandle, False, INFINITE, QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do
  181. PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
  182. else
  183. WaitForSingleObject(ulong(FHandle), INFINITE);
  184. GetExitCodeThread(FHandle, Result);
  185. end;
  186. {
  187. $Log$
  188. Revision 1.3 2000-07-25 11:27:35 jonas
  189. * fixed missing comment openers for log section
  190. Revision 1.2 2000/07/13 11:33:07 michael
  191. + removed logs
  192. }