MISC.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:18k
源码类别:

Windows编程

开发平台:

Visual C++

  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. //    AtoH - Converts ascii to network order hex
  15. //    BtoH - Converts ascii byte to numeric
  16. //    deregistername - Notifies "Available" peers of clients non-availability
  17. //    senddatamessage - Sends a message to a client node
  18. //    recvdatamessage - reads an entire message
  19. //    UpdateClientList - Updates Client Status Listbox
  20. //    MakeServSock - Attempts to initialize socket for listening
  21. //
  22. //  COMMENTS:
  23. //
  24. //
  25. #include <windows.h>            // required for all Windows applications
  26. #include <windowsx.h>
  27. #include <nspapi.h>
  28. #include <svcguid.h>
  29. #include <wsipx.h>
  30. #include <wsnetbs.h>
  31. #include "globals.h"            // prototypes specific to this application
  32. //
  33. //  FUNCTION: CenterWindow(HWND, HWND)
  34. //
  35. //  PURPOSE:  Center one window over another.
  36. //
  37. //  PARAMETERS:
  38. //    hwndChild - The handle of the window to be centered.
  39. //    hwndParent- The handle of the window to center on.
  40. //
  41. //  RETURN VALUE:
  42. //
  43. //    TRUE  - Success
  44. //    FALSE - Failure
  45. //
  46. //  COMMENTS:
  47. //
  48. //    Dialog boxes take on the screen position that they were designed
  49. //    at, which is not always appropriate. Centering the dialog over a
  50. //    particular window usually results in a better position.
  51. //
  52. BOOL CenterWindow(HWND hwndChild, HWND hwndParent)
  53. {
  54.     RECT    rcChild, rcParent;
  55.     int     cxChild, cyChild, cxParent, cyParent;
  56.     int     cxScreen, cyScreen, xNew, yNew;
  57.     HDC     hdc;
  58.     // Get the Height and Width of the child window
  59.     GetWindowRect(hwndChild, &rcChild);
  60.     cxChild = rcChild.right - rcChild.left;
  61.     cyChild = rcChild.bottom - rcChild.top;
  62.     // Get the Height and Width of the parent window
  63.     GetWindowRect(hwndParent, &rcParent);
  64.     cxParent = rcParent.right - rcParent.left;
  65.     cyParent = rcParent.bottom - rcParent.top;
  66.     // Get the display limits
  67.     hdc = GetDC(hwndChild);
  68.     cxScreen = GetDeviceCaps(hdc, HORZRES);
  69.     cyScreen = GetDeviceCaps(hdc, VERTRES);
  70.     ReleaseDC(hwndChild, hdc);
  71.     // Calculate new X position, then adjust for screen
  72.     xNew = rcParent.left + ((cxParent - cxChild) / 2);
  73.     if (xNew < 0)
  74.     {
  75.         xNew = 0;
  76.     }
  77.     else if ((xNew + cxChild) > cxScreen)
  78.     {
  79.         xNew = cxScreen - cxChild;
  80.     }
  81.     // Calculate new Y position, then adjust for screen
  82.     yNew = rcParent.top  + ((cyParent - cyChild) / 2);
  83.     if (yNew < 0)
  84.     {
  85.         yNew = 0;
  86.     }
  87.     else if ((yNew + cyChild) > cyScreen)
  88.     {
  89.         yNew = cyScreen - cyChild;
  90.     }
  91.     // Set it, and return
  92.     return SetWindowPos(hwndChild,
  93.                         NULL,
  94.                         xNew, yNew,
  95.                         0, 0,
  96.                         SWP_NOSIZE | SWP_NOZORDER);
  97. }
  98. //
  99. //  FUNCTION: AtoH(char *, char *, int)
  100. //
  101. //  PURPOSE:  Converts ascii string to network order hex
  102. //
  103. //  PARAMETERS:
  104. //    src    - pointer to input ascii string
  105. //    dest   - pointer to output hex
  106. //    destlen - size of dest
  107. //
  108. //  COMMENTS:
  109. //
  110. //    2 ascii bytes make a hex byte so must put 1st ascii byte of pair
  111. //    into upper nibble and 2nd ascii byte of pair into lower nibble.
  112. //
  113. void AtoH(char * src, char * dest, int destlen)
  114. {
  115.     char * srcptr;
  116.     srcptr = src;
  117.     while(destlen--)
  118.     {
  119.     *dest = BtoH(*srcptr++) << 4;    // Put 1st ascii byte in upper nibble.
  120.     *dest++ += BtoH(*srcptr++);      // Add 2nd ascii byte to above.
  121.     }
  122. }
  123. //
  124. //  FUNCTION: BtoH(char *, char *, int)
  125. //
  126. //  PURPOSE:  Converts ascii byte to numeric
  127. //
  128. //  PARAMETERS:
  129. //    ch - ascii byte to convert
  130. //
  131. //  RETURNS:
  132. //    associated numeric value
  133. //
  134. //  COMMENTS:
  135. //
  136. //    Will convert any hex ascii digit to its numeric counterpart.
  137. //    Puts in 0xff if not a valid hex digit.
  138. //
  139. unsigned char BtoH(char ch)
  140. {
  141.     if (ch >= '0' && ch <= '9') return (ch - '0');        // Handle numerals
  142.     if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA);  // Handle capitol hex digits
  143.     if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA);  // Handle small hex digits
  144.     return(255);
  145. }
  146. //
  147. //  FUNCTION: deregistername(char *)
  148. //
  149. //  PURPOSE:  Removes client's availability from other "AVAILABLE" clients
  150. //
  151. //  PARAMETERS:
  152. //    name - name to deregister
  153. //
  154. //  RETURNS:
  155. //    nothing
  156. //
  157. //  COMMENTS:
  158. //
  159. //    Between the time when a client connects to the server and when it starts
  160. //    a chat, the client is in "AVAILABLE" state.  It keeps of list of other
  161. //    available peers.  deregistername removes a previously available client
  162. //    from the lists of all the other available clients
  163. //
  164. void deregistername(char * name)
  165. {
  166.     int j;
  167.     // Set up message header
  168.     xferbuf.hdr.signature = MYSIGNATURE;
  169.     xferbuf.hdr.length = REALLEN(name) + HDRSIZE;
  170.     xferbuf.hdr.command = DEREGISTER_NAME;
  171.     // Message data is simply the name
  172.     lstrcpy(xferbuf.data, name);
  173.     // Send to every connected client whose status is SOCKET_AVAILABLE
  174.     for (j = 0; j < NextFree; j++)
  175.     {
  176.         if (ConnectedSockets[j].status == SOCKSTAT_AVAILABLE)
  177.         {
  178.             senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  179.         }
  180.     }
  181.     return;
  182. }
  183. //
  184. //  FUNCTION: senddatamessage(SOCKET, LPDATAMSG)
  185. //
  186. //  PURPOSE:  Sends a message to a client
  187. //
  188. //  PARAMETERS:
  189. //    sock - Client socket to send data on
  190. //    sendbuf - message to send
  191. //
  192. //  RETURNS:
  193. //    TRUE - message sent
  194. //
  195. //  COMMENTS:
  196. //
  197. //    Performs send() until entire message is sent
  198. //
  199. BOOL senddatamessage (SOCKET sock, LPDATAMSG sendbuf)
  200. {
  201.     int totalbytes, bytessent;
  202.    int thissendsize;
  203.     bytessent = 0;                    // start count of bytessent
  204.     totalbytes = sendbuf->hdr.length; // read total bytes from message header
  205.     while(bytessent < totalbytes)
  206.     {
  207.         // We may not be able to send the entire message with a single
  208.       // send.  Therefore continue sending until the whole thing
  209.       // is gone.
  210.         if ((thissendsize = send(sock,
  211.                                 (char *)sendbuf + bytessent,
  212.                                 totalbytes - bytessent,
  213.                                 0)) == SOCKET_ERROR)
  214.       {
  215.            // Error
  216.           return FALSE;
  217.        }
  218.         bytessent += thissendsize;
  219.     }
  220.     return TRUE;
  221. }
  222. //
  223. //  FUNCTION: recvdatamessage(LPSOCKDATA, LPDATAMSG)
  224. //
  225. //  PURPOSE:  Receives a message from a client
  226. //
  227. //  PARAMETERS:
  228. //    lpSockdat - pointer to sockdata struct of socket we are receiving data on.
  229. //    recvbuf - buffer to receive data into.
  230. //
  231. //  RETURNS:
  232. //    TRUE - message received
  233. //    FALSE - message not received
  234. //
  235. //  COMMENTS:
  236. //    Performs recv() until entire message is received
  237. //
  238. BOOL recvdatamessage (LPSOCKDATA lpSockdat, LPDATAMSG recvbuf)
  239. {
  240.     int readsize, totalbytesread, msgsize, bytesread;
  241.     if (lpSockdat->type == SOCK_SEQPACKET)
  242.     {
  243.         // Message mode protocol!!  Just post one big read.
  244.         readsize = sizeof(*recvbuf);
  245.     }
  246.     else
  247.     {
  248.         // Stream mode protocol!!  Just read header...then read data (data size determined
  249.         // from header)
  250.         readsize = HDRSIZE;
  251.     }
  252.     if((totalbytesread = recv(lpSockdat->sock, (char *)recvbuf, readsize, 0)) == SOCKET_ERROR)
  253.     {
  254.         // ERROR  -- just return dropping message
  255.         return FALSE;
  256.     }
  257.     // Check for my signature at the beginning of the message
  258.     if(recvbuf->hdr.signature != MYSIGNATURE)
  259.     {
  260.         // I've received some data that's in mid message--drop it
  261.         return FALSE;
  262.     }
  263.     // Read size of message
  264.     msgsize = recvbuf->hdr.length;
  265.     readsize = msgsize - totalbytesread;
  266.     while(totalbytesread < msgsize)
  267.     {
  268.         // we should only get hear for stream sockets
  269.         if((bytesread = recv(lpSockdat->sock,
  270.                              (char *)recvbuf + totalbytesread,
  271.                              readsize,
  272.                              0)) == SOCKET_ERROR)
  273.         {
  274.             if (WSAGetLastError() != WSAEWOULDBLOCK)
  275.             {
  276.                 // ERROR -- throw out message
  277.                 return FALSE;
  278.             }
  279.             // If you got a WSAWOULDBLOCK error, just keep trying...it shouldn't take
  280.             // too much longer for the rest of the message to get here.  Let's hope
  281.             // we don't hog the CPU so the data doesn't get to us.
  282.         }
  283.         totalbytesread += bytesread;
  284.         readsize -= bytesread;
  285.     }
  286.     return TRUE;
  287. }
  288. //
  289. //  FUNCTION: UpdateClientList(char *, int, char *)
  290. //
  291. //  PURPOSE:  Updates Client Status List box
  292. //
  293. //  PARAMETERS:
  294. //    name - name of client to update
  295. //    status - status of client to display
  296. //    peername - connected peer for status = IN_SESSION
  297. //
  298. //  RETURNS:
  299. //    nothing
  300. //
  301. //  COMMENTS:
  302. //    Finds and updates client status in listbox, or adds
  303. //    it if client is new
  304. //
  305. void UpdateClientList(char * name, int status, char * peername)
  306. {
  307.     int index;
  308.     char outtext[80];
  309.     // Find list box entry with name in it
  310.     index = SendMessage(hwndClientList,
  311.                         LB_FINDSTRING,
  312.                         (WPARAM)-1,
  313.                         (LPARAM)name);
  314.     // Delete the entry--we'll add a new entry below
  315.     SendMessage(hwndClientList, LB_DELETESTRING, index, 0);
  316.     switch (status)
  317.     {
  318.         case SOCKSTAT_CLOSED:  // No new entry required.  Just return.
  319.             return;
  320.        case SOCKSTAT_AVAILABLE:  // build available entry
  321.             wsprintf(outtext, GetStringRes(IDS_AVAILABLE), name);
  322.        break;
  323.        case SOCKSTAT_INSESSION:  // build in_session entry
  324.             wsprintf(outtext, GetStringRes (IDS_SESSION), name, peername);
  325.        break;
  326.        case SOCKSTAT_REQSESSION: // build reqsession entry
  327.             wsprintf(outtext, GetStringRes(IDS_SESSION_SETUP), name, peername);
  328.     }
  329.    // Add the new list box entry to the client status list box
  330.     SendMessage(hwndClientList, LB_ADDSTRING, 0, (LPARAM)&outtext);
  331. }
  332. //
  333. //  FUNCTION: MakeServSock(HWND, LPSOCKDATA, LPPROTOCOL_INFO)
  334. //
  335. //  PURPOSE:  Attempts to initialize server side socket for listening
  336. //
  337. //  PARAMETERS:
  338. //    hwnd - handle to main window
  339. //    ServSocks - SOCKDATA struct to hold socket specific information
  340. //    lpProtBuf - PROTOCOL_INFO struct describing protocol to
  341. //                attempt listen on
  342. //
  343. //  RETURNS:
  344. //    TRUE - Listen successfully posted
  345. //    FALSE - Initialization failed
  346. //
  347. //  COMMENTS:
  348. //    Given the protocol triple in the PROTOCOL_INFO struct, we call
  349. //    socket(), then GetAddressByName(), then bind(), listen(), and
  350. //    finally WSAAsyncSelect() to get socket it appropriate state
  351. //    for listening.  If we fail at any point, then cleanup and do
  352. //    not use protocol
  353. //
  354. BOOL MakeServSock(HWND hwnd, LPSOCKDATA ServSocks, LPPROTOCOL_INFO lpProtBuf)
  355. {
  356.    CSADDR_INFO CSABuf[10];
  357.    DWORD dwCSABufsize = sizeof(CSABuf);
  358.    GUID guidNW =  SVCID_NETWARE(NWCHATID);  // Macro generates GUID using hard coded NetWare Service Type
  359.    GUID guidDNS = SVCID_TCP(DNSCHATID);    // Macro generates GUID using hard coded port
  360.    LPSOCKADDR_NB lpNBaddr;
  361.    // open socket using protocol defined by PROTOCOL_INFO structure
  362.    if ((ServSocks->sock = socket(lpProtBuf->iAddressFamily,
  363.                                        lpProtBuf->iSocketType,
  364.                                        lpProtBuf->iProtocol)) == SOCKET_ERROR)
  365.    {
  366.        // ERROR
  367.       return FALSE;  // This will reuse the current ServSocks structure
  368.    }
  369.    // Populate SOCKDATA structure
  370.    ServSocks->status = SOCKSTAT_INIT;
  371.    ServSocks->type = lpProtBuf->iSocketType;
  372.    ServSocks->protocol = lpProtBuf->iProtocol;
  373.    ServSocks->currconnects = 0;
  374.    ServSocks->lpProtocolName = lpProtBuf->lpProtocol;
  375.    // ***********************************************************************
  376.    //
  377.    //    Below we will be calling GetAddressByName with the RES_SERVICE
  378.    //    option in order to find the necessary sockaddr structure to use
  379.    //    for the following bind() call.  At this point, GetAddressByName()
  380.    //    only supports the DNS and the SAP/Bindery name spaces.  Ultimately
  381.    //    a single call to GetAddressByName will return information on
  382.    //    all available protocols, but this requires a central database
  383.    //    which is currently not available.  In the mean time we will make
  384.    //    name space specific calls to GetAddressByName.
  385.    //
  386.    // ***********************************************************************
  387.    switch (lpProtBuf->iAddressFamily)
  388.    {
  389.        case AF_IPX:
  390.            // Use SAP/Bindery Name Space
  391.            if (GetAddressByName(0,    // Since GUID is name space specific, we don't need to specify distinct name space.
  392.                                 &guidNW,  // GUID defined by NetWare service type.
  393.                                 "GLOBAL CHAT SERVER",  // This parameter is actually not used for RES_SERVICE calls.
  394.                                 NULL,    // Since GUID implies the protocol, we don't need to specify a distinct one.
  395.                                 RES_SERVICE,  // Specifies that we are just looking for local address to bind to.
  396.                                 NULL,   // Currently not supported
  397.                                 CSABuf, // Structure which will hold information for bind() call
  398.                                 &dwCSABufsize,  // Size of CSABuf
  399.                                 NULL,   //  Currently not supported
  400.                                 NULL)   // Currently not supported
  401.                                 < 1)    // We need at least one address returned in order to bind()
  402.            {
  403.                // Error--cleanup
  404.             closesocket(ServSocks->sock);
  405.             return FALSE;
  406.            }
  407.          // Copy sockaddr info and addresslength
  408.          memcpy(&ServSocks->addr, CSABuf[0].LocalAddr.lpSockaddr, sizeof(struct sockaddr));
  409.          ServSocks->addrlen = CSABuf[0].LocalAddr.iSockaddrLength;
  410.            break;
  411.       case AF_INET:
  412.            // Use DNS Name Space
  413.            if (GetAddressByName(0,   // Since GUID is name space specific, we don't need to specify
  414.                                 &guidDNS,  // GUID defined by TCP port number
  415.                                 "globchat",  // This parameter is actually not used for RES_SERVICE calls
  416.                                 NULL,    // GUID implies protocol so no need to specify
  417.                                 RES_SERVICE,  // Specifies that we are trying to find local address to bind to
  418.                                 NULL,  // Currently not supported
  419.                                 CSABuf, // Results buffer
  420.                                 &dwCSABufsize,   // Size of results buffer
  421.                                 NULL,    // Not supported
  422.                                 NULL)    // Not supported
  423.                                 < 1)   // Need at least one address returned in order to bind()
  424.            {
  425.                // Error -- cleanup
  426.             closesocket(ServSocks->sock);
  427.             return FALSE;
  428.            }
  429.          // Copy sockaddr info and address length
  430.          memcpy(&ServSocks->addr, CSABuf[0].LocalAddr.lpSockaddr, sizeof(struct sockaddr));
  431.          ServSocks->addrlen = CSABuf[0].LocalAddr.iSockaddrLength;
  432.            break;
  433.        case AF_NETBIOS:
  434.            // no netbios name space provider so we will simulate GetAddressByName() results
  435.          lpNBaddr = (LPSOCKADDR_NB)&ServSocks->addr;
  436.            SET_NETBIOS_SOCKADDR(lpNBaddr,
  437.                                 NETBIOS_GROUP_NAME,
  438.                                 "GLOBSERV",
  439.                                 0);
  440.          ServSocks->addrlen = lpProtBuf->iMaxSockAddr;
  441.            break;
  442.    }
  443.    // We have an address to bind() to, so do it!
  444.    if (bind(ServSocks->sock,
  445.             &ServSocks->addr,
  446.            ServSocks->addrlen) == SOCKET_ERROR)
  447.    {
  448.        // Error -- cleanup
  449.       closesocket(ServSocks->sock);
  450.       return FALSE;
  451.    }
  452.    // Find out the specific local address
  453.    if (getsockname(ServSocks->sock,
  454.                    &ServSocks->addr,
  455.                    &ServSocks->addrlen) == SOCKET_ERROR)
  456.    {
  457.        // Error -- better cleanup
  458.        closesocket(ServSocks->sock);
  459.       return FALSE;
  460.    }
  461.    // Listen on the socket
  462.    if (listen(ServSocks->sock, 5) == SOCKET_ERROR)
  463.    {
  464.        // Error -- cleanup
  465.        closesocket(ServSocks->sock);
  466.       return FALSE;
  467.    }
  468.    // Set up window message to indicate connection
  469.    if (WSAAsyncSelect(ServSocks->sock,
  470.                       hwnd,
  471.                      MW_CONNECTED,
  472.                   FD_ACCEPT) == SOCKET_ERROR)
  473.    {
  474.        // Error -- cleanup
  475.       closesocket(ServSocks->sock);
  476.       return FALSE;
  477.    }
  478.    // Success!!!
  479.    return TRUE;
  480. }
  481. //---------------------------------------------------------------------------
  482. //
  483. // FUNCTION:    GetStringRes (int id INPUT ONLY)
  484. //
  485. // COMMENTS:    Load the resource string with the ID given, and return a
  486. //              pointer to it.  Notice that the buffer is common memory so
  487. //              the string must be used before this call is made a second time.
  488. //
  489. //---------------------------------------------------------------------------
  490. LPTSTR GetStringRes (int id)
  491. {
  492.   static TCHAR buffer[MAX_PATH];
  493.   buffer[0]=0;
  494.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  495.   return buffer;
  496. }