4 lcore compatible interface for windows
\r 
  11 //note: events after release are normal and are the apps responsibility to deal with safely
\r 
  15     classes,windows,mmsystem;
\r 
  20     tlcomponent = class(tcomponent)
\r 
  24       destructor destroy; override;
\r 
  27     tltimer=class(tlcomponent)
\r 
  30       procedure setenabled(newvalue : boolean);
\r 
  32       ontimer:tnotifyevent;
\r 
  33       initialevent:boolean;
\r 
  34       initialdone:boolean;
\r 
  37       interval:integer;        {milliseconds, default 1000}
\r 
  39       property enabled:boolean read fenabled write setenabled;
\r 
  40       constructor create(aowner:tcomponent);override;
\r 
  41       destructor destroy;override;
\r 
  44     ttaskevent=procedure(wparam,lparam:longint) of object;
\r 
  46     tltask=class(tobject)
\r 
  48       handler  : ttaskevent;
\r 
  53       constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
  56 procedure messageloop;
\r 
  57 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
  58 procedure disconnecttasks(aobj:tobject);
\r 
  59 procedure exitmessageloop;
\r 
  60 procedure processmessages;
\r 
  61 procedure wcoreinit;
\r 
  64   onshutdown:procedure(s:ansistring);
\r 
  77   WINMSG_TASK=WM_USER;
\r 
  82   timesubtract:integer;
\r 
  83   firsttask,lasttask,currenttask:tltask;
\r 
  85 procedure tlcomponent.release;
\r 
  90 destructor tlcomponent.destroy;
\r 
  92   disconnecttasks(self);
\r 
  96 {------------------------------------------------------------------------------}
\r 
  98 procedure tltimer.setenabled(newvalue : boolean);
\r 
 100   fenabled := newvalue;
\r 
 102   initialdone := false;
\r 
 105 constructor tltimer.create;
\r 
 107   inherited create(AOwner);
\r 
 108   nexttimer := firsttimer;
\r 
 111   if assigned(nexttimer) then nexttimer.prevtimer := self;
\r 
 112   firsttimer := self;
\r 
 119 destructor tltimer.destroy;
\r 
 121   if prevtimer <> nil then begin
\r 
 122     prevtimer.nexttimer := nexttimer;
\r 
 124     firsttimer := nexttimer;
\r 
 126   if nexttimer <> nil then begin
\r 
 127     nexttimer.prevtimer := prevtimer;
\r 
 132 {------------------------------------------------------------------------------}
\r 
 134 function wcore_timehandler:integer;
\r 
 139   currenttimer,temptimer:tltimer;
\r 
 141   if not assigned(firsttimer) then begin
\r 
 146   tvnow := timegettime;
\r 
 147   if (tvnow and ((-1) shl rollover_bits)) <> timesubtract then begin
\r 
 148     currenttimer := firsttimer;
\r 
 149     while assigned(currenttimer) do begin
\r 
 150       dec(currenttimer.nextts,(1 shl rollover_bits));
\r 
 151       currenttimer := currenttimer.nexttimer;
\r 
 153     timesubtract := tvnow and ((-1) shl rollover_bits);
\r 
 155   tvnow := tvnow and ((1 shl rollover_bits)-1);
\r 
 157   currenttimer := firsttimer;
\r 
 158   while assigned(currenttimer) do begin
\r 
 159     if tvnow >= currenttimer.nextts then begin
\r 
 160       if assigned(currenttimer.ontimer) then begin
\r 
 161         if currenttimer.enabled then begin
\r 
 162           if currenttimer.initialevent or currenttimer.initialdone then currenttimer.ontimer(currenttimer);
\r 
 163           currenttimer.initialdone := true;
\r 
 166       currenttimer.nextts := tvnow+currenttimer.interval;
\r 
 168     temptimer := currenttimer;
\r 
 169     currenttimer := currenttimer.nexttimer;
\r 
 170     if temptimer.released then temptimer.free;
\r 
 174   currenttimer := firsttimer;
\r 
 175   while assigned(currenttimer) do begin
\r 
 176     if currenttimer.nextts < tv then tv := currenttimer.nextts;
\r 
 177     currenttimer := currenttimer.nexttimer;
\r 
 179   result := tv-tvnow;
\r 
 180   if result < 15 then result := 15;
\r 
 183 {------------------------------------------------------------------------------}
\r 
 185 constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
 188   handler   := ahandler;
\r 
 192   {nexttask  := firsttask;
\r 
 193   firsttask := self;}
\r 
 194   if assigned(lasttask) then begin
\r 
 195     lasttask.nexttask := self;
\r 
 198     postmessage(hwndwcore,WINMSG_TASK,0,0);
\r 
 201   //ahandler(wparam,lparam);
\r 
 204 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
 206   tltask.create(ahandler,aobj,awparam,alparam);
\r 
 209 procedure disconnecttasks(aobj:tobject);
\r 
 211   currenttasklocal : tltask ;
\r 
 214   for counter := 0 to 1 do begin
\r 
 215     if counter = 0 then begin
\r 
 216       currenttasklocal := firsttask; //main list of tasks
\r 
 218       currenttasklocal := currenttask; //needed in case called from a task
\r 
 220     // note i don't bother to destroy the links here as that will happen when
\r 
 221     // the list of tasks is processed anyway
\r 
 222     while assigned(currenttasklocal) do begin
\r 
 223       if currenttasklocal.obj = aobj then begin
\r 
 224         currenttasklocal.obj := nil;
\r 
 225         currenttasklocal.handler := nil;
\r 
 227       currenttasklocal := currenttasklocal.nexttask;
\r 
 236   if firsttask = nil then exit;
\r 
 238   currenttask := firsttask;
\r 
 241   while assigned(currenttask) do begin
\r 
 242     if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
\r 
 243     temptask := currenttask;
\r 
 244     currenttask := currenttask.nexttask;
\r 
 247   currenttask := nil;
\r 
 250 {------------------------------------------------------------------------------}
\r 
 252 procedure exitmessageloop;
\r 
 254   postmessage(hwndwcore,WM_QUIT,0,0);
\r 
 257   {$ifdef threadtimer}
\r 
 260 const timerid_wcore=$1000;
\r 
 263 function MyWindowProc(
\r 
 267     alParam : LPARAM): Integer; stdcall;
\r 
 272   Result := 0;  // This means we handled the message
\r 
 274   {MsgRec.hwnd    := ahWnd;}
\r 
 275   MsgRec.wParam  := awParam;
\r 
 276   MsgRec.lParam  := alParam;
\r 
 280     {$ifndef threadtimer}
\r 
 282       if msgrec.wparam = timerid_wcore then begin
\r 
 283         a := wcore_timehandler;
\r 
 284         killtimer(hwndwcore,timerid_wcore);
\r 
 285         settimer(hwndwcore,timerid_wcore,a,nil);
\r 
 290     {WINMSG_TASK:dotasks;}
\r 
 299       Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r 
 305   MyWindowClass : TWndClass = (style         : 0;
\r 
 306                                  lpfnWndProc   : @MyWindowProc;
\r 
 313                                  lpszMenuName  : nil;
\r 
 314                                  lpszClassName : 'wcoreClass');
\r 
 316 procedure wcoreinit;
\r 
 318   if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r 
 319   //writeln('about to create wcore handle, hinstance=',hinstance);
\r 
 320   hwndwcore := CreateWindowEx(WS_EX_TOOLWINDOW,
\r 
 321                                MyWindowClass.lpszClassName,
\r 
 322                                '',        { Window name   }
\r 
 323                                WS_POPUP,  { Window Style  }
\r 
 325                                0, 0,      { Width, Height }
\r 
 328                                HInstance, { hInstance     }
\r 
 329                                nil);      { CreateParam   }
\r 
 331   if hwndwcore = 0 then halt;
\r 
 333   {$ifdef threadtimer}
\r 
 336   if settimer(hwndwcore,timerid_wcore,15,nil) = 0 then halt;
\r 
 342 procedure messageloop;
\r 
 348   while GetMessage(MsgRec, 0, 0, 0) do begin
\r 
 349     TranslateMessage(MsgRec);
\r 
 350     DispatchMessage(MsgRec);
\r 
 351     {if not peekmessage(msgrec,0,0,0,PM_NOREMOVE) then onidle}
\r 
 354   if hWndwcore <> 0 then begin
\r 
 355     DestroyWindow(hwndwcore);
\r 
 359   {$ifdef threadtimer}
\r 
 362   killtimer(hwndwcore,timerid_wcore);
\r 
 366 function ProcessMessage : Boolean;
\r 
 371     if PeekMessage(MsgRec, 0, 0, 0, PM_REMOVE) then begin
\r 
 373       TranslateMessage(MsgRec);
\r 
 374       DispatchMessage(MsgRec);
\r 
 378 procedure processmessages;
\r 
 380   while processmessage do;
\r