]> git.saurik.com Git - wxWidgets.git/blob - src/msw/gsockmsw.cpp
Fixed inability to select no superscript and no subscript in wxRichTextCtrl's
[wxWidgets.git] / src / msw / gsockmsw.cpp
1 /* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket)
3 * Name: src/msw/gsockmsw.cpp
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$
9 * -------------------------------------------------------------------------
10 */
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_SOCKETS
20
21 /*
22 * DONE: for WinCE we need to replace WSAAsyncSelect
23 * (Windows message-based notification of network events for a socket)
24 * with another mechanism.
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.
29 */
30
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
36 # pragma warning(disable:4115) /* named type definition in parentheses */
37 #endif
38
39 #include "wx/private/gsocket.h"
40 #include "wx/apptrait.h"
41 #include "wx/link.h"
42
43 wxFORCE_LINK_THIS_MODULE(gsockmsw)
44
45 extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance();
46 #define INSTANCE wxGetInstance()
47
48 #ifdef __WXWINCE__
49 #include <winsock.h>
50 #include "wx/msw/wince/net.h"
51 #include "wx/hashmap.h"
52 WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash,wxIntegerEqual,SocketHash);
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 */
70 extern "C" WXDLLIMPEXP_BASE HWND
71 wxCreateHiddenWindow(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
83 #ifndef __WXWINCE__
84 typedef int (PASCAL *WSAAsyncSelectFunc)(SOCKET,HWND,u_int,long);
85 #else
86 /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
87 */
88 typedef struct _WSANETWORKEVENTS {
89 long lNetworkEvents;
90 int iErrorCode[10];
91 } WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
92 typedef HANDLE (PASCAL *WSACreateEventFunc)();
93 typedef int (PASCAL *WSAEventSelectFunc)(SOCKET,HANDLE,long);
94 typedef int (PASCAL *WSAWaitForMultipleEventsFunc)(long,HANDLE,BOOL,long,BOOL);
95 typedef int (PASCAL *WSAEnumNetworkEventsFunc)(SOCKET,HANDLE,LPWSANETWORKEVENTS);
96 #endif //__WXWINCE__
97
98 LRESULT CALLBACK _GSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM);
99
100 /* Global variables */
101
102 static HWND hWin;
103 static CRITICAL_SECTION critical;
104 static GSocket* socketList[MAXSOCKETS];
105 static int firstAvailable;
106
107 #ifndef __WXWINCE__
108 static WSAAsyncSelectFunc gs_WSAAsyncSelect = NULL;
109 #else
110 static SocketHash socketHash;
111 static unsigned int currSocket;
112 HANDLE hThread[MAXSOCKETS];
113 static WSACreateEventFunc gs_WSACreateEvent = NULL;
114 static WSAEventSelectFunc gs_WSAEventSelect = NULL;
115 static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents = NULL;
116 static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents = NULL;
117 /* This structure will be used to pass data on to the thread that handles socket events.
118 */
119 typedef struct thread_data{
120 HWND hEvtWin;
121 unsigned long msgnumber;
122 unsigned long fd;
123 unsigned long lEvent;
124 }thread_data;
125 #endif
126
127 static HMODULE gs_wsock32dll = 0;
128
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 */
135 DWORD WINAPI SocketThread(LPVOID data)
136 {
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;
174 }
175 #endif
176
177 // ----------------------------------------------------------------------------
178 // MSW implementation of GSocketManager
179 // ----------------------------------------------------------------------------
180
181 class GSocketMSWManager : public GSocketManager
182 {
183 public:
184 virtual bool OnInit();
185 virtual void OnExit();
186
187 virtual bool Init_Socket(GSocket *socket);
188 virtual void Close_Socket(GSocket *socket);
189 virtual void Destroy_Socket(GSocket *socket);
190
191 virtual void Install_Callback(GSocket *socket, GSocketEvent event);
192 virtual void Uninstall_Callback(GSocket *socket, GSocketEvent event);
193 };
194
195 /* Global initializers */
196
197 bool GSocketMSWManager::OnInit()
198 {
199 static LPCTSTR pclassname = NULL;
200 int i;
201
202 /* Create internal window for event notifications */
203 hWin = wxCreateHiddenWindow(&pclassname, CLASSNAME, _GSocket_Internal_WinProc);
204 if (!hWin)
205 return false;
206
207 /* Initialize socket list */
208 InitializeCriticalSection(&critical);
209
210 for (i = 0; i < MAXSOCKETS; i++)
211 {
212 socketList[i] = NULL;
213 }
214 firstAvailable = 0;
215
216 /* Load WSAAsyncSelect from wsock32.dll (we don't link against it
217 statically to avoid dependency on wsock32.dll for apps that don't use
218 sockets): */
219 #ifndef __WXWINCE__
220 gs_wsock32dll = LoadLibrary(wxT("wsock32.dll"));
221 if (!gs_wsock32dll)
222 return false;
223 gs_WSAAsyncSelect =(WSAAsyncSelectFunc)GetProcAddress(gs_wsock32dll,
224 "WSAAsyncSelect");
225 if (!gs_WSAAsyncSelect)
226 return false;
227 #else
228 /* On WinCE we load ws2.dll which will provide the needed functions.
229 */
230 gs_wsock32dll = LoadLibrary(wxT("ws2.dll"));
231 if (!gs_wsock32dll)
232 return false;
233 gs_WSAEventSelect =(WSAEventSelectFunc)GetProcAddress(gs_wsock32dll,
234 wxT("WSAEventSelect"));
235 if (!gs_WSAEventSelect)
236 return false;
237
238 gs_WSACreateEvent =(WSACreateEventFunc)GetProcAddress(gs_wsock32dll,
239 wxT("WSACreateEvent"));
240 if (!gs_WSACreateEvent)
241 return false;
242
243 gs_WSAWaitForMultipleEvents =(WSAWaitForMultipleEventsFunc)GetProcAddress(gs_wsock32dll,
244 wxT("WSAWaitForMultipleEvents"));
245 if (!gs_WSAWaitForMultipleEvents)
246 return false;
247
248 gs_WSAEnumNetworkEvents =(WSAEnumNetworkEventsFunc)GetProcAddress(gs_wsock32dll,
249 wxT("WSAEnumNetworkEvents"));
250 if (!gs_WSAEnumNetworkEvents)
251 return false;
252
253 currSocket = 0;
254 #endif
255
256 return true;
257 }
258
259 void GSocketMSWManager::OnExit()
260 {
261 #ifdef __WXWINCE__
262 /* Delete the threads here */
263 for(unsigned int i=0; i < currSocket; i++)
264 CloseHandle(hThread[i]);
265 #endif
266 /* Destroy internal window */
267 DestroyWindow(hWin);
268 UnregisterClass(CLASSNAME, INSTANCE);
269
270 /* Unlock wsock32.dll */
271 if (gs_wsock32dll)
272 {
273 FreeLibrary(gs_wsock32dll);
274 gs_wsock32dll = 0;
275 }
276
277 /* Delete critical section */
278 DeleteCriticalSection(&critical);
279 }
280
281 /* Per-socket GUI initialization / cleanup */
282
283 bool GSocketMSWManager::Init_Socket(GSocket *socket)
284 {
285 int i;
286
287 /* Allocate a new message number for this socket */
288 EnterCriticalSection(&critical);
289
290 i = firstAvailable;
291 while (socketList[i] != NULL)
292 {
293 i = (i + 1) % MAXSOCKETS;
294
295 if (i == firstAvailable) /* abort! */
296 {
297 LeaveCriticalSection(&critical);
298 return false;
299 }
300 }
301 socketList[i] = socket;
302 firstAvailable = (i + 1) % MAXSOCKETS;
303 socket->m_msgnumber = (i + WM_USER);
304
305 LeaveCriticalSection(&critical);
306
307 return true;
308 }
309
310 void GSocketMSWManager::Close_Socket(GSocket *socket)
311 {
312 Uninstall_Callback(socket, GSOCK_MAX_EVENT /* unused anyhow */);
313
314 closesocket(socket->m_fd);
315 }
316
317 void GSocketMSWManager::Destroy_Socket(GSocket *socket)
318 {
319 /* Remove the socket from the list */
320 EnterCriticalSection(&critical);
321
322 const int msgnum = socket->m_msgnumber;
323 if ( msgnum )
324 {
325 // we need to remove any pending messages for this socket to avoid having
326 // them sent to a new socket which could reuse the same message number as
327 // soon as we destroy this one
328 MSG msg;
329 while ( ::PeekMessage(&msg, hWin, msgnum, msgnum, PM_REMOVE) )
330 ;
331
332 socketList[msgnum - WM_USER] = NULL;
333 }
334 //else: the socket has never been created successfully
335
336 LeaveCriticalSection(&critical);
337 }
338
339 /* Windows proc for asynchronous event handling */
340
341 LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd,
342 UINT uMsg,
343 WPARAM wParam,
344 LPARAM lParam)
345 {
346 GSocket *socket;
347 GSocketEvent event;
348
349 if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1))
350 {
351 EnterCriticalSection(&critical);
352 socket = socketList[(uMsg - WM_USER)];
353 event = (GSocketEvent) -1;
354
355 /* Check that the socket still exists (it has not been
356 * destroyed) and for safety, check that the m_fd field
357 * is what we expect it to be.
358 */
359 if ((socket != NULL) && ((WPARAM)socket->m_fd == wParam))
360 {
361 switch WSAGETSELECTEVENT(lParam)
362 {
363 case FD_READ: event = GSOCK_INPUT; break;
364 case FD_WRITE: event = GSOCK_OUTPUT; break;
365 case FD_ACCEPT: event = GSOCK_CONNECTION; break;
366 case FD_CONNECT:
367 {
368 if (WSAGETSELECTERROR(lParam) != 0)
369 event = GSOCK_LOST;
370 else
371 event = GSOCK_CONNECTION;
372 break;
373 }
374 case FD_CLOSE: event = GSOCK_LOST; break;
375 }
376
377 if (event != -1)
378 {
379 if (event == GSOCK_LOST)
380 socket->m_detected = GSOCK_LOST_FLAG;
381 else
382 socket->m_detected |= (1 << event);
383 }
384 }
385
386 LeaveCriticalSection(&critical);
387
388 if ( socket )
389 socket->NotifyOnStateChange(event);
390
391 return (LRESULT) 0;
392 }
393 else
394 return DefWindowProc(hWnd, uMsg, wParam, lParam);
395 }
396
397 /*
398 * Enable all event notifications; we need to be notified of all
399 * events for internal processing, but we will only notify users
400 * when an appropriate callback function has been installed.
401 */
402 void GSocketMSWManager::Install_Callback(GSocket *socket,
403 GSocketEvent WXUNUSED(event))
404 {
405 if (socket->m_fd != INVALID_SOCKET)
406 {
407 /* We could probably just subscribe to all events regardless
408 * of the socket type, but MS recommends to do it this way.
409 */
410 long lEvent = socket->m_server?
411 FD_ACCEPT : (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
412 #ifndef __WXWINCE__
413 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, lEvent);
414 #else
415 /*
416 * WinCE creates a thread for socket event handling.
417 * All needed parameters get passed through the thread_data structure.
418 */
419
420 thread_data* d = new thread_data;
421 d->lEvent = lEvent;
422 d->hEvtWin = hWin;
423 d->msgnumber = socket->m_msgnumber;
424 d->fd = socket->m_fd;
425 socketHash[socket->m_fd] = true;
426 hThread[currSocket++] = CreateThread(NULL, 0, &SocketThread,(LPVOID)d, 0, NULL);
427 #endif
428 }
429 }
430
431 /*
432 * Disable event notifications (used when shutting down the socket)
433 */
434 void GSocketMSWManager::Uninstall_Callback(GSocket *socket,
435 GSocketEvent WXUNUSED(event))
436 {
437 if (socket->m_fd != INVALID_SOCKET)
438 {
439 #ifndef __WXWINCE__
440 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
441 #else
442 //Destroy the thread
443 socketHash[socket->m_fd] = false;
444 #endif
445 }
446 }
447
448 // set the wxBase variable to point to our GSocketManager implementation
449 //
450 // see comments in wx/msw/apptbase.h for the explanation of why do we do it
451 // like this
452 static struct ManagerSetter
453 {
454 ManagerSetter()
455 {
456 static GSocketMSWManager s_manager;
457 wxAppTraits::SetDefaultSocketManager(&s_manager);
458 }
459 } gs_managerSetter;
460
461 #endif // wxUSE_SOCKETS