]> git.saurik.com Git - wxWidgets.git/blame - src/msw/gsockmsw.cpp
handle correctly never/always shown scrollbars in GetClientSize()
[wxWidgets.git] / src / msw / gsockmsw.cpp
CommitLineData
51fe4b60
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/gsockmsw.cpp
3// Purpose: MSW-specific socket support
4// Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia
5// Created: April 1997
6// Copyright: (C) 1999-1997, Guilhem Lavaux
7// (C) 1999-2000, Guillermo Rodriguez Garcia
8// (C) 2008 Vadim Zeitlin
9// RCS_ID: $Id$
10// License: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
b7ceceb1 13
86afa786
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
2804f77d
VZ
21#if wxUSE_SOCKETS
22
b7ceceb1 23/*
dbfb61b3 24 * DONE: for WinCE we need to replace WSAAsyncSelect
b7ceceb1
DE
25 * (Windows message-based notification of network events for a socket)
26 * with another mechanism.
dbfb61b3
JS
27 * As WSAAsyncSelect is not present on WinCE, it now uses
28 * WSACreateEvent, WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents.
29 * When enabling eventhandling for a socket a new thread it created that keeps track of the events
30 * and posts a messageto the hidden window to use the standard message loop.
b7ceceb1
DE
31 */
32
b7ceceb1
DE
33/* including rasasync.h (included from windows.h itself included from
34 * wx/setup.h and/or winsock.h results in this warning for
35 * RPCNOTIFICATION_ROUTINE
36 */
37#ifdef _MSC_VER
1c8681b4 38# pragma warning(disable:4115) /* named type definition in parentheses */
b7ceceb1
DE
39#endif
40
60913641 41#include "wx/private/socket.h"
2804f77d 42#include "wx/apptrait.h"
a3cf8dca
VZ
43#include "wx/link.h"
44
45wxFORCE_LINK_THIS_MODULE(gsockmsw)
b7ceceb1 46
2804f77d 47extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance();
b7ceceb1
DE
48#define INSTANCE wxGetInstance()
49
2804f77d 50#ifdef __WXWINCE__
b7ceceb1
DE
51#include <winsock.h>
52#include "wx/msw/wince/net.h"
7ec69821 53#include "wx/hashmap.h"
84aa68c4 54WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash,wxIntegerEqual,SocketHash);
b7ceceb1
DE
55#endif
56
57#include <string.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <stddef.h>
61#include <ctype.h>
62
63#include <winsock.h>
64
65#ifdef _MSC_VER
66# pragma warning(default:4115) /* named type definition in parentheses */
67#endif
68
51fe4b60 69#define CLASSNAME TEXT("_wxSocket_Internal_Window_Class")
b7ceceb1
DE
70
71/* implemented in utils.cpp */
32524c8f 72extern "C" WXDLLIMPEXP_BASE HWND
b7ceceb1
DE
73wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
74
51fe4b60 75/* Maximum number of different wxSocket objects at a given time.
b7ceceb1
DE
76 * This value can be modified at will, but it CANNOT be greater
77 * than (0x7FFF - WM_USER + 1)
78 */
79#define MAXSOCKETS 1024
80
81#if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
82#error "MAXSOCKETS is too big!"
83#endif
84
dbfb61b3 85#ifndef __WXWINCE__
1c8681b4 86typedef int (PASCAL *WSAAsyncSelectFunc)(SOCKET,HWND,u_int,long);
dbfb61b3
JS
87#else
88/* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
89*/
90typedef struct _WSANETWORKEVENTS {
91 long lNetworkEvents;
92 int iErrorCode[10];
93} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
2804f77d 94typedef HANDLE (PASCAL *WSACreateEventFunc)();
dbfb61b3
JS
95typedef int (PASCAL *WSAEventSelectFunc)(SOCKET,HANDLE,long);
96typedef int (PASCAL *WSAWaitForMultipleEventsFunc)(long,HANDLE,BOOL,long,BOOL);
97typedef int (PASCAL *WSAEnumNetworkEventsFunc)(SOCKET,HANDLE,LPWSANETWORKEVENTS);
98#endif //__WXWINCE__
b7ceceb1 99
51fe4b60 100LRESULT CALLBACK wxSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM);
c90cc42e 101
b7ceceb1
DE
102/* Global variables */
103
b7ceceb1
DE
104static HWND hWin;
105static CRITICAL_SECTION critical;
51fe4b60 106static wxSocketImplMSW *socketList[MAXSOCKETS];
b7ceceb1 107static int firstAvailable;
dbfb61b3
JS
108
109#ifndef __WXWINCE__
1c8681b4 110static WSAAsyncSelectFunc gs_WSAAsyncSelect = NULL;
dbfb61b3 111#else
84aa68c4 112static SocketHash socketHash;
dbfb61b3
JS
113static unsigned int currSocket;
114HANDLE hThread[MAXSOCKETS];
115static WSACreateEventFunc gs_WSACreateEvent = NULL;
116static WSAEventSelectFunc gs_WSAEventSelect = NULL;
117static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents = NULL;
118static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents = NULL;
119/* This structure will be used to pass data on to the thread that handles socket events.
120*/
121typedef struct thread_data{
7ec69821
WS
122 HWND hEvtWin;
123 unsigned long msgnumber;
124 unsigned long fd;
125 unsigned long lEvent;
dbfb61b3
JS
126}thread_data;
127#endif
128
1c8681b4 129static HMODULE gs_wsock32dll = 0;
b7ceceb1 130
dbfb61b3
JS
131
132#ifdef __WXWINCE__
133/* This thread handles socket events on WinCE using WSAEventSelect() as WSAAsyncSelect is not supported.
134* When an event occures for the socket, it is checked what kind of event happend and the correct message gets posted
135* so that the hidden window can handle it as it would in other MSW builds.
136*/
137DWORD WINAPI SocketThread(LPVOID data)
138{
7ec69821
WS
139 WSANETWORKEVENTS NetworkEvents;
140 thread_data* d = (thread_data *)data;
141
142 HANDLE NetworkEvent = gs_WSACreateEvent();
143 gs_WSAEventSelect(d->fd, NetworkEvent, d->lEvent);
144
145 while(socketHash[d->fd] == true)
146 {
147 if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent, FALSE,INFINITE, FALSE)) == WAIT_FAILED)
148 {
149 printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
150 return 0;
151 }
152 if (gs_WSAEnumNetworkEvents(d->fd ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR)
153 {
154 printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
155 return 0;
156 }
157
158 long flags = NetworkEvents.lNetworkEvents;
159 if (flags & FD_READ)
160 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_READ);
161 if (flags & FD_WRITE)
162 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_WRITE);
163 if (flags & FD_OOB)
164 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_OOB);
165 if (flags & FD_ACCEPT)
166 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_ACCEPT);
167 if (flags & FD_CONNECT)
168 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CONNECT);
169 if (flags & FD_CLOSE)
170 ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CLOSE);
171
172 }
173 gs_WSAEventSelect(d->fd, NetworkEvent, 0);
174 ExitThread(0);
175 return 0;
dbfb61b3
JS
176}
177#endif
178
2804f77d 179// ----------------------------------------------------------------------------
51fe4b60 180// MSW implementation of wxSocketManager
2804f77d 181// ----------------------------------------------------------------------------
dbfb61b3 182
51fe4b60 183class wxSocketMSWManager : public wxSocketManager
1c6dd11c 184{
2804f77d
VZ
185public:
186 virtual bool OnInit();
187 virtual void OnExit();
188
51fe4b60
VZ
189 virtual wxSocketImpl *CreateSocket(wxSocketBase& wxsocket)
190 {
191 return new wxSocketImplMSW(wxsocket);
192 }
193 virtual void Install_Callback(wxSocketImpl *socket, wxSocketNotify event);
194 virtual void Uninstall_Callback(wxSocketImpl *socket, wxSocketNotify event);
2804f77d 195};
c90cc42e 196
b7ceceb1
DE
197/* Global initializers */
198
51fe4b60 199bool wxSocketMSWManager::OnInit()
b7ceceb1 200{
84aa68c4
JS
201 static LPCTSTR pclassname = NULL;
202 int i;
b7ceceb1 203
84aa68c4 204 /* Create internal window for event notifications */
51fe4b60 205 hWin = wxCreateHiddenWindow(&pclassname, CLASSNAME, wxSocket_Internal_WinProc);
84aa68c4
JS
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
51fe4b60
VZ
258 // finally initialize WinSock
259 WSADATA wsaData;
260 return WSAStartup((1 << 8) | 1, &wsaData) == 0;
b7ceceb1
DE
261}
262
51fe4b60 263void wxSocketMSWManager::OnExit()
b7ceceb1 264{
dbfb61b3 265#ifdef __WXWINCE__
1c6dd11c 266/* Delete the threads here */
7ec69821
WS
267 for(unsigned int i=0; i < currSocket; i++)
268 CloseHandle(hThread[i]);
dbfb61b3 269#endif
b7ceceb1
DE
270 /* Destroy internal window */
271 DestroyWindow(hWin);
272 UnregisterClass(CLASSNAME, INSTANCE);
273
1c8681b4
DE
274 /* Unlock wsock32.dll */
275 if (gs_wsock32dll)
276 {
277 FreeLibrary(gs_wsock32dll);
278 gs_wsock32dll = 0;
279 }
280
b7ceceb1
DE
281 /* Delete critical section */
282 DeleteCriticalSection(&critical);
51fe4b60
VZ
283
284 WSACleanup();
b7ceceb1
DE
285}
286
287/* Per-socket GUI initialization / cleanup */
288
51fe4b60
VZ
289wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket)
290 : wxSocketImpl(wxsocket)
b7ceceb1 291{
b7ceceb1
DE
292 /* Allocate a new message number for this socket */
293 EnterCriticalSection(&critical);
294
51fe4b60 295 int i = firstAvailable;
b7ceceb1
DE
296 while (socketList[i] != NULL)
297 {
298 i = (i + 1) % MAXSOCKETS;
299
300 if (i == firstAvailable) /* abort! */
301 {
302 LeaveCriticalSection(&critical);
51fe4b60
VZ
303 m_msgnumber = 0; // invalid
304 return;
b7ceceb1
DE
305 }
306 }
51fe4b60 307 socketList[i] = this;
b7ceceb1 308 firstAvailable = (i + 1) % MAXSOCKETS;
51fe4b60 309 m_msgnumber = (i + WM_USER);
b7ceceb1
DE
310
311 LeaveCriticalSection(&critical);
f0fbbe23
VZ
312}
313
51fe4b60 314wxSocketImplMSW::~wxSocketImplMSW()
b7ceceb1
DE
315{
316 /* Remove the socket from the list */
317 EnterCriticalSection(&critical);
cab9b205 318
51fe4b60 319 if ( m_msgnumber )
eb97543d 320 {
cab9b205
VZ
321 // we need to remove any pending messages for this socket to avoid having
322 // them sent to a new socket which could reuse the same message number as
323 // soon as we destroy this one
324 MSG msg;
51fe4b60 325 while ( ::PeekMessage(&msg, hWin, m_msgnumber, m_msgnumber, PM_REMOVE) )
cab9b205
VZ
326 ;
327
51fe4b60 328 socketList[m_msgnumber - WM_USER] = NULL;
cab9b205 329 }
eb97543d 330 //else: the socket has never been created successfully
cab9b205 331
b7ceceb1
DE
332 LeaveCriticalSection(&critical);
333}
334
335/* Windows proc for asynchronous event handling */
336
51fe4b60 337LRESULT CALLBACK wxSocket_Internal_WinProc(HWND hWnd,
b7ceceb1
DE
338 UINT uMsg,
339 WPARAM wParam,
340 LPARAM lParam)
341{
51fe4b60
VZ
342 wxSocketImplMSW *socket;
343 wxSocketNotify event;
b7ceceb1
DE
344
345 if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1))
346 {
347 EnterCriticalSection(&critical);
348 socket = socketList[(uMsg - WM_USER)];
51fe4b60 349 event = (wxSocketNotify) -1;
b7ceceb1
DE
350
351 /* Check that the socket still exists (it has not been
352 * destroyed) and for safety, check that the m_fd field
353 * is what we expect it to be.
354 */
ff55f837 355 if ((socket != NULL) && ((WPARAM)socket->m_fd == wParam))
b7ceceb1
DE
356 {
357 switch WSAGETSELECTEVENT(lParam)
358 {
51fe4b60
VZ
359 case FD_READ: event = wxSOCKET_INPUT; break;
360 case FD_WRITE: event = wxSOCKET_OUTPUT; break;
361 case FD_ACCEPT: event = wxSOCKET_CONNECTION; break;
b7ceceb1
DE
362 case FD_CONNECT:
363 {
364 if (WSAGETSELECTERROR(lParam) != 0)
51fe4b60 365 event = wxSOCKET_LOST;
b7ceceb1 366 else
51fe4b60 367 event = wxSOCKET_CONNECTION;
b7ceceb1
DE
368 break;
369 }
51fe4b60 370 case FD_CLOSE: event = wxSOCKET_LOST; break;
b7ceceb1
DE
371 }
372
373 if (event != -1)
374 {
51fe4b60
VZ
375 if (event == wxSOCKET_LOST)
376 socket->m_detected = wxSOCKET_LOST_FLAG;
b7ceceb1
DE
377 else
378 socket->m_detected |= (1 << event);
379 }
380 }
381
b7ceceb1
DE
382 LeaveCriticalSection(&critical);
383
83a7ab5c
VZ
384 if ( socket )
385 socket->NotifyOnStateChange(event);
b7ceceb1
DE
386
387 return (LRESULT) 0;
388 }
389 else
390 return DefWindowProc(hWnd, uMsg, wParam, lParam);
391}
392
f0fbbe23 393/*
b7ceceb1
DE
394 * Enable all event notifications; we need to be notified of all
395 * events for internal processing, but we will only notify users
f0fbbe23 396 * when an appropriate callback function has been installed.
b7ceceb1 397 */
51fe4b60
VZ
398void wxSocketMSWManager::Install_Callback(wxSocketImpl *socket_,
399 wxSocketNotify WXUNUSED(event))
b7ceceb1 400{
51fe4b60
VZ
401 wxSocketImplMSW * const socket = static_cast<wxSocketImplMSW *>(socket_);
402
b7ceceb1
DE
403 if (socket->m_fd != INVALID_SOCKET)
404 {
405 /* We could probably just subscribe to all events regardless
406 * of the socket type, but MS recommends to do it this way.
407 */
408 long lEvent = socket->m_server?
409 FD_ACCEPT : (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
dbfb61b3 410#ifndef __WXWINCE__
1c8681b4 411 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, lEvent);
dbfb61b3
JS
412#else
413/*
414* WinCE creates a thread for socket event handling.
1c6dd11c 415* All needed parameters get passed through the thread_data structure.
dbfb61b3 416*/
84aa68c4 417
7ec69821
WS
418 thread_data* d = new thread_data;
419 d->lEvent = lEvent;
420 d->hEvtWin = hWin;
421 d->msgnumber = socket->m_msgnumber;
422 d->fd = socket->m_fd;
423 socketHash[socket->m_fd] = true;
424 hThread[currSocket++] = CreateThread(NULL, 0, &SocketThread,(LPVOID)d, 0, NULL);
dbfb61b3 425#endif
b7ceceb1
DE
426 }
427}
428
f0fbbe23
VZ
429/*
430 * Disable event notifications (used when shutting down the socket)
b7ceceb1 431 */
51fe4b60
VZ
432void wxSocketMSWManager::Uninstall_Callback(wxSocketImpl *socket_,
433 wxSocketNotify WXUNUSED(event))
b7ceceb1 434{
51fe4b60
VZ
435 wxSocketImplMSW * const socket = static_cast<wxSocketImplMSW *>(socket_);
436
b7ceceb1
DE
437 if (socket->m_fd != INVALID_SOCKET)
438 {
dbfb61b3 439#ifndef __WXWINCE__
1c8681b4 440 gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
dbfb61b3 441#else
7ec69821
WS
442 //Destroy the thread
443 socketHash[socket->m_fd] = false;
dbfb61b3 444#endif
b7ceceb1
DE
445 }
446}
447
51fe4b60 448// set the wxBase variable to point to our wxSocketManager implementation
2804f77d 449//
51fe4b60 450// see comments in wx/apptrait.h for the explanation of why do we do it
2804f77d
VZ
451// like this
452static struct ManagerSetter
453{
454 ManagerSetter()
455 {
51fe4b60 456 static wxSocketMSWManager s_manager;
2804f77d
VZ
457 wxAppTraits::SetDefaultSocketManager(&s_manager);
458 }
a3cf8dca 459} gs_managerSetter;
b7ceceb1 460
2804f77d 461#endif // wxUSE_SOCKETS