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