1 unit lcorewsaasyncselect;
\r 
  10   dnswin, //to call init
\r 
  11   wcore,lcore,bsearchtree,sysutils,windows,winsock,pgtypes,messages,classes,lsocket;
\r 
  14   twineventcore=class(teventcore)
\r 
  16     procedure processmessages; override;
\r 
  17     procedure messageloop; override;
\r 
  18     procedure exitmessageloop;override;
\r 
  19     procedure setfdreverse(fd : integer;reverseto : tlasio); override;
\r 
  20     procedure rmasterset(fd : integer;islistensocket : boolean); override;
\r 
  21     procedure rmasterclr(fd: integer); override;
\r 
  22     procedure wmasterset(fd : integer); override;
\r 
  23     procedure wmasterclr(fd: integer); override;
\r 
  26   wm_dotasks=wm_user+1;
\r 
  28   twintimerwrapperinterface=class(ttimerwrapperinterface)
\r 
  30     function createwrappedtimer : tobject;override;
\r 
  31 //    procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);override;
\r 
  32     procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);override;
\r 
  33     procedure setenabled(wrappedtimer : tobject;newvalue : boolean);override;
\r 
  34     procedure setinterval(wrappedtimer : tobject;newvalue : integer);override;
\r 
  37 procedure twineventcore.processmessages;
\r 
  39   wcore.processmessages;//pass off to wcore
\r 
  41 procedure twineventcore.messageloop;
\r 
  43   wcore.messageloop; //pass off to wcore
\r 
  45 procedure twineventcore.exitmessageloop;
\r 
  47   wcore.exitmessageloop;
\r 
  50   fdreverse : thashtable;
\r 
  51   fdwatches : thashtable;
\r 
  53 procedure twineventcore.setfdreverse(fd : integer;reverseto : tlasio);
\r 
  55   if findtree(@fdreverse,inttostr(fd)) <> nil then deltree(@fdreverse,inttostr(fd));
\r 
  56   if reverseto <> nil then addtree(@fdreverse,inttostr(fd),reverseto);
\r 
  61 procedure dowsaasyncselect(fd:integer; leventadd: integer; leventremove : integer);
\r 
  63   leventold : integer;
\r 
  64   leventnew : integer;
\r 
  65   wsaaresult : integer;
\r 
  67   leventold := taddrint(findtree(@fdwatches,inttostr(fd)));
\r 
  68   leventnew := leventold or leventadd;
\r 
  69   leventnew := leventnew and not leventremove;
\r 
  70   if leventold <> leventnew then begin
\r 
  71     if leventold <> 0 then deltree(@fdwatches,inttostr(fd));
\r 
  72     if leventnew <> 0 then addtree(@fdwatches,inttostr(fd),pointer(leventnew));
\r 
  74   wsaaresult := wsaasyncselect(fd,hwndlcore,wm_user,leventnew);
\r 
  79 //to allow detection of errors:
\r 
  80 //if we are asked to monitor for read or accept we also monitor for close
\r 
  81 //if we are asked to monitor for write we also monitor for connect
\r 
  84 procedure twineventcore.rmasterset(fd : integer;islistensocket : boolean);
\r 
  86   if islistensocket then begin
\r 
  87 //    writeln('setting accept watch for socket number ',fd);
\r 
  88     dowsaasyncselect(fd,FD_ACCEPT or FD_CLOSE,0);
\r 
  90 //    writeln('setting read watch for socket number',fd);
\r 
  91     dowsaasyncselect(fd,FD_READ or FD_CLOSE,0);
\r 
  94 procedure twineventcore.rmasterclr(fd: integer);
\r 
  96   //writeln('clearing read of accept watch for socket number ',fd);
\r 
  97   dowsaasyncselect(fd,0,FD_ACCEPT or FD_READ or FD_CLOSE);
\r 
  99 procedure twineventcore.wmasterset(fd : integer);
\r 
 101   dowsaasyncselect(fd,FD_WRITE or FD_CONNECT,0);
\r 
 104 procedure twineventcore.wmasterclr(fd: integer);
\r 
 106   dowsaasyncselect(fd,0,FD_WRITE or FD_CONNECT);
\r 
 110   tasksoutstanding : boolean;
\r 
 112 function MyWindowProc(
\r 
 116     alParam : LPARAM): Integer; stdcall;
\r 
 121   readtrigger : boolean;
\r 
 122   writetrigger : boolean;
\r 
 125 //  writeln('got a message');
\r 
 126   Result := 0;  // This means we handled the message
\r 
 127   if (ahwnd=hwndlcore) and (aumsg=wm_user) then begin
\r 
 128 //    writeln('it appears to be a response to our wsaasyncselect');
\r 
 130     event := alparam and $FFFF;
\r 
 131     error := alparam shr 16;
\r 
 132 //    writeln('socket=',socket,' event=',event,' error=',error);
\r 
 133     readtrigger := false;
\r 
 134     writetrigger := false;
\r 
 135     lasio := findtree(@fdreverse,inttostr(socket));
\r 
 136     if assigned(lasio) then begin
\r 
 137       if (error <> 0) or ((event and FD_CLOSE) <> 0) then begin
\r 
 138         if (lasio.state = wsconnecting) and (error <> 0) then begin
\r 
 139           if lasio is tlsocket then tlsocket(lasio).connectionfailedhandler(error)
\r 
 141           lasio.internalclose(error);
\r 
 144         if (event and (FD_READ or FD_ACCEPT)) <> 0 then readtrigger := true;
\r 
 145         if (event and (FD_WRITE)) <> 0 then writetrigger := true;
\r 
 147         if readtrigger or writetrigger then lasio.handlefdtrigger(readtrigger,writetrigger);
\r 
 149       // don't reset the event manually for listen sockets to avoid unwanted
\r 
 150       // extra onsessionavailable events
\r 
 151       if (taddrint(findtree(@fdwatches,inttostr(socket))) and (FD_ACCEPT)) = 0 then dowsaasyncselect(socket,0,0); // if not a listen socket reset watches
\r 
 153   end else if (ahwnd=hwndlcore) and (aumsg=wm_dotasks) then begin
\r 
 154       //writeln('processing tasks');
\r 
 155       tasksoutstanding := false;
\r 
 158       //writeln('passing unknown message to defwindowproc');
\r 
 159       //not passing unknown messages on to defwindowproc will cause window
\r 
 160       //creation to fail! --plugwash
\r 
 161       Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r 
 166 procedure winaddtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
 168   if not tasksoutstanding then PostMessage(hwndlcore,wm_dotasks,0,0);
\r 
 169   tasksoutstanding := true;
\r 
 172   twcoretimer = wcore.tltimer;
\r 
 174 function twintimerwrapperinterface.createwrappedtimer : tobject;
\r 
 176   result := twcoretimer.create(nil);
\r 
 178 procedure twintimerwrapperinterface.setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);
\r 
 180   twcoretimer(wrappedtimer).ontimer := newvalue;
\r 
 182 procedure twintimerwrapperinterface.setenabled(wrappedtimer : tobject;newvalue : boolean);
\r 
 184   twcoretimer(wrappedtimer).enabled := newvalue;
\r 
 188 procedure twintimerwrapperinterface.setinterval(wrappedtimer : tobject;newvalue : integer);
\r 
 190   twcoretimer(wrappedtimer).interval := newvalue;
\r 
 194   MyWindowClass : TWndClass = (style         : 0;
\r 
 195                                  lpfnWndProc   : @MyWindowProc;
\r 
 202                                  lpszMenuName  : nil;
\r 
 203                                  lpszClassName : 'lcoreClass');
\r 
 204   GInitData: TWSAData;
\r 
 208 procedure lcoreinit;
\r 
 210   if (inited) then exit;
\r 
 214   eventcore := twineventcore.create;
\r 
 215   if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r 
 216   //writeln('about to create lcore handle, hinstance=',hinstance);
\r 
 217   hwndlcore := CreateWindowEx(WS_EX_TOOLWINDOW,
\r 
 218                                MyWindowClass.lpszClassName,
\r 
 219                                '',        { Window name   }
\r 
 220                                WS_POPUP,  { Window Style  }
\r 
 222                                0, 0,      { Width, Height }
\r 
 225                                HInstance, { hInstance     }
\r 
 226                                nil);      { CreateParam   }
\r 
 227   //writeln('lcore hwnd is ',hwndlcore);
\r 
 228   //writeln('last error is ',GetLastError);
\r 
 229   onaddtask := winaddtask;
\r 
 230   timerwrapperinterface := twintimerwrapperinterface.create(nil);
\r 
 232   WSAStartup(2, GInitData);
\r 
 233   absolutemaxs := maxlongint;
\r