Back to index

lightning-sunbird  0.9+nobinonly
stubinstall.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/LGPL 2.1/GPL 2.0
00003  *
00004  * The contents of this file are subject to the Mozilla Public
00005  * License Version 1.1 (the "License"); you may not use this file
00006  * except in compliance with the License. You may obtain a copy of
00007  * the License at http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS
00010  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00011  * implied. See the License for the specific language governing
00012  * rights and limitations under the License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is IBM Corporation.
00017  * Portions created by IBM are
00018  *   Copyright (C) 2002, International Business Machines Corporation.
00019  *   All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *     Troy Chevalier <troy@netscape.com>
00023  *     Sean Su <ssu@netscape.com>
00024  *
00025  *  Alternatively, the contents of this file may be used under the terms of
00026  *  either of the GNU General Public License Version 2 or later (the "GPL"),
00027  *  or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  *  in which case the provisions of the GPL or the LGPL are applicable instead
00029  *  of those above. If you wish to allow use of your version of this file only
00030  *  under the terms of either the GPL or the LGPL, and not to allow others to
00031  *  use your version of this file under the terms of the MPL, indicate your
00032  *  decision by deleting the provisions above and replace them with the notice
00033  *  and other provisions required by the LGPL or the GPL. If you do not delete
00034  *  the provisions above, a recipient may use your version of this file under
00035  *  the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #define INCL_PM
00040 #define INCL_DOS
00041 #define INCL_DOSERRORS
00042 #include <os2.h>
00043 #include <string.h>
00044 #include <memory.h>
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <sys\stat.h>
00048 
00049 
00050 #include "resource.h"
00051 #include "nsINIParser.h"
00052 
00053 #define MAX_BUF       4096
00054 #define WIZ_TEMP_DIR  "ns_temp"
00055 
00056 /* Mode of Setup to run in */
00057 #define NORMAL                          0
00058 #define SILENT                          1
00059 #define AUTO                            2
00060 
00061 /* PP: Parse Path */
00062 #define PP_FILENAME_ONLY                1
00063 #define PP_PATH_ONLY                    2
00064 #define PP_ROOT_ONLY                    3
00065 
00066 #define CLASS_NAME_SETUP_DLG            "MozillaSetupDlg"
00067 
00069 // Global Declarations
00070 
00071 char      szTitle[MAX_BUF];
00072 char      szCmdLineToSetup[MAX_BUF];
00073 BOOL      gbUncompressOnly;
00074 ULONG     ulMode;
00075 static ULONG  nTotalBytes = 0;  // sum of all the FILE resources
00076 
00077 char szOSTempDir[CCHMAXPATH];
00078 
00080 // Utility Functions
00081 
00082 BOOL isFAT(char* szPath)
00083 {
00084   APIRET rc;
00085   ULONG ulSize;
00086   PFSQBUFFER2 pfsqbuf2;
00087   CHAR szDrive[3];
00088 
00089   ulSize = sizeof(FSQBUFFER2) + 3 * CCHMAXPATH;
00090   pfsqbuf2 = (PFSQBUFFER2)malloc(ulSize);
00091   strncpy(szDrive, szPath, 2);
00092   szDrive[2] = '\0';
00093 
00094   DosError(FERR_DISABLEHARDERR);
00095   rc = DosQueryFSAttach(szDrive, 0, FSAIL_QUERYNAME,
00096                         pfsqbuf2, &ulSize);
00097   DosError(FERR_ENABLEHARDERR);
00098 
00099   if (rc == NO_ERROR) {
00100     if (strcmp((char*)(pfsqbuf2->szFSDName + pfsqbuf2->cbName), "FAT") != 0)
00101       return FALSE;
00102   }
00103 
00104   return TRUE;
00105 }
00106 
00107 HWND FindWindow(PCSZ pszAtomString)
00108 {
00109   ATOM atom;
00110   HENUM henum;
00111   HWND hwndClient, hwnd = NULLHANDLE;
00112 
00113 
00114   atom = WinFindAtom(WinQuerySystemAtomTable(), pszAtomString);
00115   if (atom) {
00116     henum = WinBeginEnumWindows(HWND_DESKTOP);
00117     while ((hwnd = WinGetNextWindow(henum)) != NULLHANDLE)
00118     {
00119       ULONG ulWindowWord;
00120       ulWindowWord = WinQueryWindowULong(hwnd, QWL_USER);
00121       if (ulWindowWord == atom) {
00122         break;
00123       }
00124     }
00125   }
00126   WinEndEnumWindows(henum);
00127   return  hwnd;
00128 }
00129 
00130 // this function appends a backslash at the end of a string,
00131 // if one does not already exists.
00132 static void AppendBackSlash(PSZ szInput, ULONG ulInputSize)
00133 {
00134   if(szInput != NULL)
00135   {
00136     if(szInput[strlen(szInput) - 1] != '\\')
00137     {
00138       if(((ULONG)strlen(szInput) + 1) < ulInputSize)
00139       {
00140         strcat(szInput, "\\");
00141       }
00142     }
00143   }
00144 }
00145 
00146 // This function is similar to GetFullPathName except instead of
00147 // using the current drive and directory it uses the path of the
00148 // directory designated for temporary files
00149 // If you don't specify a filename, you just get the temp dir without
00150 // a trailing slash
00151 static BOOL
00152 GetFullTempPathName(PCSZ szFileName, ULONG ulBufferLength, PSZ szBuffer)
00153 {
00154   strcpy(szBuffer, szOSTempDir);
00155   AppendBackSlash(szBuffer, MAX_BUF);
00156   strcat(szBuffer, WIZ_TEMP_DIR);
00157 
00158   if (szFileName) {
00159     AppendBackSlash(szBuffer, MAX_BUF);
00160     strcat(szBuffer, szFileName);
00161   }
00162 
00163   return TRUE;
00164 }
00165 
00166 
00167 static void CreateDirectoriesAll(char* szPath)
00168 {
00169   int     i;
00170   int     iLen = strlen(szPath);
00171   char    szCreatePath[CCHMAXPATH];
00172 
00173   memset(szCreatePath, 0, CCHMAXPATH);
00174   memcpy(szCreatePath, szPath, iLen);
00175   for(i = 0; i < iLen; i++)
00176   {
00177     if((iLen > 1) &&
00178       ((i != 0) && ((szPath[i] == '\\') || (szPath[i] == '/'))) &&
00179       (!((szPath[0] == '\\') && (i == 1)) && !((szPath[1] == ':') && (i == 2))))
00180     {
00181       szCreatePath[i] = '\0';
00182       DosCreateDir(szCreatePath, NULL);  
00183       szCreatePath[i] = szPath[i];
00184     }
00185   }
00186 }
00187 
00188 // This function removes a directory and its subdirectories
00189 void DirectoryRemove(PSZ szDestination, BOOL bRemoveSubdirs)
00190 {
00191   HDIR            hFile;
00192   FILEFINDBUF3    fdFile;
00193   ULONG           ulFindCount;
00194   ULONG           ulAttrs;
00195   char            szDestTemp[MAX_BUF];
00196   BOOL            bFound;
00197 
00198   if(bRemoveSubdirs == TRUE)
00199   {
00200     strcpy(szDestTemp, szDestination);
00201     AppendBackSlash(szDestTemp, sizeof(szDestTemp));
00202     strcat(szDestTemp, "*");
00203 
00204     ulFindCount = 1;
00205     hFile = HDIR_CREATE;
00206     ulAttrs = FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED;
00207     if((DosFindFirst(szDestTemp, &hFile, ulAttrs, &fdFile, sizeof(fdFile), &ulFindCount, FIL_STANDARD)) != NO_ERROR)
00208       bFound = FALSE;
00209     else
00210       bFound = TRUE;
00211     while(bFound == TRUE)
00212     {
00213       if((stricmp(fdFile.achName, ".") != 0) && (stricmp(fdFile.achName, "..") != 0))
00214       {
00215         /* create full path */
00216         strcpy(szDestTemp, szDestination);
00217         AppendBackSlash(szDestTemp, sizeof(szDestTemp));
00218         strcat(szDestTemp, fdFile.achName);
00219 
00220         if(fdFile.attrFile & FILE_DIRECTORY)
00221         {
00222           DirectoryRemove(szDestTemp, bRemoveSubdirs);
00223         }
00224         else
00225         {
00226           DosDelete(szDestTemp);
00227         }
00228       }
00229 
00230       ulFindCount = 1;
00231       if (DosFindNext(hFile, &fdFile, sizeof(fdFile), &ulFindCount) != NO_ERROR)
00232          bFound = FALSE;
00233       else
00234          bFound = TRUE;
00235     }
00236 
00237     DosFindClose(hFile);
00238   }
00239   
00240   DosDeleteDir(szDestination);
00241 }
00242 
00243 void RemoveBackSlash(PSZ szInput)
00244 {
00245   int   iCounter;
00246   ULONG ulInputLen;
00247 
00248   if(szInput != NULL)
00249   {
00250     ulInputLen = strlen(szInput);
00251 
00252     for(iCounter = ulInputLen -1; iCounter >= 0 ; iCounter--)
00253     {
00254       if(szInput[iCounter] == '\\')
00255         szInput[iCounter] = '\0';
00256       else
00257         break;
00258     }
00259   }
00260 }
00261 
00262 void ParsePath(PSZ szInput, PSZ szOutput, ULONG ulOutputSize, ULONG ulType)
00263 {
00264   int   iCounter;
00265   ULONG ulCounter;
00266   ULONG ulInputLen;
00267   BOOL  bFound;
00268 
00269   if((szInput != NULL) && (szOutput != NULL))
00270   {
00271     bFound        = TRUE;
00272     ulInputLen    = strlen(szInput);
00273     memset(szOutput, 0, ulOutputSize);
00274 
00275     if(ulInputLen < ulOutputSize)
00276     {
00277       switch(ulType)
00278       {
00279         case PP_FILENAME_ONLY:
00280           for(iCounter = ulInputLen - 1; iCounter >= 0; iCounter--)
00281           {
00282             if(szInput[iCounter] == '\\')
00283             {
00284               strcpy(szOutput, &szInput[iCounter + 1]);
00285               bFound = TRUE;
00286               break;
00287             }
00288           }
00289           if(bFound == FALSE)
00290             strcpy(szOutput, szInput);
00291 
00292           break;
00293 
00294         case PP_PATH_ONLY:
00295           for(iCounter = ulInputLen - 1; iCounter >= 0; iCounter--)
00296           {
00297             if(szInput[iCounter] == '\\')
00298             {
00299               strcpy(szOutput, szInput);
00300               szOutput[iCounter + 1] = '\0';
00301               bFound = TRUE;
00302               break;
00303             }
00304           }
00305           if(bFound == FALSE)
00306             strcpy(szOutput, szInput);
00307 
00308           break;
00309 
00310         case PP_ROOT_ONLY:
00311           if(szInput[1] == ':')
00312           {
00313             szOutput[0] = szInput[0];
00314             szOutput[1] = szInput[1];
00315             AppendBackSlash(szOutput, ulOutputSize);
00316           }
00317           else if(szInput[1] == '\\')
00318           {
00319             int iFoundBackSlash = 0;
00320             for(ulCounter = 0; ulCounter < ulInputLen; ulCounter++)
00321             {
00322               if(szInput[ulCounter] == '\\')
00323               {
00324                 szOutput[ulCounter] = szInput[ulCounter];
00325                 ++iFoundBackSlash;
00326               }
00327 
00328               if(iFoundBackSlash == 3)
00329                 break;
00330             }
00331 
00332             if(iFoundBackSlash != 0)
00333               AppendBackSlash(szOutput, ulOutputSize);
00334           }
00335           break;
00336       }
00337     }
00338   }
00339 }
00340 
00341 void ParseCommandLine(int argc, char *argv[])
00342 {
00343   char  szArgVBuf[MAX_BUF];
00344   int   i = 1;
00345 
00346   memset(szCmdLineToSetup, 0, MAX_BUF);
00347   ulMode = NORMAL;
00348   gbUncompressOnly = FALSE;
00349   strcpy(szCmdLineToSetup, " ");
00350   while(i < argc)
00351   {
00352     if((stricmp(argv[i], "-ms") == 0) || (stricmp(argv[i], "/ms") == 0))
00353     {
00354       ulMode = SILENT;
00355     }
00356     else if((stricmp(argv[i], "-u") == 0) || (stricmp(argv[i], "/u") == 0))
00357     {
00358       gbUncompressOnly = TRUE;
00359     }
00360     strcat(szCmdLineToSetup, argv[i]); 
00361     strcat(szCmdLineToSetup, " ");
00362     ++i;
00363   }
00364 }
00365 
00367 // Extract Files Dialog
00368 
00369 // Window proc for dialog
00370 MRESULT EXPENTRY DialogProc(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
00371 {
00372   switch (msg) {
00373     case WM_INITDLG:
00374       {
00375         SWP swpDlg;
00376         WinQueryWindowPos(hwndDlg, &swpDlg);
00377         WinSetWindowPos(hwndDlg,
00378                         HWND_TOP,
00379                         (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)/2)-(swpDlg.cx/2),
00380                         (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)/2)-(swpDlg.cy/2),
00381                         0,
00382                         0,
00383                         SWP_MOVE);
00384         WinSendMsg(WinWindowFromID(hwndDlg, IDC_GAUGE),SLM_SETSLIDERINFO,
00385                    MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE),
00386                    0);
00387       }
00388   }
00389   return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
00390 }
00391 
00392 void DeleteTempFiles(ULONG ulNumFiles)
00393 {
00394   ULONG ulSize;
00395   void* pFileData;
00396   FILE* fhFile;
00397   char  szTmpFile[CCHMAXPATH] = "";
00398   char  szFileName[CCHMAXPATH] = "";
00399 
00400   for (int i=1;i<=ulNumFiles;i++) {
00401     WinLoadString(0, NULLHANDLE, ID_FILE_BASE+i, CCHMAXPATH, szFileName);
00402     GetFullTempPathName(szFileName, sizeof(szTmpFile), szTmpFile);
00403     DosDelete(szTmpFile);
00404   }
00405 }
00406 
00407 
00408 BOOL
00409 ExtractFiles(ULONG ulNumFiles, HWND hwndDlg)
00410 {
00411   ULONG ulSize;
00412   void* pFileData;
00413   FILE* fhFile;
00414   char  szTmpFile[CCHMAXPATH] = "";
00415   char  szFileName[CCHMAXPATH] = "";
00416   char  szArcLstFile[CCHMAXPATH] = "";
00417   char  szStatus[256];
00418   char  szText[256];
00419   ULONG nBytesWritten = 0;
00420 
00421   WinLoadString(0, NULLHANDLE, IDS_STATUS_EXTRACTING, sizeof(szText), szText);
00422 
00423   if(gbUncompressOnly == FALSE) {
00424     // CreateDirectoriesAll takes a fully qualified file, so we create one
00425     GetFullTempPathName("tempfile", sizeof(szTmpFile), szTmpFile);
00426     CreateDirectoriesAll(szTmpFile);
00427     GetFullTempPathName("Archive.lst", sizeof(szArcLstFile), szArcLstFile);
00428   } else {
00429     strcpy(szArcLstFile, "Archive.lst");
00430   }
00431 
00432   for (int i=1;i<=ulNumFiles;i++) {
00433     WinLoadString(0, NULLHANDLE, ID_FILE_BASE+i, CCHMAXPATH, szFileName);
00434     // Update the UI
00435     sprintf(szStatus, szText, szFileName);
00436     WinSetWindowText(WinWindowFromID(hwndDlg, IDC_STATUS), szStatus);
00437     if(gbUncompressOnly == FALSE) {
00438       GetFullTempPathName(szFileName, sizeof(szTmpFile), szTmpFile);
00439     } else {
00440       strcpy(szTmpFile, szFileName);
00441     }
00442 
00443     DosQueryResourceSize(NULLHANDLE, RT_RCDATA, ID_FILE_BASE+i, &ulSize);
00444     DosGetResource(NULLHANDLE, RT_RCDATA, ID_FILE_BASE+i, &pFileData);
00445     FILE* fhFile = fopen(szTmpFile, "wb+");
00446     fwrite(pFileData, ulSize, 1, fhFile);
00447     fclose(fhFile);
00448     DosFreeResource(pFileData);
00449     nBytesWritten += ulSize;
00450     WinSendMsg(WinWindowFromID(hwndDlg, IDC_GAUGE), SLM_SETSLIDERINFO,
00451                                MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE),
00452                                MPARAM(nBytesWritten * 100 / nTotalBytes));
00453     WritePrivateProfileString("Archives", szFileName, "TRUE", szArcLstFile);
00454   }
00455 }
00456 
00457 BOOL FileExists(PSZ szFile)
00458 {
00459   struct stat st;
00460   int statrv;
00461 
00462   statrv = stat(szFile, &st);
00463   if (statrv == 0)
00464      return(TRUE);
00465   else
00466      return (FALSE);
00467 }
00468 
00469 void RunInstaller(ULONG ulNumFiles, HWND hwndDlg)
00470 {
00471   char                szCmdLine[MAX_BUF];
00472   char                szSetupFile[CCHMAXPATH];
00473   char                szUninstallFile[CCHMAXPATH];
00474   char                szArcLstFile[CCHMAXPATH];
00475   char                szText[256];
00476   char                szTempPath[CCHMAXPATH];
00477   char                szFilename[CCHMAXPATH];
00478   char                szBuf[MAX_BUF];
00479   ULONG               ulLen;
00480 
00481   // Update UI
00482   WinSendMsg(WinWindowFromID(hwndDlg, IDC_GAUGE),SLM_SETSLIDERINFO,
00483              MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE),
00484              0);
00485   WinLoadString(0, NULLHANDLE, IDS_STATUS_LAUNCHING_SETUP, sizeof(szText), szText);
00486   WinSetWindowText(WinWindowFromID(hwndDlg, IDC_STATUS), szText);
00487 
00488   // Setup program is in the directory specified for temporary files
00489   GetFullTempPathName("Archive.lst",   sizeof(szArcLstFile),    szArcLstFile);
00490   GetFullTempPathName("SETUP.EXE",     sizeof(szSetupFile),     szSetupFile);
00491   GetFullTempPathName("uninstall.exe", sizeof(szUninstallFile), szUninstallFile);
00492 
00493   GetPrivateProfileString("Archives", "uninstall.exe", "", szBuf, sizeof(szBuf), szArcLstFile);
00494   if(FileExists(szUninstallFile) && (*szBuf != '\0'))
00495   {
00496     strcpy(szCmdLine, szUninstallFile);
00497     ulLen = strlen(szUninstallFile);
00498   }
00499   else
00500   {
00501     strcpy(szCmdLine, szSetupFile);
00502     PPIB ppib;
00503     PTIB ptib;
00504     char buffer[CCHMAXPATH];
00505     DosGetInfoBlocks( &ptib, &ppib);
00506     DosQueryModuleName(ppib->pib_hmte, sizeof(szBuf), szBuf);
00507     ParsePath(szBuf, szFilename, sizeof(szFilename), PP_FILENAME_ONLY);
00508 
00509     strcat(szCmdLine, " -n ");
00510     strcat(szCmdLine, szFilename);
00511     ulLen = strlen(szSetupFile);
00512   }
00513 
00514   strcat(szCmdLine, szCmdLineToSetup);
00515 
00516   // Launch the installer
00517   RESULTCODES rcChild;
00518   PID pidChild;
00519   CHAR szLoadError[CCHMAXPATH];
00520 
00521   szCmdLine[strlen(szCmdLine)] = '\0';
00522   szCmdLine[strlen(szCmdLine)+1] = '\0';
00523   szCmdLine[ulLen] = '\0';
00524 
00525   DosExecPgm(szLoadError,
00526              sizeof(szLoadError),
00527              EXEC_ASYNCRESULT,
00528              szCmdLine,
00529              NULL,
00530              &rcChild,
00531              szCmdLine);
00532 
00533   if(ulMode != SILENT)
00534   {
00535     WinDestroyWindow(hwndDlg);
00536   }
00537 
00538   DosWaitChild(DCWA_PROCESS,
00539                DCWW_WAIT,
00540                &rcChild,
00541                &pidChild,
00542                rcChild.codeTerminate);
00543 
00544   DeleteTempFiles(ulNumFiles);
00545 
00546   GetFullTempPathName("Archive.lst", sizeof(szTempPath), szTempPath);
00547   DosDelete(szTempPath);
00548   GetFullTempPathName("xpcom.ns", sizeof(szTempPath), szTempPath);
00549   DirectoryRemove(szTempPath, TRUE);
00550   GetFullTempPathName(NULL, sizeof(szTempPath), szTempPath);
00551   DirectoryRemove(szTempPath, TRUE);
00552 }
00553 
00554 int main(int argc, char *argv[], char *envp[])
00555 {
00556   HAB hab;
00557   HMQ hmq;
00558   HWND hwndFW, hwndDlg;
00559   ATOM atom;
00560 
00561   hab = WinInitialize(0);
00562   hmq = WinCreateMsgQueue(hab,0);
00563 
00564   atom = WinAddAtom(WinQuerySystemAtomTable(), "NSExtracting");
00565 
00566   char *tempEnvVar = NULL;
00567 
00568   // determine the system's TEMP path
00569   tempEnvVar = getenv("TMP");
00570   if ((tempEnvVar) && (!(isFAT(tempEnvVar)))) {
00571     strcpy(szOSTempDir, tempEnvVar);
00572   }
00573   else
00574   {
00575     tempEnvVar = getenv("TEMP");
00576     if (tempEnvVar)
00577       strcpy(szOSTempDir, tempEnvVar);
00578   }
00579   if ((!tempEnvVar) || (isFAT(tempEnvVar)))
00580   {
00581     ULONG ulBootDrive = 0;
00582     APIRET rc;
00583     char  buffer[] = " :\\OS2\\";
00584     DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
00585                     &ulBootDrive, sizeof(ulBootDrive));
00586     buffer[0] = 'A' - 1 + ulBootDrive;
00587     if (isFAT(buffer)) {
00588        /* Try current disk if boot drive is FAT */
00589        ULONG ulDriveNum;
00590        ULONG ulDriveMap;
00591        strcpy(buffer, " :\\");
00592        DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
00593        buffer[0] = 'A' - 1 + ulDriveNum;
00594        if (isFAT(buffer)) {
00595          int i;
00596          for (i = 2; i < 26; i++) {
00597            if ((ulDriveMap<<(31-i)) >> 31) {
00598              buffer[0] = 'A' + i;
00599              if (!(isFAT(buffer))) {
00600                 break;
00601              }
00602            }
00603          }
00604          if (i == 26) {
00605             char szBuf[MAX_BUF];
00606             WinLoadString(0, NULLHANDLE, IDS_ERROR_NO_LONG_FILENAMES, sizeof(szBuf), szBuf);
00607             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szBuf, NULL, 0, MB_ICONEXCLAMATION);
00608             return(1);
00609          }
00610        }
00611     }
00612     strcpy(szOSTempDir, buffer);
00613     strcat(szOSTempDir, "TEMP");
00614   }
00615 
00616   WinLoadString(0, NULLHANDLE, IDS_TITLE, MAX_BUF, szTitle);
00617 
00618   /* Allow only one instance of stubnsinstall to run.
00619    * Detect a previous instance of stubnsinstall, bring it to the 
00620    * foreground, and quit current instance */
00621   if(FindWindow("NSExtracting") != NULL)
00622     return(1);
00623 
00624   /* Allow only one instance of Setup to run.
00625    * Detect a previous instance of Setup, and quit */
00626   if((hwndFW = FindWindow(CLASS_NAME_SETUP_DLG)) != NULL)
00627   {
00628     WinSetActiveWindow(HWND_DESKTOP, hwndFW);
00629     return(1);
00630   }
00631 
00632   // Parse the command line
00633   ParseCommandLine(argc, argv);
00634 
00635   ULONG ulSize;
00636   ULONG ulNumFiles = 0;
00637   INT i = 1;
00638   APIRET rc = NO_ERROR;
00639 
00640   while(rc == NO_ERROR) {
00641     rc = DosQueryResourceSize(NULLHANDLE, RT_RCDATA, ID_FILE_BASE+i, &ulSize);
00642     if (rc == NO_ERROR) {
00643       nTotalBytes += ulSize;
00644       ulNumFiles++;
00645     }
00646     i++;
00647   }
00648 
00649   if(ulMode != SILENT)
00650   {
00651     hwndDlg = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP, DialogProc, NULLHANDLE, IDD_EXTRACTING, NULL);
00652     WinSetWindowULong(hwndDlg, QWL_USER, atom);
00653     WinSetWindowPos(hwndDlg, 0, 0, 0, 0, 0, SWP_SHOW | SWP_ACTIVATE);
00654   }
00655 
00656   // Extract the files
00657   ExtractFiles(ulNumFiles, hwndDlg);
00658 
00659   if (gbUncompressOnly == FALSE) {
00660     // Launch the install program and wait for it to finish
00661     RunInstaller(ulNumFiles, hwndDlg);
00662   }
00663 
00664   WinDeleteAtom(WinQuerySystemAtomTable(), atom);
00665 
00666   WinDestroyMsgQueue(hmq);
00667   WinTerminate(hab);
00668 }