home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / globchat / client / misc.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  11KB  |  388 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   misc.c
  9. //
  10. //  PURPOSE:  Contains all helper functions "global" to the application.
  11. //
  12. //  FUNCTIONS:
  13. //    CenterWindow    - Center one window over another.
  14. //    ReceiveInBox    - Reads incoming socket data.
  15. //    SendOutBox      - Writes outgoing socket data.
  16. //    AtoH            - Converts ascii string to network order hex
  17. //    BtoH            - Converts ascii byte to hex
  18. //    senddatamessage - Sends a message to the server
  19. //    recvdatamessage - Receives a message from the server
  20. //
  21. //  COMMENTS:
  22. //
  23. //
  24.  
  25. #include <windows.h>            // required for all Windows applications
  26. #include <windowsx.h>
  27. #include <wsipx.h>
  28. #include <wsnetbs.h>
  29. #include <nspapi.h>
  30. #include "globals.h"            // prototypes specific to this application
  31.  
  32.  
  33.  
  34. //
  35. //  FUNCTION: CenterWindow(HWND, HWND)
  36. //
  37. //  PURPOSE:  Center one window over another.
  38. //
  39. //  PARAMETERS:
  40. //    hwndChild - The handle of the window to be centered.
  41. //    hwndParent- The handle of the window to center on.
  42. //
  43. //  RETURN VALUE:
  44. //
  45. //    TRUE  - Success
  46. //    FALSE - Failure
  47. //
  48. //  COMMENTS:
  49. //
  50. //    Dialog boxes take on the screen position that they were designed
  51. //    at, which is not always appropriate. Centering the dialog over a
  52. //    particular window usually results in a better position.
  53. //
  54.  
  55. BOOL CenterWindow(HWND hwndChild, HWND hwndParent)
  56. {
  57.     RECT    rcChild, rcParent;
  58.     int     cxChild, cyChild, cxParent, cyParent;
  59.     int     cxScreen, cyScreen, xNew, yNew;
  60.     HDC     hdc;
  61.  
  62.     // Get the Height and Width of the child window
  63.     GetWindowRect(hwndChild, &rcChild);
  64.     cxChild = rcChild.right - rcChild.left;
  65.     cyChild = rcChild.bottom - rcChild.top;
  66.  
  67.     // Get the Height and Width of the parent window
  68.     GetWindowRect(hwndParent, &rcParent);
  69.     cxParent = rcParent.right - rcParent.left;
  70.     cyParent = rcParent.bottom - rcParent.top;
  71.  
  72.     // Get the display limits
  73.     hdc = GetDC(hwndChild);
  74.     cxScreen = GetDeviceCaps(hdc, HORZRES);
  75.     cyScreen = GetDeviceCaps(hdc, VERTRES);
  76.     ReleaseDC(hwndChild, hdc);
  77.  
  78.     // Calculate new X position, then adjust for screen
  79.     xNew = rcParent.left + ((cxParent - cxChild) / 2);
  80.     if (xNew < 0)
  81.     {
  82.         xNew = 0;
  83.     }
  84.     else if ((xNew + cxChild) > cxScreen)
  85.     {
  86.         xNew = cxScreen - cxChild;
  87.     }
  88.  
  89.     // Calculate new Y position, then adjust for screen
  90.     yNew = rcParent.top  + ((cyParent - cyChild) / 2);
  91.     if (yNew < 0)
  92.     {
  93.         yNew = 0;
  94.     }
  95.     else if ((yNew + cyChild) > cyScreen)
  96.     {
  97.         yNew = cyScreen - cyChild;
  98.     }
  99.  
  100.     // Set it, and return
  101.     return SetWindowPos(hwndChild,
  102.                         NULL,
  103.                         xNew, yNew,
  104.                         0, 0,
  105.                         SWP_NOSIZE | SWP_NOZORDER);
  106. }
  107.  
  108. //
  109. //  FUNCTION: ReceiveInBox(HWND, WPARAM, LPARAM, char *, int)
  110. //
  111. //  PURPOSE:  Reads incoming data from socket and process message
  112. //
  113. //  PARAMETERS:
  114. //    hWnd      - Handle to current window
  115. //    uParam    - WPARAM (unused)
  116. //    lParam    - LPARAM contains event (FD_READ or FD_CLOSE).
  117. //    szRBuf    - Receive Buffer
  118. //    cRBufLen  - size of Receive Buffer
  119. //
  120. //  RETURN VALUE:
  121. //
  122. //    TRUE  - Data Read
  123. //    FALSE - If FD_CLOSE message or recv failed
  124. //
  125. //  COMMENTS:
  126. //
  127. //    Called if socket has data OR if it is closed.  If closed post
  128. //    WM_DISCONNECTED message.  Else read data and make sure it is
  129. //    NULL terminated.
  130. //
  131.  
  132. BOOL ReceiveInBox(HWND hWnd, WPARAM uParam, LPARAM lParam, char * szRBuf, int cRBufLen)
  133. {
  134.     char outtext[80];
  135.  
  136.  
  137.     if (LOWORD(lParam) == FD_CLOSE)                   // Is this a FD_CLOSE event?
  138.     {
  139.         SendMessage(hWnd, MW_DISCONNECTED, 0, 0);     // Yes, post message
  140.         return(FALSE);
  141.     }
  142.  
  143.     if (!recvdatamessage(&MySock, &xferbuf))         // Receive data
  144.     {
  145.         return(TRUE);
  146.     }
  147.  
  148.     // Switch on message command
  149.     switch (xferbuf.hdr.command)
  150.     {
  151.         case XFER_DATA:   // Chat data...put it in buffer
  152.             lstrcpy(szRBuf, xferbuf.data);
  153.             cRBufLen = xferbuf.hdr.length - HDRSIZE;
  154.             break;
  155.  
  156.         case SESSION_CLOSE:  // Peer killed us...cleanup
  157.             MySock.status = SOCKSTAT_AVAILABLE;
  158.  
  159.             // Clear event indicator since we need to transfer message
  160.          // indications to the dialog we are about to create
  161.             if (WSAAsyncSelect(MySock.sock, hWnd, 0, 0) == SOCKET_ERROR)
  162.             {
  163.                 // oops
  164.                 return FALSE;
  165.             }
  166.             PostMessage(hWnd, WM_COMMAND, MAKELONG(IDM_SELECT, 0), 0);
  167.  
  168.             wsprintf(outtext, GetStringRes(IDS_CHAT_AVAILABLE), MySock.name);
  169.             SetWindowText(hWnd, outtext);
  170.             return FALSE;
  171.  
  172.         default:
  173.             break;
  174.             // unexpected meesage...drop it
  175.     }
  176.     return TRUE;
  177. }
  178.  
  179. //
  180. //  FUNCTION: SendOutBox(char *, int)
  181. //
  182. //  PURPOSE:  Sends outbox text via data message
  183. //
  184. //  PARAMETERS:
  185. //    szSBuf    - Send Buffer
  186. //    cSBufLen  - size of Send Buffer
  187. //
  188. //  COMMENTS:
  189. //
  190. //    Writes send buffer to socket
  191. //
  192.  
  193. void SendOutBox(char * szSBuf, int cSBufLen)
  194. {
  195.     xferbuf.hdr.signature = MYSIGNATURE;
  196.     xferbuf.hdr.length = cSBufLen + HDRSIZE;
  197.     xferbuf.hdr.command = XFER_DATA;
  198.     lstrcpy(xferbuf.data, szSBuf);
  199.     senddatamessage(MySock.sock, &xferbuf);
  200.     return;
  201. }
  202.  
  203. //
  204. //  FUNCTION: AtoH(char *, char *, int)
  205. //
  206. //  PURPOSE:  Converts ascii string to network order hex
  207. //
  208. //  PARAMETERS:
  209. //    src    - pointer to input ascii string
  210. //    dest   - pointer to output hex
  211. //    destlen - size of dest
  212. //
  213. //  COMMENTS:
  214. //
  215. //    2 ascii bytes make a hex byte so must put 1st ascii byte of pair
  216. //    into upper nibble and 2nd ascii byte of pair into lower nibble.
  217. //
  218.  
  219. void AtoH(char * src, char * dest, int destlen)
  220. {
  221.     char * srcptr;
  222.  
  223.     srcptr = src;
  224.  
  225.     while(destlen--)
  226.     {
  227.     *dest = BtoH(*srcptr++) << 4;    // Put 1st ascii byte in upper nibble.
  228.     *dest++ += BtoH(*srcptr++);      // Add 2nd ascii byte to above.
  229.     }
  230. }
  231.  
  232. //
  233. //  FUNCTION: BtoH(char *, char *, int)
  234. //
  235. //  PURPOSE:  Converts ascii byte to numeric
  236. //
  237. //  PARAMETERS:
  238. //    ch - ascii byte to convert
  239. //
  240. //  RETURNS:
  241. //    associated numeric value
  242. //
  243. //  COMMENTS:
  244. //
  245. //    Will convert any hex ascii digit to its numeric counterpart.
  246. //    Puts in 0xff if not a valid hex digit.
  247. //
  248.  
  249. unsigned char BtoH(char ch)
  250. {
  251.     if (ch >= '0' && ch <= '9') return (ch - '0');        // Handle numerals
  252.     if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA);  // Handle capitol hex digits
  253.     if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA);  // Handle small hex digits
  254.     return(255);
  255. }
  256.  
  257. //
  258. //  FUNCTION: senddatamessage(SOCKET, LPDATAMSG)
  259. //
  260. //  PURPOSE:  sends a chat message to the server
  261. //
  262. //  PARAMETERS:
  263. //    sock    - our socket handle
  264. //    sendbuf - the message to send
  265. //
  266. //  RETURNS:
  267. //    ascii byte
  268. //
  269. //  COMMENTS:
  270. //    Send() may not be able to send entire message continue to send until
  271. //    entire message is sent
  272. //
  273.  
  274. BOOL senddatamessage (SOCKET sock, LPDATAMSG sendbuf)
  275. {
  276.     int totalbytes, bytessent;
  277.  
  278.     bytessent = 0;                          // Set initial count to zero
  279.     totalbytes = sendbuf->hdr.length;     // Set total bytes to send
  280.  
  281.    // loop until entire message is sent
  282.     while(bytessent < totalbytes)
  283.     {
  284.         bytessent += send(sock,
  285.                           (char *)sendbuf + bytessent,
  286.                           totalbytes - bytessent,
  287.                           0);
  288.     }
  289.  
  290.     return TRUE;
  291. }
  292.  
  293. //
  294. //  FUNCTION: recvdatamessage(LPSOCKDATA, LPDATAMSG)
  295. //
  296. //  PURPOSE:  receives chat message from server
  297. //
  298. //  PARAMETERS:
  299. //    lpSockdat - SOCKDATA structure
  300. //    recvbuf   - buffer for incoming data
  301. //
  302. //  RETURNS:
  303. //    TRUE  - Message received
  304. //    FALSE - Message not received
  305. //
  306. //  COMMENTS:
  307. //   For stream sockets we will need to make sure that we read
  308. //    an entire message--no more, no less.  Find message size from
  309. //    message header.
  310. //
  311.  
  312. BOOL recvdatamessage (LPSOCKDATA lpSockdat, LPDATAMSG recvbuf)
  313. {
  314.     int readsize, totalbytesread, msgsize, bytesread;
  315.  
  316.     if (lpSockdat->type == SOCK_SEQPACKET)
  317.     {
  318.         // Message mode protocol!!  Just post one big read.
  319.         readsize = sizeof(*recvbuf);
  320.     }
  321.     else
  322.     {
  323.         // Stream mode protocol!!  Just read header...then read data (data size determined
  324.         // from header)
  325.         readsize = HDRSIZE;
  326.     }
  327.     if((totalbytesread = recv(lpSockdat->sock, (char *)recvbuf, readsize, 0)) == SOCKET_ERROR)
  328.     {
  329.         // ERROR  -- just return
  330.         return FALSE;
  331.     }
  332.  
  333.     // Check for my signature at the beginning of the message
  334.     if(recvbuf->hdr.signature != MYSIGNATURE)
  335.     {
  336.         // I've received some data that's in mid message--drop it
  337.         return FALSE;
  338.     }
  339.  
  340.     // Read size of message
  341.     msgsize = recvbuf->hdr.length;
  342.     readsize = msgsize - totalbytesread;
  343.  
  344.     while(totalbytesread < msgsize)
  345.     {
  346.         // we should only get hear for stream sockets
  347.         if((bytesread = recv(lpSockdat->sock,
  348.                              (char *)recvbuf + totalbytesread,
  349.                              readsize,
  350.                              0)) == SOCKET_ERROR)
  351.         {
  352.             if (WSAGetLastError() != WSAEWOULDBLOCK)
  353.             {
  354.                 // ERROR -- throw out message
  355.                 return FALSE;
  356.             }
  357.             // If you got a WSAWOULDBLOCK error, just keep trying...it shouldn't take
  358.             // too much longer for the rest of the message to get here.  Let's hope
  359.             // we don't hog the CPU so the data doesn't get to us.
  360.         }
  361.         totalbytesread += bytesread;
  362.         readsize -= bytesread;
  363.     }
  364.  
  365.     return TRUE;
  366. }
  367.  
  368. //---------------------------------------------------------------------------
  369. //
  370. // FUNCTION:    GetStringRes (int id INPUT ONLY)
  371. //
  372. // COMMENTS:    Load the resource string with the ID given, and return a
  373. //              pointer to it.  Notice that the buffer is common memory so
  374. //              the string must be used before this call is made a second time.
  375. //
  376. //---------------------------------------------------------------------------
  377.  
  378. LPTSTR GetStringRes (int id)
  379. {
  380.   static TCHAR buffer[MAX_PATH];
  381.  
  382.   buffer[0]=0;
  383.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  384.   return buffer;
  385. }
  386.  
  387.  
  388.