1 /* ------------------------------------------------------------------------- 
   2  * Project: GSocket (Generic Socket) 
   4  * Author:  Guillermo Rodriguez Garcia <guille@iies.es> 
   5  * Purpose: GSocket GUI-specific MSW code 
   7  * ------------------------------------------------------------------------- 
  11  * PLEASE don't put C++ comments here - this is a C source file. 
  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 
  19 #  pragma warning(disable:4115) /* named type definition in parentheses */ 
  22 #ifndef __GSOCKET_STANDALONE__ 
  27 #if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) 
  29 #ifndef __GSOCKET_STANDALONE__ 
  31 #include "wx/msw/gsockmsw.h" 
  32 #include "wx/gsocket.h" 
  34 #define INSTANCE wxGetInstance() 
  41 /* If not using wxWindows, a global var called hInst must 
  42  * be available and it must contain the app's instance 
  45 #define INSTANCE hInst 
  47 #endif /* __GSOCKET_STANDALONE__ */ 
  59 #  pragma warning(default:4115) /* named type definition in parentheses */ 
  62 #define CLASSNAME  TEXT("_GSocket_Internal_Window_Class") 
  63 #define WINDOWNAME TEXT("_GSocket_Internal_Window_Name") 
  65 /* Maximum number of different GSocket objects at a given time. 
  66  * This value can be modified at will, but it CANNOT be greater 
  67  * than (0x7FFF - WM_USER + 1) 
  69 #define MAXSOCKETS 1024 
  71 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1)) 
  72 #error "MAXSOCKETS is too big!" 
  76 /* Global variables */ 
  78 extern HINSTANCE INSTANCE
; 
  80 static CRITICAL_SECTION critical
; 
  81 static GSocket
* socketList
[MAXSOCKETS
]; 
  82 static int firstAvailable
; 
  84 /* Global initializers */ 
  86 int GSocket_Init(void) 
  92   /* Create internal window for event notifications */ 
  94   winClass
.lpfnWndProc   
= _GSocket_Internal_WinProc
; 
  95   winClass
.cbClsExtra    
= 0; 
  96   winClass
.cbWndExtra    
= 0; 
  97   winClass
.hInstance     
= INSTANCE
; 
  98   winClass
.hIcon         
= (HICON
) NULL
; 
  99   winClass
.hCursor       
= (HCURSOR
) NULL
; 
 100   winClass
.hbrBackground 
= (HBRUSH
) NULL
; 
 101   winClass
.lpszMenuName  
= (LPCTSTR
) NULL
; 
 102   winClass
.lpszClassName 
= CLASSNAME
; 
 104   RegisterClass(&winClass
); 
 105   hWin 
= CreateWindow(CLASSNAME
, 
 108                       (HWND
) NULL
, (HMENU
) NULL
, INSTANCE
, (LPVOID
) NULL
); 
 110   if (!hWin
) return FALSE
; 
 112   /* Initialize socket list */ 
 113   InitializeCriticalSection(&critical
); 
 115   for (i 
= 0; i 
< MAXSOCKETS
; i
++) 
 117     socketList
[i
] = NULL
; 
 121   /* Initialize WinSocket */ 
 122   return (WSAStartup((1 << 8) | 1, &wsaData
) == 0); 
 125 void GSocket_Cleanup(void) 
 127   /* Destroy internal window */ 
 129   UnregisterClass(CLASSNAME
, INSTANCE
); 
 131   /* Delete critical section */ 
 132   DeleteCriticalSection(&critical
); 
 134   /* Cleanup WinSocket */ 
 138 /* Per-socket GUI initialization / cleanup */ 
 140 int _GSocket_GUI_Init(GSocket 
*socket
) 
 144   /* Allocate a new message number for this socket */ 
 145   EnterCriticalSection(&critical
); 
 148   while (socketList
[i
] != NULL
) 
 150     i 
= (i 
+ 1) % MAXSOCKETS
; 
 152     if (i 
== firstAvailable
)    /* abort! */ 
 154       LeaveCriticalSection(&critical
); 
 158   socketList
[i
] = socket
; 
 159   firstAvailable 
= (i 
+ 1) % MAXSOCKETS
; 
 160   socket
->m_msgnumber 
= (i 
+ WM_USER
); 
 162   LeaveCriticalSection(&critical
); 
 167 void _GSocket_GUI_Destroy(GSocket 
*socket
) 
 169   /* Remove the socket from the list */ 
 170   EnterCriticalSection(&critical
); 
 171   socketList
[(socket
->m_msgnumber 
- WM_USER
)] = NULL
; 
 172   LeaveCriticalSection(&critical
); 
 175 /* Windows proc for asynchronous event handling */ 
 177 LRESULT CALLBACK 
_GSocket_Internal_WinProc(HWND hWnd
, 
 184   GSocketCallback cback
; 
 187   if (uMsg 
>= WM_USER 
&& uMsg 
<= (WM_USER 
+ MAXSOCKETS 
- 1)) 
 189     EnterCriticalSection(&critical
); 
 190     socket 
= socketList
[(uMsg 
- WM_USER
)]; 
 195     /* Check that the socket still exists (it has not been 
 196      * destroyed) and for safety, check that the m_fd field 
 197      * is what we expect it to be. 
 199     if ((socket 
!= NULL
) && (socket
->m_fd 
== wParam
)) 
 201       switch WSAGETSELECTEVENT(lParam
) 
 203         case FD_READ
:    event 
= GSOCK_INPUT
; break; 
 204         case FD_WRITE
:   event 
= GSOCK_OUTPUT
; break; 
 205         case FD_ACCEPT
:  event 
= GSOCK_CONNECTION
; break; 
 208           if (WSAGETSELECTERROR(lParam
) != 0) 
 211             event 
= GSOCK_CONNECTION
; 
 214         case FD_CLOSE
:   event 
= GSOCK_LOST
; break; 
 219         cback 
= socket
->m_cbacks
[event
]; 
 220         data 
= socket
->m_data
[event
]; 
 222         if (event 
== GSOCK_LOST
) 
 223           socket
->m_detected 
= GSOCK_LOST_FLAG
; 
 225           socket
->m_detected 
|= (1 << event
); 
 229     /* OK, we can now leave the critical section because we have 
 230      * already obtained the callback address (we make no further 
 231      * accesses to socket->whatever). However, the app should 
 232      * be prepared to handle events from a socket that has just 
 235     LeaveCriticalSection(&critical
); 
 238       (cback
)(socket
, event
, data
); 
 243     return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
); 
 246 /* _GSocket_Enable_Events: 
 247  *  Enable all event notifications; we need to be notified of all 
 248  *  events for internal processing, but we will only notify users 
 249  *  when an appropiate callback function has been installed. 
 251 void _GSocket_Enable_Events(GSocket 
*socket
) 
 253   assert (socket 
!= NULL
); 
 255   if (socket
->m_fd 
!= INVALID_SOCKET
) 
 257     /* We could probably just subscribe to all events regardless 
 258      * of the socket type, but MS recommends to do it this way. 
 260     long lEvent 
= socket
->m_server
? 
 261                   FD_ACCEPT 
: (FD_READ 
| FD_WRITE 
| FD_CONNECT 
| FD_CLOSE
); 
 263     WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
); 
 267 /* _GSocket_Disable_Events: 
 268  *  Disable event notifications (when shutdowning the socket) 
 270 void _GSocket_Disable_Events(GSocket 
*socket
) 
 272   assert (socket 
!= NULL
); 
 274   if (socket
->m_fd 
!= INVALID_SOCKET
) 
 276     WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0); 
 280 #else /* !wxUSE_SOCKETS */ 
 283  * Translation unit shouldn't be empty, so include this typedef to make the 
 284  * compiler (VC++ 6.0, for example) happy 
 286 typedef void (*wxDummy
)(); 
 288 #endif  /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */