Back to index

lightning-sunbird  0.9+nobinonly
nsinstall.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Troy Chevalier <troy@netscape.com>
00025  *   Sean Su <ssu@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include <windows.h>
00042 
00043 // stdlib.h and malloc.h are needed to build with WIN32_LEAN_AND_MEAN
00044 #include <stdlib.h>
00045 #include <malloc.h>
00046 #include <ctype.h>
00047 
00048 #include "resource.h"
00049 #include "zlib.h"
00050 
00051 #define BAR_MARGIN    1
00052 #define BAR_SPACING   0
00053 #define BAR_WIDTH     6
00054 #define MAX_BUF       4096
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                "MozillaSetup"
00067 #define CLASS_NAME_SETUP_DLG            "MozillaSetupDlg"
00068 
00069 char      szTitle[MAX_BUF];
00070 char      szCmdLineToSetup[MAX_BUF];
00071 BOOL      gbUncompressOnly;
00072 DWORD     dwMode;
00073 HINSTANCE hInst;
00074 char      gszWizTempDir[20] = "ns_temp";
00075 char      gszFileToUncompress[MAX_BUF];
00076 BOOL      gbAllowMultipleInstalls = FALSE;
00077 
00079 // Global Declarations
00080 
00081 static DWORD  nTotalBytes = 0;  // sum of all the FILE resources
00082 
00083 struct ExtractFilesDlgInfo {
00084        HWND   hWndDlg;
00085        int           nMaxBars;     // maximum number of bars that can be displayed
00086        int           nBars;        // current number of bars to display
00087 } dlgInfo;
00088 
00090 // Utility Functions
00091 
00092 // This function is similar to GetFullPathName except instead of
00093 // using the current drive and directory it uses the path of the
00094 // directory designated for temporary files
00095 static BOOL
00096 GetFullTempPathName(LPCTSTR lpszFileName, DWORD dwBufferLength, LPTSTR lpszBuffer)
00097 {
00098        DWORD  dwLen;
00099 
00100        dwLen = GetTempPath(dwBufferLength, lpszBuffer);
00101        if (lpszBuffer[dwLen - 1] != '\\')
00102               strcat(lpszBuffer, "\\");
00103        strcat(lpszBuffer, gszWizTempDir);
00104 
00105   dwLen = lstrlen(lpszBuffer);
00106        if (lpszBuffer[dwLen - 1] != '\\')
00107               strcat(lpszBuffer, "\\");
00108        strcat(lpszBuffer, lpszFileName);
00109 
00110        return TRUE;
00111 }
00112 
00113 /* Function to remove quotes from a string */
00114 void RemoveQuotes(LPSTR lpszSrc, LPSTR lpszDest, int iDestSize)
00115 {
00116   char *lpszBegin;
00117 
00118   if(lstrlen(lpszSrc) > iDestSize)
00119     return;
00120 
00121   if(*lpszSrc == '\"')
00122     lpszBegin = &lpszSrc[1];
00123   else
00124     lpszBegin = lpszSrc;
00125 
00126   lstrcpy(lpszDest, lpszBegin);
00127 
00128   if(lpszDest[lstrlen(lpszDest) - 1] == '\"')
00129     lpszDest[lstrlen(lpszDest) - 1] = '\0';
00130 }
00131 
00132 /* Function to locate the first non space character in a string,
00133  * and return a pointer to it. */
00134 LPSTR GetFirstNonSpace(LPSTR lpszString)
00135 {
00136   int   i;
00137   int   iStrLength;
00138 
00139   iStrLength = lstrlen(lpszString);
00140 
00141   for(i = 0; i < iStrLength; i++)
00142   {
00143     if(!isspace(lpszString[i]))
00144       return(&lpszString[i]);
00145   }
00146 
00147   return(NULL);
00148 }
00149 
00150 /* Function to return the argument count given a command line input
00151  * format string */
00152 int GetArgC(LPSTR lpszCommandLine)
00153 {
00154   int   i;
00155   int   iArgCount;
00156   int   iStrLength;
00157   LPSTR lpszBeginStr;
00158   BOOL  bFoundQuote;
00159   BOOL  bFoundSpace;
00160 
00161   iArgCount    = 0;
00162   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
00163 
00164   if(lpszBeginStr == NULL)
00165     return(iArgCount);
00166 
00167   iStrLength   = lstrlen(lpszBeginStr);
00168   bFoundQuote  = FALSE;
00169   bFoundSpace  = TRUE;
00170 
00171   for(i = 0; i < iStrLength; i++)
00172   {
00173     if(lpszCommandLine[i] == '\"')
00174     {
00175       if(bFoundQuote == FALSE)
00176       {
00177         ++iArgCount;
00178         bFoundQuote = TRUE;
00179       }
00180       else
00181       {
00182         bFoundQuote = FALSE;
00183       }
00184     }
00185     else if(bFoundQuote == FALSE)
00186     {
00187       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
00188       {
00189         ++iArgCount;
00190         bFoundSpace = FALSE;
00191       }
00192       else if(isspace(lpszCommandLine[i]))
00193       {
00194         bFoundSpace = TRUE;
00195       }
00196     }
00197   }
00198 
00199   return(iArgCount);
00200 }
00201 
00202 /* Function to return a specific argument parameter from a given command line input
00203  * format string. */
00204 LPSTR GetArgV(LPSTR lpszCommandLine, int iIndex, LPSTR lpszDest, int iDestSize)
00205 {
00206   int   i;
00207   int   j;
00208   int   iArgCount;
00209   int   iStrLength;
00210   LPSTR lpszBeginStr;
00211   LPSTR lpszDestTemp;
00212   BOOL  bFoundQuote;
00213   BOOL  bFoundSpace;
00214 
00215   iArgCount    = 0;
00216   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
00217 
00218   if(lpszDest)
00219     *lpszDest = '\0';
00220   if(lpszBeginStr == NULL)
00221     return(NULL);
00222 
00223   lpszDestTemp = (char *)calloc(iDestSize, sizeof(char));
00224   if(lpszDestTemp == NULL)
00225   {
00226     MessageBox(NULL, "Out of memory", NULL, MB_OK | MB_ICONEXCLAMATION);
00227     exit(1);
00228   }
00229 
00230   iStrLength    = lstrlen(lpszBeginStr);
00231   bFoundQuote   = FALSE;
00232   bFoundSpace   = TRUE;
00233   j             = 0;
00234 
00235   for(i = 0; i < iStrLength; i++)
00236   {
00237     if(lpszCommandLine[i] == '\"')
00238     {
00239       if(bFoundQuote == FALSE)
00240       {
00241         ++iArgCount;
00242         bFoundQuote = TRUE;
00243       }
00244       else
00245       {
00246         bFoundQuote = FALSE;
00247       }
00248     }
00249     else if(bFoundQuote == FALSE)
00250     {
00251       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
00252       {
00253         ++iArgCount;
00254         bFoundSpace = FALSE;
00255       }
00256       else if(isspace(lpszCommandLine[i]))
00257       {
00258         bFoundSpace = TRUE;
00259       }
00260     }
00261 
00262     if((iIndex == (iArgCount - 1)) &&
00263       ((bFoundQuote == TRUE) || (bFoundSpace == FALSE) ||
00264       ((bFoundQuote == FALSE) && (lpszCommandLine[i] == '\"'))))
00265     {
00266       if(j < iDestSize)
00267       {
00268         lpszDestTemp[j] = lpszCommandLine[i];
00269         ++j;
00270       }
00271       else
00272       {
00273         lpszDestTemp[j] = '\0';
00274       }
00275     }
00276   }
00277 
00278   RemoveQuotes(lpszDestTemp, lpszDest, iDestSize);
00279   free(lpszDestTemp);
00280   return(lpszDest);
00281 }
00282 
00283 // this function appends a backslash at the end of a string,
00284 // if one does not already exists.
00285 void AppendBackSlash(LPSTR szInput, DWORD dwInputSize)
00286 {
00287   if(szInput != NULL)
00288   {
00289     if(szInput[strlen(szInput) - 1] != '\\')
00290     {
00291       if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
00292       {
00293         lstrcat(szInput, "\\");
00294       }
00295     }
00296   }
00297 }
00298 
00299 HRESULT CreateDirectoriesAll(char* szPath)
00300 {
00301   int     i;
00302   int     iLen = lstrlen(szPath);
00303   char    szCreatePath[MAX_BUF];
00304   HRESULT hrResult;
00305 
00306   ZeroMemory(szCreatePath, MAX_BUF);
00307   memcpy(szCreatePath, szPath, iLen);
00308   for(i = 0; i < iLen; i++)
00309   {
00310     if((iLen > 1) &&
00311       ((i != 0) && ((szPath[i] == '\\') || (szPath[i] == '/'))) &&
00312       (!((szPath[0] == '\\') && (i == 1)) && !((szPath[1] == ':') && (i == 2))))
00313     {
00314       szCreatePath[i] = '\0';
00315       hrResult        = CreateDirectory(szCreatePath, NULL);
00316       szCreatePath[i] = szPath[i];
00317     }
00318   }
00319   return(hrResult);
00320 }
00321 
00322 // This function removes a directory and its subdirectories
00323 HRESULT DirectoryRemove(LPSTR szDestination, BOOL bRemoveSubdirs)
00324 {
00325   HANDLE          hFile;
00326   WIN32_FIND_DATA fdFile;
00327   char            szDestTemp[MAX_BUF];
00328   BOOL            bFound;
00329 
00330   if(GetFileAttributes(szDestination) == -1)
00331     return(0);
00332 
00333   if(bRemoveSubdirs == TRUE)
00334   {
00335     lstrcpy(szDestTemp, szDestination);
00336     AppendBackSlash(szDestTemp, sizeof(szDestTemp));
00337     lstrcat(szDestTemp, "*");
00338 
00339     bFound = TRUE;
00340     hFile = FindFirstFile(szDestTemp, &fdFile);
00341     while((hFile != INVALID_HANDLE_VALUE) && (bFound == TRUE))
00342     {
00343       if((lstrcmpi(fdFile.cFileName, ".") != 0) && (lstrcmpi(fdFile.cFileName, "..") != 0))
00344       {
00345         /* create full path */
00346         lstrcpy(szDestTemp, szDestination);
00347         AppendBackSlash(szDestTemp, sizeof(szDestTemp));
00348         lstrcat(szDestTemp, fdFile.cFileName);
00349 
00350         if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00351         {
00352           DirectoryRemove(szDestTemp, bRemoveSubdirs);
00353         }
00354         else
00355         {
00356           DeleteFile(szDestTemp);
00357         }
00358       }
00359 
00360       bFound = FindNextFile(hFile, &fdFile);
00361     }
00362 
00363     FindClose(hFile);
00364   }
00365   
00366   RemoveDirectory(szDestination);
00367   return(0);
00368 }
00369 
00370 void RemoveBackSlash(LPSTR szInput)
00371 {
00372   int   iCounter;
00373   DWORD dwInputLen;
00374 
00375   if(szInput != NULL)
00376   {
00377     dwInputLen = lstrlen(szInput);
00378 
00379     for(iCounter = dwInputLen -1; iCounter >= 0 ; iCounter--)
00380     {
00381       if(szInput[iCounter] == '\\')
00382         szInput[iCounter] = '\0';
00383       else
00384         break;
00385     }
00386   }
00387 }
00388 
00389 void ParsePath(LPSTR szInput, LPSTR szOutput, DWORD dwOutputSize, DWORD dwType)
00390 {
00391   int   iCounter;
00392   DWORD dwCounter;
00393   DWORD dwInputLen;
00394   BOOL  bFound;
00395 
00396   if((szInput != NULL) && (szOutput != NULL))
00397   {
00398     bFound        = TRUE;
00399     dwInputLen    = lstrlen(szInput);
00400     ZeroMemory(szOutput, dwOutputSize);
00401 
00402     if(dwInputLen < dwOutputSize)
00403     {
00404       switch(dwType)
00405       {
00406         case PP_FILENAME_ONLY:
00407           for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
00408           {
00409             if(szInput[iCounter] == '\\')
00410             {
00411               lstrcpy(szOutput, &szInput[iCounter + 1]);
00412               bFound = TRUE;
00413               break;
00414             }
00415           }
00416           if(bFound == FALSE)
00417             lstrcpy(szOutput, szInput);
00418 
00419           break;
00420 
00421         case PP_PATH_ONLY:
00422           for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
00423           {
00424             if(szInput[iCounter] == '\\')
00425             {
00426               lstrcpy(szOutput, szInput);
00427               szOutput[iCounter + 1] = '\0';
00428               bFound = TRUE;
00429               break;
00430             }
00431           }
00432           if(bFound == FALSE)
00433             lstrcpy(szOutput, szInput);
00434 
00435           break;
00436 
00437         case PP_ROOT_ONLY:
00438           if(szInput[1] == ':')
00439           {
00440             szOutput[0] = szInput[0];
00441             szOutput[1] = szInput[1];
00442             AppendBackSlash(szOutput, dwOutputSize);
00443           }
00444           else if(szInput[1] == '\\')
00445           {
00446             int iFoundBackSlash = 0;
00447             for(dwCounter = 0; dwCounter < dwInputLen; dwCounter++)
00448             {
00449               if(szInput[dwCounter] == '\\')
00450               {
00451                 szOutput[dwCounter] = szInput[dwCounter];
00452                 ++iFoundBackSlash;
00453               }
00454 
00455               if(iFoundBackSlash == 3)
00456                 break;
00457             }
00458 
00459             if(iFoundBackSlash != 0)
00460               AppendBackSlash(szOutput, dwOutputSize);
00461           }
00462           break;
00463       }
00464     }
00465   }
00466 }
00467 
00468 void ParseCommandLine(LPSTR lpszCmdLine)
00469 {
00470   char  szArgVBuf[MAX_BUF];
00471   int   i;
00472   int   iArgC;
00473 
00474   *szCmdLineToSetup = '\0';
00475   *gszFileToUncompress = '\0';
00476   dwMode = NORMAL;
00477   gbUncompressOnly = FALSE;
00478   iArgC  = GetArgC(lpszCmdLine);
00479   i      = 0;
00480   while(i < iArgC)
00481   {
00482     GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
00483     if((lstrcmpi(szArgVBuf, "-ms") == 0) || (lstrcmpi(szArgVBuf, "/ms") == 0))
00484     {
00485       dwMode = SILENT;
00486     }
00487     else if((lstrcmpi(szArgVBuf, "-u") == 0) || (lstrcmpi(szArgVBuf, "/u") == 0))
00488     {
00489       gbUncompressOnly = TRUE;
00490       GetArgV(lpszCmdLine, i + 1, szArgVBuf, sizeof(szArgVBuf));
00491       if((*szArgVBuf != '\0') && (*szArgVBuf != '-'))
00492       {
00493         lstrcpy(gszFileToUncompress, szArgVBuf);
00494         ++i; // found filename to uncompress, update 'i' for the next iteration
00495       }
00496     }
00497     else if((lstrcmpi(szArgVBuf, "-mmi") == 0) || (lstrcmpi(szArgVBuf, "/mmi") == 0))
00498     {
00499       gbAllowMultipleInstalls = TRUE;
00500     }
00501 
00502     ++i;
00503   }
00504 
00505   lstrcpy(szCmdLineToSetup, " ");
00506   lstrcat(szCmdLineToSetup, lpszCmdLine);
00507 }
00508 
00509 // Centers the specified window over the desktop. Assumes the window is
00510 // smaller both horizontally and vertically than the desktop
00511 static void
00512 CenterWindow(HWND hWndDlg)
00513 {
00514        RECT   rect;
00515        int           iLeft, iTop;
00516 
00517        GetWindowRect(hWndDlg, &rect);
00518        iLeft = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
00519        iTop = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
00520 
00521        SetWindowPos(hWndDlg, NULL, iLeft, iTop, -1, -1,
00522               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
00523 }
00524 
00526 // Extract Files Dialog
00527 
00528 // This routine processes windows messages that are in queue
00529 void ProcessWindowsMessages()
00530 {
00531   MSG msg;
00532 
00533   while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
00534   {
00535     TranslateMessage(&msg);
00536     DispatchMessage(&msg);
00537   }
00538 }
00539 
00540 // This routine updates the status string in the extracting dialog
00541 static void
00542 SetStatusLine(LPCTSTR lpszStatus)
00543 {
00544        HWND   hWndLabel;
00545 
00546   if(dwMode != SILENT)
00547   {
00548          hWndLabel = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS);
00549          SetWindowText(hWndLabel, lpszStatus);
00550          UpdateWindow(hWndLabel);
00551   }
00552 }
00553 
00554 // This routine will update the progress bar to the specified percentage
00555 // (value between 0 and 100)
00556 static void
00557 UpdateProgressBar(unsigned value)
00558 {
00559        int    nBars;
00560 
00561   if(dwMode != SILENT)
00562   {
00563     // Figure out how many bars should be displayed
00564     nBars = dlgInfo.nMaxBars * value / 100;
00565 
00566     // Only paint if we need to display more bars
00567     if (nBars > dlgInfo.nBars)
00568     {
00569       HWND    hWndGauge = GetDlgItem(dlgInfo.hWndDlg, IDC_GAUGE);
00570       RECT    rect;
00571 
00572       // Update the gauge state before painting
00573       dlgInfo.nBars = nBars;
00574 
00575       // Only invalidate the part that needs updating
00576       GetClientRect(hWndGauge, &rect);
00577       InvalidateRect(hWndGauge, &rect, FALSE);
00578     
00579       // Update the whole extracting dialog. We do this because we don't
00580       // have a message loop to process WM_PAINT messages in case the
00581       // extracting dialog was exposed
00582       UpdateWindow(dlgInfo.hWndDlg);
00583     }
00584   }
00585 }
00586 
00587 // Window proc for dialog
00588 BOOL APIENTRY
00589 DialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
00590 {
00591   if(dwMode != SILENT)
00592   {
00593     switch (msg) {
00594       case WM_INITDIALOG:
00595         // Center the dialog over the desktop
00596         CenterWindow(hWndDlg);
00597         return FALSE;
00598 
00599       case WM_COMMAND:
00600         DestroyWindow(hWndDlg);
00601         return TRUE;
00602     }
00603   }
00604 
00605        return FALSE;  // didn't handle the message
00606 }
00607 
00609 // Resource Callback Functions
00610 
00611 BOOL APIENTRY
00612 DeleteTempFilesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
00613 {
00614        char   szTmpFile[MAX_PATH];
00615 
00616        // Get the path to the file in the temp directory
00617        GetFullTempPathName(lpszName, sizeof(szTmpFile), szTmpFile);
00618 
00619        // Delete the file
00620        DeleteFile(szTmpFile);
00621        return TRUE;
00622 }
00623 
00624 BOOL APIENTRY
00625 SizeOfResourcesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
00626 {
00627        HRSRC  hResInfo;
00628 
00629        // Find the resource
00630        hResInfo = FindResource((HINSTANCE)hModule, lpszName, lpszType);
00631 
00632 #ifdef _DEBUG
00633        if (!hResInfo) {
00634               char   buf[512];
00635 
00636               wsprintf(buf, "Error '%d' when loading FILE resource: %s", GetLastError(), lpszName);
00637               MessageBox(NULL, buf, szTitle, MB_OK | MB_ICONEXCLAMATION);
00638               return FALSE;
00639        }
00640 #endif
00641 
00642        // Add its size to the total size. Note that the return value is subject
00643        // to alignment rounding, but it's close enough for our purposes
00644        nTotalBytes += SizeofResource(NULL, hResInfo);
00645 
00646        // Release the resource
00647        FreeResource(hResInfo);
00648        return TRUE;  // keep enumerating
00649 }
00650 
00651 BOOL APIENTRY
00652 ExtractFilesProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
00653 {
00654        char   szTmpFile[MAX_PATH];
00655        char   szArcLstFile[MAX_PATH];
00656        HRSRC  hResInfo;
00657        HGLOBAL       hGlobal;
00658        LPBYTE lpBytes;
00659        LPBYTE lptr;
00660        LPBYTE lpBytesUnCmp;
00661        HANDLE hFile;
00662        char   szStatus[128];
00663        char   szText[4096];
00664        
00665        // Update the UI
00666        LoadString(hInst, IDS_STATUS_EXTRACTING, szText, sizeof(szText));
00667        wsprintf(szStatus, szText, lpszName);
00668        SetStatusLine(szStatus);
00669 
00670   if(gbUncompressOnly == TRUE)
00671     lstrcpy(szTmpFile, lpszName);
00672   else
00673   {
00674          // Create a file in the temp directory
00675          GetFullTempPathName(lpszName, sizeof(szTmpFile), szTmpFile);
00676     CreateDirectoriesAll(szTmpFile);
00677   }
00678 
00679   if((*gszFileToUncompress != '\0') && (lstrcmpi(lpszName, gszFileToUncompress) != 0))
00680     // We have a file to uncompress, but the one found is not the one we want,
00681     // so return TRUE to continue looking for the right one.
00682     return TRUE;
00683 
00684        // Extract the file
00685        hResInfo = FindResource((HINSTANCE)hModule, lpszName, lpszType);
00686        hGlobal = LoadResource((HINSTANCE)hModule, hResInfo);
00687        lpBytes = (LPBYTE)LockResource(hGlobal);
00688 
00689        // Create the file
00690        hFile = CreateFile(szTmpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
00691 
00692        if (hFile != INVALID_HANDLE_VALUE) {
00693               DWORD  dwSize;
00694               DWORD  dwSizeUnCmp;
00695     DWORD dwTemp;
00696 
00697          GetFullTempPathName("Archive.lst", sizeof(szArcLstFile), szArcLstFile);
00698     WritePrivateProfileString("Archives", lpszName, "TRUE", szArcLstFile);
00699 
00700     lptr = (LPBYTE)malloc((*(LPDWORD)(lpBytes + sizeof(DWORD))) + 1);
00701     if(!lptr)
00702     {
00703       char szBuf[512];
00704 
00705       LoadString(hInst, IDS_ERROR_OUT_OF_MEMORY, szBuf, sizeof(szBuf));
00706       MessageBox(NULL, szBuf, NULL, MB_OK | MB_ICONEXCLAMATION);
00707       return FALSE;
00708     }
00709 
00710     lpBytesUnCmp = lptr;
00711     dwSizeUnCmp  = *(LPDWORD)(lpBytes + sizeof(DWORD));
00712 
00713               // Copy the file. The first DWORD specifies the size of the file
00714               dwSize = *(LPDWORD)lpBytes;
00715               lpBytes += (sizeof(DWORD) * 2);
00716 
00717     dwTemp = uncompress(lpBytesUnCmp, &dwSizeUnCmp, lpBytes, dwSize);
00718 
00719     while (dwSizeUnCmp > 0)
00720     {
00721                      DWORD  dwBytesToWrite, dwBytesWritten;
00722 
00723       ProcessWindowsMessages();
00724 
00725                      dwBytesToWrite = dwSizeUnCmp > 4096 ? 4096 : dwSizeUnCmp;
00726                      if (!WriteFile(hFile, lpBytesUnCmp, dwBytesToWrite, &dwBytesWritten, NULL))
00727       {
00728                             char szBuf[512];
00729 
00730        LoadString(hInst, IDS_STATUS_EXTRACTING, szText, sizeof(szText));
00731                             wsprintf(szBuf, szText, szTmpFile);
00732                             MessageBox(NULL, szBuf, szTitle, MB_OK | MB_ICONEXCLAMATION);
00733                             FreeResource(hResInfo);
00734         if(lptr)
00735           free(lptr);
00736 
00737                             return FALSE;
00738                      }
00739 
00740                      dwSizeUnCmp -= dwBytesWritten;
00741                      lpBytesUnCmp += dwBytesWritten;
00742 
00743                      // Update the UI to reflect the total number of bytes written
00744                      static DWORD  nBytesWritten = 0;
00745 
00746                      nBytesWritten += dwBytesWritten;
00747                      UpdateProgressBar(nBytesWritten * 100 / nTotalBytes);
00748               }
00749 
00750               CloseHandle(hFile);
00751        }
00752 
00753        // Release the resource
00754        FreeResource(hResInfo);
00755   if(lptr)
00756     free(lptr);
00757 
00758   if((*gszFileToUncompress != '\0') && (lstrcmpi(lpszName, gszFileToUncompress) == 0))
00759     // We have a file to uncompress, and we have uncompressed it,
00760     // so return FALSE to stop uncompressing any other file.
00761     return FALSE;
00762 
00763        return TRUE;  // keep enumerating
00764 }
00765 
00767 // Progress bar
00768 
00769 // Draws a recessed border around the gauge
00770 static void
00771 DrawGaugeBorder(HWND hWnd)
00772 {
00773        HDC           hDC = GetWindowDC(hWnd);
00774        RECT   rect;
00775        int           cx, cy;
00776        HPEN   hShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
00777        HGDIOBJ       hOldPen;
00778 
00779        GetWindowRect(hWnd, &rect);
00780        cx = rect.right - rect.left;
00781        cy = rect.bottom - rect.top;
00782 
00783        // Draw a dark gray line segment
00784        hOldPen = SelectObject(hDC, (HGDIOBJ)hShadowPen);
00785        MoveToEx(hDC, 0, cy - 1, NULL);
00786        LineTo(hDC, 0, 0);
00787        LineTo(hDC, cx - 1, 0);
00788 
00789        // Draw a white line segment
00790        SelectObject(hDC, GetStockObject(WHITE_PEN));
00791        MoveToEx(hDC, 0, cy - 1, NULL);
00792        LineTo(hDC, cx - 1, cy - 1);
00793        LineTo(hDC, cx - 1, 0);
00794 
00795        SelectObject(hDC, hOldPen);
00796        DeleteObject(hShadowPen);
00797        ReleaseDC(hWnd, hDC);
00798 }
00799 
00800 // Draws the progress bar
00801 static void
00802 DrawProgressBar(HWND hWnd)
00803 {
00804        PAINTSTRUCT   ps;
00805        HDC                  hDC = BeginPaint(hWnd, &ps);
00806        RECT          rect;
00807        HBRUSH        hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
00808 
00809        // Draw the bars
00810        GetClientRect(hWnd, &rect);
00811        rect.left = rect.top = BAR_MARGIN;
00812        rect.bottom -= BAR_MARGIN;
00813        rect.right = rect.left + BAR_WIDTH;
00814 
00815        for (int i = 0; i < dlgInfo.nBars; i++) {
00816               RECT   dest;
00817 
00818               if (IntersectRect(&dest, &ps.rcPaint, &rect))
00819                      FillRect(hDC, &rect, hBrush);
00820               OffsetRect(&rect, BAR_WIDTH + BAR_SPACING, 0);
00821        }
00822 
00823        DeleteObject(hBrush);
00824        EndPaint(hWnd, &ps);
00825 }
00826 
00827 // Adjusts the width of the gauge based on the maximum number of bars
00828 static void
00829 SizeToFitGauge(HWND hWnd)
00830 {
00831        RECT   rect;
00832        int           cx;
00833 
00834        // Get the window size in pixels
00835        GetWindowRect(hWnd, &rect);
00836 
00837        // Size the width to fit
00838        cx = 2 * GetSystemMetrics(SM_CXBORDER) + 2 * BAR_MARGIN +
00839               dlgInfo.nMaxBars * BAR_WIDTH + (dlgInfo.nMaxBars - 1) * BAR_SPACING;
00840 
00841        SetWindowPos(hWnd, NULL, -1, -1, cx, rect.bottom - rect.top,
00842               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
00843 }
00844 
00845 // Window proc for gauge
00846 LRESULT APIENTRY
00847 GaugeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
00848 {
00849        DWORD  dwStyle;
00850        RECT   rect;
00851 
00852        switch (msg) {
00853               case WM_NCCREATE:
00854                      dwStyle = GetWindowLong(hWnd, GWL_STYLE);
00855                      SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_BORDER);
00856                      return TRUE;
00857 
00858               case WM_CREATE:
00859                      // Figure out the maximum number of bars that can be displayed
00860                      GetClientRect(hWnd, &rect);
00861                      dlgInfo.nBars = 0;
00862                      dlgInfo.nMaxBars = (rect.right - rect.left - 2 * BAR_MARGIN + BAR_SPACING) /
00863                             (BAR_WIDTH + BAR_SPACING);
00864 
00865                      // Size the gauge to exactly fit the maximum number of bars
00866                      SizeToFitGauge(hWnd);
00867                      return TRUE;
00868 
00869               case WM_NCPAINT:
00870                      DrawGaugeBorder(hWnd);
00871                      return TRUE;
00872 
00873               case WM_PAINT:
00874                      DrawProgressBar(hWnd);
00875                      return TRUE;
00876        }
00877 
00878        return DefWindowProc(hWnd, msg, wParam, lParam);
00879 }
00880 
00881 HRESULT FileExists(LPSTR szFile)
00882 {
00883   DWORD rv;
00884 
00885   if((rv = GetFileAttributes(szFile)) == -1)
00886   {
00887     return(FALSE);
00888   }
00889   else
00890   {
00891     return(rv);
00892   }
00893 }
00894 
00896 // WinMain
00897 
00898 static BOOL
00899 RunInstaller()
00900 {
00901   PROCESS_INFORMATION pi;
00902   STARTUPINFO         sti;
00903   char                szCmdLine[MAX_BUF];
00904   char                szSetupFile[MAX_BUF];
00905   char                szUninstallFile[MAX_BUF];
00906   char                szArcLstFile[MAX_BUF];
00907   BOOL                bRet;
00908   char                szText[256];
00909   char                szTempPath[MAX_BUF];
00910   char                szTmp[MAX_PATH];
00911   char                xpiDir[MAX_PATH];
00912   char                szFilename[MAX_BUF];
00913   char                szBuf[MAX_BUF];
00914 
00915   if(gbUncompressOnly == TRUE)
00916     return(TRUE);
00917 
00918   // Update UI
00919   UpdateProgressBar(100);
00920   LoadString(hInst, IDS_STATUS_LAUNCHING_SETUP, szText, sizeof(szText));
00921   SetStatusLine(szText);
00922 
00923   memset(&sti,0,sizeof(sti));
00924   sti.cb = sizeof(STARTUPINFO);
00925 
00926   // Setup program is in the directory specified for temporary files
00927   GetFullTempPathName("", MAX_BUF, szTempPath);
00928        GetFullTempPathName("Archive.lst",   sizeof(szArcLstFile),    szArcLstFile);
00929   GetFullTempPathName("SETUP.EXE",     sizeof(szSetupFile),     szSetupFile);
00930   GetFullTempPathName("uninstall.exe", sizeof(szUninstallFile), szUninstallFile);
00931 
00932   GetPrivateProfileString("Archives", "uninstall.exe", "", szBuf, sizeof(szBuf), szArcLstFile);
00933   if((FileExists(szUninstallFile) != FALSE) && (*szBuf != '\0'))
00934   {
00935     lstrcpy(szCmdLine, szUninstallFile);
00936   }
00937   else
00938   {
00939     lstrcpy(szCmdLine, szSetupFile);
00940     GetModuleFileName(NULL, szFilename, sizeof(szFilename));
00941     ParsePath(szFilename, xpiDir, sizeof(xpiDir), PP_PATH_ONLY);
00942     AppendBackSlash(xpiDir, sizeof(xpiDir));
00943     lstrcat(xpiDir, "xpi");
00944     if(FileExists(xpiDir))
00945     {
00946       GetShortPathName(xpiDir, szBuf, sizeof(szBuf));
00947       lstrcat(szCmdLine, " -a ");
00948       lstrcat(szCmdLine, szBuf);
00949     }
00950     lstrcat(szCmdLine, " -n ");
00951     lstrcat(szCmdLine, szFilename);
00952   }
00953 
00954   if(szCmdLine != NULL)
00955     lstrcat(szCmdLine, szCmdLineToSetup);
00956 
00957   // Launch the installer
00958   bRet = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, szTempPath, &sti, &pi);
00959 
00960   if (!bRet)
00961     return FALSE;
00962 
00963   CloseHandle(pi.hThread);
00964 
00965   // Wait for the InstallShield UI to appear before taking down the dialog box
00966   WaitForInputIdle(pi.hProcess, 3000);  // wait up to 3 seconds
00967   if(dwMode != SILENT)
00968   {
00969     DestroyWindow(dlgInfo.hWndDlg);
00970   }
00971 
00972   // Wait for the installer to complete
00973   WaitForSingleObject(pi.hProcess, INFINITE);
00974   CloseHandle(pi.hProcess);
00975 
00976 
00977   // Delete the files from the temp directory
00978   EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)DeleteTempFilesProc, 0);
00979 
00980   // delete archive.lst file in the temp directory
00981   GetFullTempPathName("Archive.lst", sizeof(szTmp), szTmp);
00982   DeleteFile(szTmp);
00983   GetFullTempPathName("xpcom.ns", sizeof(szTmp), szTmp);
00984   DirectoryRemove(szTmp, TRUE);
00985   DirectoryRemove(szTempPath, FALSE);
00986   return TRUE;
00987 }
00988 
00989 int APIENTRY
00990 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
00991 {
00992   WNDCLASS  wc;
00993   HWND      hwndFW;
00994 
00995        hInst = hInstance;
00996        LoadString(hInst, IDS_TITLE, szTitle, MAX_BUF);
00997 
00998   // Parse the command line
00999   ParseCommandLine(lpCmdLine);
01000   
01001   /*  Allow multiple installer instances with the 
01002       provision that each instance is guaranteed 
01003       to have its own unique setup directory 
01004    */
01005   if(FindWindow("NSExtracting", "Extracting...") != NULL ||
01006     (hwndFW = FindWindow(CLASS_NAME_SETUP_DLG, NULL)) != NULL ||
01007     (hwndFW = FindWindow(CLASS_NAME_SETUP, NULL)) != NULL)
01008   {
01009     if (gbAllowMultipleInstalls)
01010     {
01011       char szTempPath[MAX_BUF];
01012       GetFullTempPathName("", MAX_BUF, szTempPath);
01013       DWORD dwLen = lstrlen(gszWizTempDir);
01014 
01015       for(int i = 1; i <= 100 && (FileExists(szTempPath) != FALSE); i++)
01016       {
01017         itoa(i, (gszWizTempDir + dwLen), 10);
01018         GetFullTempPathName("", MAX_BUF, szTempPath);
01019       }
01020 
01021       if (FileExists(szTempPath) != FALSE)
01022       {
01023         MessageBox(NULL, "Cannot create temp directory", NULL, MB_OK | MB_ICONEXCLAMATION);
01024         exit(1);
01025       }
01026     }
01027     else
01028     {
01029       if (hwndFW!=NULL)
01030       {
01031         ShowWindow(hwndFW, SW_RESTORE);
01032         SetForegroundWindow(hwndFW);
01033       }
01034       return(1);
01035     }
01036   }
01037 
01038        // Figure out the total size of the resources
01039        EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)SizeOfResourcesProc, 0);
01040 
01041   // Register a class for the gauge
01042   memset(&wc, 0, sizeof(wc));
01043   wc.lpfnWndProc   = (WNDPROC)GaugeWndProc;
01044   wc.hInstance     = hInstance;
01045   wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
01046   wc.lpszClassName = "NSGauge";
01047   RegisterClass(&wc);
01048 
01049   // Register a class for the main dialog
01050   memset(&wc, 0, sizeof(wc));
01051   wc.style         = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
01052   wc.lpfnWndProc   = DefDlgProc;
01053   wc.cbClsExtra    = 0;
01054   wc.cbWndExtra    = DLGWINDOWEXTRA;
01055   wc.hInstance     = hInstance;
01056   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
01057   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
01058   wc.lpszClassName = "NSExtracting";
01059   RegisterClass(&wc);
01060 
01061   if(dwMode != SILENT)
01062   {
01063          // Display the dialog box
01064          dlgInfo.hWndDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_EXTRACTING), NULL, (DLGPROC)DialogProc);
01065          UpdateWindow(dlgInfo.hWndDlg);
01066   }
01067 
01068        // Extract the files
01069        EnumResourceNames(NULL, "FILE", (ENUMRESNAMEPROC)ExtractFilesProc, 0);
01070        
01071        // Launch the install program and wait for it to finish
01072        RunInstaller();
01073        return 0;  
01074 }