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 / connect.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  22KB  |  618 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:   connect.c
  9. //
  10. //  PURPOSE:   Displays the "Connect" dialog box
  11. //
  12. //  FUNCTIONS:
  13. //    CmdConnect              - Displays the "Connect" dialog box
  14. //    Connect                 - Processes messages for "Connect" dialog box.
  15. //    MsgConnectInit          - Initializes edit controls
  16. //    MsgConnectReadyForWrite - Sends name registration message when connection
  17. //                              established with server
  18. //    MsgConnectCommand       - Process WM_COMMAND message sent to the connect box.
  19. //    CmdConnectDone          - Free the connect box and related data.
  20. //    CmdConnectNow           - Establishes connection to server.
  21. //    CmdConnectEnableOK      - Enables/Disables OK button when input data is
  22. //                              valid/invalid
  23. //
  24. //  COMMENTS:
  25. //
  26. //
  27.  
  28. #include <windows.h>            // required for all Windows applications
  29. #include <windowsx.h>
  30. #include <wsipx.h>              // IPX sockets
  31. #include <wsnetbs.h>            // NetBIOS sockets
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <nspapi.h>
  35. #include <svcguid.h>
  36. #include "globals.h"            // prototypes specific to this application
  37.  
  38. #define WSN_READYFORWRITE   700 // dlg window message indicating the connection is ready to send on
  39.  
  40. //   Function Definitions
  41.  
  42. LRESULT CALLBACK Connect(HWND, UINT, WPARAM, LPARAM);
  43. LRESULT MsgConnectInit(HWND, UINT, WPARAM, LPARAM);
  44. LRESULT MsgConnectReadyForWrite(HWND, UINT, WPARAM, LPARAM);
  45. LRESULT MsgConnectCommand(HWND, UINT, WPARAM, LPARAM);
  46. LRESULT CmdConnectNow(HWND, WORD, WORD, HWND);
  47. LRESULT CmdConnectDone(HWND, WORD, WORD, HWND);
  48. LRESULT CmdConnectEnableOK(HWND, WORD, WORD, HWND);
  49.  
  50. // Connect dialog message table definition.
  51. MSD rgmsdConnect[] =
  52. {
  53.     {WM_COMMAND,        MsgConnectCommand},
  54.     {WM_INITDIALOG,     MsgConnectInit},
  55.     {WSN_READYFORWRITE,  MsgConnectReadyForWrite}
  56. };
  57.  
  58. MSDI msdiConnect =
  59. {
  60.     sizeof(rgmsdConnect) / sizeof(MSD),
  61.     rgmsdConnect,
  62.     edwpNone
  63. };
  64.  
  65. // Connect dialog command table definition.
  66. CMD rgcmdConnect[] =
  67. {
  68.     {IDOK,        CmdConnectNow},
  69.     {IDCANCEL,    CmdConnectDone},
  70.     {CD_NAME,     CmdConnectEnableOK},
  71.     {CD_PROTOCOL, CmdConnectEnableOK},
  72.    {CD_SERVER,   CmdConnectEnableOK}
  73. };
  74.  
  75. CMDI cmdiConnect =
  76. {
  77.     sizeof(rgcmdConnect) / sizeof(CMD),
  78.     rgcmdConnect,
  79.     edwpNone
  80. };
  81.  
  82. // Module specific "globals"  Used when a variable needs to be
  83. // accessed in more than one handler function.
  84.  
  85. HFONT hfontDlg;
  86.  
  87. //
  88. //  FUNCTION: CmdConnect(HWND, WORD, WORD, HWND)
  89. //
  90. //  PURPOSE: Displays the "Connect" dialog box
  91. //
  92. //  PARAMETERS:
  93. //    hwnd      - Window handle
  94. //    wCommand  - IDM_CONNECT (unused)
  95. //    wNotify   - Notification number (unused)
  96. //    hwndCtrl  - NULL (unused)
  97. //
  98. //  RETURN VALUE:
  99. //
  100. //    Always returns 0 - Message handled
  101. //
  102. //  COMMENTS:
  103. //    To process the IDM_CONNECT message, call DialogBox() to display the
  104. //    Connect dialog box.
  105.  
  106. LRESULT CmdConnect(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  107. {
  108.  
  109.     // Start dialog box
  110.     if(DialogBox(hInst, "ConnectBox", hwnd, (DLGPROC)Connect))
  111.     {
  112.         // We have a connection and have registered our name.  Set up Select dialog.
  113.         PostMessage(hwnd, WM_COMMAND, MAKELONG(IDM_SELECT,0), 0);
  114.         return 0;
  115.     }
  116.  
  117.     // Connection failed - reset window title
  118.     SetWindowText(hwnd, szTitle);
  119.     return 0;
  120. }
  121.  
  122.  
  123. //
  124. //  FUNCTION: Connect(HWND, UINT, WPARAM, LPARAM)
  125. //
  126. //  PURPOSE:  Processes messages for "Connect" dialog box.
  127. //
  128. //  PARAMETERS:
  129. //    hdlg - window handle of the dialog box
  130. //    wMessage - type of message
  131. //    wparam - message-specific information
  132. //    lparam - message-specific information
  133. //
  134. //  RETURN VALUE:
  135. //    TRUE - message handled
  136. //    FALSE - message not handled
  137. //
  138. //  COMMENTS:
  139. //
  140. //     Gets connection information from user and then establishes a connection.
  141. //
  142. //     Connect when user clicks on the OK button.  Kill Dialog when connection
  143. //     established.
  144. //
  145.  
  146. LRESULT CALLBACK Connect(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  147. {
  148.     return DispMessage(&msdiConnect, hdlg, uMessage, wparam, lparam);
  149. }
  150.  
  151.  
  152. //
  153. //  FUNCTION: MsgConnectInit(HWND, UINT, WPARAM, LPARAM)
  154. //
  155. //  PURPOSE: To center dialog, limit size of edit controls, and set up available protocols
  156. //           to connect with
  157. //
  158. //  PARAMETERS:
  159. //    hdlg - The window handling the message.
  160. //    uMessage - The message number. (unused).
  161. //    wparam - Message specific data (unused).
  162. //    lparam - Message specific data (unused).
  163. //
  164. //  RETURN VALUE:
  165. //    Always returns 0 - message handled.
  166. //
  167. //  COMMENTS:
  168. //    Set size of edit controls for the following
  169. //           Network  8  chars (4 2-digit hex numbers)
  170. //           Node     12 chars (6 2-digit hex numbers)
  171. //           Socket   4  chars (2 2-digit hex numbers)
  172. //
  173.  
  174. LRESULT MsgConnectInit(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  175. {
  176.     int numStrucs;
  177.     int j, k;
  178.     int iProtBufSize = 0;
  179.    char outtext[80];
  180.  
  181.     // Create a font to use
  182.     hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  183.                           VARIABLE_PITCH | FF_SWISS, "");
  184.  
  185.     // Center the dialog over the application window
  186.     CenterWindow (hdlg, GetWindow (hdlg, GW_OWNER));
  187.  
  188.    // Call EnumProtocols with NULL buffer in order to determine size of buffer required
  189.    EnumProtocols(NULL, NULL, &iProtBufSize);
  190.  
  191.     if (((LPVOID)lpProtBuf = VirtualAlloc(NULL,
  192.                                           iProtBufSize,
  193.                                           MEM_COMMIT,
  194.                                           PAGE_READWRITE)) == NULL)
  195.     {
  196.         // ERROR -- abort
  197.         return 0;
  198.     }
  199.  
  200.     // Calling EnumProtocols with large enough buffer
  201.     if ((numStrucs = EnumProtocols(NULL, lpProtBuf, &iProtBufSize)) == SOCKET_ERROR)
  202.     {
  203.         // Error -- abort
  204.         return 0;
  205.     }
  206.  
  207.    // Add every connection oriented protocol to protocol combo box
  208.     for (j = 0, k = 0; j < numStrucs; j++)
  209.     {
  210.         if ((lpProtBuf[j].dwServiceFlags & XP_CONNECTIONLESS) == 0)
  211.         {
  212.          wsprintf(outtext, "%2d: %s", k, lpProtBuf[j].lpProtocol);
  213.             SendMessage(GetDlgItem(hdlg, CD_PROTOCOL), CB_ADDSTRING, 0, (LPARAM)outtext);
  214.             goodprots[k++] = j; // Keep track of good protocols
  215.         }
  216.     }
  217.  
  218.     // Limit size of edit controls
  219.     SendDlgItemMessage(hdlg, CD_NAME, EM_LIMITTEXT, 15, 0);
  220.  
  221.     // Initialize Edit Controls
  222.     SetDlgItemText(hdlg, CD_NAME, szConnectName);
  223.  
  224.     return (TRUE);
  225. }
  226.  
  227. //
  228. //  FUNCTION: MsgConnectReadyForWrite(HWND, UINT, WPARAM, LPARAM)
  229. //
  230. //  PURPOSE: Receive notification of connected socket and register name
  231. //
  232. //  PARAMETERS:
  233. //    hwnd - The window handing the message.
  234. //    uMessage - The message number. (unused).
  235. //    wparam - Message specific data (unused).
  236. //    lparam - Message specific data (unused).
  237. //
  238. //  RETURN VALUE:
  239. //    Always returns 0 - message handled.
  240. //
  241. //  COMMENTS:
  242. //    Uses this DispCommand function defined in wndproc.c combined
  243. //    with the cmdiConnect structure defined in this file to handle
  244. //    the command messages for the Connect dialog box.
  245. //
  246.  
  247. LRESULT MsgConnectReadyForWrite(HWND   hwnd,
  248.                                 UINT   uMessage,
  249.                                 WPARAM wparam,
  250.                                 LPARAM lparam)
  251. {
  252.     char outtext[80];
  253.  
  254.     // Build our name
  255.     GetDlgItemText(hwnd, CD_NAME, MySock.name, sizeof(MySock.name));
  256.  
  257.     // Build name registration packet
  258.     xferbuf.hdr.signature = MYSIGNATURE;                 // signature
  259.     xferbuf.hdr.length = REALLEN(MySock.name) + HDRSIZE;
  260.     lstrcpy(xferbuf.data, MySock.name);                  // copy name
  261.     xferbuf.hdr.command = REGISTER_NAME;                 // REGISTER_NAME command
  262.  
  263.     // Lets send it
  264.     senddatamessage(MySock.sock, &xferbuf);
  265.  
  266.     wsprintf(outtext, GetStringRes(IDS_CHAT_AVAIL), MySock.name);
  267.  
  268.     SetWindowText(GetParent(hwnd), outtext);
  269.  
  270.     EndDialog(hwnd, TRUE);          // Exit the dialog
  271.     DeleteObject (hfontDlg);
  272.     return (TRUE);
  273. }
  274.  
  275. //
  276. //  FUNCTION: MsgConnectCommand(HWND, UINT, WPARAM, LPARAM)
  277. //
  278. //  PURPOSE: Process WM_COMMAND message sent to the Connect box.
  279. //
  280. //  PARAMETERS:
  281. //    hwnd - The window handing the message.
  282. //    uMessage - The message number. (unused).
  283. //    wparam - Message specific data (unused).
  284. //    lparam - Message specific data (unused).
  285. //
  286. //  RETURN VALUE:
  287. //    Always returns 0 - message handled.
  288. //
  289. //  COMMENTS:
  290. //    Uses this DispCommand function defined in wndproc.c combined
  291. //    with the cmdiConnect structure defined in this file to handle
  292. //    the command messages for the Connect dialog box.
  293. //
  294.  
  295. LRESULT MsgConnectCommand(HWND   hwnd,
  296.                           UINT   uMessage,
  297.                           WPARAM wparam,
  298.                           LPARAM lparam)
  299. {
  300.     return DispCommand(&cmdiConnect, hwnd, wparam, lparam);
  301. }
  302.  
  303. //
  304. //  FUNCTION: CmdConnectDone(HWND, WORD, HWND)
  305. //
  306. //  PURPOSE: Free the Connect box and related data.
  307. //
  308. //  PARAMETERS:
  309. //    hdlg - The window handling the command.
  310. //    wCommand - The command to be handled (unused).
  311. //    wNotify   - Notification number (unused)
  312. //    hwndCtrl - NULL (unused).
  313. //
  314. //  RETURN VALUE:
  315. //    Always returns TRUE.
  316. //
  317. //  COMMENTS:
  318. //    Cleans up sockets then calls EndDialog to finish the dialog session.
  319. //
  320.  
  321. LRESULT CmdConnectDone(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  322. {
  323.  
  324.     closesocket(MySock.sock);      // Free any aborted socket resources
  325.     EndDialog(hdlg, FALSE);        // Exit Dialog -- rtrn false since no connection
  326.     return TRUE;
  327. }
  328.  
  329. //
  330. //  FUNCTION: CmdConnectNow(HWND, WORD, HWND)
  331. //
  332. //  PURPOSE: Establish the connection
  333. //
  334. //  PARAMETERS:
  335. //    hdlg - The window handling the command.
  336. //    wCommand - The command to be handled (unused).
  337. //    wNotify   - Notification number (unused)
  338. //    hwndCtrl - NULL (unused).
  339. //
  340. //  RETURN VALUE:
  341. //    Always returns TRUE.
  342. //
  343. //  COMMENTS:
  344. //    Makes Connection calls
  345. //
  346.  
  347. LRESULT CmdConnectNow(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  348. {
  349.     int iIndex;
  350.     char outtext[80];
  351.     int numStrucs;
  352.    GUID guidNW = SVCID_NETWARE(NWCHATID);
  353.    GUID guidDNS = SVCID_TCP(DNSCHATID);
  354.  
  355.     // Get protocol selected
  356.     iIndex = SendMessage(GetDlgItem(hdlg, CD_PROTOCOL), CB_GETCURSEL, 0, 0);
  357.  
  358.    // ************************************************************************
  359.    //
  360.    //    Below we will be calling GetAddressByName with the RES_FIND_MULTIPLE
  361.    //    option in order to find a remote address to connect() to.  At this
  362.    //    point, GetAddressByName() only supports the DNS and the SAP/Bindery
  363.    //    name spaces.  Ultimately a single call to GetAddressByName will
  364.    //    query all available protocols and name spaces, but this requires a
  365.    //    central database which is currently not available.  In the mean time
  366.    //    we will make name space specific calls to GetAddressByName.
  367.    //
  368.    // ***********************************************************************
  369.  
  370.     switch (lpProtBuf[goodprots[iIndex]].iAddressFamily)
  371.     {
  372.         case AF_IPX:
  373.           //  SAP/Bindery Name Space
  374.           dwCSABufsize = sizeof(CSABuf);
  375.             if (((numStrucs = GetAddressByName(0,  // GUID indicates name space so we don't need to specify
  376.                                                &guidNW, // GUID generated from NetWare service type
  377.                                                "GLOBCHAT", // Name of service to look for
  378.                                                NULL, // GUID implies IPX/SPX protocols
  379.                                                RES_FIND_MULTIPLE, // We might get multiple responses
  380.                                                NULL, // Not currently supported
  381.                                                CSABuf, // results buffer
  382.                                                &dwCSABufsize,  // size of results buffer
  383.                                                NULL,  // not supported
  384.                                                NULL)  // not supported
  385.                                                ) == SOCKET_ERROR) || (numStrucs == 0))
  386.             {
  387.                 // Error -- try another protocol.  We've got lots!
  388.  
  389.                 MessageBox(hdlg, GetStringRes(IDS_ERR_SERVER_NOT_FOUND), NULL, MB_OK);
  390.                 EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  391.                 SetFocus(GetDlgItem(hdlg, CD_PROTOCOL));
  392.                 return 0;
  393.             }
  394.             break;
  395.  
  396.         case AF_INET:
  397.             //  DNS Name Space
  398.  
  399.             // Static Name Space requires us to specify the host name
  400.             GetDlgItemText(hdlg, CD_SERVER, lpServName, sizeof(lpServName));
  401.          dwCSABufsize = sizeof(CSABuf);
  402.             if (((numStrucs = GetAddressByName(0,    // GUID indicates name space so we don't need to specify
  403.                                              &guidDNS, // GUID generated from TCP port number
  404.                                              lpServName, // Name of host to look for
  405.                                              NULL, // GUID implies UDP/TCP protocols
  406.                                              RES_FIND_MULTIPLE, // We might get multiple responses
  407.                                              NULL, // Not currently supported
  408.                                              CSABuf, // results buffer
  409.                                              &dwCSABufsize, // size of results buffer
  410.                                              NULL, // not supported
  411.                                              NULL) // not supported
  412.                                              ) == SOCKET_ERROR) || (numStrucs == 0))
  413.             {
  414.                 // Error -- try another protocol.  We've got lots!
  415.  
  416.                 MessageBox(hdlg, GetStringRes(IDS_ERR_SERVER_NOT_FOUND), NULL, MB_OK);
  417.  
  418.                 EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  419.                 SetFocus(GetDlgItem(hdlg, CD_PROTOCOL));
  420.                 return 0;
  421.             }
  422.             break;
  423.  
  424.         case AF_NETBIOS:
  425.          // NetBIOS name space???
  426.  
  427.             // no netbios name space provider so fill in lpCSABuf ourselves
  428.             numStrucs = 1;
  429.             CSABuf[0].iSocketType = lpProtBuf[goodprots[iIndex]].iSocketType;
  430.             CSABuf[0].iProtocol = lpProtBuf[goodprots[iIndex]].iProtocol;
  431.  
  432.             SET_NETBIOS_SOCKADDR(&NBAddr,
  433.                                  NETBIOS_GROUP_NAME,
  434.                                  "GLOBSERV",
  435.                                  0);
  436.            CSABuf[0].RemoteAddr.lpSockaddr = (LPSOCKADDR)&NBAddr;
  437.          CSABuf[0].RemoteAddr.iSockaddrLength = sizeof(NBAddr);
  438.             break;
  439.  
  440.         default:
  441.           // We don't support anything else
  442.             MessageBox(hdlg,
  443.                        GetStringRes(IDS_ERR_NAMESPACE_NOT_SUPPORTED),
  444.                        NULL, MB_OK);
  445.  
  446.             EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  447.             SetFocus(GetDlgItem(hdlg, CD_PROTOCOL));
  448.             return 0;
  449.     }
  450.  
  451.    // Populate SOCKDATA struct
  452.     MySock.type = lpProtBuf[goodprots[iIndex]].iSocketType;
  453.     MySock.protocol = lpProtBuf[goodprots[iIndex]].iProtocol;
  454.  
  455.     SetDlgItemText(hdlg, CD_HELP, GetStringRes(IDS_CALLING_SOCKET));
  456.  
  457.    // Call socket() using triple provided by EnumProtocols()
  458.     if((MySock.sock = socket(lpProtBuf[goodprots[iIndex]].iAddressFamily,
  459.                              lpProtBuf[goodprots[iIndex]].iSocketType,
  460.                              lpProtBuf[goodprots[iIndex]].iProtocol)) == INVALID_SOCKET)
  461.     {
  462.         // ERROR
  463.         wsprintf(outtext, GetStringRes(IDS_ERR_SOCKET_FAILED), WSAGetLastError());
  464.         SetDlgItemText(hdlg, CD_HELP, outtext);
  465.         return 0;
  466.     }
  467.  
  468.     SetDlgItemText(hdlg, CD_HELP, GetStringRes(IDS_CALLING_CONNECT));
  469.  
  470.    // Call connect() using info from GetAddressByName()
  471.     if (connect(MySock.sock,
  472.                 CSABuf[0].RemoteAddr.lpSockaddr,
  473.                 CSABuf[0].RemoteAddr.iSockaddrLength) == SOCKET_ERROR)
  474.     {
  475.         // ERROR
  476.         wsprintf(outtext,
  477.                  GetStringRes(IDS_ERR_CONNECT_FAILED), WSAGetLastError());
  478.  
  479.         SetDlgItemText(hdlg, CD_HELP, outtext);
  480.         return 0;
  481.     }
  482.  
  483.     // Signal for when we are ready for writing
  484.  
  485.     SetDlgItemText(hdlg, CD_HELP, GetStringRes(IDS_WAITING_FOR_ACCEPT));
  486.  
  487.    // Specify message to signal accepted socket
  488.     if (WSAAsyncSelect(MySock.sock, hdlg, WSN_READYFORWRITE, FD_WRITE) == SOCKET_ERROR)
  489.     {
  490.         wsprintf(outtext,
  491.                  GetStringRes(IDS_ERR_WSAASYNCSELECT), WSAGetLastError());
  492.  
  493.         SetDlgItemText(hdlg, CD_HELP, outtext);
  494.         return 0;
  495.     }
  496.     return 0;
  497.  
  498. }
  499.  
  500. //
  501. //  FUNCTION: CmdConnectEnableOK(HWND, WORD, WORD, HWND)
  502. //
  503. //  PURPOSE: Enable/Disable OK button when input data is valid/invalid
  504. //
  505. //  PARAMETERS:
  506. //    hdlg - The window handling the command.
  507. //    wCommand - The command to be handled (unused).
  508. //    wNotify   - Notification number (unused)
  509. //    hwndCtrl - NULL (unused).
  510. //
  511. //  RETURN VALUE:
  512. //    Always returns TRUE.
  513. //
  514. //  COMMENTS:
  515. //    Checks for acceptable name and protocol.  We also need an acceptable
  516. //    machine name for TCP/IP protocol since DNS name space is static
  517. //
  518.  
  519. LRESULT CmdConnectEnableOK(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  520. {
  521.     char buf[128];
  522.    int iIndex;
  523.  
  524.     // Is message a change notification?
  525.     if ((wNotify == CBN_SELCHANGE) || (wNotify == EN_CHANGE))
  526.     {
  527.         // Yes!, get protocol
  528.         iIndex = SendMessage(GetDlgItem(hdlg, CD_PROTOCOL), CB_GETCURSEL, 0, 0);
  529.       if (iIndex == LB_ERR)
  530.       {
  531.           // No protocol selected...OK disabled
  532.           EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  533.           return TRUE;
  534.       }
  535.         // Protocol selected!  Check which one...
  536.         switch(lpProtBuf[goodprots[iIndex]].iAddressFamily)
  537.         {
  538.             case AF_IPX:
  539.             case AF_NETBIOS:
  540.                 // For IPX and NetBIOS, we don't need the machine name
  541.             // so hide that edit control
  542.                 ShowWindow(GetDlgItem(hdlg, CD_SERVER), SW_HIDE);
  543.                 ShowWindow(GetDlgItem(hdlg, CD_SERVER_TEXT), SW_HIDE);
  544.  
  545.             // We already have a protocol selected.  Do we have a name?
  546.                 if(GetDlgItemText(hdlg, CD_NAME, buf, sizeof(buf)) >= 1)
  547.                 {
  548.                     // Yes, we have a name and a protocol.  Enable OK.
  549.                     EnableWindow(GetDlgItem(hdlg, IDOK), TRUE);
  550.                 }
  551.             else
  552.             {
  553.                 // We don't have a name.  Disable OK.
  554.                 EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  555.             }
  556.                 return TRUE;
  557.  
  558.             case AF_INET:
  559.              // For TCP/IP we need a protocol, name, and machine name
  560.             // in order for data to be valid
  561.  
  562.             // Enable Machine name edit control and text
  563.                 ShowWindow(GetDlgItem(hdlg, CD_SERVER), SW_SHOW);
  564.             ShowWindow(GetDlgItem(hdlg, CD_SERVER_TEXT), SW_SHOW);
  565.             EnableWindow(GetDlgItem(hdlg, CD_SERVER), TRUE);
  566.             EnableWindow(GetDlgItem(hdlg, CD_SERVER_TEXT), TRUE);
  567.  
  568.                 // We have a protocol selected.  Do we have a name and a server name
  569.                 if((GetDlgItemText(hdlg, CD_NAME, buf, sizeof(buf)) >= 1) &&
  570.                    (GetDlgItemText(hdlg, CD_SERVER, buf, sizeof(buf)) >= 1))
  571.                 {
  572.                     // YES!  Enable OK.
  573.                     EnableWindow(GetDlgItem(hdlg, IDOK), TRUE);
  574.                SendMessage(GetDlgItem(hdlg, IDOK), BM_SETSTYLE, (WPARAM) LOWORD(BS_DEFPUSHBUTTON), MAKELPARAM(TRUE, 0));
  575.                 }
  576.             else
  577.             {
  578.                 // No name or server name.  Disable OK.
  579.                 EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  580.             }
  581.                 return TRUE;
  582.  
  583.             default:
  584.                 // We only support DNS, SAP/Bindery, and we simulate NetBIOS name spaces.
  585.  
  586.                 SetDlgItemText(hdlg, CD_HELP,
  587.                                GetStringRes(IDS_ERR_UNSUPPORTED_PROTOCOL));
  588.  
  589.                 EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
  590.                 return TRUE;
  591.         }
  592.     }
  593.  
  594.     // When protocol combo box gets the focus, set help text at bottom of dialog
  595.     if (wNotify == CBN_SETFOCUS)
  596.     {
  597.         SetDlgItemText(hdlg, CD_HELP,
  598.                        GetStringRes(IDS_SELECT_PROTOCOL));
  599.     }
  600.  
  601.     if (wNotify == EN_SETFOCUS)
  602.     {
  603.         if (hwndCtrl == GetDlgItem(hdlg, CD_NAME))
  604.         {
  605.             // When name edit control gets the focus, set help text at bottom of dialog.
  606.  
  607.             SetDlgItemText(hdlg, CD_HELP, GetStringRes(IDS_ENTER_NAME));
  608.         }
  609.         else
  610.         {
  611.             // When server edit control gets the focus, set help text at bottom of dialog.
  612.  
  613.             SetDlgItemText(hdlg, CD_HELP, GetStringRes(IDS_ENTER_MACHINE_NAME));
  614.         }
  615.     }
  616.     return TRUE;
  617. }
  618.