]> git.saurik.com Git - wxWidgets.git/blame - src/msw/gsockmsw.c
unapplied part of Dimitri's patch at his request
[wxWidgets.git] / src / msw / gsockmsw.c
CommitLineData
70988afb
GRG
1/* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket)
3 * Name: gsockmsw.c
4 * Author: Guillermo Rodriguez Garcia <guille@iies.es>
5 * Purpose: GSocket GUI-specific MSW code
6 * CVSID: $Id$
7 * -------------------------------------------------------------------------
8 */
9
10/*
11 * PLEASE don't put C++ comments here - this is a C source file.
12 */
13
8a9c2246
VZ
14/* including rasasync.h (included from windows.h itself included from
15 * wx/setup.h and/or winsock.h results in this warning for
16 * RPCNOTIFICATION_ROUTINE
17 */
18#ifdef _MSC_VER
19# pragma warning(disable:4115) /* named type definition in parentheses */
20#endif
21
70988afb 22#ifndef __GSOCKET_STANDALONE__
33ac7e6f 23#include "wx/defs.h"
70988afb
GRG
24#include "wx/setup.h"
25#endif
26
27#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__)
28
29#ifndef __GSOCKET_STANDALONE__
30
31#include "wx/msw/gsockmsw.h"
32#include "wx/gsocket.h"
33
34#define INSTANCE wxGetInstance()
35
36#else
37
38#include "gsockmsw.h"
39#include "gsocket.h"
40
41/* If not using wxWindows, a global var called hInst must
f4929e86 42 * be available and it must contain the app's instance
70988afb
GRG
43 * handle.
44 */
45#define INSTANCE hInst
46
47#endif /* __GSOCKET_STANDALONE__ */
48
49#include <assert.h>
50#include <string.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <stddef.h>
54#include <ctype.h>
8a9c2246 55
70988afb
GRG
56#include <winsock.h>
57
8a9c2246
VZ
58#ifdef _MSC_VER
59# pragma warning(default:4115) /* named type definition in parentheses */
60#endif
61
9aee09a3
VZ
62#define CLASSNAME TEXT("_GSocket_Internal_Window_Class")
63#define WINDOWNAME TEXT("_GSocket_Internal_Window_Name")
70988afb
GRG
64
65/* Maximum number of different GSocket objects at a given time.
66 * This value can be modified at will, but it CANNOT be greater
67 * than (0x7FFF - WM_USER + 1)
68 */
69#define MAXSOCKETS 1024
70
71#if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
72#error "MAXSOCKETS is too big!"
73#endif
74
75
76/* Global variables */
77
78extern HINSTANCE INSTANCE;
79static HWND hWin;
80static CRITICAL_SECTION critical;
81static GSocket* socketList[MAXSOCKETS];
82static int firstAvailable;
83
84/* Global initializers */
85
5c9eff30 86int GSocket_Init(void)
70988afb
GRG
87{
88 WSADATA wsaData;
89 WNDCLASS winClass;
90 int i;
91
92 /* Create internal window for event notifications */
93 winClass.style = 0;
94 winClass.lpfnWndProc = _GSocket_Internal_WinProc;
95 winClass.cbClsExtra = 0;
96 winClass.cbWndExtra = 0;
97 winClass.hInstance = INSTANCE;
98 winClass.hIcon = (HICON) NULL;
99 winClass.hCursor = (HCURSOR) NULL;
100 winClass.hbrBackground = (HBRUSH) NULL;
101 winClass.lpszMenuName = (LPCTSTR) NULL;
102 winClass.lpszClassName = CLASSNAME;
103
104 RegisterClass(&winClass);
105 hWin = CreateWindow(CLASSNAME,
106 WINDOWNAME,
107 0, 0, 0, 0, 0,
108 (HWND) NULL, (HMENU) NULL, INSTANCE, (LPVOID) NULL);
109
110 if (!hWin) return FALSE;
111
112 /* Initialize socket list */
113 InitializeCriticalSection(&critical);
114
115 for (i = 0; i < MAXSOCKETS; i++)
116 {
117 socketList[i] = NULL;
118 }
119 firstAvailable = 0;
120
121 /* Initialize WinSocket */
122 return (WSAStartup((1 << 8) | 1, &wsaData) == 0);
123}
124
ed2eb9af 125void GSocket_Cleanup(void)
70988afb
GRG
126{
127 /* Destroy internal window */
128 DestroyWindow(hWin);
129 UnregisterClass(CLASSNAME, INSTANCE);
130
131 /* Delete critical section */
132 DeleteCriticalSection(&critical);
133
134 /* Cleanup WinSocket */
135 WSACleanup();
136}
137
138/* Per-socket GUI initialization / cleanup */
139
27a97d02 140int _GSocket_GUI_Init(GSocket *socket)
70988afb
GRG
141{
142 int i;
143
144 /* Allocate a new message number for this socket */
145 EnterCriticalSection(&critical);
146
147 i = firstAvailable;
148 while (socketList[i] != NULL)
149 {
150 i = (i + 1) % MAXSOCKETS;
151
152 if (i == firstAvailable) /* abort! */
153 {
154 LeaveCriticalSection(&critical);
155 return FALSE;
156 }
157 }
158 socketList[i] = socket;
159 firstAvailable = (i + 1) % MAXSOCKETS;
160 socket->m_msgnumber = (i + WM_USER);
161
162 LeaveCriticalSection(&critical);
163
164 return TRUE;
165}
166
167void _GSocket_GUI_Destroy(GSocket *socket)
168{
169 /* Remove the socket from the list */
170 EnterCriticalSection(&critical);
171 socketList[(socket->m_msgnumber - WM_USER)] = NULL;
172 LeaveCriticalSection(&critical);
173}
174
175/* Windows proc for asynchronous event handling */
176
177LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd,
178 UINT uMsg,
179 WPARAM wParam,
180 LPARAM lParam)
181{
182 GSocket *socket;
183 GSocketEvent event;
184 GSocketCallback cback;
185 char *data;
186
187 if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1))
188 {
189 EnterCriticalSection(&critical);
190 socket = socketList[(uMsg - WM_USER)];
191 event = -1;
192 cback = NULL;
193 data = NULL;
194
195 /* Check that the socket still exists (it has not been
196 * destroyed) and for safety, check that the m_fd field
197 * is what we expect it to be.
198 */
199 if ((socket != NULL) && (socket->m_fd == wParam))
200 {
201 switch WSAGETSELECTEVENT(lParam)
202 {
203 case FD_READ: event = GSOCK_INPUT; break;
204 case FD_WRITE: event = GSOCK_OUTPUT; break;
205 case FD_ACCEPT: event = GSOCK_CONNECTION; break;
206 case FD_CONNECT:
207 {
208 if (WSAGETSELECTERROR(lParam) != 0)
209 event = GSOCK_LOST;
210 else
211 event = GSOCK_CONNECTION;
212 break;
213 }
214 case FD_CLOSE: event = GSOCK_LOST; break;
215 }
216
217 if (event != -1)
218 {
219 cback = socket->m_cbacks[event];
220 data = socket->m_data[event];
221
222 if (event == GSOCK_LOST)
223 socket->m_detected = GSOCK_LOST_FLAG;
224 else
225 socket->m_detected |= (1 << event);
226 }
227 }
228
229 /* OK, we can now leave the critical section because we have
230 * already obtained the callback address (we make no further
231 * accesses to socket->whatever). However, the app should
232 * be prepared to handle events from a socket that has just
233 * been closed!
234 */
235 LeaveCriticalSection(&critical);
236
237 if (cback != NULL)
238 (cback)(socket, event, data);
239
240 return (LRESULT) 0;
241 }
242 else
243 return DefWindowProc(hWnd, uMsg, wParam, lParam);
244}
245
246/* _GSocket_Enable_Events:
247 * Enable all event notifications; we need to be notified of all
248 * events for internal processing, but we will only notify users
249 * when an appropiate callback function has been installed.
250 */
251void _GSocket_Enable_Events(GSocket *socket)
252{
253 assert (socket != NULL);
254
255 if (socket->m_fd != INVALID_SOCKET)
256 {
ed2eb9af
GRG
257 /* We could probably just subscribe to all events regardless
258 * of the socket type, but MS recommends to do it this way.
259 */
260 long lEvent = socket->m_server?
261 FD_ACCEPT : (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
262
263 WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, lEvent);
70988afb
GRG
264 }
265}
266
267/* _GSocket_Disable_Events:
268 * Disable event notifications (when shutdowning the socket)
269 */
270void _GSocket_Disable_Events(GSocket *socket)
271{
272 assert (socket != NULL);
273
274 if (socket->m_fd != INVALID_SOCKET)
275 {
276 WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
277 }
278}
279
280#else /* !wxUSE_SOCKETS */
281
33ac7e6f 282/*
70988afb
GRG
283 * Translation unit shouldn't be empty, so include this typedef to make the
284 * compiler (VC++ 6.0, for example) happy
285 */
3a922bb4 286typedef void (*wxDummy)();
70988afb
GRG
287
288#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */