1 /* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket)
4 * Author: Guillermo Rodriguez Garcia <guille@iies.es>
5 * Purpose: GSocket GUI-specific MSW code
7 * -------------------------------------------------------------------------
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
26 * TODO: for WinCE we need to replace WSAAsyncSelect
27 * (Windows message-based notification of network events for a socket)
28 * with another mechanism.
29 * We may need to have a separate thread that polls for socket events
30 * using select() and sends a message to the main thread.
34 * PLEASE don't put C++ comments here - this is a C source file.
37 /* including rasasync.h (included from windows.h itself included from
38 * wx/setup.h and/or winsock.h results in this warning for
39 * RPCNOTIFICATION_ROUTINE
42 # pragma warning(disable:4115) /* named type definition in parentheses */
45 /* This needs to be before the wx/defs/h inclusion
50 /* windows.h results in tons of warnings at max warning level */
52 # pragma warning(push, 1)
57 # pragma warning(disable:4514)
61 #ifndef __GSOCKET_STANDALONE__
62 # include "wx/platform.h"
63 # include "wx/setup.h"
66 #if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__)
68 #ifndef __GSOCKET_STANDALONE__
70 #include "wx/msw/gsockmsw.h"
71 #include "wx/gsocket.h"
73 extern "C" HINSTANCE
wxGetInstance(void);
74 #define INSTANCE wxGetInstance()
81 /* If not using wxWidgets, a global var called hInst must
82 * be available and it must contain the app's instance
85 #define INSTANCE hInst
87 #endif /* __GSOCKET_STANDALONE__ */
94 #include "wx/msw/wince/net.h"
106 # pragma warning(default:4115) /* named type definition in parentheses */
109 #define CLASSNAME TEXT("_GSocket_Internal_Window_Class")
111 /* implemented in utils.cpp */
112 extern "C" WXDLLIMPEXP_BASE HWND
113 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
115 /* Maximum number of different GSocket objects at a given time.
116 * This value can be modified at will, but it CANNOT be greater
117 * than (0x7FFF - WM_USER + 1)
119 #define MAXSOCKETS 1024
121 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
122 #error "MAXSOCKETS is too big!"
125 typedef int (PASCAL
*WSAAsyncSelectFunc
)(SOCKET
,HWND
,u_int
,long);
127 LRESULT CALLBACK
_GSocket_Internal_WinProc(HWND
, UINT
, WPARAM
, LPARAM
);
129 /* Global variables */
131 extern HINSTANCE INSTANCE
;
133 static CRITICAL_SECTION critical
;
134 static GSocket
* socketList
[MAXSOCKETS
];
135 static int firstAvailable
;
136 static WSAAsyncSelectFunc gs_WSAAsyncSelect
= NULL
;
137 static HMODULE gs_wsock32dll
= 0;
139 bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop()
142 /* Global initializers */
144 bool GSocketGUIFunctionsTableConcrete::OnInit()
146 static LPCTSTR pclassname
= NULL
;
149 /* Create internal window for event notifications */
150 hWin
= wxCreateHiddenWindow(&pclassname
, CLASSNAME
, _GSocket_Internal_WinProc
);
154 /* Initialize socket list */
155 InitializeCriticalSection(&critical
);
157 for (i
= 0; i
< MAXSOCKETS
; i
++)
159 socketList
[i
] = NULL
;
163 /* Load WSAAsyncSelect from wsock32.dll (we don't link against it
164 statically to avoid dependency on wsock32.dll for apps that don't use
166 gs_wsock32dll
= LoadLibraryA("wsock32.dll");
169 gs_WSAAsyncSelect
=(WSAAsyncSelectFunc
)GetProcAddress(gs_wsock32dll
,
171 if (!gs_WSAAsyncSelect
)
177 void GSocketGUIFunctionsTableConcrete::OnExit()
179 /* Destroy internal window */
181 UnregisterClass(CLASSNAME
, INSTANCE
);
183 /* Unlock wsock32.dll */
186 FreeLibrary(gs_wsock32dll
);
190 /* Delete critical section */
191 DeleteCriticalSection(&critical
);
194 /* Per-socket GUI initialization / cleanup */
196 bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket
*socket
)
200 /* Allocate a new message number for this socket */
201 EnterCriticalSection(&critical
);
204 while (socketList
[i
] != NULL
)
206 i
= (i
+ 1) % MAXSOCKETS
;
208 if (i
== firstAvailable
) /* abort! */
210 LeaveCriticalSection(&critical
);
214 socketList
[i
] = socket
;
215 firstAvailable
= (i
+ 1) % MAXSOCKETS
;
216 socket
->m_msgnumber
= (i
+ WM_USER
);
218 LeaveCriticalSection(&critical
);
223 void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket
*socket
)
225 /* Remove the socket from the list */
226 EnterCriticalSection(&critical
);
227 socketList
[(socket
->m_msgnumber
- WM_USER
)] = NULL
;
228 LeaveCriticalSection(&critical
);
231 /* Windows proc for asynchronous event handling */
233 LRESULT CALLBACK
_GSocket_Internal_WinProc(HWND hWnd
,
240 GSocketCallback cback
;
243 if (uMsg
>= WM_USER
&& uMsg
<= (WM_USER
+ MAXSOCKETS
- 1))
245 EnterCriticalSection(&critical
);
246 socket
= socketList
[(uMsg
- WM_USER
)];
247 event
= (GSocketEvent
) -1;
251 /* Check that the socket still exists (it has not been
252 * destroyed) and for safety, check that the m_fd field
253 * is what we expect it to be.
255 if ((socket
!= NULL
) && (socket
->m_fd
== wParam
))
257 switch WSAGETSELECTEVENT(lParam
)
259 case FD_READ
: event
= GSOCK_INPUT
; break;
260 case FD_WRITE
: event
= GSOCK_OUTPUT
; break;
261 case FD_ACCEPT
: event
= GSOCK_CONNECTION
; break;
264 if (WSAGETSELECTERROR(lParam
) != 0)
267 event
= GSOCK_CONNECTION
;
270 case FD_CLOSE
: event
= GSOCK_LOST
; break;
275 cback
= socket
->m_cbacks
[event
];
276 data
= socket
->m_data
[event
];
278 if (event
== GSOCK_LOST
)
279 socket
->m_detected
= GSOCK_LOST_FLAG
;
281 socket
->m_detected
|= (1 << event
);
285 /* OK, we can now leave the critical section because we have
286 * already obtained the callback address (we make no further
287 * accesses to socket->whatever). However, the app should
288 * be prepared to handle events from a socket that has just
291 LeaveCriticalSection(&critical
);
294 (cback
)(socket
, event
, data
);
299 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
302 /* _GSocket_Enable_Events:
303 * Enable all event notifications; we need to be notified of all
304 * events for internal processing, but we will only notify users
305 * when an appropiate callback function has been installed.
307 void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket
*socket
)
309 assert (socket
!= NULL
);
311 if (socket
->m_fd
!= INVALID_SOCKET
)
313 /* We could probably just subscribe to all events regardless
314 * of the socket type, but MS recommends to do it this way.
316 long lEvent
= socket
->m_server
?
317 FD_ACCEPT
: (FD_READ
| FD_WRITE
| FD_CONNECT
| FD_CLOSE
);
319 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
);
323 /* _GSocket_Disable_Events:
324 * Disable event notifications (when shutdowning the socket)
326 void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket
*socket
)
328 assert (socket
!= NULL
);
330 if (socket
->m_fd
!= INVALID_SOCKET
)
332 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0);
336 #else /* !wxUSE_SOCKETS */
339 * Translation unit shouldn't be empty, so include this typedef to make the
340 * compiler (VC++ 6.0, for example) happy
342 typedef void (*wxDummy
)();
344 #endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */