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.

lcorewsaasyncselect.pas 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. unit lcorewsaasyncselect;
  2. interface
  3. procedure lcoreinit;
  4. implementation
  5. uses wcore,lcore,bsearchtree,sysutils,windows,winsock,pgtypes,messages,classes,lsocket;
  6. type
  7. twineventcore=class(teventcore)
  8. public
  9. procedure processmessages; override;
  10. procedure messageloop; override;
  11. procedure exitmessageloop;override;
  12. procedure setfdreverse(fd : integer;reverseto : tlasio); override;
  13. procedure rmasterset(fd : integer;islistensocket : boolean); override;
  14. procedure rmasterclr(fd: integer); override;
  15. procedure wmasterset(fd : integer); override;
  16. procedure wmasterclr(fd: integer); override;
  17. end;
  18. const
  19. wm_dotasks=wm_user+1;
  20. type
  21. twintimerwrapperinterface=class(ttimerwrapperinterface)
  22. public
  23. function createwrappedtimer : tobject;override;
  24. // procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);override;
  25. procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);override;
  26. procedure setenabled(wrappedtimer : tobject;newvalue : boolean);override;
  27. procedure setinterval(wrappedtimer : tobject;newvalue : integer);override;
  28. end;
  29. procedure twineventcore.processmessages;
  30. begin
  31. wcore.processmessages;//pass off to wcore
  32. end;
  33. procedure twineventcore.messageloop;
  34. begin
  35. wcore.messageloop; //pass off to wcore
  36. end;
  37. procedure twineventcore.exitmessageloop;
  38. begin
  39. wcore.exitmessageloop;
  40. end;
  41. var
  42. fdreverse : thashtable;
  43. fdwatches : thashtable;
  44. procedure twineventcore.setfdreverse(fd : integer;reverseto : tlasio);
  45. begin
  46. if findtree(@fdreverse,inttostr(fd)) <> nil then deltree(@fdreverse,inttostr(fd));
  47. if reverseto <> nil then addtree(@fdreverse,inttostr(fd),reverseto);
  48. end;
  49. var
  50. hwndlcore : hwnd;
  51. procedure dowsaasyncselect(fd:integer; leventadd: integer; leventremove : integer);
  52. var
  53. leventold : integer;
  54. leventnew : integer;
  55. wsaaresult : integer;
  56. begin
  57. leventold := taddrint(findtree(@fdwatches,inttostr(fd)));
  58. leventnew := leventold or leventadd;
  59. leventnew := leventnew and not leventremove;
  60. if leventold <> leventnew then begin
  61. if leventold <> 0 then deltree(@fdwatches,inttostr(fd));
  62. if leventnew <> 0 then addtree(@fdwatches,inttostr(fd),pointer(leventnew));
  63. end;
  64. wsaaresult := wsaasyncselect(fd,hwndlcore,wm_user,leventnew);
  65. end;
  66. //to allow detection of errors:
  67. //if we are asked to monitor for read or accept we also monitor for close
  68. //if we are asked to monitor for write we also monitor for connect
  69. procedure twineventcore.rmasterset(fd : integer;islistensocket : boolean);
  70. begin
  71. if islistensocket then begin
  72. // writeln('setting accept watch for socket number ',fd);
  73. dowsaasyncselect(fd,FD_ACCEPT or FD_CLOSE,0);
  74. end else begin
  75. // writeln('setting read watch for socket number',fd);
  76. dowsaasyncselect(fd,FD_READ or FD_CLOSE,0);
  77. end;
  78. end;
  79. procedure twineventcore.rmasterclr(fd: integer);
  80. begin
  81. //writeln('clearing read of accept watch for socket number ',fd);
  82. dowsaasyncselect(fd,0,FD_ACCEPT or FD_READ or FD_CLOSE);
  83. end;
  84. procedure twineventcore.wmasterset(fd : integer);
  85. begin
  86. dowsaasyncselect(fd,FD_WRITE or FD_CONNECT,0);
  87. end;
  88. procedure twineventcore.wmasterclr(fd: integer);
  89. begin
  90. dowsaasyncselect(fd,0,FD_WRITE or FD_CONNECT);
  91. end;
  92. var
  93. tasksoutstanding : boolean;
  94. function MyWindowProc(
  95. ahWnd : HWND;
  96. auMsg : Integer;
  97. awParam : WPARAM;
  98. alParam : LPARAM): Integer; stdcall;
  99. var
  100. socket : integer;
  101. event : integer;
  102. error : integer;
  103. readtrigger : boolean;
  104. writetrigger : boolean;
  105. lasio : tlasio;
  106. begin
  107. // writeln('got a message');
  108. Result := 0; // This means we handled the message
  109. if (ahwnd=hwndlcore) and (aumsg=wm_user) then begin
  110. // writeln('it appears to be a response to our wsaasyncselect');
  111. socket := awparam;
  112. event := alparam and $FFFF;
  113. error := alparam shr 16;
  114. // writeln('socket=',socket,' event=',event,' error=',error);
  115. readtrigger := false;
  116. writetrigger := false;
  117. lasio := findtree(@fdreverse,inttostr(socket));
  118. if assigned(lasio) then begin
  119. if (error <> 0) or ((event and FD_CLOSE) <> 0) then begin
  120. if (lasio.state = wsconnecting) and (error <> 0) then begin
  121. if lasio is tlsocket then tlsocket(lasio).connectionfailedhandler(error)
  122. end else begin
  123. lasio.internalclose(error);
  124. end;
  125. end else begin
  126. if (event and (FD_READ or FD_ACCEPT)) <> 0 then readtrigger := true;
  127. if (event and (FD_WRITE)) <> 0 then writetrigger := true;
  128. if readtrigger or writetrigger then lasio.handlefdtrigger(readtrigger,writetrigger);
  129. end;
  130. // don't reset the event manually for listen sockets to avoid unwanted
  131. // extra onsessionavailible events
  132. if (taddrint(findtree(@fdwatches,inttostr(socket))) and (FD_ACCEPT)) = 0 then dowsaasyncselect(socket,0,0); // if not a listen socket reset watches
  133. end;
  134. end else if (ahwnd=hwndlcore) and (aumsg=wm_dotasks) then begin
  135. //writeln('processing tasks');
  136. tasksoutstanding := false;
  137. processtasks;
  138. end else begin
  139. //writeln('passing unknown message to defwindowproc');
  140. //not passing unknown messages on to defwindowproc will cause window
  141. //creation to fail! --plugwash
  142. Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
  143. end;
  144. end;
  145. procedure winaddtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  146. begin
  147. if not tasksoutstanding then PostMessage(hwndlcore,wm_dotasks,0,0);
  148. end;
  149. type
  150. twcoretimer = wcore.tltimer;
  151. function twintimerwrapperinterface.createwrappedtimer : tobject;
  152. begin
  153. result := twcoretimer.create(nil);
  154. end;
  155. procedure twintimerwrapperinterface.setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);
  156. begin
  157. twcoretimer(wrappedtimer).ontimer := newvalue;
  158. end;
  159. procedure twintimerwrapperinterface.setenabled(wrappedtimer : tobject;newvalue : boolean);
  160. begin
  161. twcoretimer(wrappedtimer).enabled := newvalue;
  162. end;
  163. procedure twintimerwrapperinterface.setinterval(wrappedtimer : tobject;newvalue : integer);
  164. begin
  165. twcoretimer(wrappedtimer).interval := newvalue;
  166. end;
  167. var
  168. MyWindowClass : TWndClass = (style : 0;
  169. lpfnWndProc : @MyWindowProc;
  170. cbClsExtra : 0;
  171. cbWndExtra : 0;
  172. hInstance : 0;
  173. hIcon : 0;
  174. hCursor : 0;
  175. hbrBackground : 0;
  176. lpszMenuName : nil;
  177. lpszClassName : 'lcoreClass');
  178. GInitData: TWSAData;
  179. var
  180. inited:boolean;
  181. procedure lcoreinit;
  182. begin
  183. if (inited) then exit;
  184. eventcore := twineventcore.create;
  185. if Windows.RegisterClass(MyWindowClass) = 0 then halt;
  186. //writeln('about to create lcore handle, hinstance=',hinstance);
  187. hwndlcore := CreateWindowEx(WS_EX_TOOLWINDOW,
  188. MyWindowClass.lpszClassName,
  189. '', { Window name }
  190. WS_POPUP, { Window Style }
  191. 0, 0, { X, Y }
  192. 0, 0, { Width, Height }
  193. 0, { hWndParent }
  194. 0, { hMenu }
  195. HInstance, { hInstance }
  196. nil); { CreateParam }
  197. //writeln('lcore hwnd is ',hwndlcore);
  198. //writeln('last error is ',GetLastError);
  199. onaddtask := winaddtask;
  200. timerwrapperinterface := twintimerwrapperinterface.create(nil);
  201. WSAStartup(2, GInitData);
  202. absoloutemaxs := maxlongint;
  203. inited := true;
  204. end;
  205. end.