
//-----------------------------------------------------------------------------
// This is a part of the Microsoft Source Code Samples. 
// Copyright (C) 1993-1996 Microsoft Corporation.
// All rights reserved. 
//  
// This source code is only intended as a supplement to 
// Microsoft Development Tools and/or WinHelp documentation.
// See these sources for detailed information regarding the 
// Microsoft samples programs.
//-----------------------------------------------------------------------------

/****************************************************************************\
*  wsock.c -- sample program demonstrating Windows Sockets APIs.
*
*  Demonstrates basic sockets programming with the Windows Sockets API.
*  Allows two occurances of the application to connect.  Also, displays
*  information about a host computer.
*
****************************************************************************/

#include <windows.h>       /* required for all Windows applications */
#include <stdio.h>         /* for sprintf                           */
#include <string.h>        /* for strlen                            */
#include <memory.h>
#include <process.h>       /* for _beginthread                      */
#include "wsock.h"         /* specific to this program              */

HANDLE hInst;              /* current instance                      */

SOCKET sock;
u_short portno;            /* Which tcp port are we going to use?   */

char szBuff[ 80 ];         /* Temp buffer - used to pass strings    */
                           /* to and from dialog boxes, etc         */

char gpszHelloWorld[]= "Hello World.";

#define MAX_PENDING_CONNECTS 4  /* The backlog allowed for listen() */
#define NO_FLAGS_SET         0  /* Used with recv()/send()          */
#define MY_MSG_LENGTH       80  /* msg buffer sent back and forth   */

/****************************************************************************
*
*    FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
*
*    PURPOSE: calls initialization function, processes message loop
*
*\***************************************************************************/

WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
    )
{

    MSG msg;

    UNREFERENCED_PARAMETER( lpCmdLine );

    if (!hPrevInstance)                  /* Other instances of app running? */
        if (!InitApplication(hInstance)) /* Initialize shared things        */
            return (FALSE);              /* Exits if unable to initialize   */

    /*
    *   Perform initializations that apply to a specific instance
    */
    if (!InitInstance(hInstance, nCmdShow))
        return (FALSE);

    /*
    *   Acquire and dispatch messages until a WM_QUIT message is received.
    */
    while (GetMessage(&msg,        /* message structure                      */
            NULL,                  /* handle of window receiving the message */
            0,             /* lowest message to examine              */
            0))            /* highest message to examine             */
        {
        TranslateMessage(&msg);    /* Translates virtual key codes           */
        DispatchMessage(&msg);     /* Dispatches message to window           */
   }
    return (msg.wParam);           /* Returns the value from PostQuitMessage */
}


/****************************************************************************
*
*    FUNCTION: InitApplication(HANDLE)
*
*    PURPOSE: Initializes window data and registers window class
*
*\***************************************************************************/

BOOL InitApplication(HANDLE hInstance)       /* current instance             */
{
    WNDCLASS  wc;

    /* Fill in window class structure with parameters that describe the       */
    /* main window.                                                           */

    wc.style = 0;                    /* Class style(s).                    */
    wc.lpfnWndProc = (WNDPROC)MainWndProc;       /* Function to retrieve messages for  */
                                        /* windows of this class.             */
    wc.cbClsExtra = 0;                  /* No per-class extra data.           */
    wc.cbWndExtra = 0;                  /* No per-window extra data.          */
    wc.hIcon = LoadIcon (hInstance, "wsockicon"); /* Icon name from .RC        */
    wc.hInstance = hInstance;          /* Application that owns the class.   */
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "WSockMenu";   /* Name of menu resource in .RC file. */
    wc.lpszClassName = "WSockWClass"; /* Name used in call to CreateWindow. */

    /* Register the window class and return success/failure code. */

    return (RegisterClass(&wc));

}


/****************************************************************************\
*
*    FUNCTION:  InitInstance(HANDLE, int)
*
*    PURPOSE:  Saves instance handle and creates main window
*
*\***************************************************************************/

BOOL InitInstance(
    HANDLE          hInstance,          /* Current instance identifier.       */
    int             nCmdShow)           /* Param for first ShowWindow() call. */
{
    HWND            hWnd;               /* Main window handle.                */

    /* Save the instance handle in static variable, which will be used in  */
    /* many subsequence calls from this application to Windows.            */

    hInst = hInstance;

    /* Create a main window for this application instance.  */

    hWnd = CreateWindow(
        "WSockWClass",                  /* See RegisterClass() call.          */
        "Windows Sockets Sample Application",   /* Text for window title bar.         */
        WS_OVERLAPPEDWINDOW,            /* Window style.                      */
        CW_USEDEFAULT,                  /* Default horizontal position.       */
        CW_USEDEFAULT,                  /* Default vertical position.         */
        CW_USEDEFAULT,                  /* Default width.                     */
        CW_USEDEFAULT,                  /* Default height.                    */
        NULL,                           /* Overlapped windows have no parent. */
        NULL,                           /* Use the window class menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    );

    /* If window could not be created, return "failure" */

    if (!hWnd)
        return (FALSE);

    /* Make the window visible; update its client area; and return "success" */

    ShowWindow(hWnd, nCmdShow);  /* Show the window                        */
    UpdateWindow(hWnd);          /* Sends WM_PAINT message                 */
    return (TRUE);               /* Returns the value from PostQuitMessage */

}

/****************************************************************************\
*
*    FUNCTION: AcceptThreadProc(PTHREADPACK tp)
*
*    PURPOSE:  Use blocking accept() calls and display a message box when
*              a connection is made.
*
*\***************************************************************************/

void AcceptThreadProc( PTHREADPACK ptp )
{
   SOCKADDR_IN acc_sin;    /* Accept socket address - internet style */
   int acc_sin_len;        /* Accept socket address length */
   int status;
   char szMsg[ MY_MSG_LENGTH ];


   acc_sin_len = sizeof(acc_sin);

   wsprintf( szBuff, "thread #%d created.", ptp->nThread);
   MessageBox(ptp->hWnd, szBuff, "FYI", MB_OK);

   sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
            (int FAR *) &acc_sin_len );

   if (sock < 0) {
      sprintf(szBuff, "%d is the error", WSAGetLastError());

      MessageBox(ptp->hWnd, szBuff, "accept(sock) failed", MB_OK);

   }

   wsprintf( szBuff, "Thread #%d accepted something\n\nCheck for incoming messages?", ptp->nThread);

   /*
   *   Now have a connection --
   *   SetConnectMenus() grays/enables proper menu items
   */
   SetConnectMenus( ptp->hWnd );


   while (1) {

      /*
      *   By default sockets are created in blocking mode.
      *   Just keep reading until process destroyed.
      */
      status = recv( sock, szMsg, MY_MSG_LENGTH, NO_FLAGS_SET );

      if (status == SOCKET_ERROR) {
         wsprintf( szMsg, "Error %d", WSAGetLastError() );
         MessageBox( ptp->hWnd, szMsg, "Error with recv()", MB_OK);
         _endthread();
      }
          szMsg[status] = '\0';  /* NULL-terminate the string */

      if (status)
         MessageBox( ptp->hWnd, szMsg, "From thread", MB_OK);
      else  {
         MessageBox( ptp->hWnd, "Connection broken", "Error", MB_OK);
         _endthread();
      }

   }    /* while (forever) */
}

/****************************************************************************\
*
*    FUNCTION:  FillAddr(HWND, PSOCKADDR_IN, BOOL)
*
*    PURPOSE:  Retrieves the IP address and port number.
*
*    COMMENTS:
*        This function is called in two conditions.
*            1.) When a client is preparing to call connect(), or
*            2.) When a server host is going to call bind(), listen() and
*                accept().
*        In both situations, a SOCKADDR_IN structure is filled.
*        However, different fields are filled depending on the condition.
*
*   ASSUMPTION:
*      szBuff is a global variable that contains the remote host name or NULL
*      if local.
*      bClient determines if this is being called by a client ( will be
*         performing a connect ) or a server ( will be listening )
*
*
*\***************************************************************************/

BOOL FillAddr(
        HWND hWnd,
        PSOCKADDR_IN psin,
        BOOL bClient)
{
   DWORD dwSize;
   PHOSTENT phe;
   PSERVENT pse;
   char szTemp[200];
   int status;


   psin->sin_family = AF_INET;


   /*
   *   If we are setting up for a listen() call (bConnect = FALSE),
   *   fill servent with our address.
   */
   if (bClient) {
      phe = gethostbyname(szBuff);
      if (phe == NULL) {
         sprintf(szTemp, "%d is the error. Make sure '%s' is listed in the hosts file.", WSAGetLastError(), szBuff);

         MessageBox(hWnd, szTemp, "gethostbyname() failed.", MB_OK);
         return FALSE;
      }
      memcpy((char FAR *)&(psin->sin_addr), phe->h_addr,
         phe->h_length);

      }
   else { // server

      /*
      *   Retrieve my ip address.  Assuming the hosts file in
      *   in %systemroot%/system/drivers/etc/hosts contains my computer name.
      */

      dwSize = sizeof(szBuff);
      gethostname(szBuff, dwSize);

      psin->sin_addr.s_addr = INADDR_ANY;
      }


   /*
   *   Retrieve the Port number
   */
   status = DialogBox(hInst,             /* current instance         */
      "TCPPORTNUM",                      /* resource to use          */
      hWnd,                              /* parent handle            */
      GetTcpPort);                       /* instance address         */

   switch(status) {
      case 0:               /* User cancelled request from prev. dialog box */
         return FALSE;

      case 1:               /* actual port number entered */
         psin->sin_port = htons(portno);        /* Convert to network ordering */
         break;

      case 2:               /* service name entereted */
         /*
         *   Find the service name, szBuff, which is a type tcp protocol in
         *   the "services" file.
         */
         pse = getservbyname(szBuff, "tcp");
         if (pse == NULL)  {
            sprintf(szBuff, "%d is the error. Make sure this is a valid TCP service.", WSAGetLastError());
            MessageBox(hWnd, szBuff, "getservbyname(sock) failed", MB_OK);
            return FALSE;
         }
         psin->sin_port = pse->s_port;
         break;

      default:
         return FALSE;
   }
   return TRUE;
}

/****************************************************************************
*
*    FUNCTION: SetConnectMenus( HWND )
*
*    PURPOSE: Gray/Enable the proper menu items after a connection has been
*             established.
*
*\***************************************************************************/

void SetConnectMenus( HWND hWnd )
{
   /*
   *   Disable/enable proper menu items.
   */
   EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED );
   EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_ENABLED );
   EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED );
   EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED );

   /*
   *   Reflect socket connection in title bar.
   */
   SetWindowText( hWnd, "Connected");
}

/****************************************************************************\
*
*    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
*
*    PURPOSE:  Processes main window messages
*
* MESSAGES:
*  WM_CREATE   - call WSAStartUp() and display description message
*  WSA_ACCEPT  - User-defined message used with WSAAsyncSelect().  Sent
*                by the Windows Sockets DLL when a socket connection is
*                pending.
*
*  WM_COMMAND
*  IDM_CONNECT - Connect to a remote host.
*  IDM_LISTEN  - Use the BSD-Style accept().
*  IDM_ALISTEN - Use the Windows Sockets Asynchronous APIs to detect when
*                a connection is made.
*  IDM_CANCEL  - Cancel the Asynchronous call above.
*  IDM_TLISTEN - Uses two threads to accept network connections (using the
*                BSD-Style accept().
*  IDM_HOSTNAME- Display information about a host.
*  IDM_ABOUT   - About box.
*
*  WM_DESTROY  - destroy window and call the WSACleanUp()
*
*\***************************************************************************/

LONG APIENTRY MainWndProc(
        HWND hWnd,                /* window handle                   */
        UINT message,             /* type of message                 */
        UINT wParam,              /* additional information          */
        LONG lParam)              /* additional information          */
{
   int status;             /* Status Code */
   SOCKADDR_IN local_sin;  /* Local socket - internet style */
   SOCKADDR_IN acc_sin;    /* Accept socket address - internet style */
   int acc_sin_len;        /* Accept socket address length */


   switch (message) {
   case WM_CREATE:
   {
      WSADATA WSAData;
      char szTemp[80];

      if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0) {
         MessageBox( hWnd, WSAData.szDescription, WSAData.szSystemStatus, MB_OK);
      }
      else {
         sprintf(szTemp, "%d is the err", status);
         MessageBox( hWnd, szTemp, "Error", MB_OK);
      }
   }
   break;   /* WM_CREATE */

   /*
   *    Notification if data is waiting on a socket.  This comes
   *    from Windows Sockets (via WSAAsyncSelect()).
   */
   case WSA_READ:
   {
      char szTemp[ MY_MSG_LENGTH ];

      if (WSAGETSELECTEVENT(lParam) == FD_READ) {
         status = recv((SOCKET)wParam, szTemp, MY_MSG_LENGTH, NO_FLAGS_SET );

         if (status) {
            szTemp[ status ] = '\0';
            MessageBox( hWnd, szTemp, "WSA_READ", MB_OK);
         }
         else
            MessageBox( hWnd, "Connection broken", "Error", MB_OK);
      }
      else {    /* FD_CLOSE -- connection dropped */
         MessageBox( hWnd, "Connection lost", "WSA_READ", MB_OK);
         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
      }


   }
   break;       /* WSA_READ*/

   case WSA_ACCEPT: /* Notification if a socket connection is pending. */
      /*
      *   Disable/enable proper menu items.
      */
      EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
      EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
      EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
      EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
      EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
      EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);

      if (WSAGETSELECTERROR( lParam ) == 0) {   /* Success */

         /*
         *   Accept the incoming connection.
         */
         acc_sin_len = sizeof( acc_sin );
         sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
            (int FAR *) &acc_sin_len );

         if (sock < 0) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK);
            break;
         }

         MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK);

         /*
         *   Now have a connection --
         *   SetConnectMenus() grays/enables proper menu items
         */
         SetConnectMenus( hWnd );

         /*
         *   Send main window a WSA_READ when either data is pending on
         *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
         */
         if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
            wsprintf(szBuff, "%d (0x%x)", status, status);
            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
            closesocket( sock );
         }
      }
      else {
         MessageBox(hWnd, "accept()", "Error occured!", MB_OK);

         /*
         *   Cancel any further notifications.
         */
         WSAAsyncSelect( sock, hWnd, 0, 0);
         SetWindowText( hWnd, "Async Listen call canceled");
      }
      break;   /* WSA_ACCEPT */



   case WM_COMMAND:        /* message: command from application menu */
      switch(LOWORD(wParam)) {
      case IDM_CONNECT: /* Client - connect to remote host */
      {
         /*

         When a network client wants to connect to a server,
         it must have:
            1.) a TCP port number (gotten via getservbyname())
            and
            2.) an IP address of the remote host (gotten via gethostbyname()).

         The following summarizes the steps used to connect.
         Make a dialog box (HostName)
         Get the name of the remote host computer in which
          to connect from the user (store string in "szBuff" global var)
       * Check to see if the hosts file knows the computer (gethostbyname)
       * Get the host information (hostent structure filled)
       * Fill in the address of the remote host into the servent structure (memcpy)
       * Make a dialog box (TCPPORTNUM)
       * Get the NAME of the port to connect to on the remote host from the
         user.
       * Get the port number (getservbyname)
       * Fill in the port number of the servent structure
         Establish a connection (connect)

         The * prefixed steps are done in the FillAddr() procedure.


         */
         SOCKADDR_IN dest_sin;  /* DESTination Socket INternet */



         /* Get the name of the remote host. Store the string in szBuff. */

         status = DialogBox(hInst,
            "HOSTNAME",
            hWnd,
            GetHostName);

         if (!status)   /* User cancelled request from prev. dialog box */
            break;

         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
            MessageBox(hWnd, "socket() failed", "Error", MB_OK);
            break;
         }

         /*
         *    Retrieve the IP address and TCP Port number
         *    Global variable szBuff contains the remote host name.
         */
         if (!FillAddr( hWnd, &dest_sin, TRUE)) {
            closesocket( sock );
            break;
         }


         if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) {
            closesocket( sock );
            MessageBox(hWnd, "connect() failed", "Error", MB_OK);
            break;
         }
         MessageBox(hWnd, "connect() worked!", "Success!", MB_OK);

         /*
         *   Now have a connection --
         *   SetConnectMenus() grays/enables proper menu items
         */
         SetConnectMenus( hWnd );

         /*
         *   Send main window a WSA_READ when either data is pending on
         *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
         */
         if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
            wsprintf(szBuff, "%d (0x%x)");
            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
            closesocket( sock );
         }

      }
      break;   /* IDM_CONNECT */

      case IDM_CONNECTANDSEND:
      {
         //
         //
         //  In order to simulate a more typical real-world client, here
         //   we make the connection, and then immediately send it data.
         //
         //  See IDM_CONNECT above for full comments.

         SOCKADDR_IN dest_sin;

         status = DialogBox(hInst,
            "HOSTNAME",
            hWnd,
            GetHostName);

         if (!status)
            break;

         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
            MessageBox(hWnd, "socket() failed", "Error", MB_OK);
            break;
         }

         if (!FillAddr( hWnd, &dest_sin, TRUE)) {
            closesocket( sock );
            break;
         }


         if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) {
            MessageBox(hWnd, "connect() failed", "Error", MB_OK);
            closesocket( sock );
            break;
         }

         if (send (sock, gpszHelloWorld, lstrlen (gpszHelloWorld), 0 ) == SOCKET_ERROR) {
            wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
            MessageBox( hWnd, szBuff, "Error on send()", MB_OK);
            closesocket( sock );
            break;
         }


         MessageBox(hWnd, "connect() & send() worked!", "Success!", MB_OK);

         SetConnectMenus( hWnd );

         if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
            wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
            closesocket( sock );
         }

      }
      break;   // IDM_CONNECTANDSEND


      case IDM_ACCEPTEX:
      {
        //
        // Demonstrate the use of AcceptEx().
        //

#define MAX_BYTES        2000
#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16
        SOCKET sListenSocket;
        SOCKET sAcceptSocket;
        char   pData [MAX_BYTES];
        OVERLAPPED olResult;
        DWORD dwBytes;


        //
        // For this API, we need to create two sockets ahead of time.
        //  The listen socket goes through the standard bind/listen steps.
        //

        sListenSocket = socket( AF_INET, SOCK_STREAM, 0);
        sAcceptSocket = socket( AF_INET, SOCK_STREAM, 0);
        if ((sListenSocket == INVALID_SOCKET) || (sAcceptSocket == INVALID_SOCKET)) {
           MessageBox(hWnd, "sock == INVALID_SOCKET", "socket() failed", MB_OK);
           closesocket(sListenSocket);
           closesocket(sAcceptSocket);
           break;
        }

        //
        //   Retrieve the IP address and TCP Port number
        //

        if (!FillAddr(hWnd, &local_sin, FALSE ))
           break;

        //
        //   Associate an address with the socket
        //

        if (bind( sListenSocket, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
           wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
           MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
           break;
        }

        //
        //   And go into the listening state.
        //

        if (listen( sListenSocket, MAX_PENDING_CONNECTS ) < 0) {
           wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
           MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
           break;
        }

        //
        //   Disable/enable proper menu items.
        //

        EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
        EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);

        SetWindowText( hWnd, "AcceptEx..");

        //
        //  Create an event for our overlapped structure (required).
        //

        memset (&olResult,  0, sizeof(olResult));
        olResult.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        dwBytes = 0;

        //
        //  AcceptEx makes the most sense when used with I/O
        //   CompletionPorts and TransmitFile.
        //   We show a very basic usage here...
        //

        if (AcceptEx( sListenSocket,
                      sAcceptSocket,
                      pData,
                      MAX_BYTES - 2*PADDED_ADDR_SIZE,
                      PADDED_ADDR_SIZE,
                      PADDED_ADDR_SIZE,
                      &dwBytes,
                      &olResult) == FALSE) {

            if (WSAGetLastError() != ERROR_IO_PENDING) {
               wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
               MessageBox( hWnd, szBuff, "Error on AcceptEx()", MB_OK);
               break;
            } else {

               //
               // In our contrived scenario, we expect GetLastError to be
               //  ERROR_IO_PENDING.  A real app would do other work.
               //  Since this is a simple sample, we will just block waiting
               //  for some input to come through the socket.
               //

               GetOverlappedResult ( (HANDLE) sAcceptSocket,
                                     &olResult,
                                     &dwBytes,
                                     TRUE);
               pData[dwBytes] = 0;
               MessageBox(hWnd, pData, "AcceptEx received data", MB_OK);

            }
        }

        //
        //  As per the documentation, poke the new socket so that it will have
        //   the correct properties and can be used by other functions.
        //

        if (setsockopt( sAcceptSocket,
                        SOL_SOCKET,
                        SO_UPDATE_ACCEPT_CONTEXT,
                        (char *)&sListenSocket,
                        sizeof(sListenSocket) )) {
                wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
                MessageBox( hWnd, szBuff, "Error in setsockopt()", MB_OK);
                break;
        } else {

        //
        //  sAcceptSocket is now OK for use by other functions.
        //  set it into our global socket (sock)
        //
            sock = sAcceptSocket;
        }

        //
        //  In any case, we are done with our listen socket
        //

        closesocket( sListenSocket );

        //
        //  Now have a connection --
        //   SetConnectMenus() grays/enables proper menu items

        SetConnectMenus( hWnd );

        //
        //  Send main window a WSA_READ when either data is pending on
        //  the socket (FD_READ) or the connection is closed (FD_CLOSE)

        if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
           wsprintf(szBuff, "%d (0x%x)");
           MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
           closesocket( sock );
        }
      }
      break;   /* IDM_ACCEPTEX */


      case IDM_LISTEN:
      {
         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
            MessageBox(hWnd, "socket() failed", "Error", MB_OK);
            closesocket(sock);
            break;
         }

         /*
         *   Retrieve the IP address and TCP Port number
         */

         if (!FillAddr(hWnd, &local_sin, FALSE ))
            break;

         /*
         *   Disable/enable proper menu items.
         */
         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);

         SetWindowText( hWnd, "Waiting for connection..");


         /*
         *   Associate an address with a socket. (bind)
         */
         if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
            break;
         }

         if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
            break;
         }

         acc_sin_len = sizeof(acc_sin);


         sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
            (int FAR *) &acc_sin_len );
         if (sock < 0) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK);
            break;
         }

         MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK);

         /*
         *   Now have a connection --
         *   SetConnectMenus() grays/enables proper menu items
         */
         SetConnectMenus( hWnd );

         /*
         *   Send main window a WSA_READ when either data is pending on
         *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
         */
         if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
            wsprintf(szBuff, "%d (0x%x)");
            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
            closesocket( sock );
         }

      }
      break;   /* IDM_LISTEN */

      /*
      *   Asynchronous Listen - Using WSA extensions.
      */
      case IDM_ALISTEN:
      {

         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
            MessageBox(hWnd, "socket() failed", "Error", MB_OK);
            break;
         }
         /*
         *   Retrieve the IP address and TCP Port number
         */

         if (!FillAddr( hWnd, &local_sin, FALSE)) {
            closesocket( sock );
            break;
         }

         /*
         *   Disable/enable proper menu items.
         */
         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);

         SetWindowText( hWnd, "Waiting for connection.. (Async)");


         /*
         *   Associate an address with a socket. (bind)
         */
         if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
            closesocket( sock );
            break;
         }

         if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
            break;
         }

         /*
         *   Send window a WSA_ACCEPT when something is trying to connect.
         */
         if ((status = WSAAsyncSelect( sock, hWnd, WSA_ACCEPT, FD_ACCEPT)) > 0) {
            wsprintf( szBuff, "%d (0x%x)");
            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
            SetWindowText( hWnd, "Async listen cancelled");
            closesocket( sock );
         }

      }
      break;   /* IDM_ALISTEN */


      /*
      *   Cancel an asynchronous call.
      */
      case IDM_CANCEL:
         WSAAsyncSelect( sock, hWnd, 0, 0);
         SetWindowText( hWnd, "Async Listen cancelled..");

         /*
         *   Disable/enable proper menu items.
         */
         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_ENABLED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_ENABLED);

         break;   /* IDM_CANCEL */

      /*
      * Listen in the main thread -- spawn and accept two network
      *  connections inside two threads.
      */
      case IDM_TLISTEN:
      {
         static THREADPACK tp;

         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
            MessageBox(hWnd, "socket() failed", "Error", MB_OK);
            closesocket(sock);
            break;
         }

         /*
         *   Retrieve the IP address and TCP Port number
         */

         if (!FillAddr(hWnd, &local_sin, FALSE ))
            break;

         /*
         *   Disable/enable proper menu items.
         */
         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);

         SetWindowText( hWnd, "Waiting for connection..");


         /*
         *   Associate an address with a socket. (bind)
         */
         if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
            break;
         }

         if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
            sprintf(szBuff, "%d is the error", WSAGetLastError());

            MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
            break;
         }

         tp.nThread = 0;
         tp.hWnd = hWnd;

         _beginthread(AcceptThreadProc, 0, &tp);

         }
         break;   /* IDM_TLISTEN */


      /*
      *   Display host information.
      */
      case IDM_HOSTNAME:

         /*
         *  Prompt the user and retrieve the text name of the host.
         */
         status = DialogBox(hInst,
            "HOSTNAME",
            hWnd,
            GetHostName);


         if (status == TRUE) {   /* If user hit "OK" .. */

         /*
         *   Get the host information
         */

         if ((phe = gethostbyname( szBuff )) == NULL) {
            MessageBox(hWnd, "gethostbyname() failed", "Error", MB_OK);
            break;
         }
         else {

         /*
         *   Display the host information ..
         */
            DialogBox(hInst,
               "DISPLAYHOST",
               hWnd,
               DisplayHostEnt);
         }
      }
      break;   /* IDM_HOSTNAME */
      /*
      *   Send a message to (via TCP connection) to remote host.
      */
      case IDM_SENDTCP:
         DialogBox(hInst,                /* current instance         */
            "GetString",                 /* resource to use          */
            hWnd,                        /* parent handle            */
            GetSendString);              /* instance address         */

        /*
        *   Assumption -- The GetString dialog box proc fills the global
        *   string buffer, szBuff, with the desired string to send.
        */
        send(sock, szBuff, strlen(szBuff), NO_FLAGS_SET );

        break;   /* IDM_SENDTCP */



      case IDM_ABOUT:
         DialogBox(hInst,                /* current instance         */
            "AboutBox",                  /* resource to use          */
            hWnd,                        /* parent handle            */
            About);                      /* About() instance address */

         break;   /* IDM_ABOUT */

      default:
         /* Lets Windows process it          */
         return (DefWindowProc(hWnd, message, wParam, lParam));
         break;
      }
   break;


   /*
   *   Clean up.  Takes care of any open socket descriptors.
   */
   case WM_DESTROY:
      WSACleanup();
      PostQuitMessage(0);
      break;

   default:                       /* Passes it on if unproccessed    */
      return (DefWindowProc(hWnd, message, wParam, lParam));

   }
   return (0);

}
