home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / dwsetup.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  25.8 KB  |  1,065 lines

  1. /* Copyright (C) 1999, 2000, Ghostgum Software Pty Ltd.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. // $Id: dwsetup.cpp,v 1.5 2000/09/22 05:35:02 lpd Exp $
  20. //
  21. //
  22. // This is the setup program for Win32 AFPL Ghostscript
  23. //
  24. // The starting point is a self extracting zip archive
  25. // with the following contents:
  26. //   setupgs.exe
  27. //   uninstgs.exe
  28. //   filelist.txt      (contains list of program files)
  29. //   fontlist.txt      (contains list of font files)
  30. //   gs#.##\*          (files listed in filelist.txt)
  31. //   fonts\*           (fonts listed in fontlist.txt)
  32. // This is the same as the zip file created by Aladdin Enterprises,
  33. // with the addition of setupgs.exe, uninstgs.exe, filelist.txt and 
  34. // fontlist.txt.
  35. //
  36. // The first line of the files filelist.txt and fontlist.txt
  37. // contains the uninstall name to be used.  
  38. // The second line contains name of the main directory where 
  39. // uninstall log files are to be placed.  
  40. // Subsequent lines contain files to be copied (but not directories).
  41. // For example, filelist.txt might contain:
  42. //   AFPL Ghostscript 6.50
  43. //   gs6.50
  44. //   gs6.50\bin\gsdll32.dll
  45. //   gs6.50\lib\gs_init.ps
  46. // The file fontlist.txt might contain:
  47. //   AFPL Ghostscript Fonts
  48. //   fonts
  49. //   fonts\n019003l.pfb
  50. //   fonts\n019023l.pfb
  51. //
  52. // The default install directory is c:\gs.
  53. // The default Start Menu Folder is Ghostscript.
  54. // These are set in the resources.
  55. // The setup program will create the following uninstall log files
  56. //   c:\gs\gs#.##\uninstal.txt
  57. //   c:\gs\fonts\uninstal.txt
  58. // The uninstall program (accessed through control panel) will not 
  59. // remove directories nor will it remove itself.
  60. //
  61. // If the install directory is the same as the current file 
  62. // location, no files will be copied, but the existence of each file 
  63. // will be checked.  This allows the archive to be unzipped, then
  64. // configured in its current location.  Running the uninstall will not 
  65. // remove uninstgs.exe, setupgs.exe, filelist.txt or fontlist.txt.
  66.  
  67.  
  68. #define STRICT
  69. #include <windows.h>
  70. #include <shellapi.h>
  71. #include <objbase.h>
  72. #include <shlobj.h>
  73. #include <stdio.h>
  74. #include <direct.h>
  75.  
  76. #ifdef MAX_PATH
  77. #define MAXSTR MAX_PATH
  78. #else
  79. #define MAXSTR 256
  80. #endif
  81.  
  82. #include "dwsetup.h"
  83. #include "dwinst.h"
  84.  
  85. //#define DEBUG
  86.  
  87. #define UNINSTALLPROG "uninstgs.exe"
  88.  
  89.  
  90. /////////////////////////////////
  91. // Globals
  92.  
  93. CInstall cinst;
  94.  
  95. // TRUE = Place Start Menu items in All Users.
  96. // FALSE = Current User
  97. BOOL g_bUseCommon;
  98.  
  99. // TRUE = Destination is the same as Source, so don't copy files.
  100. BOOL g_bNoCopy;
  101.  
  102. // Source directory, usually a temporary directory created by
  103. // unzip self extractor.
  104. CHAR g_szSourceDir[MAXSTR];
  105.  
  106. // Target directory for program and fonts.
  107. // Default loaded from resources
  108. CHAR g_szTargetDir[MAXSTR];
  109.  
  110. // Target Group for shortcut.
  111. // Default loaded from resources
  112. CHAR g_szTargetGroup[MAXSTR];
  113.  
  114. // Setup application name, loaded from resources
  115. CHAR g_szAppName[MAXSTR];
  116.  
  117. BOOL g_bInstallFonts = TRUE;
  118. BOOL g_bAllUsers = FALSE;
  119.  
  120.  
  121. HWND g_hMain;        // Main install dialog
  122. HWND g_hWndText;    // Install log dialog
  123. HINSTANCE g_hInstance;
  124.  
  125. // If a directory is listed on the command line, g_bBatch will
  126. // be TRUE and a silent install will occur.
  127. BOOL g_bBatch = FALSE;    
  128.  
  129. BOOL g_bQuit = FALSE;    // TRUE = Get out of message loop.
  130. BOOL g_bError = FALSE;    // TRUE = Install was not successful
  131. BOOL is_winnt = FALSE;    // Disable "All Users" if not NT.
  132.  
  133.  
  134. // Prototypes
  135. BOOL CALLBACK MainDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  136. void gs_addmess_count(const char *str, int count);
  137. void gs_addmess(const char *str);
  138. void gs_addmess_update(void);
  139. BOOL init();
  140. BOOL install_all();
  141. BOOL install_prog();
  142. BOOL install_fonts();
  143. BOOL make_filelist(int argc, char *argv[]);
  144.  
  145.  
  146. //////////////////////////////////////////////////////////////////////
  147. // Entry point
  148. //////////////////////////////////////////////////////////////////////
  149.  
  150. int APIENTRY WinMain(HINSTANCE hInstance,
  151.                      HINSTANCE hPrevInstance,
  152.                      LPSTR     lpCmdLine,
  153.                      int       nCmdShow)
  154. {
  155.     MSG msg;
  156.     g_hInstance = hInstance;
  157.     
  158.     if (!init()) {
  159.         MessageBox(HWND_DESKTOP, "Initialisation failed", 
  160.             g_szAppName, MB_OK);
  161.         return 1;
  162.     }
  163.     
  164.     if (!g_bBatch) {
  165.         while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
  166.             if (!IsDialogMessage(g_hWndText, &msg) && 
  167.                 !IsDialogMessage(g_hMain, &msg)) {
  168.                 TranslateMessage(&msg);
  169.                 DispatchMessage(&msg);
  170.             }
  171.         }
  172.         DestroyWindow(g_hMain);
  173.     }
  174.     
  175.     return (g_bError ? 1 : 0);
  176. }
  177.  
  178.  
  179.  
  180.  
  181. //////////////////////////////////////////////////////////////////////
  182. // Text log window
  183. //////////////////////////////////////////////////////////////////////
  184.  
  185.  
  186. #define TWLENGTH 32768
  187. #define TWSCROLL 1024
  188. char twbuf[TWLENGTH];
  189. int twend;
  190.  
  191. // Modeless Dialog Box
  192. BOOL CALLBACK 
  193. TextWinDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  194. {
  195.     switch(message) {
  196.     case WM_INITDIALOG:
  197.         EnableWindow(g_hMain, FALSE);
  198.         return TRUE;
  199.     case WM_COMMAND:
  200.         switch(LOWORD(wParam)) {
  201.         case IDC_TEXTWIN_COPY:
  202.             {HGLOBAL hglobal;
  203.             LPSTR p;
  204.             DWORD result;
  205.             int start, end;
  206.             result = SendDlgItemMessage(hwnd, IDC_TEXTWIN_MLE, EM_GETSEL, (WPARAM)0, (LPARAM)0);
  207.             start = LOWORD(result);
  208.             end   = HIWORD(result);
  209.             if (start == end) {
  210.                 start = 0;
  211.                 end = twend;
  212.             }
  213.             hglobal = GlobalAlloc(GHND | GMEM_SHARE, end-start+1);
  214.             if (hglobal == (HGLOBAL)NULL) {
  215.                 MessageBeep(-1);
  216.                 return(FALSE);
  217.             }
  218.             p = (char *)GlobalLock(hglobal);
  219.             if (p == (LPSTR)NULL) {
  220.                 MessageBeep(-1);
  221.                 return(FALSE);
  222.             }
  223.             lstrcpyn(p, twbuf+start, end-start);
  224.             GlobalUnlock(hglobal);
  225.             OpenClipboard(hwnd);
  226.             EmptyClipboard();
  227.             SetClipboardData(CF_TEXT, hglobal);
  228.             CloseClipboard();
  229.             }
  230.             break;
  231.         case IDCANCEL:
  232.             g_bQuit = TRUE;
  233.             DestroyWindow(hwnd);
  234.             return TRUE;
  235.         }
  236.         break;
  237.     case WM_CLOSE:
  238.             DestroyWindow(hwnd);
  239.             return TRUE;
  240.     case WM_DESTROY:
  241.             g_bQuit = TRUE;
  242.             g_hWndText = (HWND)NULL;
  243.             EnableWindow(g_hMain, TRUE);
  244.             PostQuitMessage(0);
  245.             break;
  246.     }
  247.     return FALSE;
  248. }
  249.  
  250.  
  251.  
  252. // Add string to log window
  253. void
  254. gs_addmess_count(const char *str, int count)
  255. {
  256.     const char *s;
  257.     char *p;
  258.     int i, lfcount;
  259.     MSG msg;
  260.     
  261.     // we need to add \r after each \n, so count the \n's
  262.     lfcount = 0;
  263.     s = str;
  264.     for (i=0; i<count; i++) {
  265.         if (*s == '\n')
  266.             lfcount++;
  267.         s++;
  268.     }
  269.     
  270.     if (count + lfcount >= TWSCROLL)
  271.         return;        // too large
  272.     if (count + lfcount + twend >= TWLENGTH-1) {
  273.         // scroll buffer
  274.         twend -= TWSCROLL;
  275.         memmove(twbuf, twbuf+TWSCROLL, twend);
  276.     }
  277.     p = twbuf+twend;
  278.     for (i=0; i<count; i++) {
  279.         if (*str == '\n') {
  280.             *p++ = '\r';
  281.         }
  282.         *p++ = *str++;
  283.     }
  284.     twend += (count + lfcount);
  285.     *(twbuf+twend) = '\0';
  286.     
  287.     
  288.     // Update the dialog box
  289.     if (g_bBatch)
  290.         return;
  291.     
  292.     gs_addmess_update();
  293.     while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
  294.         if (!IsDialogMessage(g_hWndText, &msg) && 
  295.             !IsDialogMessage(g_hMain, &msg)) {
  296.             TranslateMessage(&msg);
  297.             DispatchMessage(&msg);
  298.         }
  299.     }
  300. }
  301.  
  302. void
  303. gs_addmess(const char *str)
  304. {
  305.     gs_addmess_count(str, lstrlen(str));
  306.     
  307. }
  308.  
  309.  
  310. void
  311. gs_addmess_update(void)
  312. {
  313.     HWND hwndmess = g_hWndText;
  314.     
  315.     if (g_bBatch)
  316.         return;
  317.     
  318.     if (IsWindow(hwndmess)) {
  319.         HWND hwndtext = GetDlgItem(hwndmess, IDC_TEXTWIN_MLE);
  320.         DWORD linecount;
  321.         SendMessage(hwndtext, WM_SETREDRAW, FALSE, 0);
  322.         SetDlgItemText(hwndmess, IDC_TEXTWIN_MLE, twbuf);
  323.         linecount = SendDlgItemMessage(hwndmess, IDC_TEXTWIN_MLE, EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
  324.         SendDlgItemMessage(hwndmess, IDC_TEXTWIN_MLE, EM_LINESCROLL, (WPARAM)0, (LPARAM)linecount-14);
  325.         SendMessage(hwndtext, WM_SETREDRAW, TRUE, 0);
  326.         InvalidateRect(hwndtext, (LPRECT)NULL, TRUE);
  327.         UpdateWindow(hwndtext);
  328.     }
  329. }
  330.  
  331.  
  332. //////////////////////////////////////////////////////////////////////
  333. // Browse dialog box 
  334. //////////////////////////////////////////////////////////////////////
  335.  
  336. // nasty GLOBALS
  337. char szFolderName[MAXSTR];
  338. char szDirName[MAXSTR];
  339.  
  340. BOOL CALLBACK 
  341. DirDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  342. {
  343.     WORD notify_message;
  344.     
  345.     switch(message) {
  346.     case WM_INITDIALOG:
  347.         DlgDirList(hwnd, szDirName, IDC_FILES, IDC_FOLDER, 
  348.             DDL_DRIVES | DDL_DIRECTORY);
  349.         SetDlgItemText(hwnd, IDC_TARGET, szFolderName);
  350.         return FALSE;
  351.     case WM_COMMAND:
  352.         notify_message = HIWORD(wParam);
  353.         switch (LOWORD(wParam)) {
  354.         case IDC_FILES:
  355.             if (notify_message == LBN_DBLCLK) {
  356.                 CHAR szPath[MAXSTR];
  357.                 DlgDirSelectEx(hwnd, szPath, sizeof(szPath), IDC_FILES);
  358.                 DlgDirList(hwnd, szPath, IDC_FILES, IDC_FOLDER, 
  359.                     DDL_DRIVES | DDL_DIRECTORY);
  360.             }
  361.             return FALSE;
  362.         case IDOK:
  363.             GetDlgItemText(hwnd, IDC_FOLDER, szDirName, sizeof(szDirName));
  364.             GetDlgItemText(hwnd, IDC_TARGET, szFolderName, sizeof(szFolderName));
  365.             EndDialog(hwnd, TRUE);
  366.             return TRUE;
  367.         case IDCANCEL:
  368.             EndDialog(hwnd, FALSE);
  369.             return TRUE;
  370.         }
  371.         return FALSE;
  372.     }
  373.     return FALSE;
  374. }
  375.  
  376.  
  377. //////////////////////////////////////////////////////////////////////
  378. // Initialisation and Main dialog box
  379. //////////////////////////////////////////////////////////////////////
  380.  
  381. void
  382. message_box(const char *str)
  383. {
  384.     MessageBox(HWND_DESKTOP, str, g_szAppName, MB_OK);
  385. }
  386.  
  387.  
  388. BOOL
  389. init()
  390. {
  391.     DWORD dwVersion = GetVersion();
  392.     // get source directory
  393.     GetCurrentDirectory(sizeof(g_szSourceDir), g_szSourceDir);
  394.     
  395.     // load strings
  396.     LoadString(g_hInstance, IDS_APPNAME, g_szAppName, sizeof(g_szAppName));
  397.     LoadString(g_hInstance, IDS_TARGET_GROUP, 
  398.         g_szTargetGroup, sizeof(g_szTargetGroup));
  399.     
  400.     if (LOBYTE(LOWORD(dwVersion)) < 4) {
  401.         MessageBox(HWND_DESKTOP, 
  402.             "This install program needs Windows 4.0 or later",
  403.             g_szAppName, MB_OK);
  404.         return FALSE;
  405.     }
  406.     if ( (HIWORD(dwVersion) & 0x8000) == 0)
  407.         is_winnt = TRUE;
  408.     
  409.     
  410.     cinst.SetMessageFunction(message_box);
  411.  
  412. #define MAXCMDTOKENS 128
  413.  
  414.     int argc;
  415.     LPSTR argv[MAXCMDTOKENS];
  416.     LPSTR p;
  417.     char command[256];
  418.     char *args;
  419.     char *d, *e;
  420.      
  421.     p = GetCommandLine();
  422.  
  423.     argc = 0;
  424.     args = (char *)malloc(lstrlen(p)+1);
  425.     if (args == (char *)NULL)
  426.         return 1;
  427.        
  428.     // Parse command line handling quotes.
  429.     d = args;
  430.     while (*p) {
  431.         // for each argument
  432.  
  433.         if (argc >= MAXCMDTOKENS - 1)
  434.             break;
  435.  
  436.         e = d;
  437.         while ((*p) && (*p != ' ')) {
  438.             if (*p == '\042') {
  439.                 // Remove quotes, skipping over embedded spaces.
  440.                 // Doesn't handle embedded quotes.
  441.                 p++;
  442.                 while ((*p) && (*p != '\042'))
  443.                     *d++ =*p++;
  444.             }
  445.             else 
  446.                 *d++ = *p;
  447.             if (*p)
  448.                 p++;
  449.         }
  450.         *d++ = '\0';
  451.         argv[argc++] = e;
  452.  
  453.         while ((*p) && (*p == ' '))
  454.             p++;    // Skip over trailing spaces
  455.     }
  456.     argv[argc] = NULL;
  457.  
  458.     if (strlen(argv[0]) == 0) {
  459.         GetModuleFileName(g_hInstance, command, sizeof(command)-1);
  460.         argv[0] = command;
  461.     }
  462.  
  463.     if (argc > 2) {
  464.         // Probably creating filelist.txt
  465.         return make_filelist(argc, argv);
  466.     }
  467.  
  468.  
  469.     // check if batch mode requested
  470.     // get location of target directory from command line as argv[1]
  471.     if (argc == 2) {
  472.         strncpy(g_szTargetDir, argv[1], sizeof(g_szTargetDir));
  473.         g_bBatch = TRUE;
  474.         if (is_winnt)
  475.             g_bAllUsers = TRUE;
  476.     }
  477.     if (g_bBatch) {
  478.         if (!install_all()) {
  479.             // display log showing error
  480.             g_bBatch = FALSE;
  481.             g_hWndText = CreateDialogParam(g_hInstance, 
  482.                 MAKEINTRESOURCE(IDD_TEXTWIN), 
  483.                 (HWND)HWND_DESKTOP, TextWinDlgProc, 
  484.                 (LPARAM)NULL);
  485.             gs_addmess_update();
  486.         }
  487.         return TRUE;
  488.     }
  489.     
  490.     // Interactive setup
  491.     LoadString(g_hInstance, IDS_TARGET_DIR, 
  492.         g_szTargetDir, sizeof(g_szTargetDir));
  493.     
  494.     // main dialog box
  495.     g_hMain = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_MAIN), (HWND)NULL, MainDlgProc, (LPARAM)NULL);
  496.     // centre dialog on screen
  497.     int width = GetSystemMetrics(SM_CXFULLSCREEN);
  498.     int height = GetSystemMetrics(SM_CYFULLSCREEN);
  499.     RECT rect;
  500.     GetWindowRect(g_hMain, &rect);
  501.     MoveWindow(g_hMain, (width - (rect.right - rect.left))/2,
  502.         (height - (rect.bottom - rect.top))/2,
  503.         (rect.right - rect.left),
  504.         (rect.bottom - rect.top), FALSE);
  505.     
  506.     // initialize targets
  507.     cinst.SetMessageFunction(message_box);
  508.     if (!cinst.Init(g_szSourceDir, "filelist.txt"))
  509.         return FALSE;
  510.  
  511.     SetDlgItemText(g_hMain, IDC_TARGET_DIR, g_szTargetDir);
  512.     SetDlgItemText(g_hMain, IDC_TARGET_GROUP, g_szTargetGroup);
  513.     SetDlgItemText(g_hMain, IDC_PRODUCT_NAME, cinst.GetUninstallName());
  514.     SendDlgItemMessage(g_hMain, IDC_INSTALL_FONTS, BM_SETCHECK, BST_CHECKED, 0);
  515.     ShowWindow(g_hMain, SW_SHOWNORMAL);
  516.     
  517.     return (g_hMain != (HWND)NULL); /* success */
  518. }
  519.  
  520.  
  521. // Main Modeless Dialog Box
  522. BOOL CALLBACK 
  523. MainDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  524. {
  525.     switch(message) {
  526.     case WM_INITDIALOG:
  527.         EnableWindow(GetDlgItem(hwnd, IDC_ALLUSERS), is_winnt);
  528.         return TRUE;
  529.     case WM_COMMAND:
  530.         switch(LOWORD(wParam)) {
  531.         case IDC_README:
  532.             {
  533.             char buf[MAXSTR];
  534.             sprintf(buf, "%s\\%s\\doc\\Readme.htm", g_szSourceDir,
  535.                 cinst.GetMainDir());
  536.             ShellExecute(hwnd, NULL, buf, NULL, g_szSourceDir, 
  537.                 SW_SHOWNORMAL);
  538.             }
  539.             return TRUE;
  540.         case IDC_BROWSE_DIR:
  541.             { char dir[MAXSTR];
  542.             char *p;
  543.             GetDlgItemText(hwnd, IDC_TARGET_DIR, dir, sizeof(dir));
  544.             strcpy(szDirName, dir);
  545.             if ( (p = strrchr(szDirName, '\\')) != (char *)NULL ) {
  546.                 strcpy(szFolderName, p+1);
  547.                 if (p == szDirName+2)
  548.                     p++;    // step over c:\   //
  549.                 *p = '\0';
  550.             }
  551.             else {
  552.                 strcpy(szDirName, "c:\\");
  553.                 strcpy(szFolderName, dir);
  554.             }
  555.             if (DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DIRDLG), 
  556.                 hwnd, DirDlgProc)) {
  557.                 strcpy(dir, szDirName);
  558.                 if (strlen(dir) && (dir[strlen(dir)-1] != '\\'))
  559.                     strcat(dir, "\\");
  560.                 strcat(dir, szFolderName);
  561.                 SetDlgItemText(hwnd, IDC_TARGET_DIR, dir);
  562.             }
  563.             }
  564.             return TRUE;
  565.         case IDC_BROWSE_GROUP:
  566.             { char dir[MAXSTR];
  567.             char programs[MAXSTR];
  568.             char *p;
  569.             GetDlgItemText(hwnd, IDC_TARGET_GROUP, dir, sizeof(dir));
  570.             cinst.GetPrograms(
  571.                 SendDlgItemMessage(hwnd, IDC_ALLUSERS,
  572.                 BM_GETCHECK, 0, 0) == BST_CHECKED,
  573.                 programs, sizeof(programs));
  574.             strcpy(szDirName, programs);
  575.             strcpy(szFolderName, dir);
  576.             if (DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DIRDLG), 
  577.                 hwnd, DirDlgProc)) {
  578.                 strcpy(dir, szFolderName);
  579.                 p = szDirName;
  580.                 if (strnicmp(szDirName, programs, 
  581.                     strlen(programs)) == 0) {
  582.                     p += strlen(programs);
  583.                     if (*p == '\\')
  584.                         p++;
  585.                     strcpy(dir, p);
  586.                     if (strlen(dir) && 
  587.                         (dir[strlen(dir)-1] != '\\'))
  588.                         strcat(dir, "\\");
  589.                     strcat(dir, szFolderName);
  590.                 }
  591.                 SetDlgItemText(hwnd, IDC_TARGET_GROUP, dir);
  592.             }
  593.             }
  594.             return TRUE;
  595.         case IDCANCEL:
  596.             PostQuitMessage(0);
  597.             return TRUE;
  598.         case IDC_INSTALL:
  599.             GetDlgItemText(hwnd, IDC_TARGET_DIR, 
  600.                 g_szTargetDir, sizeof(g_szTargetDir));
  601.             GetDlgItemText(hwnd, IDC_TARGET_GROUP, 
  602.                 g_szTargetGroup, sizeof(g_szTargetGroup));
  603.             g_bInstallFonts = (SendDlgItemMessage(g_hMain, 
  604.                 IDC_INSTALL_FONTS, BM_GETCHECK, 0, 0) 
  605.                 == BST_CHECKED);
  606.             g_bAllUsers = (SendDlgItemMessage(hwnd, 
  607.                 IDC_ALLUSERS, BM_GETCHECK, 0, 0
  608.                 ) == BST_CHECKED);
  609.             
  610.             // install log dialog box
  611.             g_hWndText = CreateDialogParam(g_hInstance, 
  612.                 MAKEINTRESOURCE(IDD_TEXTWIN), 
  613.                 (HWND)hwnd, TextWinDlgProc, (LPARAM)NULL);
  614.             EnableWindow(GetDlgItem(hwnd, IDC_INSTALL), FALSE);
  615.             if (install_all())
  616.                 PostQuitMessage(0);
  617.             return TRUE;
  618.         default:
  619.             return(FALSE);
  620.         }
  621.         case WM_CLOSE:
  622.             PostQuitMessage(0);
  623.             return TRUE;
  624.     }
  625.     return FALSE;
  626. }
  627.  
  628. // install program and files
  629. BOOL
  630. install_all()
  631. {
  632.     gs_addmess("Source Directory=");
  633.     gs_addmess(g_szSourceDir);
  634.     gs_addmess("\n");
  635.     gs_addmess("Target Directory=");
  636.     gs_addmess(g_szTargetDir);
  637.     gs_addmess("\n");
  638.     gs_addmess("Target Shell Folder=");
  639.     gs_addmess(g_szTargetGroup);
  640.     gs_addmess("\n");
  641.     gs_addmess(g_bAllUsers ? "  All users\n" : "  Current user\n");
  642.     
  643.     if (stricmp(g_szSourceDir, g_szTargetDir) == 0) {
  644.         // Don't copy files
  645.         if (!g_bBatch)
  646.             if (::MessageBox(g_hWndText, "Install location is the same as the current file location.  No files will be copied.", g_szAppName, MB_OKCANCEL) 
  647.                 != IDOK) {
  648.                 return FALSE;
  649.             }
  650.         g_bNoCopy = TRUE;
  651.     }
  652.     
  653.     
  654.     if (g_bQuit)
  655.         return FALSE;
  656.     
  657.     if (!install_prog()) {
  658.         cinst.CleanUp();
  659.         g_bError = TRUE;
  660.         return FALSE;
  661.     }
  662.     if (g_bInstallFonts && !install_fonts()) {
  663.         cinst.CleanUp();
  664.         g_bError = TRUE;
  665.         return FALSE;
  666.     }
  667.     
  668.     gs_addmess("Install successful\n");
  669.     
  670.     // show start menu folder
  671.     if (!g_bBatch) {
  672.         char szFolder[MAXSTR];
  673.         szFolder[0] = '\0';
  674.         cinst.GetPrograms(g_bAllUsers, szFolder, sizeof(szFolder));
  675.         strcat(szFolder, "\\");
  676.         strcat(szFolder, g_szTargetGroup);
  677.         ShellExecute(HWND_DESKTOP, "open", szFolder, 
  678.             NULL, NULL, SW_SHOWNORMAL);
  679.     }
  680.     
  681. #ifdef DEBUG
  682.     return FALSE;
  683. #endif
  684.  
  685.     return TRUE;
  686. }
  687.  
  688. BOOL
  689. install_prog()
  690. {
  691.     char *regkey1 = "AFPL Ghostscript";
  692.     char regkey2[16];
  693.     char szDLL[MAXSTR];
  694.     char szLIB[MAXSTR];
  695.     char szProgram[MAXSTR];
  696.     char szArguments[MAXSTR];
  697.     char szDescription[MAXSTR];
  698.     char szDotVersion[MAXSTR];
  699.     
  700.     if (g_bQuit)
  701.         return FALSE;
  702.     
  703.     cinst.SetMessageFunction(gs_addmess);
  704.     cinst.SetTargetDir(g_szTargetDir);
  705.     cinst.SetTargetGroup(g_szTargetGroup);
  706.     cinst.SetAllUsers(g_bAllUsers);
  707.     if (!cinst.Init(g_szSourceDir, "filelist.txt"))
  708.         return FALSE;
  709.     
  710.     // Get GS version number
  711.     gs_addmess("Installing Program...\n");
  712.     int nGSversion = 0;
  713.     const char *p = cinst.GetMainDir();
  714.     while (*p && !isdigit(*p))    // skip over "gs" prefix
  715.         p++;
  716.     if (strlen(p) == 4)
  717.         nGSversion = (p[0]-'0')*100 + (p[2]-'0')*10 + (p[3]-'0');
  718.     else if (strlen(p) == 3)
  719.         nGSversion = (p[0]-'0')*100 + (p[2]-'0')*10;
  720.         strncpy(szDotVersion, p, sizeof(szDotVersion));
  721.     strncpy(regkey2, szDotVersion, sizeof(regkey2));
  722.     
  723.     // copy files
  724.     if (!cinst.InstallFiles(g_bNoCopy, &g_bQuit)) {
  725.         gs_addmess("Program install failed\n");
  726.         return FALSE;
  727.     }
  728.     
  729.     if (g_bQuit)
  730.         return FALSE;
  731.     
  732.     // write registry entries
  733.     gs_addmess("Updating Registry\n");
  734.     if (!cinst.UpdateRegistryBegin()) {
  735.         gs_addmess("Failed to begin registry update\n");
  736.         return FALSE;
  737.     }
  738.     if (!cinst.UpdateRegistryKey(regkey1, regkey2)) {
  739.         gs_addmess("Failed to open/create registry application key\n");
  740.         return FALSE;
  741.     }
  742.     strcpy(szDLL, g_szTargetDir);
  743.     strcat(szDLL, "\\");
  744.     strcat(szDLL, cinst.GetMainDir());
  745.     strcat(szDLL, "\\bin\\gsdll32.dll");
  746.     if (!cinst.UpdateRegistryValue(regkey1, regkey2, "GS_DLL", szDLL)) {
  747.         gs_addmess("Failed to add registry value\n");
  748.         return FALSE;
  749.     }
  750.     strcpy(szLIB, g_szTargetDir);
  751.     strcat(szLIB, "\\");
  752.     strcat(szLIB, cinst.GetMainDir());
  753.     strcat(szLIB, "\\lib;");
  754.     strcat(szLIB, g_szTargetDir);
  755.     strcat(szLIB, "\\fonts");
  756.     if (!cinst.UpdateRegistryValue(regkey1, regkey2, "GS_LIB", szLIB)) {
  757.         gs_addmess("Failed to add registry value\n");
  758.         return FALSE;
  759.     }
  760.     if (!cinst.UpdateRegistryEnd()) {
  761.         gs_addmess("Failed to end registry update\n");
  762.         return FALSE;
  763.     }
  764.     if (g_bQuit)
  765.         return FALSE;
  766.     
  767.     // Add Start Menu items
  768.     gs_addmess("Adding Start Menu items\n");
  769.     if (!cinst.StartMenuBegin()) {
  770.         gs_addmess("Failed to begin Start Menu update\n");
  771.         return FALSE;
  772.     }
  773.     strcpy(szProgram, g_szTargetDir);
  774.     strcat(szProgram, "\\");
  775.     strcat(szProgram, cinst.GetMainDir());
  776.     strcat(szProgram, "\\bin\\gswin32.exe");
  777.     strcpy(szArguments, "\042-I");
  778.     strcat(szArguments, szLIB);
  779.     strcat(szArguments, "\042");
  780.     sprintf(szDescription, "Ghostscript %s", szDotVersion);
  781.     if (!cinst.StartMenuAdd(szDescription, szProgram, szArguments)) {
  782.         gs_addmess("Failed to add Start Menu item\n");
  783.         return FALSE;
  784.     }
  785.     strcpy(szProgram, g_szTargetDir);
  786.     strcat(szProgram, "\\");
  787.     strcat(szProgram, cinst.GetMainDir());
  788.     strcat(szProgram, "\\doc\\Readme.htm");
  789.     sprintf(szDescription, "Ghostscript Readme %s", szDotVersion);
  790.     if (!cinst.StartMenuAdd(szDescription, szProgram, NULL)) {
  791.         gs_addmess("Failed to add Start Menu item\n");
  792.         return FALSE;
  793.     }
  794.     if (!cinst.StartMenuEnd()) {
  795.         gs_addmess("Failed to end Start Menu update\n");
  796.         return FALSE;
  797.     }
  798.     
  799.     // consolidate logs into one uninstall file
  800.     if (cinst.MakeLog()) {
  801.         // add uninstall entry for "Add/Remove Programs"
  802.         gs_addmess("Adding uninstall program\n");
  803.         if (!cinst.WriteUninstall(UNINSTALLPROG, g_bNoCopy)) {
  804.             gs_addmess("Failed to write uninstall entry\n");
  805.             return FALSE;
  806.         }
  807.     }
  808.     else {
  809.         gs_addmess("Failed to write uninstall log\n");
  810.         // If batch install, files might be on a server
  811.         // in a write protected directory.
  812.         // Don't return an error for batch install.
  813.         if (g_bBatch)
  814.             return TRUE;
  815.         return FALSE;
  816.     }
  817.     
  818.     gs_addmess("Program install successful\n");
  819.     return TRUE;
  820. }
  821.  
  822.  
  823. BOOL
  824. install_fonts()
  825. {
  826.     cinst.SetMessageFunction(gs_addmess);
  827.     cinst.SetTargetDir(g_szTargetDir);
  828.     cinst.SetTargetGroup(g_szTargetGroup);
  829.     cinst.SetAllUsers(g_bAllUsers);
  830.     if (!cinst.Init(g_szSourceDir, "fontlist.txt"))
  831.         return FALSE;
  832.     
  833.     // copy files
  834.     if (!cinst.InstallFiles(g_bNoCopy, &g_bQuit)) {
  835.         gs_addmess("Font install failed\n");
  836.         return FALSE;
  837.     }
  838.     
  839.     if (g_bQuit)
  840.         return FALSE;
  841.     
  842.     if (g_bNoCopy) {
  843.         // Don't write uninstall log or entry
  844.         // since we didn't copy any files.
  845.         cinst.CleanUp();
  846.     }
  847.     else {
  848.         // consolidate logs into one uninstall file
  849.         if (cinst.MakeLog()) {
  850.             // add uninstall entry for "Add/Remove Programs"
  851.             gs_addmess("Adding uninstall program\n");
  852.             if (!cinst.WriteUninstall(UNINSTALLPROG, g_bNoCopy)) {
  853.                 gs_addmess("Failed to write uninstall entry\n");
  854.                 return FALSE;
  855.             }
  856.         }
  857.         else {
  858.             gs_addmess("Failed to write uninstall log\n");
  859.             // If batch install, files might be on a server
  860.             // in a write protected directory.
  861.             // Don't return an error for batch install.
  862.             if (g_bBatch)
  863.                 return TRUE;
  864.             return FALSE;
  865.         }
  866.     }
  867.     
  868.     gs_addmess("Font install successful\n");
  869.     return TRUE;
  870. }
  871.  
  872.  
  873.  
  874. //////////////////////////////////////////////////////////////////////
  875. // Create file list
  876. //////////////////////////////////////////////////////////////////////
  877.  
  878. FILE *fList;
  879.  
  880. typedef int (*PFN_dodir)(const char *name);
  881.  
  882. /* Called once for each directory */
  883. int
  884. dodir(const char *filename)
  885. {
  886.     return 0;
  887. }
  888.  
  889. /* Called once for each file */
  890. int
  891. dofile(const char *filename)
  892. {
  893.     if (fList != (FILE *)NULL) {
  894.         fputs(filename, fList);
  895.         fputs("\n", fList);
  896.     }
  897.     
  898.     return 0;
  899. }
  900.  
  901.  
  902. /* Walk through directory 'path', calling dodir() for given directory
  903.  * and dofile() for each file.
  904.  * If recurse=1, recurse into subdirectories, calling dodir() for
  905.  * each directory.
  906.  */
  907. int 
  908. dirwalk(char *path, int recurse, PFN_dodir dodir, PFN_dodir dofile)
  909. {    
  910.     WIN32_FIND_DATA find_data;
  911.     HANDLE find_handle;
  912.     char pattern[MAXSTR];    /* orig pattern + modified pattern */
  913.     char base[MAXSTR];
  914.     char name[MAXSTR];
  915.     BOOL bMore = TRUE;
  916.     char *p;
  917.     
  918.     
  919.     if (path) {
  920.         strcpy(pattern, path);
  921.         if (strlen(pattern) != 0)  {
  922.             p = pattern + strlen(pattern) -1;
  923.             if (*p == '\\')
  924.                 *p = '\0';        // truncate trailing backslash
  925.         }
  926.         
  927.         strcpy(base, pattern);
  928.         if (strchr(base, '*') != NULL) {
  929.             // wildcard already included
  930.             // truncate it from the base path
  931.             if ( (p = strrchr(base, '\\')) != NULL )
  932.                 *(++p) = '\0';
  933.         }
  934.         else if (isalpha(pattern[0]) && 
  935.             pattern[1]==':' && pattern[2]=='\0')  {
  936.             strcat(pattern, "\\*");        // search entire disk
  937.             strcat(base, "\\");
  938.         }
  939.         else {
  940.             // wildcard NOT included
  941.             // check to see if path is a directory
  942.             find_handle = FindFirstFile(pattern, &find_data);
  943.             if (find_handle != INVALID_HANDLE_VALUE) {
  944.                 FindClose(find_handle);
  945.                 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  946.                     strcat(pattern, "\\*");        // yes, search files 
  947.                     strcat(base, "\\");
  948.                 }
  949.                 else {
  950.                     dofile(path);                // no, return just this file
  951.                     return 0;
  952.                 }
  953.             }
  954.             else
  955.                 return 1;    // path invalid
  956.         }
  957.     }
  958.     else {
  959.         base[0] = '\0';
  960.         strcpy(pattern, "*");
  961.     }
  962.     
  963.     find_handle = FindFirstFile(pattern,  &find_data);
  964.     if (find_handle == INVALID_HANDLE_VALUE)
  965.         return 1;
  966.     
  967.     while (bMore) {
  968.         strcpy(name, base);
  969.         strcat(name, find_data.cFileName);
  970.         if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  971.             if ( strcmp(find_data.cFileName, ".") && 
  972.                 strcmp(find_data.cFileName, "..") ) {
  973.                 dodir(name);
  974.                 if (recurse)
  975.                     dirwalk(name, recurse, dodir, dofile);
  976.             }
  977.         }
  978.         else {
  979.             dofile(name);
  980.         }
  981.         bMore = FindNextFile(find_handle, &find_data);
  982.     }
  983.     FindClose(find_handle);
  984.     
  985.     return 0;
  986. }
  987.  
  988.  
  989.  
  990. // This is used when creating a file list.
  991.  
  992. BOOL make_filelist(int argc, char *argv[])
  993. {
  994.     char *title = NULL;
  995.     char *dir = NULL;
  996.     char *list = NULL;
  997.     int i;
  998.     g_bBatch = TRUE;    // Don't run message loop
  999.     
  1000.     for (i=1; i<argc; i++) {
  1001.         if (strcmp(argv[i], "-title") == 0) {
  1002.             i++;
  1003.             title = argv[i];
  1004.         }
  1005.         else if (strcmp(argv[i], "-dir") == 0) {
  1006.             i++;
  1007.             dir = argv[i];
  1008.         }
  1009.         else if (strcmp(argv[i], "-list") == 0) {
  1010.             i++;
  1011.             list = argv[i];
  1012.         }
  1013.         else {
  1014.             if ((title == NULL) || (strlen(title) == 0) ||
  1015.             (dir == NULL) || (strlen(dir) == 0) ||
  1016.             (list == NULL) || (strlen(list) == 0)) {
  1017.             message_box("Usage: setupgs -title \042AFPL Ghostscript #.##\042 -dir \042gs#.##\042 -list \042filelist.txt\042 spec1 spec2 specn\n");
  1018.             return FALSE;
  1019.             }
  1020.             if (fList == (FILE *)NULL) {
  1021.                 if ( (fList = fopen(list, "w")) == (FILE *)NULL ) {
  1022.                     message_box("Can't write list file\n");
  1023.                     return FALSE;
  1024.                 }
  1025.                 fputs(title, fList);
  1026.                 fputs("\n", fList);
  1027.                 fputs(dir, fList);
  1028.                 fputs("\n", fList);
  1029.             }
  1030.             if (argv[i][0] == '@') {
  1031.             // Use @filename with list of files/directories
  1032.             // to avoid DOS command line limit
  1033.             FILE *f;
  1034.             char buf[MAXSTR];
  1035.             int j;
  1036.             if ( (f = fopen(&(argv[i][1]), "r")) != (FILE *)NULL) {
  1037.                 while (fgets(buf, sizeof(buf), f)) {
  1038.                 // remove trailing newline and spaces
  1039.                 while ( ((j = strlen(buf)-1) >= 0) &&
  1040.                     ((buf[j] == '\n') || (buf[j] == ' ')) )
  1041.                     buf[j] = '\0';
  1042.                     dirwalk(buf, TRUE, &dodir, &dofile);
  1043.                 }
  1044.                 fclose(f);
  1045.             }
  1046.             else {
  1047.                 wsprintf(buf, "Can't open @ file \042%s\042",
  1048.                     &argv[i][1]);
  1049.                 message_box(buf);
  1050.             }
  1051.             }
  1052.             else
  1053.                 dirwalk(argv[i], TRUE, &dodir, &dofile);
  1054.         }
  1055.     }
  1056.     
  1057.     if (fList != (FILE *)NULL) {
  1058.         fclose(fList);
  1059.     fList = NULL;
  1060.     }
  1061.     return TRUE;
  1062. }
  1063.  
  1064. //////////////////////////////////////////////////////////////////////
  1065.