]> git.saurik.com Git - wxWidgets.git/blame - src/msw/gsockmsw.cpp
scrolling UPP moved
[wxWidgets.git] / src / msw / gsockmsw.cpp
CommitLineData
b7ceceb1
DE
1/* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket)
79630806 3 * Name: gsockmsw.cpp
b7ceceb1
DE
4 * Author: Guillermo Rodriguez Garcia <guille@iies.es>
5 * Purpose: GSocket GUI-specific MSW code
6 * CVSID: $Id$
7 * -------------------------------------------------------------------------
8 */
9
86afa786
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
b7ceceb1 17/*
dbfb61b3 18 * DONE: for WinCE we need to replace WSAAsyncSelect
b7ceceb1
DE
19 * (Windows message-based notification of network events for a socket)
20 * with another mechanism.
dbfb61b3
JS
21 * As WSAAsyncSelect is not present on WinCE, it now uses
22 * WSACreateEvent, WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents.
23 * When enabling eventhandling for a socket a new thread it created that keeps track of the events
24 * and posts a messageto the hidden window to use the standard message loop.
b7ceceb1
DE
25 */
26
b7ceceb1
DE
27/* including rasasync.h (included from windows.h itself included from
28 * wx/setup.h and/or winsock.h results in this warning for
29 * RPCNOTIFICATION_ROUTINE
30 */
31#ifdef _MSC_VER
1c8681b4 32# pragma warning(disable:4115) /* named type definition in parentheses */
b7ceceb1
DE
33#endif
34
35/* This needs to be before the wx/defs/h inclusion
36 * for some reason
37 */
38
39#ifdef __WXWINCE__
1c8681b4
DE
40 /* windows.h results in tons of warnings at max warning level */
41# ifdef _MSC_VER
42# pragma warning(push, 1)
43# endif
44# include <windows.h>
45# ifdef _MSC_VER
46# pragma warning(pop)
47# pragma warning(disable:4514)
48# endif
b7ceceb1
DE
49#endif
50
51#ifndef __GSOCKET_STANDALONE__
52# include "wx/platform.h"
53# include "wx/setup.h"
54#endif
55
56#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__)
57
58#ifndef __GSOCKET_STANDALONE__
59
60#include "wx/msw/gsockmsw.h"
61#include "wx/gsocket.h"
62
ebb97a41 63extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
b7ceceb1
DE
64#define INSTANCE wxGetInstance()
65
854bac91 66#else /* __GSOCKET_STANDALONE__ */
b7ceceb1
DE
67
68#include "gsockmsw.h"
69#include "gsocket.h"
70
77ffb593 71/* If not using wxWidgets, a global var called hInst must
b7ceceb1
DE
72 * be available and it must contain the app's instance
73 * handle.
74 */
854bac91 75extern HINSTANCE hInst;
b7ceceb1
DE
76#define INSTANCE hInst
77
854bac91 78#endif /* !__GSOCKET_STANDALONE__/__GSOCKET_STANDALONE__ */
b7ceceb1
DE
79
80#ifndef __WXWINCE__
81#include <assert.h>
82#else
83#define assert(x)
84#include <winsock.h>
85#include "wx/msw/wince/net.h"
86#endif
87
88#include <string.h>
89#include <stdio.h>
90#include <stdlib.h>
91#include <stddef.h>
92#include <ctype.h>
93
94#include <winsock.h>
95
96#ifdef _MSC_VER
97# pragma warning(default:4115) /* named type definition in parentheses */
98#endif
99
100#define CLASSNAME TEXT("_GSocket_Internal_Window_Class")
101
102/* implemented in utils.cpp */
32524c8f 103extern "C" WXDLLIMPEXP_BASE HWND
b7ceceb1
DE
104wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
105
106/* Maximum number of different GSocket objects at a given time.
107 * This value can be modified at will, but it CANNOT be greater
108 * than (0x7FFF - WM_USER + 1)
109 */
110#define MAXSOCKETS 1024
111
112#if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
113#error "MAXSOCKETS is too big!"
114#endif
115
dbfb61b3 116#ifndef __WXWINCE__
1c8681b4 117typedef int (PASCAL *WSAAsyncSelectFunc)(SOCKET,HWND,u_int,long);
dbfb61b3
JS
118#else
119/* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
120*/
121typedef struct _WSANETWORKEVENTS {
122 long lNetworkEvents;
123 int iErrorCode[10];
124} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
125typedef HANDLE (PASCAL *WSACreateEventFunc)(void);
126typedef int (PASCAL *WSAEventSelectFunc)(SOCKET,HANDLE,long);
127typedef int (PASCAL *WSAWaitForMultipleEventsFunc)(long,HANDLE,BOOL,long,BOOL);
128typedef int (PASCAL *WSAEnumNetworkEventsFunc)(SOCKET,HANDLE,LPWSANETWORKEVENTS);
129#endif //__WXWINCE__
b7ceceb1 130
c90cc42e
DE
131LRESULT CALLBACK _GSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM);
132
b7ceceb1
DE
133/* Global variables */
134
b7ceceb1
DE
135static HWND hWin;
136static CRITICAL_SECTION critical;
137static GSocket* socketList[MAXSOCKETS];
138static int firstAvailable;
dbfb61b3
JS
139
140#ifndef __WXWINCE__
1c8681b4 141static WSAAsyncSelectFunc gs_WSAAsyncSelect = NULL;
dbfb61b3
JS
142#else
143/* Setup WinCE specific stuff
144*/
145static socket_running;
146static unsigned int currSocket;
147HANDLE hThread[MAXSOCKETS];
148static WSACreateEventFunc gs_WSACreateEvent = NULL;
149static WSAEventSelectFunc gs_WSAEventSelect = NULL;
150static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents = NULL;
151static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents = NULL;
152/* This structure will be used to pass data on to the thread that handles socket events.
153*/
154typedef struct thread_data{
1c6dd11c
WS
155 HWND hEvtWin;
156 unsigned long msgnumber;
157 unsigned long fd;
158 unsigned long lEvent;
dbfb61b3
JS
159}thread_data;
160#endif
161
1c8681b4 162static HMODULE gs_wsock32dll = 0;
b7ceceb1 163
dbfb61b3
JS
164
165#ifdef __WXWINCE__
166/* This thread handles socket events on WinCE using WSAEventSelect() as WSAAsyncSelect is not supported.
167* When an event occures for the socket, it is checked what kind of event happend and the correct message gets posted
168* so that the hidden window can handle it as it would in other MSW builds.
169*/
170DWORD WINAPI SocketThread(LPVOID data)
171{
1c6dd11c
WS
172 WSANETWORKEVENTS NetworkEvents;
173 thread_data* d = (thread_data *)data;
174
175 HANDLE NetworkEvent = gs_WSACreateEvent();
176 gs_WSAEventSelect(d->fd, NetworkEvent, d->lEvent);
177
178 while(socket_running)
179 {
180 if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent, FALSE,INFINITE, FALSE)) == WAIT_FAILED)
181 {
182 printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
183 return 0;
184 }
185 if (gs_WSAEnumNetworkEvents(d->fd ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR)
186 {
187 printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
188 return 0;
189 }
190
191 long flags = NetworkEvents.lNetworkEvents;
192 if (flags & FD_READ)
193 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_READ);
194 if (flags & FD_WRITE)
195 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_WRITE);
196 if (flags & FD_OOB)
197 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_OOB);
198 if (flags & FD_ACCEPT)
199 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_ACCEPT);
200 if (flags & FD_CONNECT)
201 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CONNECT);
202 if (flags & FD_CLOSE)
203 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CLOSE);
204
205 }
206 gs_WSAEventSelect(d->fd, NetworkEvent, 0);
207 ExitThread(0);
208 return 0;
dbfb61b3
JS
209}
210#endif
211
212
c90cc42e 213bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop()
1c6dd11c
WS
214{
215 return true;
216}
c90cc42e 217
b7ceceb1
DE
218/* Global initializers */
219
c90cc42e 220bool GSocketGUIFunctionsTableConcrete::OnInit()
b7ceceb1 221{
1c6dd11c
WS
222 static LPCTSTR pclassname = NULL;
223 int i;
b7ceceb1 224
1c6dd11c
WS
225 /* Create internal window for event notifications */
226 hWin = wxCreateHiddenWindow(&pclassname, CLASSNAME, _GSocket_Internal_WinProc);
227 if (!hWin)
228 return false;
b7ceceb1 229
1c6dd11c
WS
230 /* Initialize socket list */
231 InitializeCriticalSection(&critical);
b7ceceb1 232
1c6dd11c
WS
233 for (i = 0; i < MAXSOCKETS; i++)
234 {
235 socketList[i] = NULL;
236 }
237 firstAvailable = 0;
b7ceceb1 238
1c6dd11c
WS
239 /* Load WSAAsyncSelect from wsock32.dll (we don't link against it
240 statically to avoid dependency on wsock32.dll for apps that don't use
241 sockets): */
dbfb61b3 242#ifndef __WXWINCE__
1c6dd11c
WS
243 gs_wsock32dll = LoadLibrary(wxT("wsock32.dll"));
244 if (!gs_wsock32dll)
245 return false;
246 gs_WSAAsyncSelect =(WSAAsyncSelectFunc)GetProcAddress(gs_wsock32dll,
247 "WSAAsyncSelect");
248 if (!gs_WSAAsyncSelect)
249 return false;
dbfb61b3
JS
250#else
251/* On WinCE we load ws2.dll which will provide the needed functions.
252*/
1c6dd11c
WS
253 gs_wsock32dll = LoadLibrary(wxT("ws2.dll"));
254 if (!gs_wsock32dll)
255 return false;
256 gs_WSAEventSelect =(WSAEventSelectFunc)GetProcAddress(gs_wsock32dll,
257 wxT("WSAEventSelect"));
258 if (!gs_WSAEventSelect)
259 return false;
260
261 gs_WSACreateEvent =(WSACreateEventFunc)GetProcAddress(gs_wsock32dll,
262 wxT("WSACreateEvent"));
263 if (!gs_WSACreateEvent)
264 return false;
265
266 gs_WSAWaitForMultipleEvents =(WSAWaitForMultipleEventsFunc)GetProcAddress(gs_wsock32dll,
267 wxT("WSAWaitForMultipleEvents"));
268 if (!gs_WSAWaitForMultipleEvents)
269 return false;
270
271 gs_WSAEnumNetworkEvents =(WSAEnumNetworkEventsFunc)GetProcAddress(gs_wsock32dll,
272 wxT("WSAEnumNetworkEvents"));
273 if (!gs_WSAEnumNetworkEvents)
274 return false;
275
276 currSocket = 0;
dbfb61b3 277#endif
1c6dd11c
WS
278
279 return true;
b7ceceb1
DE
280}
281
c90cc42e 282void GSocketGUIFunctionsTableConcrete::OnExit()
b7ceceb1 283{
dbfb61b3 284#ifdef __WXWINCE__
1c6dd11c
WS
285/* Delete the threads here */
286 for(unsigned int i=0; i < currSocket; i++)
287 CloseHandle(hThread[i]);
dbfb61b3 288#endif
b7ceceb1
DE
289 /* Destroy internal window */
290 DestroyWindow(hWin);
291 UnregisterClass(CLASSNAME, INSTANCE);
292
1c8681b4
DE
293 /* Unlock wsock32.dll */
294 if (gs_wsock32dll)
295 {
296 FreeLibrary(gs_wsock32dll);
297 gs_wsock32dll = 0;
298 }
299
b7ceceb1
DE
300 /* Delete critical section */
301 DeleteCriticalSection(&critical);
302}
303
304/* Per-socket GUI initialization / cleanup */
305
c90cc42e 306bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket)
b7ceceb1
DE
307{
308 int i;
309
310 /* Allocate a new message number for this socket */
311 EnterCriticalSection(&critical);
312
313 i = firstAvailable;
314 while (socketList[i] != NULL)
315 {
316 i = (i + 1) % MAXSOCKETS;
317
318 if (i == firstAvailable) /* abort! */
319 {
320 LeaveCriticalSection(&critical);
c90cc42e 321 return false;
b7ceceb1
DE
322 }
323 }
324 socketList[i] = socket;
325 firstAvailable = (i + 1) % MAXSOCKETS;
326 socket->m_msgnumber = (i + WM_USER);
327
328 LeaveCriticalSection(&critical);
329
c90cc42e 330 return true;
b7ceceb1
DE
331}
332
c90cc42e 333void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket)
b7ceceb1
DE
334{
335 /* Remove the socket from the list */
336 EnterCriticalSection(&critical);
337 socketList[(socket->m_msgnumber - WM_USER)] = NULL;
338 LeaveCriticalSection(&critical);
339}
340
341/* Windows proc for asynchronous event handling */
342
343LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd,
344 UINT uMsg,
345 WPARAM wParam,
346 LPARAM lParam)
347{
348 GSocket *socket;
349 GSocketEvent event;
350 GSocketCallback cback;
351 char *data;
352
353 if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1))
354 {
355 EnterCriticalSection(&critical);
356 socket = socketList[(uMsg - WM_USER)];
357 event = (GSocketEvent) -1;
358 cback = NULL;
359 data = NULL;
360
361 /* Check that the socket still exists (it has not been
362 * destroyed) and for safety, check that the m_fd field
363 * is what we expect it to be.
364 */
365 if ((socket != NULL) && (socket->m_fd == wParam))
366 {
367 switch WSAGETSELECTEVENT(lParam)
368 {
369 case FD_READ: event = GSOCK_INPUT; break;
370 case FD_WRITE: event = GSOCK_OUTPUT; break;
371 case FD_ACCEPT: event = GSOCK_CONNECTION; break;
372 case FD_CONNECT:
373 {
374 if (WSAGETSELECTERROR(lParam) != 0)
375 event = GSOCK_LOST;
376 else
377 event = GSOCK_CONNECTION;
378 break;
379 }
380 case FD_CLOSE: event = GSOCK_LOST; break;
381 }
382
383 if (event != -1)
384 {
385 cback = socket->m_cbacks[event];
386 data = socket->m_data[event];
387
388 if (event == GSOCK_LOST)
389 socket->m_detected = GSOCK_LOST_FLAG;
390 else
391 socket->m_detected |= (1 << event);
392 }
393 }
394
395 /* OK, we can now leave the critical section because we have
396 * already obtained the callback address (we make no further
397 * accesses to socket->whatever). However, the app should
398 * be prepared to handle events from a socket that has just
399 * been closed!
400 */
401 LeaveCriticalSection(&critical);
402
403 if (cback != NULL)
404 (cback)(socket, event, data);
405
406 return (LRESULT) 0;
407 }
408 else
409 return DefWindowProc(hWnd, uMsg, wParam, lParam);
410}
411
412/* _GSocket_Enable_Events:
413 * Enable all event notifications; we need to be notified of all
414 * events for internal processing, but we will only notify users
415 * when an appropiate callback function has been installed.
416 */
c90cc42e 417void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket)
b7ceceb1
DE
418{
419 assert (socket != NULL);
420
421 if (socket->m_fd != INVALID_SOCKET)
422 {
423 /* We could probably just subscribe to all events regardless
424 * of the socket type, but MS recommends to do it this way.
425 */
426 long lEvent = socket->m_server?
427 FD_ACCEPT : (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
dbfb61b3 428#ifndef __WXWINCE__
1c8681b4 429 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, lEvent);
dbfb61b3
JS
430#else
431/*
432* WinCE creates a thread for socket event handling.
1c6dd11c 433* All needed parameters get passed through the thread_data structure.
dbfb61b3 434*/
1c6dd11c
WS
435 socket_running = true;
436 thread_data* d = new thread_data;
437 d->lEvent = lEvent;
438 d->hEvtWin = hWin;
439 d->msgnumber = socket->m_msgnumber;
440 d->fd = socket->m_fd;
441 hThread[currSocket++] = CreateThread(NULL, 0, &SocketThread,(LPVOID)d, 0, NULL);
dbfb61b3 442#endif
b7ceceb1
DE
443 }
444}
445
446/* _GSocket_Disable_Events:
447 * Disable event notifications (when shutdowning the socket)
448 */
c90cc42e 449void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket)
b7ceceb1
DE
450{
451 assert (socket != NULL);
452
453 if (socket->m_fd != INVALID_SOCKET)
454 {
dbfb61b3 455#ifndef __WXWINCE__
1c8681b4 456 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
dbfb61b3 457#else
1c6dd11c
WS
458 //Destroy the thread
459 //TODO: This needs to be changed, maybe using another global event that could be triggered.
460 socket_running = false;
dbfb61b3 461#endif
b7ceceb1
DE
462 }
463}
464
465#else /* !wxUSE_SOCKETS */
466
467/*
468 * Translation unit shouldn't be empty, so include this typedef to make the
469 * compiler (VC++ 6.0, for example) happy
470 */
471typedef void (*wxDummy)();
472
473#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */