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