]> git.saurik.com Git - wxWidgets.git/blob - src/msw/gsockmsw.c
better learn the operators...
[wxWidgets.git] / src / msw / gsockmsw.c
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
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
22 #ifndef __GSOCKET_STANDALONE__
23 #include "wx/defs.h"
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
42 * be available and it must contain the app's instance
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>
55
56 #include <winsock.h>
57
58 #ifdef _MSC_VER
59 # pragma warning(default:4115) /* named type definition in parentheses */
60 #endif
61
62 #define CLASSNAME "_GSocket_Internal_Window_Class"
63 #define WINDOWNAME "_GSocket_Internal_Window_Name"
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
78 extern HINSTANCE INSTANCE;
79 static HWND hWin;
80 static CRITICAL_SECTION critical;
81 static GSocket* socketList[MAXSOCKETS];
82 static int firstAvailable;
83
84 /* Global initializers */
85
86 int GSocket_Init(void)
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
125 void GSocket_Cleanup(void)
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
140 int _GSocket_GUI_Init(GSocket *socket)
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
167 void _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
177 LRESULT 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 */
251 void _GSocket_Enable_Events(GSocket *socket)
252 {
253 assert (socket != NULL);
254
255 if (socket->m_fd != INVALID_SOCKET)
256 {
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);
264 }
265 }
266
267 /* _GSocket_Disable_Events:
268 * Disable event notifications (when shutdowning the socket)
269 */
270 void _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
282 /*
283 * Translation unit shouldn't be empty, so include this typedef to make the
284 * compiler (VC++ 6.0, for example) happy
285 */
286 typedef (*wxDummy)();
287
288 #endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */