]> git.saurik.com Git - wxWidgets.git/blame - src/msw/gsockmsw.c
OS/2 VisualAge doesn't know about lower case true and false and redefine a for loop...
[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
GRG
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>
8a9c2246 54
70988afb
GRG
55#include <winsock.h>
56
8a9c2246
VZ
57#ifdef _MSC_VER
58# pragma warning(default:4115) /* named type definition in parentheses */
59#endif
60
70988afb
GRG
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
77extern HINSTANCE INSTANCE;
78static HWND hWin;
79static CRITICAL_SECTION critical;
80static GSocket* socketList[MAXSOCKETS];
81static int firstAvailable;
82
83/* Global initializers */
84
5c9eff30 85int GSocket_Init(void)
70988afb
GRG
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
ed2eb9af 124void GSocket_Cleanup(void)
70988afb
GRG
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
139bool _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
166void _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
176LRESULT 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 */
250void _GSocket_Enable_Events(GSocket *socket)
251{
252 assert (socket != NULL);
253
254 if (socket->m_fd != INVALID_SOCKET)
255 {
ed2eb9af
GRG
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);
70988afb
GRG
263 }
264}
265
266/* _GSocket_Disable_Events:
267 * Disable event notifications (when shutdowning the socket)
268 */
269void _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 */
285typedef (*wxDummy)();
286
287#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */