1 /* ------------------------------------------------------------------------- 
   2  * Project: GSocket (Generic Socket) 
   4  * Author:  Guillermo Rodriguez Garcia <guille@iies.es> 
   5  * Purpose: GSocket GUI-specific MSW code 
   7  * ------------------------------------------------------------------------- 
  11  * TODO: for WinCE we need to replace WSAAsyncSelect 
  12  * (Windows message-based notification of network events for a socket) 
  13  * with another mechanism. 
  14  * We may need to have a separate thread that polls for socket events 
  15  * using select() and sends a message to the main thread. 
  19  * PLEASE don't put C++ comments here - this is a C source file. 
  22 /* including rasasync.h (included from windows.h itself included from 
  23  * wx/setup.h and/or winsock.h results in this warning for 
  24  * RPCNOTIFICATION_ROUTINE 
  27 #   pragma warning(disable:4115) /* named type definition in parentheses */ 
  30 /* This needs to be before the wx/defs/h inclusion 
  35     /* windows.h results in tons of warnings at max warning level */ 
  37 #       pragma warning(push, 1) 
  39            "unreferenced inline function has been removed": this is not 
  40            suppressed by push above as it is given at the end of the 
  43 #       pragma warning(disable:4514) 
  51 #ifndef __GSOCKET_STANDALONE__ 
  52 #   include "wx/platform.h" 
  53 #   include "wx/setup.h" 
  56 #if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) 
  58 #ifndef __GSOCKET_STANDALONE__ 
  60 #include "wx/msw/gsockmsw.h" 
  61 #include "wx/gsocket.h" 
  63 HINSTANCE 
wxGetInstance(void); 
  64 #define INSTANCE wxGetInstance() 
  71 /* If not using wxWindows, a global var called hInst must 
  72  * be available and it must contain the app's instance 
  75 #define INSTANCE hInst 
  77 #endif /* __GSOCKET_STANDALONE__ */ 
  84 #include "wx/msw/wince/net.h" 
  96 #  pragma warning(default:4115) /* named type definition in parentheses */ 
  99 #define CLASSNAME  TEXT("_GSocket_Internal_Window_Class") 
 101 /* implemented in utils.cpp */ 
 102 extern WXDLLIMPEXP_BASE HWND
 
 103 wxCreateHiddenWindow(LPCTSTR 
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
); 
 105 /* Maximum number of different GSocket objects at a given time. 
 106  * This value can be modified at will, but it CANNOT be greater 
 107  * than (0x7FFF - WM_USER + 1) 
 109 #define MAXSOCKETS 1024 
 111 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1)) 
 112 #error "MAXSOCKETS is too big!" 
 115 typedef int (PASCAL 
*WSAAsyncSelectFunc
)(SOCKET
,HWND
,u_int
,long); 
 117 /* Global variables */ 
 119 extern HINSTANCE INSTANCE
; 
 121 static CRITICAL_SECTION critical
; 
 122 static GSocket
* socketList
[MAXSOCKETS
]; 
 123 static int firstAvailable
; 
 124 static WSAAsyncSelectFunc gs_WSAAsyncSelect 
= NULL
; 
 125 static HMODULE gs_wsock32dll 
= 0; 
 127 /* Global initializers */ 
 129 int _GSocket_GUI_Init(void) 
 131   static LPCTSTR pclassname 
= NULL
; 
 134   /* Create internal window for event notifications */ 
 135   hWin 
= wxCreateHiddenWindow(&pclassname
, CLASSNAME
, _GSocket_Internal_WinProc
); 
 139   /* Initialize socket list */ 
 140   InitializeCriticalSection(&critical
); 
 142   for (i 
= 0; i 
< MAXSOCKETS
; i
++) 
 144     socketList
[i
] = NULL
; 
 148   /* Load WSAAsyncSelect from wsock32.dll (we don't link against it 
 149      statically to avoid dependency on wsock32.dll for apps that don't use 
 151   gs_wsock32dll 
= LoadLibraryA("wsock32.dll"); 
 154   gs_WSAAsyncSelect 
=(WSAAsyncSelectFunc
)GetProcAddress(gs_wsock32dll
, 
 156   if (!gs_WSAAsyncSelect
) 
 162 void _GSocket_GUI_Cleanup(void) 
 164   /* Destroy internal window */ 
 166   UnregisterClass(CLASSNAME
, INSTANCE
); 
 168   /* Unlock wsock32.dll */ 
 171       FreeLibrary(gs_wsock32dll
); 
 175   /* Delete critical section */ 
 176   DeleteCriticalSection(&critical
); 
 179 /* Per-socket GUI initialization / cleanup */ 
 181 int _GSocket_GUI_Init_Socket(GSocket 
*socket
) 
 185   /* Allocate a new message number for this socket */ 
 186   EnterCriticalSection(&critical
); 
 189   while (socketList
[i
] != NULL
) 
 191     i 
= (i 
+ 1) % MAXSOCKETS
; 
 193     if (i 
== firstAvailable
)    /* abort! */ 
 195       LeaveCriticalSection(&critical
); 
 199   socketList
[i
] = socket
; 
 200   firstAvailable 
= (i 
+ 1) % MAXSOCKETS
; 
 201   socket
->m_msgnumber 
= (i 
+ WM_USER
); 
 203   LeaveCriticalSection(&critical
); 
 208 void _GSocket_GUI_Destroy_Socket(GSocket 
*socket
) 
 210   /* Remove the socket from the list */ 
 211   EnterCriticalSection(&critical
); 
 212   socketList
[(socket
->m_msgnumber 
- WM_USER
)] = NULL
; 
 213   LeaveCriticalSection(&critical
); 
 216 /* Windows proc for asynchronous event handling */ 
 218 LRESULT CALLBACK 
_GSocket_Internal_WinProc(HWND hWnd
, 
 225   GSocketCallback cback
; 
 228   if (uMsg 
>= WM_USER 
&& uMsg 
<= (WM_USER 
+ MAXSOCKETS 
- 1)) 
 230     EnterCriticalSection(&critical
); 
 231     socket 
= socketList
[(uMsg 
- WM_USER
)]; 
 232     event 
= (GSocketEvent
) -1; 
 236     /* Check that the socket still exists (it has not been 
 237      * destroyed) and for safety, check that the m_fd field 
 238      * is what we expect it to be. 
 240     if ((socket 
!= NULL
) && (socket
->m_fd 
== wParam
)) 
 242       switch WSAGETSELECTEVENT(lParam
) 
 244         case FD_READ
:    event 
= GSOCK_INPUT
; break; 
 245         case FD_WRITE
:   event 
= GSOCK_OUTPUT
; break; 
 246         case FD_ACCEPT
:  event 
= GSOCK_CONNECTION
; break; 
 249           if (WSAGETSELECTERROR(lParam
) != 0) 
 252             event 
= GSOCK_CONNECTION
; 
 255         case FD_CLOSE
:   event 
= GSOCK_LOST
; break; 
 260         cback 
= socket
->m_cbacks
[event
]; 
 261         data 
= socket
->m_data
[event
]; 
 263         if (event 
== GSOCK_LOST
) 
 264           socket
->m_detected 
= GSOCK_LOST_FLAG
; 
 266           socket
->m_detected 
|= (1 << event
); 
 270     /* OK, we can now leave the critical section because we have 
 271      * already obtained the callback address (we make no further 
 272      * accesses to socket->whatever). However, the app should 
 273      * be prepared to handle events from a socket that has just 
 276     LeaveCriticalSection(&critical
); 
 279       (cback
)(socket
, event
, data
); 
 284     return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
); 
 287 /* _GSocket_Enable_Events: 
 288  *  Enable all event notifications; we need to be notified of all 
 289  *  events for internal processing, but we will only notify users 
 290  *  when an appropiate callback function has been installed. 
 292 void _GSocket_Enable_Events(GSocket 
*socket
) 
 294   assert (socket 
!= NULL
); 
 296   if (socket
->m_fd 
!= INVALID_SOCKET
) 
 298     /* We could probably just subscribe to all events regardless 
 299      * of the socket type, but MS recommends to do it this way. 
 301     long lEvent 
= socket
->m_server
? 
 302                   FD_ACCEPT 
: (FD_READ 
| FD_WRITE 
| FD_CONNECT 
| FD_CLOSE
); 
 304     gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
); 
 308 /* _GSocket_Disable_Events: 
 309  *  Disable event notifications (when shutdowning the socket) 
 311 void _GSocket_Disable_Events(GSocket 
*socket
) 
 313   assert (socket 
!= NULL
); 
 315   if (socket
->m_fd 
!= INVALID_SOCKET
) 
 317     gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0); 
 321 #else /* !wxUSE_SOCKETS */ 
 324  * Translation unit shouldn't be empty, so include this typedef to make the 
 325  * compiler (VC++ 6.0, for example) happy 
 327 typedef void (*wxDummy
)(); 
 329 #endif  /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */