home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / sna / tpsetup / install.c < prev    next >
Text File  |  1997-04-09  |  46KB  |  1,327 lines

  1. /*************************************************************************\
  2. *
  3. * TP Installer
  4. *
  5. * This program brings up a dialog box that prompts for TP configuration
  6. * information.  The information is then placed in the registry under
  7. * Windows NT, and in the WIN.INI file under Windows.  The WIN32 compiler
  8. * flag specifies the NT version, while the WINDOWS flag specifies the
  9. * Windows version.
  10. *
  11. * 6/93 Initial coding    ARK
  12. *
  13. \*************************************************************************/
  14.  
  15. #define STRICT
  16. #include <windows.h>
  17. #ifdef WIN32
  18. #include <winsvc.h>
  19. #endif
  20.  
  21. #ifdef        WIN32
  22.         #include <windowsx.h>
  23.  
  24. BOOL IsWin95Client( void );
  25.  
  26. #else
  27.         #include <windowsx.h16>
  28. #endif
  29.  
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <stdarg.h>
  34. #include "install.h"
  35.  
  36. HANDLE  hInst;                       // This program's instance
  37. HWND    hDialog;                     // Global handle to main dialog
  38. HWND    hTimeout;                    // A handle to the "timeout" window
  39. HWND    hList;                       // Handle to the "users" list box
  40.  
  41. WNDPROC lPrevWndProcInt = NULL,      // Holds original integer edit box window proc
  42.         lPrevWndProcAppc = NULL,     // Holds original APPC edit box window proc
  43.         lPrevWndProcInfinite = NULL, // Original window proc for "infinite"
  44.                                      // radio button
  45.         lPrevWndProcConvSec = NULL,  // Same for "conversation security" box
  46.         lPrevWndProcService = NULL;  // Same for "service" box
  47.  
  48. FARPROC lpfnInt = NULL,              // Pointer to the ValidateFieldInt
  49.                                      // procedure; becomes non-NULL upon
  50.                                      // initialization in ValidateField().
  51.         lpfnAppc = NULL;         // Pointer to ValidateFieldAppc procedure
  52.  
  53.  
  54.  
  55. /*************************************************************************\
  56. *
  57. *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  58. *
  59. *  PURPOSE: Creates the dialog box.
  60. *
  61. *  COMMENTS:
  62. *
  63. \*************************************************************************/
  64.  
  65. int PASCAL WinMain (HINSTANCE hInstance,
  66.                       HINSTANCE hPrevInstance,
  67.                       LPSTR     lpCmdLine,
  68.                       int       nCmdShow)
  69. {
  70.   DWORD retCode;
  71.   FARPROC lpfn;
  72.  
  73.   hInst   = hInstance;
  74.  
  75.   lpfn = (FARPROC) MakeProcInstance( (FARPROC)MainDlgProc, hInst);
  76.   retCode = DialogBoxParam ((HANDLE)hInst,
  77.                             (LPCSTR)"MainDlg",
  78.                             NULL,
  79.                             (DLGPROC) lpfn,
  80.                             0);
  81.   FreeProcInstance(lpfn);
  82.  
  83.   return  (retCode);
  84. }
  85. /************************************************************************/
  86. /*
  87.  *  MainDlgProc: Handle messages to the main dialog.
  88.  *  Note:  Under Windows NT, installation consists of creating a service
  89.  *         and creating some keys in the registry, while under Windows
  90.  *         we instead add slightly different information to the WIN.INI file.
  91.  *         So two different dialogs are necessary for the different operating
  92.  *         systems.  Appropriate sections of the procedure below are
  93.  *         #ifdef'ed to handle parts of the installation that are unique
  94.  *         to a particular operating system.
  95.  */
  96. /************************************************************************/
  97. BOOL CALLBACK MainDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  98.   {
  99.   static   HWND hInfinite;
  100.   char     *lpPathName, *lpTPName, *lpParameters, *lpTimeout, *lpLocalLUName;
  101.   char     *divider;
  102.   FARPROC  lpfn;
  103.   INT      nIndex, cmd;
  104.   BOOL     bService;
  105.   HWND       hwndCntl;
  106. #ifdef WIN32
  107.   DWORD       dwVersion;
  108.   HANDLE   hEvent;
  109. #endif
  110.  
  111.   switch (wMsg)
  112.     {
  113.       case WM_INITDIALOG:
  114.         hDialog = hDlg;
  115.  
  116.         // Set maximum pathname to 512 characters
  117.         SendMessage(GetDlgItem(hDlg, IDE_PATHNAME),
  118.                     EM_LIMITTEXT, MAXBINPATHLEN, 0);
  119.  
  120.         // Set maximum TP name to 128 characters
  121.         SendMessage(GetDlgItem(hDlg, IDE_TPNAME),
  122.                     EM_LIMITTEXT, MAXTPLEN, 0);
  123.  
  124.         // Default for timeout is "infinite"
  125.         CheckRadioButton(hDlg, IDD_FINITE, IDD_INFINITE, IDD_INFINITE);
  126.  
  127.         hTimeout = GetDlgItem(hDlg, IDE_TIMEOUT);
  128.         hList = GetDlgItem(hDlg, IDC_LIST);
  129.  
  130.         // Allow only numbers to be typed into the timeout box.
  131.         ValidateField(hTimeout, VALIDATE_INT);
  132.  
  133.         // Set maximum length of number to be a few digits
  134.         SendMessage(hTimeout, EM_LIMITTEXT, MAXTIMEOUTLEN, 0);
  135.  
  136.         // Allow only legal characters in "Local LU Alias" box:
  137.         ValidateField(GetDlgItem(hDlg, IDE_LOCALLU), VALIDATE_APPC);
  138.  
  139.         // Set maximum length of LU name to be 8 characters
  140.         SendMessage(GetDlgItem(hDlg, IDE_LOCALLU), EM_LIMITTEXT, MAXLULEN, 0);
  141.  
  142.         // Put an initial value in the "timeout" box & grey it out
  143.         SetDlgItemInt(hDlg, IDE_TIMEOUT, INIT_TIMEOUT, FALSE);
  144.         EnableWindow(hTimeout, FALSE);
  145.  
  146.         // Set callback procedure for radiobutton to make the timeout box
  147.         // sensitive only when "finite" is selected.
  148.         InstallCallback(hDlg, IDD_INFINITE, &lPrevWndProcInfinite, (FARPROC)InfiniteWndProc);
  149.  
  150.         // Set callback for "conversation security" to grey out user group
  151.         // box when it's turned off.
  152.         InstallCallback(hDlg, IDC_CONVSEC, &lPrevWndProcConvSec, (FARPROC)ConvSecWndProc);
  153.         // Uncheck conversation security to force grey out of user group box
  154.         SendMessage(GetDlgItem(hDlg, IDC_CONVSEC), BM_SETCHECK, 0, 0L);
  155.  
  156. #ifdef WIN32
  157.         //
  158.         // On Win95 don't allow TP to be configured as an NT service
  159.         //
  160.         dwVersion = GetVersion();
  161.         if( dwVersion < 0x80000000 &&        // Windows NT
  162.             !IsWin95Client() )                // Not Win95 client
  163.         {
  164.             // Set callback for "service" to grey out queued
  165.             // box when it's turned on.
  166.             InstallCallback(hDlg, IDC_SERVICE, &lPrevWndProcService, (FARPROC)ServiceWndProc);
  167.  
  168.             // Default for serviec is "yes"
  169.             CheckDlgButton(hDlg, IDC_SERVICE, 1);
  170.         }
  171.         else    // Non-NT or Win95 client on NT
  172.         {
  173.             // Default for service is "no"
  174.             CheckDlgButton(hDlg, IDC_SERVICE, 0);
  175.  
  176.             // Disable the whole service option
  177.             hwndCntl = GetDlgItem( hDialog, IDC_SERVICE );
  178.             EnableWindow( hwndCntl, FALSE );
  179.         }
  180. #endif
  181.  
  182.         // Default for queued is "yes"
  183.         CheckDlgButton(hDlg, IDC_QUEUED, 1);
  184.  
  185.         return TRUE;
  186.  
  187.       case WM_COMMAND:
  188.         switch (cmd = GET_WM_COMMAND_ID(wParam, lParam))
  189.           {
  190.             case IDOK:
  191.               // User hits OK; we get relevant info & try to install.
  192.  
  193.               // If TP name field is blank, error out
  194.               if (ReadString(hDlg, IDE_TPNAME, &lpTPName, MAXTPLEN) == 0)
  195.                 {
  196.                   DisplayError(hDlg, IDS_BADTPNAME);
  197.                   free(lpTPName);
  198.                   return TRUE;
  199.                 }
  200.  
  201.               // read path name
  202.               ReadString(hDlg, IDE_PATHNAME, &lpPathName, MAXBINPATHLEN);
  203.  
  204.               // read Local LU Alias
  205.               ReadString(hDlg, IDE_LOCALLU, &lpLocalLUName, MAXLULEN);
  206.  
  207.               // Get "timeout" value
  208.               if (IsDlgButtonChecked(hDlg, IDD_INFINITE) == 1)
  209.                 lpTimeout = INFINITE_TIMEOUT;
  210.               else
  211.                 {
  212.                   // Number must be filled in, or else we complain
  213.                   if (ReadString(hDlg, IDE_TIMEOUT, &lpTimeout, MAXTIMEOUTLEN + 3)
  214.                       == 0)
  215.                     {
  216.                       DisplayError(hDlg, IDS_BADTIMEOUT);
  217.                       free(lpPathName);
  218.                       free(lpTimeout);
  219.                       free(lpTPName);
  220.                       return TRUE;
  221.                     }
  222.                   else
  223.                     {
  224.                       //
  225.                       // convert to milliseconds the hard way
  226.                       //
  227.                       strcat( lpTimeout, "000" );
  228.                     }
  229.                 }
  230.  
  231.               // Split off command-line parameters from executable name.
  232.               // Win95 and NT support spaces in pathnames, it is not safe
  233.               // to assume that first space marks the end of the executable name.
  234.               // It is quite safe to assume that executable programs stil end
  235.               // with extension .exe
  236.  
  237.               if (divider = strstr(lpPathName, ".exe" ))
  238.               {
  239.                   if (divider = strchr(divider, ' '))
  240.                   {
  241.                   lpParameters = divider + 1;
  242.                   *divider = '\0';
  243.                   }
  244.                 else
  245.                 {
  246.                   lpParameters = "";
  247.                 }
  248.               }
  249.               else lpParameters = "";
  250.  
  251. #ifdef WIN32
  252.               bService = IsDlgButtonChecked(hDlg, IDC_SERVICE) == 1;
  253.  
  254.               // Install the new service; if successful, set subkeys
  255.               if (bService && InstallServiceNT(hDlg, lpTPName, lpPathName) != 0)
  256.                 {
  257.                   free(lpPathName);
  258.                   free(lpTPName);
  259.                   return TRUE;
  260.                 }
  261.  
  262.               if (CreateKeys(  lpTPName,
  263.                                bService,
  264.                                lpLocalLUName,
  265.                                IsDlgButtonChecked(hDlg, IDC_CONVSEC) == 1,
  266.                                IsDlgButtonChecked(hDlg, IDC_ALREADYVER) == 1,
  267.                                IsDlgButtonChecked(hDlg, IDC_QUEUED) == 1,
  268.                                lpTimeout,
  269.                                lpParameters,
  270.                                lpPathName
  271.                                )
  272.                                != 0)
  273.                 {
  274.                   free(lpPathName);
  275.                   free(lpTPName);
  276.                   return TRUE;
  277.                 }
  278.  
  279.               //
  280.               // Now try to open the "SNABASE_NEWTP_EVENT" event and signal
  281.               // the SnaBase to dynamically register this new TP. NOTE this will
  282.               // only work with the WIN95 SnaBase. WinNT SnaBase doesn't create
  283.               // this event.
  284.               //
  285.               hEvent = OpenEvent( EVENT_MODIFY_STATE, FALSE, "SNABASE_NEWTP_EVENT" );
  286.               if( hEvent != NULL )
  287.               {
  288.                   SetEvent( hEvent );
  289.                   CloseHandle( hEvent );
  290.               }
  291.  
  292.               DisplayInfo(hDlg, IDS_SUCCESS);
  293.  
  294. #else
  295.  
  296.               // Add entries to WIN.INI
  297.               if (InstallWindows(hDlg, lpTPName, lpPathName,
  298.                      lpLocalLUName, lpParameters,
  299.                                  IsDlgButtonChecked(hDlg, IDC_CONVSEC) == 1,
  300.                                  IsDlgButtonChecked(hDlg, IDC_ALREADYVER) == 1,
  301.                                  IsDlgButtonChecked(hDlg, IDC_QUEUED) == 1,
  302.                                  lpTimeout
  303.                                  ) != 0)
  304.                 {
  305.                   free(lpPathName);
  306.                   free(lpTPName);
  307.                   return TRUE;
  308.                 }
  309.               DisplayInfo(hDlg, IDS_SUCCESS);
  310.  
  311. #endif //ifdef WIN32
  312.  
  313.               EndDialog(hDlg, TRUE);
  314.               free(lpPathName);
  315.               free(lpTPName);
  316.               return TRUE;
  317.  
  318.             case IDCANCEL:
  319.               EndDialog(hDlg, FALSE);
  320.               return TRUE;
  321.  
  322.             case IDC_ADD:
  323.             case IDC_EDIT:
  324.               // Bring up a dialog to add or edit username & password.
  325.               // The last argument to DialogBoxParam is passed to the dialog
  326.               // procedure and used to determine whether the procedure was
  327.               // called from Add or Edit.
  328.               lpfn = (FARPROC) MakeProcInstance( (FARPROC)UserDlgProc, hInst);
  329.               DialogBoxParam (hInst,
  330.                             (LPCSTR)"UserDlg",
  331.                             hDialog,
  332.                             (DLGPROC) lpfn,
  333.                             cmd);
  334.               FreeProcInstance(lpfn);
  335.               return TRUE;
  336.  
  337.             case IDC_DELETE:
  338.               nIndex = SendMessage(hList, LB_GETCURSEL, 0, 0);
  339.               if (nIndex == LB_ERR)
  340.                 break;
  341.  
  342.               DeleteListItem(nIndex);
  343.               break;
  344.  
  345.             default:
  346.               return FALSE;
  347.           }
  348.  
  349.         break;
  350.  
  351.       case WM_DESTROY:
  352.         PostQuitMessage(0);
  353.         return TRUE;
  354.     }
  355.  
  356. #ifdef WIN32
  357.   UNREFERENCED_PARAMETER(divider);
  358.   UNREFERENCED_PARAMETER(lpParameters);
  359. #endif
  360.  
  361.     return FALSE;
  362. }
  363. /*****************************************************************************/
  364. /*
  365.  * UserDlgProc: Dialog procedure for adding or editing a username/password
  366.  *   pair.
  367.  */
  368. /*****************************************************************************/
  369. BOOL CALLBACK UserDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  370. {
  371.   char *szUsername, *szPassword, *szPasswd;
  372.   WORD nIndex;
  373.   INT  nPasswdLen;
  374.   LOCALHANDLE hLocalMem;
  375.  
  376.   switch(wMsg)
  377.     {
  378.       case WM_INITDIALOG:
  379.         // Set maximum username length
  380.         SendMessage(GetDlgItem(hDlg, IDE_USERNAME),
  381.                     EM_LIMITTEXT, MAXUSERNAMELEN, 0);
  382.  
  383.         // Set maximum password length
  384.         SendMessage(GetDlgItem(hDlg, IDE_PASSWORD),
  385.                     EM_LIMITTEXT, MAXPASSWORDLEN, 0);
  386.  
  387.         // If we were called from the Edit button, we should fill in the
  388.         // edit boxes with strings from the current selection
  389.         if (lParam == IDC_EDIT)
  390.           {
  391.             // Make sure something is currently selected
  392.             if ((nIndex = (WORD) SendMessage(hList, LB_GETCURSEL, 0, 0)) != LB_ERR)
  393.               {
  394.                 szUsername = (char *) malloc(MAXUSERNAMELEN + 1);
  395.                 SendMessage(hList, LB_GETTEXT, (WPARAM) nIndex,
  396.                             (LPARAM)(LPSTR)szUsername);
  397.                 SendMessage(GetDlgItem(hDlg, IDE_USERNAME), WM_SETTEXT, 0,
  398.                             (LPARAM)(LPSTR)szUsername);
  399.                 free(szUsername);
  400.  
  401.                 // Get pointer to password and then get password
  402.                 hLocalMem = (LOCALHANDLE) SendMessage(hList, LB_GETITEMDATA,
  403.                                                       nIndex, 0);
  404.                 if (hLocalMem != NULL)
  405.                   {
  406.                     szPasswd = (char *) LocalLock(hLocalMem);
  407.                     SendMessage(GetDlgItem(hDlg, IDE_PASSWORD), WM_SETTEXT, 0,
  408.                                     (LPARAM)(LPSTR)szPasswd);
  409.                     LocalUnlock(hLocalMem);
  410.                   }
  411.               }
  412.           }
  413.  
  414.         break;
  415.  
  416.       case WM_COMMAND:
  417.         switch(GET_WM_COMMAND_ID(wParam, lParam))
  418.           {
  419.             case IDOK:
  420.               // Complain if username is blank
  421.               if (ReadString(hDlg, IDE_USERNAME, &szUsername, MAXUSERNAMELEN)
  422.                 == 0)
  423.                 {
  424.                   DisplayError(hDlg, IDS_NOUSERNAME);
  425.                   free(szUsername);
  426.                   return TRUE;
  427.                 }
  428.  
  429.               // Read password
  430.               nPasswdLen = ReadString(hDlg, IDE_PASSWORD,
  431.                                       &szPassword, MAXPASSWORDLEN);
  432.  
  433.               // Complain if password is blank
  434.               if (nPasswdLen == 0)
  435.                 {
  436.                   DisplayError(hDlg, IDS_NOPASSWORD);
  437.                   free(szUsername);
  438.                   free(szPassword);
  439.                   return TRUE;
  440.                 }
  441.  
  442.               // If user is already listed, replace him by first deleting.
  443.               // This also takes care of the Edit button, which presumably
  444.               // will often have a username that already exists in the list.
  445.               nIndex = (WORD) SendMessage(hList, LB_SELECTSTRING, (WPARAM) -1,
  446.                                   (LPARAM) (LPSTR)szUsername);
  447.               if (nIndex != LB_ERR)
  448.                 DeleteListItem(nIndex);
  449.  
  450.               // Add the new user to the "users" list in the main dialog
  451.               nIndex = (WORD) SendMessage(hList, LB_ADDSTRING, 0,
  452.                                     (LPARAM) (LPSTR) szUsername);
  453.  
  454.               // Allocate some space for the password & store handle in list
  455.               hLocalMem = LocalAlloc(LHND, nPasswdLen + 1);
  456.               if (hLocalMem == NULL)
  457.             {
  458.               DisplayError(hDlg, IDS_OUTOFMEMORY);
  459.               SendMessage(hList, LB_SETITEMDATA, nIndex, (LPARAM) NULL);
  460.                 }
  461.               else
  462.             {
  463.               szPasswd = (char *) LocalLock(hLocalMem);
  464.               strcpy(szPasswd, szPassword);
  465.               SendMessage(hList, LB_SETITEMDATA, nIndex, (LPARAM)(LPVOID)hLocalMem);
  466.               LocalUnlock(hLocalMem);
  467.                 }
  468.  
  469.               // Force highlight to newly inserted user, & enable Delete & Edit
  470.               SendMessage(hList, LB_SETCURSEL, nIndex, 0L);
  471.               EnableWindow(GetDlgItem(hDialog, IDC_DELETE), TRUE);
  472.               EnableWindow(GetDlgItem(hDialog, IDC_EDIT), TRUE);
  473.  
  474.               EndDialog(hDlg, TRUE);
  475.               return TRUE;
  476.  
  477.             case IDCANCEL:
  478.               EndDialog(hDlg, FALSE);
  479.               return TRUE;
  480.  
  481.             default:
  482.               return FALSE;
  483.  
  484.           }
  485.         break;
  486.     }
  487.   return FALSE;
  488. }
  489.  
  490. #ifdef WIN32
  491.  
  492. /*****************************************************************************/
  493. /*
  494.  * InstallServiceNT( HWND hDlg, LPSTR lpServiceName, LPSTR lpPath )
  495.  *
  496.  * Windows NT version of installation--register a new service.
  497.  *
  498.  * Parameters
  499.  * ----------
  500.  *
  501.  * hDlg: Handle to top level dialog; used for error messages.
  502.  * lpServiceName: A string giving the name of the TP.
  503.  * lpPath: A string giving the full pathname of the TP's executable.
  504.  *
  505.  * Returns
  506.  * -------
  507.  *
  508.  *  Zero upon successful completion, nonzero otherwise.
  509.  *
  510.  * Comments
  511.  * --------
  512.  *  Installs new service if possible.  Puts up appropriate message boxes if
  513.  *  installation fails.
  514.  */
  515. /*****************************************************************************/
  516. int InstallServiceNT(HWND hDlg, LPSTR lpServiceName, LPSTR lpBinaryPath)
  517. {
  518.  
  519.   SC_HANDLE hSCManager = NULL;
  520.   SC_HANDLE hService   = NULL;
  521.   SC_LOCK   lSCLock    = NULL;
  522.  
  523.   hSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  524.  
  525.   if( hSCManager != NULL )
  526.   {
  527.     /*************************************************************************/
  528.     /* Lock the service database                                             */
  529.     /*************************************************************************/
  530.     lSCLock = LockServiceDatabase( hSCManager );
  531.     if ( lSCLock != NULL )
  532.     {
  533.       /***********************************************************************/
  534.       /* Create the service                                                  */
  535.       /***********************************************************************/
  536.       hService = CreateService( hSCManager,
  537.                                 lpServiceName,     // Service's name
  538.                                 lpServiceName,     // Display name (new for NT)
  539.                                 SERVICE_ALL_ACCESS,// Access (allow all)
  540.                                 0x10,              // Service type
  541.                                 0x3,               // Startup behavior
  542.                                 0x1,               // Error control
  543.                                 lpBinaryPath,      // Full pathname of binary
  544.                                 NULL,              // Load order group
  545.                                 NULL,              // Tag ID
  546.                                 NULL,              // Dependencies (none)
  547.                                 NULL,              // Account name
  548.                                 NULL               // Password
  549.                                 );
  550.       if ( hService != NULL )
  551.         {
  552.           /*********************************************************************/
  553.           /* Close our handle to the new service                               */
  554.           /*********************************************************************/
  555.           CloseServiceHandle( hService );
  556.         }
  557.       else
  558.         {
  559.           // Try to display the reason for the create failure
  560.           ParseCreateError(hDlg, GetLastError());
  561.  
  562.           // Must release lock in case we are called again
  563.           UnlockServiceDatabase( lSCLock );
  564.  
  565.           return 1;
  566.         }
  567.  
  568.       /***********************************************************************/
  569.       /* Unlock the database                                                 */
  570.       /***********************************************************************/
  571.       UnlockServiceDatabase( lSCLock );
  572.     }
  573.     else
  574.       {
  575.         DisplayError(hDlg, IDS_LOCKFAILED);
  576.         return 1;
  577.       }
  578.     /*************************************************************************/
  579.     /* Free our handle to the service control manager                        */
  580.     /*************************************************************************/
  581.     CloseServiceHandle( hSCManager );
  582.     return 0;
  583.   }
  584.  
  585.   DisplayError(hDlg, IDS_OPENSCMFAILED);
  586.   return 1;
  587. }
  588.  
  589. /*****************************************************************************/
  590. /*
  591.  * CreateKeys: Set the required key values for the newly created service.
  592.  *  The keys are:
  593.  *                 Linkage:
  594.  *                        OtherDependencies: REG_MULTI_SZ: SnaBase
  595.  *                Parameters:
  596.  *                        SNAServiceType: REG_DWORD: 0x5
  597.  *                        ConversationSecurity: REG_SZ:  "yes" or "no"
  598.  *                           (depending on setting of radio button in dialog box)
  599.  *                  AlreadyVerified: REG_SZ: "yes" or "no"
  600.  * If the timeout isn't infinite, there appears the key:
  601.  *                        Timeout: REG_DWORD: <timeout in seconds>
  602.  *                        Parameters: REG_SZ: cmd line parameters
  603.  * If ConversationSecurity is yes, there are also these keys:
  604.  *                        <User1>: REG_SZ: <Password1>
  605.  *                                ...
  606.  *                        <Usern>: REG_SZ: <Passwordn>
  607.  *
  608.  *  Note that the users and passwords are read from the list box.
  609.  *
  610.  *  Arguments:
  611.  *    lpServiceName is the name of the TP.
  612.  *    lpLUName is the Local LU Alias.
  613.  *    The two integer arguments give the state of the radio buttons on the
  614.  *      dialog box.  They should be zero to indicate that "No" is selected,
  615.  *      nonzero otherwise.
  616.  *    lpTimeout is a string containing the timeout value; if the timeout is
  617.  *      infinite, it holds the value of INFINITE_TIMEOUT.
  618.  *
  619.  *  Returns: 0 on success, nonzero otherwise.
  620.  */
  621. /*****************************************************************************/
  622. INT CreateKeys(LPSTR lpServiceName, BOOL bService, LPSTR lpLUName, int iConvSec,
  623.                int iAlreadyVer, int iQueued, LPSTR lpTimeout, LPSTR lpParameters,
  624.                LPSTR lpExeName)
  625. {
  626.   LPSTR  lpServiceFullName;
  627.   int    bufsize, i, nCount;
  628.   LOCALHANDLE hLocalMem;
  629.  
  630.   // If any of the buttons says "no", change the key values so that they
  631.   // will be inserted into the registry below.  This is kind of gross, but
  632.   // it keeps the loop below simple.
  633.   if (iConvSec == 0)
  634.     {
  635.       keyinfo[CONVSEC].lpData = "no";
  636.       keyinfo[CONVSEC].iDataSize = 3;
  637.     }
  638.   if (iAlreadyVer == 0)
  639.     {
  640.       keyinfo[ALREADYVER].lpData = "no";
  641.       keyinfo[ALREADYVER].iDataSize = 3;
  642.     }
  643.   if (bService == FALSE && iQueued == 0)
  644.     {
  645.       //
  646.       // the default of 5 is OK for queued support.
  647.       // needs to be redefined to 6 for nonqueued.
  648.       //
  649.       keyinfo[SNASRVTYPE].lpData = "6";
  650.       keyinfo[SNASRVTYPE].iDataSize = 4;
  651.     }
  652.  
  653.   // Put timeout in structure (it won't be written out if infinite)
  654.   keyinfo[TIMEOUT].lpData = lpTimeout;
  655.  
  656.   // Put Parameters in structure
  657.   keyinfo[PARAMETERS].lpData = lpParameters;
  658.   keyinfo[PARAMETERS].iDataSize = strlen(lpParameters) + 1;   // Count null
  659.  
  660.   // Put Local LU Alias in structure; it won't be written out if blank
  661.   keyinfo[LUNAME].lpData = lpLUName;
  662.   keyinfo[LUNAME].iDataSize = strlen(lpLUName) + 1;   // Count null
  663.  
  664.   // Create full path of TP by concatenating the registry path with the
  665.   // TP's name
  666.   bufsize = MAXREGPATHLEN + 1;
  667.   lpServiceFullName = (LPSTR) malloc(bufsize);
  668.  
  669.   i = bService ? IDS_REGISTRYPATH : IDS_REGISTRYAPPLPATH ;
  670.  
  671. #ifdef WIN32
  672.   if( IsWin95Client() )
  673.   {
  674.       i = bService ? IDS_REGISTRYPATH_WIN95 : IDS_REGISTRYAPPLPATH_WIN95;
  675.   }
  676. #endif
  677.  
  678.   LoadString( hInst, i, lpServiceFullName, bufsize );
  679.   lstrcat(lpServiceFullName, lpServiceName);
  680.  
  681.   // Write out the basic keys; first key is skipped for non-service tps
  682.   for ( i = bService ? 0 : 1; i < NUMKEYS; i++ )
  683.     {
  684.       if ( WriteKeyNT(lpServiceFullName, keyinfo[i], TRUE ) )
  685.           return 1;
  686.     }
  687.  
  688.   // if not a service then write out the path name
  689.   if ( bService == FALSE )
  690.     {
  691.       keyinfo[EXENAME].lpData = lpExeName;
  692.       keyinfo[EXENAME].iDataSize = strlen(lpExeName) + 1;   // Count null
  693.       if (WriteKeyNT(lpServiceFullName, keyinfo[EXENAME], TRUE ) )
  694.           return 1;
  695.     }
  696.  
  697.   // If timeout isn't infinite, write out the "timeout" key
  698.   if (lstrcmp(lpTimeout, INFINITE_TIMEOUT))
  699.     {
  700.       if (WriteKeyNT(lpServiceFullName, keyinfo[TIMEOUT], TRUE ) )
  701.           return 1;
  702.     }
  703.  
  704.   // If Local LU Alias isn't blank, write out its key
  705.   if (strlen(lpLUName) > 0)
  706.      {
  707.       if (WriteKeyNT(lpServiceFullName, keyinfo[LUNAME], TRUE ) )
  708.           return 1;
  709.     }
  710.  
  711.   // Only write out user stuff if conversation security is "yes"
  712.   if (iConvSec)
  713.     {
  714.       keyinfo[USER].lpName = (LPSTR) malloc(MAXUSERNAMELEN + 1);
  715.       nCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
  716.       for (i = 0; i < nCount; i++)
  717.         {
  718.           // Get username & make it the name of this key
  719.           SendMessage(hList, LB_GETTEXT, (WPARAM) i,
  720.                                   (LPARAM) keyinfo[USER].lpName);
  721.  
  722.           // Get pointer to password and then get password
  723.           hLocalMem = (LOCALHANDLE) SendMessage(hList, LB_GETITEMDATA, i, 0);
  724.           keyinfo[USER].lpData = (LPSTR) LocalLock(hLocalMem);
  725.  
  726.           // Password shouldn't be blank, but just in case...
  727.           if (keyinfo[USER].lpData == NULL)
  728.             keyinfo[USER].iDataSize = 0;
  729.           else
  730.             keyinfo[USER].iDataSize = strlen(keyinfo[USER].lpData);
  731.  
  732.           if (WriteKeyNT(lpServiceFullName, keyinfo[USER], TRUE ) )
  733.             {
  734.               LocalUnlock(hLocalMem);
  735.               return 1;
  736.             }
  737.           LocalUnlock(hLocalMem);
  738.         }
  739.     }
  740.  
  741.   free(lpServiceFullName);
  742.   return 0;
  743. }
  744. /*****************************************************************************/
  745. /*
  746.  * WriteKeyNT: Write out the given key to the registry.
  747.  * Return 0 on success, nonzero otherwise.
  748.  */
  749. /*****************************************************************************/
  750. INT WriteKeyNT(LPSTR lpServiceFullName, KEYENTRY keyinfo, BOOL bAppendParent )
  751. {
  752. static BOOL    bAskToReplace = TRUE;
  753.   DWORD     dwResult;
  754.   HKEY      hKey;
  755.   LPSTR     lpKeyName;
  756.   DWORD        dwTemp;
  757.  
  758.   lpKeyName = (LPSTR) malloc(MAXREGPATHLEN + 1);
  759.  
  760.   // Build full pathname of key by appending a backslash and the name of the
  761.   // key to the full pathname of the TP.
  762.   lstrcpy(lpKeyName, lpServiceFullName);
  763.   lstrcat(lpKeyName, TEXT("\\"));
  764.   lstrcat(lpKeyName, keyinfo.lpParent);
  765.  
  766.   // Now create the subkeys and set their values
  767.   if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,      // Predefined key
  768.       lpKeyName,                      // Our subkey's name
  769.       0,                       // Reserved
  770.       NULL,                    // Class string
  771.       REG_OPTION_NON_VOLATILE, // Option type (value is saved)
  772.       KEY_ALL_ACCESS,          // Access mask
  773.       NULL,                    // Security attributes
  774.       &hKey,                   // Handle to key is put here
  775.       &dwResult)               // Was key opened or created?
  776.       == ERROR_SUCCESS)
  777.         {
  778.           if ( bAskToReplace && dwResult == REG_OPENED_EXISTING_KEY )
  779.             {
  780.             char szCaption[64];
  781.             char szText[256];
  782.               LoadString( hInst, IDS_REPLACECAPTION, szCaption, sizeof(szCaption) );
  783.               LoadString( hInst, IDS_REPLACETEXT, szText, sizeof(szText) );
  784.               switch( MessageBox( hDialog, szText, szCaption, MB_OKCANCEL|MB_ICONQUESTION ) )
  785.                 {
  786.               case IDCANCEL:
  787.                   return 1;
  788.  
  789.                 }
  790.             }
  791.  
  792.           //
  793.           // after first successful pass no need to query
  794.           //
  795.           bAskToReplace = FALSE;
  796.  
  797.           // We stored all the values as strings, but some are actually numbers.
  798.           // So we have to make a temporary buffer to pass RegSetValueEx the
  799.           // pointer to a DWORD that it wants for DWORD data.
  800.           if ( keyinfo.iDataType == REG_DWORD )
  801.             {
  802.               dwTemp = atol(keyinfo.lpData);
  803.               keyinfo.lpData = (LPSTR) &dwTemp;
  804.               keyinfo.iDataSize = sizeof(DWORD);
  805.             }
  806.  
  807.           if (RegSetValueEx(hKey,
  808.                         keyinfo.lpName,    // Key name
  809.                         0,                    // Reserved
  810.                         keyinfo.iDataType, // Type of key data
  811.                         keyinfo.lpData,    // Key's value
  812.                         keyinfo.iDataSize  // Length of value (incl. nulls)
  813.                         )
  814.                         != ERROR_SUCCESS)
  815.             {
  816.               DisplayError(hDialog, IDS_SETKEYFAILED);
  817.               return 1;
  818.             }
  819.         }
  820.       else
  821.         {
  822.           DisplayError(hDialog, IDS_OPENKEYFAILED);
  823.           return 1;
  824.         }
  825.  
  826.   free(lpKeyName);
  827.   return 0;
  828. }
  829. /*****************************************************************************/
  830. /*
  831.  * ParseCreateError: Given an error code from a registry operation, attempt
  832.  *   to give an appropriate error message.
  833.  */
  834. /*****************************************************************************/
  835. void ParseCreateError(HWND hDlg, UINT uError)
  836. {
  837.   UINT code;
  838.   switch (uError)
  839.     {
  840.       case ERROR_INVALID_PARAMETER:
  841.         // "Invalid parameter" is a rather generic error name.  Since a blank
  842.         // service name is the most probable way the error arose, say so:
  843.         code = IDS_BADPATHNAME;
  844.         break;
  845.  
  846.       case ERROR_INVALID_NAME:
  847.         code = IDS_BADTPNAME;
  848.         break;
  849.  
  850.       case ERROR_SERVICE_EXISTS:
  851.         code = IDS_SERVICEEXISTS;
  852.         break;
  853.  
  854.       default:
  855.         // Since we don't have a code for this error, the following will bring
  856.         // up the "unknown" error message
  857.         code = uError;
  858.     }
  859.   DisplayError(hDlg, code);
  860. }
  861.  
  862. #else
  863.  
  864. /*****************************************************************************/
  865. /*
  866.  * InstallWindows: Windows version of installation; add lines to WIN.INI
  867.  *
  868.  * First we must add an entry under the heading SNAServerAutoTPs.  This entry
  869.  * has the name of the TP and points to another heading that contains TP-
  870.  * specific data.  Sample WIN.INI:
  871.  *
  872.  * [SNAServerAutoTPs]
  873.  * BounceTP = BounceTPParams
  874.  *
  875.  * [BounceTPParams]
  876.  * PathName = c:\sna\bounce.exe
  877.  * Parameters = /t
  878.  * etc....
  879.  *
  880.  * For a list of entries, see the comment at CreateKeys().  The only difference
  881.  * is that WIN.INI also contains an entry for the "queued" toggle.
  882.  *
  883.  *
  884.  * Parameters:
  885.  *    szTPName: The name of the TP
  886.  *    szBinaryPath: The full pathname of the executable
  887.  *    szLUName: Local LU Alias
  888.  *    szParameters: The list of command line parameters
  889.  *    iConvSec: "Conversation security" toggle (1 = yes, 0 = no)
  890.  *    iAlreadyVer: "Already verified" toggle
  891.  *    iQueued: "Queued" toggle
  892.  *    lpTimeout: A string specifying the timeout in seconds, e.g. "2"
  893.  *
  894.  * Returns: zero on success, nonzero otherwise
  895.  */
  896. /*****************************************************************************/
  897. INT InstallWindows(HWND hDlg, char *szTPName, char *szBinaryPath, char *szLUName,
  898.                    char *szParameters,
  899.                    int iConvSec, int iAlreadyVer, int iQueued, char *lpTimeout
  900.                    )
  901. {
  902.   char szNewKeyName[MAXTPLEN + 6];
  903.   int  i, nCount;
  904.   LOCALHANDLE hLocalMem;
  905.  
  906.   // Make new heading by concatenating TP's name and the string "Params"
  907.   strcpy(szNewKeyName, szTPName);
  908.   strcat(szNewKeyName, "Params");
  909.  
  910.   // Now add the key to the SNAServerAutoTPs heading
  911.   if (WriteKeyWindows("SNAServerAutoTPs", szTPName, szNewKeyName))
  912.     return 1;
  913.  
  914.   // Set the data fields of the keys, one at a time
  915.   keyinfo[PATHNAME].data    = szBinaryPath;
  916.   keyinfo[PARAMETERS].data  = szParameters;
  917.   keyinfo[LUNAME].data      = szLUName;
  918.   keyinfo[QUEUED].data      = iQueued ? "yes" : "no";
  919.   keyinfo[TIMEOUT].data     = lpTimeout;
  920.   keyinfo[CONVSEC].data     = iConvSec ? "yes" : "no";
  921.   keyinfo[ALREADYVER].data  = iAlreadyVer ? "yes" : "no";
  922.  
  923.   // Loop through all the keys and add them under the new "Params" heading
  924.   for (i=0; i < NUMKEYS; i++)
  925.     if (WriteKeyWindows(szNewKeyName, keyinfo[i].name, keyinfo[i].data))
  926.       return 1;
  927.  
  928.   // Only write out Local LU Alias if it's not blank
  929.   if (strlen(szLUName) > 0)
  930.     if (WriteKeyWindows(szNewKeyName, keyinfo[LUNAME].name, keyinfo[LUNAME].data))
  931.       return 1;
  932.  
  933.   // If conversation security is on, write out users & passwords
  934.   if (iConvSec)
  935.     {
  936.       keyinfo[USER].name = (char *) malloc(MAXUSERNAMELEN + 1);
  937.       nCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
  938.  
  939.       // Read usernames and passwords from list box & create keys
  940.       for (i = 0; i < nCount; i++)
  941.         {
  942.           // Get username & make it the name of this key
  943.           SendMessage(hList, LB_GETTEXT, (WPARAM) i,
  944.                                   (LPARAM)(LPSTR)keyinfo[USER].name);
  945.  
  946.           // Get pointer to password and then get password
  947.           hLocalMem = (LOCALHANDLE) SendMessage(hList, LB_GETITEMDATA, i, 0);
  948.           keyinfo[USER].data = (char *) LocalLock(hLocalMem);
  949.  
  950.           if (WriteKeyWindows(szNewKeyName, keyinfo[USER].name,
  951.                                 keyinfo[USER].data))
  952.             {
  953.               LocalUnlock(hLocalMem);
  954.               return 1;
  955.             }
  956.           LocalUnlock(hLocalMem);
  957.         }
  958.       free(keyinfo[USER].name);
  959.  
  960.     }
  961.  
  962.   return 0;
  963. }
  964. /*****************************************************************************/
  965. /*
  966.  * WriteKeyWindows:  Write the given key out to WIN.INI
  967.  * Return 0 on success, nonzero otherwise.
  968.  */
  969. /*****************************************************************************/
  970. INT WriteKeyWindows(char *heading, char *keyname, char *value)
  971. {
  972.   if (WriteProfileString(heading, keyname, value) == FALSE)
  973.     {
  974.       DisplayError(hDialog, IDS_INIWRITEFAILED);
  975.       return 1;
  976.     }
  977.   return 0;
  978. }
  979.  
  980. #endif //ifdef WIN32
  981.  
  982. /*****************************************************************************/
  983. /*
  984.  * ValidateField: Install a window procedure that handles messages to the
  985.  *   given edit window.
  986.  *
  987.  * Parameters: hwnd is the edit window, usType an identifier for the window
  988.  *   procuedure to install.  Currently the only allowed type is VALIDATE_INT,
  989.  *   which allows only digits to be typed into the edit box.
  990.  *
  991.  * Returns:  TRUE if window procedure is successfully installed,
  992.  *   FALSE otherwise.
  993. /*****************************************************************************/
  994. BOOL ValidateField( HWND hwnd, USHORT usType)
  995. {
  996.         FARPROC lpfn = NULL;
  997.         LONG        lPrevWndProc;
  998.         LONG FAR *lplNewWndProc;
  999.  
  1000.         if (hwnd == NULL) {
  1001.                 return(FALSE);
  1002.         }
  1003.  
  1004.         lPrevWndProc = GetWindowLong( hwnd, GWL_WNDPROC );
  1005.  
  1006.         if (lPrevWndProc == 0) {
  1007.                 return(FALSE);
  1008.         }
  1009.  
  1010.         // check that the old wndproc is the same as the one we have stored
  1011.         // also, get the new wndproc, based on contents of edit field
  1012.  
  1013.         // We only need two validation procedures, but if you want others
  1014.         // (such as hexadecimal, filenames, etc.) you can add extra cases
  1015.         // and procedures below.
  1016.  
  1017.         switch (usType) {
  1018.           case VALIDATE_INT:
  1019.             if (lpfnInt == NULL) {
  1020.               lpfnInt = MakeProcInstance( (FARPROC)ValidateFieldInt, hInst );
  1021.             }
  1022.             lpfn = lpfnInt;
  1023.  
  1024.             lplNewWndProc = (LONG FAR *) &lPrevWndProcInt;
  1025.             break;
  1026.  
  1027.           case VALIDATE_APPC:
  1028.             if (lpfnAppc == NULL) {
  1029.               lpfnAppc = MakeProcInstance( (FARPROC)ValidateFieldAppc, hInst );
  1030.             }
  1031.             lpfn = lpfnAppc;
  1032.  
  1033.             lplNewWndProc = (LONG FAR *) &lPrevWndProcAppc;
  1034.             break;
  1035.  
  1036.           default:
  1037.             return(FALSE);
  1038.           }
  1039.  
  1040.         if (*lplNewWndProc == (LONG) NULL) {
  1041.  
  1042.                 *lplNewWndProc = lPrevWndProc;
  1043.  
  1044.         } else {
  1045.  
  1046.                 if (*lplNewWndProc != lPrevWndProc) {
  1047.                         return(FALSE);
  1048.                 }
  1049.  
  1050.                 *lplNewWndProc = lPrevWndProc;
  1051.         }
  1052.  
  1053.         if (lpfn == NULL ||
  1054.                 SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfn) == (LONG) NULL) {
  1055.  
  1056.                 return(FALSE);
  1057.         }
  1058.         return(TRUE);
  1059. }
  1060.  
  1061. /*****************************************************************************/
  1062. /*
  1063.  * ValidateFieldInt: A window proc that allows only 0 through 9 to be typed to
  1064.  *   an edit box.
  1065.  */
  1066. /*****************************************************************************/
  1067. LRESULT CALLBACK ValidateFieldInt( HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam )
  1068. {
  1069.         if (msg == WM_CHAR) {
  1070.  
  1071.                 char ch = LOBYTE(LOWORD(wParam));
  1072.  
  1073.                 if ((ch < '0' || ch > '9') && ch != VK_BACK )
  1074.                   return(0);
  1075.         }
  1076.         // If character was legal or message wasn't WM_CHAR,
  1077.         // pass message on to default window proc.
  1078.         return CallWindowProc( lPrevWndProcInt, hwnd, msg, wParam, lParam);
  1079. }
  1080. /*****************************************************************************/
  1081. /*
  1082.  * ValidateFieldAppc: A window proc that allows only legal APPC name characters
  1083.  *    to be typed to an edit box.
  1084.  */
  1085. /*****************************************************************************/
  1086. LRESULT CALLBACK ValidateFieldAppc( HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam )
  1087. {
  1088.     if (msg == WM_CHAR) {
  1089.  
  1090.         char ch = LOBYTE(LOWORD(wParam));
  1091.  
  1092.         if (!(ch >= '0' && ch <= '9' ||
  1093.             ch >= 'A' && ch <= 'Z' ||
  1094.             ch >= 'a' && ch <= 'z' ||
  1095.             ch == '@'    ||
  1096.             ch == '#'    ||
  1097.             ch == '$'    ||
  1098.             ch == '%'    ||
  1099.             ch == VK_BACK ))
  1100.             return(0);
  1101.     }
  1102.     return CallWindowProc( lPrevWndProcAppc, hwnd, msg, wParam, lParam);
  1103. }
  1104. /*****************************************************************************/
  1105. /*
  1106.  * InstallCallback: Install a callback window proc.
  1107.  *   Arguments:
  1108.  *        hDlg: Handle of the parent dialog
  1109.  *      uId: ID of window for which callback will be installed
  1110.  *      OldWndProc: Handle for previous window proc
  1111.  *      NewWndProc: Pointer to new window proc
  1112.  */
  1113. /*****************************************************************************/
  1114. void InstallCallback(HWND hDlg, UINT uId, WNDPROC *OldWndProc, FARPROC NewWndProc)
  1115. {
  1116.   HANDLE hTemp;
  1117.  
  1118.   hTemp = GetDlgItem(hDlg, uId);
  1119.   *OldWndProc = (WNDPROC) GetWindowLong(hTemp, GWL_WNDPROC);
  1120.   SetWindowLong(hTemp, GWL_WNDPROC,
  1121.                (LONG) MakeProcInstance( (FARPROC)NewWndProc, hInst));
  1122. }
  1123. /*****************************************************************************/
  1124. /*
  1125.  * InfiniteWndProc: Disable "timeout" box when the "infinite"
  1126.  *   button is pressed, and enable it when "finite" is pressed.
  1127.  */
  1128. /*****************************************************************************/
  1129. LRESULT CALLBACK InfiniteWndProc( HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam )
  1130. {
  1131.   if (msg == BM_SETCHECK)
  1132.     // wParam is 0 if button is being turned off, 1 if being turned on
  1133.     EnableWindow(hTimeout, (wParam == 0));
  1134.   return CallWindowProc(lPrevWndProcInfinite, hwnd, msg, wParam, lParam);
  1135. }
  1136.  
  1137.  
  1138. /*****************************************************************************/
  1139. /*
  1140.  * ServiceWndProc: Disable "queued" box when the "service" button is pressed
  1141.  */
  1142. /*****************************************************************************/
  1143. LRESULT CALLBACK ServiceWndProc( HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam )
  1144. {
  1145.   HWND hwndCntl;
  1146.  
  1147.   if (msg == BM_SETCHECK) {
  1148.     //
  1149.     // wParam is 0 if button is being turned off, 1 if being turned on
  1150.     //
  1151.     hwndCntl = GetDlgItem( hDialog, IDC_QUEUED );
  1152.     EnableWindow( hwndCntl, wParam == 1 ? FALSE : TRUE );
  1153.  
  1154.     if ( wParam == 1 ) {
  1155.         SendMessage( hwndCntl, BM_SETCHECK, 1, 0 );
  1156.     }
  1157.   }
  1158.  
  1159.   return CallWindowProc(lPrevWndProcService, hwnd, msg, wParam, lParam);
  1160. }
  1161.  
  1162.  
  1163. /*****************************************************************************/
  1164. /*
  1165.  * ConvSecWndProc: Window proc for "conversation security" checkbox.  Grey
  1166.  *   out "users" group box when checkbox is off
  1167.  */
  1168. /*****************************************************************************/
  1169. LRESULT CALLBACK ConvSecWndProc( HWND hwnd, WORD msg, WPARAM wParam, LPARAM lParam )
  1170. {
  1171.   int nItems = SendMessage(hList, LB_GETCOUNT, 0, 0L);
  1172.   if (msg == BM_SETCHECK)
  1173.     {
  1174.       EnableWindow(GetDlgItem(hDialog, IDC_USERBOX), wParam == 1 ? TRUE : FALSE);
  1175.       EnableWindow(GetDlgItem(hDialog, IDC_ADD), wParam == 1 ? TRUE : FALSE);
  1176.       EnableWindow(hList, wParam == 1 ? TRUE : FALSE);
  1177.       // Only turn on Delete & Edit if there's something in the list box
  1178.       EnableWindow(GetDlgItem(hDialog, IDC_DELETE), wParam == 1 && nItems);
  1179.       EnableWindow(GetDlgItem(hDialog, IDC_EDIT), wParam == 1 && nItems);
  1180.     }
  1181.   return CallWindowProc(lPrevWndProcConvSec, hwnd, msg, wParam, lParam);
  1182. }
  1183.  
  1184.  
  1185. /*****************************************************************************/
  1186. /*
  1187.  * DeleteListItem: Handle all aspects of deleting a user from the list box,
  1188.  *   given his index.
  1189.  */
  1190. /*****************************************************************************/
  1191. void DeleteListItem(INT nIndex)
  1192. {
  1193.   LOCALHANDLE hLocalMem;
  1194.   INT nUsers;
  1195.  
  1196.   // Free associated password memory, if necessary
  1197.   if (hLocalMem = (LOCALHANDLE) SendMessage(hList, LB_GETITEMDATA,
  1198.                                             nIndex, 0))
  1199.     LocalFree(hLocalMem);
  1200.  
  1201.   // Simply remove currently selected user
  1202.   SendMessage(hList, LB_DELETESTRING, (WPARAM) nIndex, 0);
  1203.  
  1204.   nUsers = SendMessage(hList, LB_GETCOUNT, 0, 0);
  1205.  
  1206.   // Disable Delete & Edit buttons if no one is left
  1207.   if (0 == nUsers)
  1208.     {
  1209.       EnableWindow(GetDlgItem(hDialog, IDC_DELETE), FALSE);
  1210.       EnableWindow(GetDlgItem(hDialog, IDC_EDIT), FALSE);
  1211.       return;
  1212.     }
  1213.  
  1214.   // Move the highlight:
  1215.   // 1) If the deleted user was the last one in the list, go to previous user.
  1216.   // 2) Otherwise go to the next user.
  1217.   SendMessage(hList, LB_SETCURSEL,
  1218.               (nUsers == nIndex) ? (nIndex - 1) : nIndex, 0);
  1219. }
  1220. /*****************************************************************************/
  1221. /*
  1222.  * ReadString: Get the text from an edit box and turn it into a C string.
  1223.  *
  1224.  * Parameters:
  1225.  *
  1226.  * hDlg:  The dialog box.
  1227.  * id: The dialog item id.
  1228.  * lpString:  A double pointer to a character.  ReadString reserves space
  1229.  *            for the incoming string.
  1230.  * maxlen: The maximum number of characters to read from the edit box.
  1231.  *
  1232.  * Returns:
  1233.  *   The number of characters read from the edit box.
  1234.  */
  1235. /*****************************************************************************/
  1236. INT ReadString(HWND hDlg, INT id, char **lpString, INT maxlen)
  1237. {
  1238.   // Leave space for null character
  1239.   *lpString = malloc((maxlen + 1) * sizeof(char));
  1240.  
  1241.   return GetDlgItemText(hDlg, id, *lpString, maxlen+1);
  1242. }
  1243. /*****************************************************************************/
  1244. /*
  1245.  * DisplayError: Bring up MessageBox with given message code's string.
  1246.  */
  1247. /*****************************************************************************/
  1248. void DisplayError( HWND hwnd, UINT uError)
  1249. {
  1250.         char        sz[256], szFormat[256];
  1251.  
  1252.         if ( LoadString( hInst, uError, sz, sizeof(sz)) == 0 ) {
  1253.                 LoadString( hInst, IDS_UNKNOWN, szFormat, sizeof(szFormat) );
  1254.                 sprintf( sz, szFormat, uError );
  1255.         }
  1256.  
  1257.         LoadString( hInst, IDS_ERRORTITLE, szFormat, sizeof(szFormat) );
  1258.         MessageBox( hwnd, sz, szFormat, MB_ICONEXCLAMATION | MB_OK);
  1259. }
  1260. /*****************************************************************************/
  1261. /*
  1262.  * DisplayInfo:  Put up an information box with given message string.
  1263.  */
  1264. /*****************************************************************************/
  1265. void DisplayInfo( HWND hwnd, UINT uInfo)
  1266. {
  1267.         char        sz[256], szFormat[256];
  1268.  
  1269.         if ( LoadString( hInst, uInfo, sz, sizeof(sz) ) == 0 ) {
  1270.                 LoadString( hInst, IDS_NOMESSAGE, szFormat, sizeof(szFormat) );
  1271.                 sprintf( sz, szFormat, uInfo );
  1272.         }
  1273.  
  1274.         LoadString( hInst, IDS_INFOTITLE, szFormat, sizeof(szFormat) );
  1275.         MessageBox( hwnd, sz, szFormat, MB_ICONINFORMATION | MB_OK);
  1276. }
  1277.  
  1278. #ifdef WIN32
  1279. /*****************************************************************************/
  1280. /*
  1281.  * IsWin95Client( void ):  If this is the Win95 client, return TRUE
  1282.  */
  1283. /*****************************************************************************/
  1284.  
  1285. BOOL IsWin95Client( void )
  1286. {
  1287.     HKEY hKey;
  1288.     BOOL fRetval = FALSE;
  1289.     DWORD dwType=0;
  1290.     char  szBuffer[ 30 ];
  1291.     DWORD dwDataSize = sizeof( szBuffer );
  1292.  
  1293.  
  1294.     if( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\SNA Server\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey ) )
  1295.     {
  1296.         ; // fall through, return FALSE
  1297.     }
  1298.     else
  1299.     {
  1300.         if( ERROR_SUCCESS != RegQueryValueEx( hKey, "ClientType", 0, &dwType, szBuffer, &dwDataSize ) )
  1301.         {
  1302.             ; // fall through, return FALSE
  1303.         }
  1304.         else if( REG_SZ != dwType )
  1305.         {
  1306.             ; // fall through, return FALSE
  1307.         }
  1308.         else if( stricmp( szBuffer, "Windows 95" ) )
  1309.         {
  1310.             ; // fall through, return FALSE
  1311.         }
  1312.         else
  1313.         {
  1314.             fRetval = TRUE;
  1315.         }
  1316.  
  1317.         RegCloseKey( hKey );
  1318.     }
  1319.  
  1320.     return fRetval;
  1321.  
  1322. }
  1323.  
  1324. #endif
  1325.  
  1326. 
  1327.