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
9 * -------------------------------------------------------------------------
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
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.
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
36 # pragma warning(disable:4115) /* named type definition in parentheses */
39 #include "wx/gsocket.h"
40 #include "wx/apptrait.h"
42 extern "C" WXDLLIMPEXP_BASE HINSTANCE
wxGetInstance();
43 #define INSTANCE wxGetInstance()
47 #include "wx/msw/wince/net.h"
48 #include "wx/hashmap.h"
49 WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash
,wxIntegerEqual
,SocketHash
);
61 # pragma warning(default:4115) /* named type definition in parentheses */
64 #define CLASSNAME TEXT("_GSocket_Internal_Window_Class")
66 /* implemented in utils.cpp */
67 extern "C" WXDLLIMPEXP_BASE HWND
68 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
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)
74 #define MAXSOCKETS 1024
76 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
77 #error "MAXSOCKETS is too big!"
81 typedef int (PASCAL
*WSAAsyncSelectFunc
)(SOCKET
,HWND
,u_int
,long);
83 /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
85 typedef struct _WSANETWORKEVENTS
{
88 } WSANETWORKEVENTS
, FAR
* LPWSANETWORKEVENTS
;
89 typedef HANDLE (PASCAL
*WSACreateEventFunc
)();
90 typedef int (PASCAL
*WSAEventSelectFunc
)(SOCKET
,HANDLE
,long);
91 typedef int (PASCAL
*WSAWaitForMultipleEventsFunc
)(long,HANDLE
,BOOL
,long,BOOL
);
92 typedef int (PASCAL
*WSAEnumNetworkEventsFunc
)(SOCKET
,HANDLE
,LPWSANETWORKEVENTS
);
95 LRESULT CALLBACK
_GSocket_Internal_WinProc(HWND
, UINT
, WPARAM
, LPARAM
);
97 /* Global variables */
100 static CRITICAL_SECTION critical
;
101 static GSocket
* socketList
[MAXSOCKETS
];
102 static int firstAvailable
;
105 static WSAAsyncSelectFunc gs_WSAAsyncSelect
= NULL
;
107 static SocketHash socketHash
;
108 static unsigned int currSocket
;
109 HANDLE hThread
[MAXSOCKETS
];
110 static WSACreateEventFunc gs_WSACreateEvent
= NULL
;
111 static WSAEventSelectFunc gs_WSAEventSelect
= NULL
;
112 static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents
= NULL
;
113 static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents
= NULL
;
114 /* This structure will be used to pass data on to the thread that handles socket events.
116 typedef struct thread_data
{
118 unsigned long msgnumber
;
120 unsigned long lEvent
;
124 static HMODULE gs_wsock32dll
= 0;
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.
132 DWORD WINAPI
SocketThread(LPVOID data
)
134 WSANETWORKEVENTS NetworkEvents
;
135 thread_data
* d
= (thread_data
*)data
;
137 HANDLE NetworkEvent
= gs_WSACreateEvent();
138 gs_WSAEventSelect(d
->fd
, NetworkEvent
, d
->lEvent
);
140 while(socketHash
[d
->fd
] == true)
142 if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent
, FALSE
,INFINITE
, FALSE
)) == WAIT_FAILED
)
144 printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
147 if (gs_WSAEnumNetworkEvents(d
->fd
,NetworkEvent
, &NetworkEvents
) == SOCKET_ERROR
)
149 printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
153 long flags
= NetworkEvents
.lNetworkEvents
;
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
);
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
);
168 gs_WSAEventSelect(d
->fd
, NetworkEvent
, 0);
174 // ----------------------------------------------------------------------------
175 // MSW implementation of GSocketManager
176 // ----------------------------------------------------------------------------
178 class GSocketMSWManager
: public GSocketManager
181 virtual bool OnInit();
182 virtual void OnExit();
184 virtual bool Init_Socket(GSocket
*socket
);
185 virtual void Destroy_Socket(GSocket
*socket
);
187 virtual void Install_Callback(GSocket
*socket
, GSocketEvent event
);
188 virtual void Uninstall_Callback(GSocket
*socket
, GSocketEvent event
);
190 virtual void Enable_Events(GSocket
*socket
);
191 virtual void Disable_Events(GSocket
*socket
);
194 /* Global initializers */
196 bool GSocketMSWManager::OnInit()
198 static LPCTSTR pclassname
= NULL
;
201 /* Create internal window for event notifications */
202 hWin
= wxCreateHiddenWindow(&pclassname
, CLASSNAME
, _GSocket_Internal_WinProc
);
206 /* Initialize socket list */
207 InitializeCriticalSection(&critical
);
209 for (i
= 0; i
< MAXSOCKETS
; i
++)
211 socketList
[i
] = NULL
;
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
219 gs_wsock32dll
= LoadLibrary(wxT("wsock32.dll"));
222 gs_WSAAsyncSelect
=(WSAAsyncSelectFunc
)GetProcAddress(gs_wsock32dll
,
224 if (!gs_WSAAsyncSelect
)
227 /* On WinCE we load ws2.dll which will provide the needed functions.
229 gs_wsock32dll
= LoadLibrary(wxT("ws2.dll"));
232 gs_WSAEventSelect
=(WSAEventSelectFunc
)GetProcAddress(gs_wsock32dll
,
233 wxT("WSAEventSelect"));
234 if (!gs_WSAEventSelect
)
237 gs_WSACreateEvent
=(WSACreateEventFunc
)GetProcAddress(gs_wsock32dll
,
238 wxT("WSACreateEvent"));
239 if (!gs_WSACreateEvent
)
242 gs_WSAWaitForMultipleEvents
=(WSAWaitForMultipleEventsFunc
)GetProcAddress(gs_wsock32dll
,
243 wxT("WSAWaitForMultipleEvents"));
244 if (!gs_WSAWaitForMultipleEvents
)
247 gs_WSAEnumNetworkEvents
=(WSAEnumNetworkEventsFunc
)GetProcAddress(gs_wsock32dll
,
248 wxT("WSAEnumNetworkEvents"));
249 if (!gs_WSAEnumNetworkEvents
)
258 void GSocketMSWManager::OnExit()
261 /* Delete the threads here */
262 for(unsigned int i
=0; i
< currSocket
; i
++)
263 CloseHandle(hThread
[i
]);
265 /* Destroy internal window */
267 UnregisterClass(CLASSNAME
, INSTANCE
);
269 /* Unlock wsock32.dll */
272 FreeLibrary(gs_wsock32dll
);
276 /* Delete critical section */
277 DeleteCriticalSection(&critical
);
280 /* Per-socket GUI initialization / cleanup */
282 bool GSocketMSWManager::Init_Socket(GSocket
*socket
)
286 /* Allocate a new message number for this socket */
287 EnterCriticalSection(&critical
);
290 while (socketList
[i
] != NULL
)
292 i
= (i
+ 1) % MAXSOCKETS
;
294 if (i
== firstAvailable
) /* abort! */
296 LeaveCriticalSection(&critical
);
300 socketList
[i
] = socket
;
301 firstAvailable
= (i
+ 1) % MAXSOCKETS
;
302 socket
->m_msgnumber
= (i
+ WM_USER
);
304 LeaveCriticalSection(&critical
);
309 void GSocketMSWManager::Destroy_Socket(GSocket
*socket
)
311 /* Remove the socket from the list */
312 EnterCriticalSection(&critical
);
313 if ( socket
->IsOk() )
314 socketList
[(socket
->m_msgnumber
- WM_USER
)] = NULL
;
315 LeaveCriticalSection(&critical
);
318 void GSocketMSWManager::Install_Callback(GSocket
* WXUNUSED(socket
),
319 GSocketEvent
WXUNUSED(event
))
321 wxFAIL_MSG( _T("not used under MSW") );
324 void GSocketMSWManager::Uninstall_Callback(GSocket
* WXUNUSED(socket
),
325 GSocketEvent
WXUNUSED(event
))
327 wxFAIL_MSG( _T("not used under MSW") );
330 /* Windows proc for asynchronous event handling */
332 LRESULT CALLBACK
_GSocket_Internal_WinProc(HWND hWnd
,
339 GSocketCallback cback
;
342 if (uMsg
>= WM_USER
&& uMsg
<= (WM_USER
+ MAXSOCKETS
- 1))
344 EnterCriticalSection(&critical
);
345 socket
= socketList
[(uMsg
- WM_USER
)];
346 event
= (GSocketEvent
) -1;
350 /* Check that the socket still exists (it has not been
351 * destroyed) and for safety, check that the m_fd field
352 * is what we expect it to be.
354 if ((socket
!= NULL
) && (socket
->m_fd
== wParam
))
356 switch WSAGETSELECTEVENT(lParam
)
358 case FD_READ
: event
= GSOCK_INPUT
; break;
359 case FD_WRITE
: event
= GSOCK_OUTPUT
; break;
360 case FD_ACCEPT
: event
= GSOCK_CONNECTION
; break;
363 if (WSAGETSELECTERROR(lParam
) != 0)
366 event
= GSOCK_CONNECTION
;
369 case FD_CLOSE
: event
= GSOCK_LOST
; break;
374 cback
= socket
->m_cbacks
[event
];
375 data
= socket
->m_data
[event
];
377 if (event
== GSOCK_LOST
)
378 socket
->m_detected
= GSOCK_LOST_FLAG
;
380 socket
->m_detected
|= (1 << event
);
384 /* OK, we can now leave the critical section because we have
385 * already obtained the callback address (we make no further
386 * accesses to socket->whatever). However, the app should
387 * be prepared to handle events from a socket that has just
390 LeaveCriticalSection(&critical
);
393 (cback
)(socket
, event
, data
);
398 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
401 /* _GSocket_Enable_Events:
402 * Enable all event notifications; we need to be notified of all
403 * events for internal processing, but we will only notify users
404 * when an appropiate callback function has been installed.
406 void GSocketMSWManager::Enable_Events(GSocket
*socket
)
408 if (socket
->m_fd
!= INVALID_SOCKET
)
410 /* We could probably just subscribe to all events regardless
411 * of the socket type, but MS recommends to do it this way.
413 long lEvent
= socket
->m_server
?
414 FD_ACCEPT
: (FD_READ
| FD_WRITE
| FD_CONNECT
| FD_CLOSE
);
416 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
);
419 * WinCE creates a thread for socket event handling.
420 * All needed parameters get passed through the thread_data structure.
423 thread_data
* d
= new thread_data
;
426 d
->msgnumber
= socket
->m_msgnumber
;
427 d
->fd
= socket
->m_fd
;
428 socketHash
[socket
->m_fd
] = true;
429 hThread
[currSocket
++] = CreateThread(NULL
, 0, &SocketThread
,(LPVOID
)d
, 0, NULL
);
434 /* _GSocket_Disable_Events:
435 * Disable event notifications (when shutdowning the socket)
437 void GSocketMSWManager::Disable_Events(GSocket
*socket
)
439 if (socket
->m_fd
!= INVALID_SOCKET
)
442 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0);
445 socketHash
[socket
->m_fd
] = false;
450 // set the wxBase variable to point to our GSocketManager implementation
452 // see comments in wx/msw/apptbase.h for the explanation of why do we do it
454 static struct ManagerSetter
458 static GSocketMSWManager s_manager
;
459 wxAppTraits::SetDefaultSocketManager(&s_manager
);
463 #endif // wxUSE_SOCKETS