You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wcore.pas 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. { Copyright (C) 2005 Bas Steendijk and Peter Green
  2. For conditions of distribution and use, see copyright notice in zlib_license.txt
  3. which is included in the package
  4. ----------------------------------------------------------------------------- }
  5. unit wcore;
  6. {
  7. lcore compatible interface for windows
  8. - messageloop
  9. - tltimer
  10. }
  11. //note: events after release are normal and are the apps responsibility to deal with safely
  12. interface
  13. uses
  14. classes,windows,mmsystem;
  15. type
  16. float=double;
  17. tlcomponent = class(tcomponent)
  18. public
  19. released:boolean;
  20. procedure release;
  21. destructor destroy; override;
  22. end;
  23. tltimer=class(tlcomponent)
  24. private
  25. fenabled : boolean;
  26. procedure setenabled(newvalue : boolean);
  27. public
  28. ontimer:tnotifyevent;
  29. initialevent:boolean;
  30. initialdone:boolean;
  31. prevtimer:tltimer;
  32. nexttimer:tltimer;
  33. interval:integer; {miliseconds, default 1000}
  34. nextts:integer;
  35. property enabled:boolean read fenabled write setenabled;
  36. constructor create(aowner:tcomponent);override;
  37. destructor destroy;override;
  38. end;
  39. ttaskevent=procedure(wparam,lparam:longint) of object;
  40. tltask=class(tobject)
  41. public
  42. handler : ttaskevent;
  43. obj : tobject;
  44. wparam : longint;
  45. lparam : longint;
  46. nexttask : tltask;
  47. constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  48. end;
  49. procedure messageloop;
  50. procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  51. procedure disconnecttasks(aobj:tobject);
  52. procedure exitmessageloop;
  53. procedure processmessages;
  54. var
  55. onshutdown:procedure(s:string);
  56. implementation
  57. uses
  58. {$ifdef fpc}
  59. bmessages;
  60. {$else}
  61. messages;
  62. {$endif}
  63. const
  64. WINMSG_TASK=WM_USER;
  65. var
  66. hwndwcore:hwnd;
  67. firsttimer:tltimer;
  68. timesubstract:integer;
  69. firsttask,lasttask,currenttask:tltask;
  70. procedure tlcomponent.release;
  71. begin
  72. released := true;
  73. end;
  74. destructor tlcomponent.destroy;
  75. begin
  76. disconnecttasks(self);
  77. inherited destroy;
  78. end;
  79. {------------------------------------------------------------------------------}
  80. procedure tltimer.setenabled(newvalue : boolean);
  81. begin
  82. fenabled := newvalue;
  83. nextts := 0;
  84. initialdone := false;
  85. end;
  86. constructor tltimer.create;
  87. begin
  88. inherited create(AOwner);
  89. nexttimer := firsttimer;
  90. prevtimer := nil;
  91. if assigned(nexttimer) then nexttimer.prevtimer := self;
  92. firsttimer := self;
  93. interval := 1000;
  94. enabled := true;
  95. released := false;
  96. end;
  97. destructor tltimer.destroy;
  98. begin
  99. if prevtimer <> nil then begin
  100. prevtimer.nexttimer := nexttimer;
  101. end else begin
  102. firsttimer := nexttimer;
  103. end;
  104. if nexttimer <> nil then begin
  105. nexttimer.prevtimer := prevtimer;
  106. end;
  107. inherited destroy;
  108. end;
  109. {------------------------------------------------------------------------------}
  110. function wcore_timehandler:integer;
  111. const
  112. rollover_bits=30;
  113. var
  114. tv,tvnow:integer;
  115. currenttimer,temptimer:tltimer;
  116. begin
  117. if not assigned(firsttimer) then begin
  118. result := 1000;
  119. exit;
  120. end;
  121. tvnow := timegettime;
  122. if (tvnow and ((-1) shl rollover_bits)) <> timesubstract then begin
  123. currenttimer := firsttimer;
  124. while assigned(currenttimer) do begin
  125. dec(currenttimer.nextts,(1 shl rollover_bits));
  126. currenttimer := currenttimer.nexttimer;
  127. end;
  128. timesubstract := tvnow and ((-1) shl rollover_bits);
  129. end;
  130. tvnow := tvnow and ((1 shl rollover_bits)-1);
  131. currenttimer := firsttimer;
  132. while assigned(currenttimer) do begin
  133. if tvnow >= currenttimer.nextts then begin
  134. if assigned(currenttimer.ontimer) then begin
  135. if currenttimer.enabled then begin
  136. if currenttimer.initialevent or currenttimer.initialdone then currenttimer.ontimer(currenttimer);
  137. currenttimer.initialdone := true;
  138. end;
  139. end;
  140. currenttimer.nextts := tvnow+currenttimer.interval;
  141. end;
  142. temptimer := currenttimer;
  143. currenttimer := currenttimer.nexttimer;
  144. if temptimer.released then temptimer.free;
  145. end;
  146. tv := maxlongint;
  147. currenttimer := firsttimer;
  148. while assigned(currenttimer) do begin
  149. if currenttimer.nextts < tv then tv := currenttimer.nextts;
  150. currenttimer := currenttimer.nexttimer;
  151. end;
  152. result := tv-tvnow;
  153. if result < 15 then result := 15;
  154. end;
  155. {------------------------------------------------------------------------------}
  156. constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  157. begin
  158. inherited create;
  159. handler := ahandler;
  160. obj := aobj;
  161. wparam := awparam;
  162. lparam := alparam;
  163. {nexttask := firsttask;
  164. firsttask := self;}
  165. if assigned(lasttask) then begin
  166. lasttask.nexttask := self;
  167. end else begin
  168. firsttask := self;
  169. postmessage(hwndwcore,WINMSG_TASK,0,0);
  170. end;
  171. lasttask := self;
  172. //ahandler(wparam,lparam);
  173. end;
  174. procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  175. begin
  176. tltask.create(ahandler,aobj,awparam,alparam);
  177. end;
  178. procedure disconnecttasks(aobj:tobject);
  179. var
  180. currenttasklocal : tltask ;
  181. counter : byte ;
  182. begin
  183. for counter := 0 to 1 do begin
  184. if counter = 0 then begin
  185. currenttasklocal := firsttask; //main list of tasks
  186. end else begin
  187. currenttasklocal := currenttask; //needed in case called from a task
  188. end;
  189. // note i don't bother to sestroy the links here as that will happen when
  190. // the list of tasks is processed anyway
  191. while assigned(currenttasklocal) do begin
  192. if currenttasklocal.obj = aobj then begin
  193. currenttasklocal.obj := nil;
  194. currenttasklocal.handler := nil;
  195. end;
  196. currenttasklocal := currenttasklocal.nexttask;
  197. end;
  198. end;
  199. end;
  200. procedure dotasks;
  201. var
  202. temptask:tltask;
  203. begin
  204. if firsttask = nil then exit;
  205. currenttask := firsttask;
  206. firsttask := nil;
  207. lasttask := nil;
  208. while assigned(currenttask) do begin
  209. if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
  210. temptask := currenttask;
  211. currenttask := currenttask.nexttask;
  212. temptask.free;
  213. end;
  214. currenttask := nil;
  215. end;
  216. {------------------------------------------------------------------------------}
  217. procedure exitmessageloop;
  218. begin
  219. postmessage(hwndwcore,WM_QUIT,0,0);
  220. end;
  221. {$ifdef threadtimer}
  222. 'thread timer'
  223. {$else}
  224. const timerid_wcore=$1000;
  225. {$endif}
  226. function MyWindowProc(
  227. ahWnd : HWND;
  228. auMsg : Integer;
  229. awParam : WPARAM;
  230. alParam : LPARAM): Integer; stdcall;
  231. var
  232. MsgRec : TMessage;
  233. a:integer;
  234. begin
  235. Result := 0; // This means we handled the message
  236. {MsgRec.hwnd := ahWnd;}
  237. MsgRec.wParam := awParam;
  238. MsgRec.lParam := alParam;
  239. dotasks;
  240. case auMsg of
  241. {$ifndef threadtimer}
  242. WM_TIMER: begin
  243. if msgrec.wparam = timerid_wcore then begin
  244. a := wcore_timehandler;
  245. killtimer(hwndwcore,timerid_wcore);
  246. settimer(hwndwcore,timerid_wcore,a,nil);
  247. end;
  248. end;
  249. {$endif}
  250. {WINMSG_TASK:dotasks;}
  251. WM_CLOSE: begin
  252. {}
  253. end;
  254. WM_DESTROY: begin
  255. {}
  256. end;
  257. else
  258. Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
  259. end;
  260. end;
  261. var
  262. MyWindowClass : TWndClass = (style : 0;
  263. lpfnWndProc : @MyWindowProc;
  264. cbClsExtra : 0;
  265. cbWndExtra : 0;
  266. hInstance : 0;
  267. hIcon : 0;
  268. hCursor : 0;
  269. hbrBackground : 0;
  270. lpszMenuName : nil;
  271. lpszClassName : 'wcoreClass');
  272. procedure messageloop;
  273. var
  274. MsgRec : TMsg;
  275. begin
  276. if Windows.RegisterClass(MyWindowClass) = 0 then halt;
  277. //writeln('about to create wcore handle, hinstance=',hinstance);
  278. hwndwcore := CreateWindowEx(WS_EX_TOOLWINDOW,
  279. MyWindowClass.lpszClassName,
  280. '', { Window name }
  281. WS_POPUP, { Window Style }
  282. 0, 0, { X, Y }
  283. 0, 0, { Width, Height }
  284. 0, { hWndParent }
  285. 0, { hMenu }
  286. HInstance, { hInstance }
  287. nil); { CreateParam }
  288. if hwndwcore = 0 then halt;
  289. {$ifdef threadtimer}
  290. 'thread timer'
  291. {$else}
  292. if settimer(hwndwcore,timerid_wcore,15,nil) = 0 then halt;
  293. {$endif}
  294. while GetMessage(MsgRec, 0, 0, 0) do begin
  295. TranslateMessage(MsgRec);
  296. DispatchMessage(MsgRec);
  297. {if not peekmessage(msgrec,0,0,0,PM_NOREMOVE) then onidle}
  298. end;
  299. if hWndwcore <> 0 then begin
  300. DestroyWindow(hwndwcore);
  301. hWndwcore := 0;
  302. end;
  303. {$ifdef threadtimer}
  304. 'thread timer'
  305. {$else}
  306. killtimer(hwndwcore,timerid_wcore);
  307. {$endif}
  308. end;
  309. function ProcessMessage : Boolean;
  310. var
  311. Msg : TMsg;
  312. begin
  313. Result := FALSE;
  314. if PeekMessage(Msg, hwndwcore, 0, 0, PM_REMOVE) then begin
  315. Result := TRUE;
  316. DispatchMessage(Msg);
  317. end;
  318. end;
  319. procedure processmessages;
  320. begin
  321. while processmessage do;
  322. end;
  323. end.