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