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