]> git.saurik.com Git - wxWidgets.git/blame - src/msw/gsockmsw.c
Fixed crash-on-exit bug due to status bar being deleted twice (MDI apps);
[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
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
64extern HINSTANCE INSTANCE;
65static HWND hWin;
66static CRITICAL_SECTION critical;
67static GSocket* socketList[MAXSOCKETS];
68static int firstAvailable;
69
70/* Global initializers */
71
72bool GSocket_Init()
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
111void GSocket_Cleanup()
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
126bool _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
153void _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
163LRESULT 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 */
237void _GSocket_Enable_Events(GSocket *socket)
238{
239 assert (socket != NULL);
240
241 if (socket->m_fd != INVALID_SOCKET)
242 {
243 WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber,
244 FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
245 }
246}
247
248/* _GSocket_Disable_Events:
249 * Disable event notifications (when shutdowning the socket)
250 */
251void _GSocket_Disable_Events(GSocket *socket)
252{
253 assert (socket != NULL);
254
255 if (socket->m_fd != INVALID_SOCKET)
256 {
257 WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
258 }
259}
260
261#else /* !wxUSE_SOCKETS */
262
263/*
264 * Translation unit shouldn't be empty, so include this typedef to make the
265 * compiler (VC++ 6.0, for example) happy
266 */
267typedef (*wxDummy)();
268
269#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */