Back to index

lightning-sunbird  0.9+nobinonly
extra.c
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) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Sean Su <ssu@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "extern.h"
00041 #include "extra.h"
00042 #include "parser.h"
00043 #include "dialogs.h"
00044 #include "ifuncns.h"
00045 #include "process.h"
00046 #include <winver.h>
00047 
00048 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
00049 #include <shellapi.h>
00050 
00051 #define HIDWORD(l)   ((DWORD) (((ULONG) (l) >> 32) & 0xFFFF))
00052 #define LODWORD(l)   ((DWORD) (l))
00053 
00054 #define INDEX_STR_LEN       10
00055 #define PN_PROCESS          TEXT("Process")
00056 #define PN_THREAD           TEXT("Thread")
00057 
00058 ULONG  (PASCAL *NS_GetDiskFreeSpace)(LPCTSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD);
00059 ULONG  (PASCAL *NS_GetDiskFreeSpaceEx)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
00060 
00061 BOOL InitApplication(HINSTANCE hInstance)
00062 {
00063   WNDCLASS wc;
00064 
00065   wc.style         = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
00066   wc.lpfnWndProc   = DefDlgProc;
00067   wc.cbClsExtra    = 0;
00068   wc.cbWndExtra    = DLGWINDOWEXTRA;
00069   wc.hInstance     = hInstance;
00070   wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UNINSTALL));
00071   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
00072   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
00073   wc.lpszMenuName  = NULL;
00074   wc.lpszClassName = szClassName;
00075 
00076   dwScreenX = GetSystemMetrics(SM_CXSCREEN);
00077   dwScreenY = GetSystemMetrics(SM_CYSCREEN);
00078 
00079   return(RegisterClass(&wc));
00080 }
00081 
00082 void PrintError(LPSTR szMsg, DWORD dwErrorCodeSH)
00083 {
00084   DWORD dwErr;
00085   char  szErrorString[MAX_BUF];
00086 
00087   if(dwErrorCodeSH == ERROR_CODE_SHOW)
00088   {
00089     dwErr = GetLastError();
00090     wsprintf(szErrorString, "%d : %s", dwErr, szMsg);
00091   }
00092   else
00093     wsprintf(szErrorString, "%s", szMsg);
00094 
00095   if((ugUninstall.mode != SILENT) && (ugUninstall.mode != AUTO))
00096   {
00097     MessageBox(hWndMain, szErrorString, NULL, MB_ICONEXCLAMATION);
00098   }
00099   else if(ugUninstall.mode == AUTO)
00100   {
00101     ShowMessage(szErrorString, TRUE);
00102     Delay(5);
00103     ShowMessage(szErrorString, FALSE);
00104   }
00105 }
00106 
00107 void *NS_GlobalAlloc(DWORD dwMaxBuf)
00108 {
00109   LPSTR szBuf = NULL;
00110 
00111   if((szBuf = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, dwMaxBuf)) == NULL)
00112   {     
00113     if((szEGlobalAlloc == NULL) || (*szEGlobalAlloc == '\0'))
00114       PrintError(TEXT("Memory allocation error."), ERROR_CODE_HIDE);
00115     else
00116       PrintError(szEGlobalAlloc, ERROR_CODE_SHOW);
00117 
00118     return(NULL);
00119   }
00120   else
00121     return(szBuf);
00122 }
00123 
00124 void FreeMemory(void **vPointer)
00125 {
00126   if(*vPointer != NULL)
00127     *vPointer = GlobalFree(*vPointer);
00128 }
00129 
00130 HRESULT NS_LoadStringAlloc(HANDLE hInstance, DWORD dwID, LPSTR *szStringBuf, DWORD dwStringBuf)
00131 {
00132   char szBuf[MAX_BUF];
00133 
00134   if((*szStringBuf = NS_GlobalAlloc(MAX_BUF)) == NULL)
00135     exit(1);
00136   
00137   if(!LoadString(hInstance, dwID, *szStringBuf, dwStringBuf))
00138   {
00139     if((szEStringLoad == NULL) ||(*szEStringLoad == '\0'))
00140       wsprintf(szBuf, "Could not load string resource ID %d", dwID);
00141     else
00142       wsprintf(szBuf, szEStringLoad, dwID);
00143 
00144     PrintError(szBuf, ERROR_CODE_SHOW);
00145     return(1);
00146   }
00147   return(0);
00148 }
00149 
00150 HRESULT NS_LoadString(HANDLE hInstance, DWORD dwID, LPSTR szStringBuf, DWORD dwStringBuf)
00151 {
00152   char szBuf[MAX_BUF];
00153 
00154   if(!LoadString(hInstance, dwID, szStringBuf, dwStringBuf))
00155   {
00156     if((szEStringLoad == NULL) ||(*szEStringLoad == '\0'))
00157       wsprintf(szBuf, "Could not load string resource ID %d", dwID);
00158     else
00159       wsprintf(szBuf, szEStringLoad, dwID);
00160 
00161     PrintError(szBuf, ERROR_CODE_SHOW);
00162     return(1);
00163   }
00164   return(WIZ_OK);
00165 }
00166 
00167 void Delay(DWORD dwSeconds)
00168 {
00169   SleepEx(dwSeconds * 1000, FALSE);
00170 }
00171 
00172 HRESULT Initialize(HINSTANCE hInstance)
00173 {
00174   char szBuf[MAX_BUF];
00175 
00176   hDlgMessage = NULL;
00177   DetermineOSVersion();
00178   gdwWhatToDo = WTD_ASK;
00179 
00180   /* load strings from setup.exe */
00181   if(NS_LoadStringAlloc(hInst, IDS_ERROR_GLOBALALLOC, &szEGlobalAlloc, MAX_BUF))
00182     return(1);
00183   if(NS_LoadStringAlloc(hInst, IDS_ERROR_STRING_LOAD, &szEStringLoad,  MAX_BUF))
00184     return(1);
00185   if(NS_LoadStringAlloc(hInst, IDS_ERROR_DLL_LOAD,    &szEDllLoad,     MAX_BUF))
00186     return(1);
00187   if(NS_LoadStringAlloc(hInst, IDS_ERROR_STRING_NULL, &szEStringNull,  MAX_BUF))
00188     return(1);
00189 
00190   ZeroMemory(szBuf, sizeof(MAX_BUF));
00191   if((szClassName = NS_GlobalAlloc(MAX_BUF)) == NULL)
00192     return(1);
00193 
00194   lstrcpy(szClassName, CLASS_NAME_UNINSTALL_DLG);
00195   hAccelTable = LoadAccelerators(hInst, szClassName);
00196   if((szUninstallDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00197     return(1);
00198 
00199   GetModuleFileName(NULL, szBuf, sizeof(szBuf));
00200   ParsePath(szBuf, szUninstallDir, MAX_BUF, PP_PATH_ONLY);
00201 
00202   if((szTempDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00203     return(1);
00204 
00205   if((szOSTempDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00206     return(1);
00207 
00208   if((szFileIniUninstall = NS_GlobalAlloc(MAX_BUF)) == NULL)
00209     return(1);
00210 
00211   lstrcpy(szFileIniUninstall, szUninstallDir);
00212   AppendBackSlash(szFileIniUninstall, MAX_BUF);
00213   lstrcat(szFileIniUninstall, FILE_INI_UNINSTALL);
00214 
00215   if((szFileIniDefaultsInfo = NS_GlobalAlloc(MAX_BUF)) == NULL)
00216     return(1);
00217 
00218   lstrcpy(szFileIniDefaultsInfo, szUninstallDir);
00219   AppendBackSlash(szFileIniDefaultsInfo, MAX_BUF);
00220   GetPrivateProfileString("General", "Defaults Info Filename", "", szBuf, MAX_BUF, szFileIniUninstall);
00221   lstrcat(szFileIniDefaultsInfo, szBuf);
00222 
00223   // determine the system's TEMP path
00224   if(GetTempPath(MAX_BUF, szTempDir) == 0)
00225   {
00226     if(GetWindowsDirectory(szTempDir, MAX_BUF) == 0)
00227     {
00228       char szEGetWinDirFailed[MAX_BUF];
00229 
00230       if(GetPrivateProfileString("Messages", "ERROR_GET_WINDOWS_DIRECTORY_FAILED", "", 
00231                                  szEGetWinDirFailed, sizeof(szEGetWinDirFailed),
00232                                  szFileIniUninstall))
00233         PrintError(szEGetWinDirFailed, ERROR_CODE_SHOW);
00234 
00235       return(1);
00236     }
00237 
00238     AppendBackSlash(szTempDir, MAX_BUF);
00239     lstrcat(szTempDir, "TEMP");
00240   }
00241   lstrcpy(szOSTempDir, szTempDir);
00242   AppendBackSlash(szTempDir, MAX_BUF);
00243   lstrcat(szTempDir, WIZ_TEMP_DIR);
00244 
00245   /*  if multiple installer instances are allowed; 
00246       each instance requires a unique temp directory
00247    */
00248   if(gbAllowMultipleInstalls)
00249   {
00250     DWORD dwLen = lstrlen(szTempDir);
00251 
00252     if (strncmp(szUninstallDir, szTempDir, dwLen) == 0)
00253     {
00254       lstrcpy(szTempDir, szUninstallDir);
00255     }
00256     else if (!MakeUniquePath(szTempDir))
00257     {
00258       MessageBox(hWndMain, "Cannot create temp directory", NULL, MB_OK | MB_ICONEXCLAMATION);
00259       exit(1);
00260     }
00261   }
00262   else
00263   {
00264     // we're not running in mmi mode (allow multiple instances of installer
00265     // to run at the same time), we should look for and remove the dirs
00266     // that are created in the mmi mode.
00267     DWORD dwLen;
00268     char tempDirToCleanup[MAX_BUF];
00269     int i = 1;
00270 
00271     lstrcpy(tempDirToCleanup, szTempDir);
00272     dwLen = lstrlen(tempDirToCleanup);
00273     itoa(i, (tempDirToCleanup + dwLen), 10);
00274     for(i = 2; i <= 100 && (FileExists(tempDirToCleanup)); i++)
00275     {
00276       DirectoryRemove(tempDirToCleanup, TRUE);
00277       itoa(i, (tempDirToCleanup + dwLen), 10);
00278     }
00279   }
00280 
00281   if(!FileExists(szTempDir))
00282   {
00283     AppendBackSlash(szTempDir, MAX_BUF);
00284     CreateDirectoriesAll(szTempDir);
00285     if(!FileExists(szTempDir))
00286     {
00287       char szECreateTempDir[MAX_BUF];
00288 
00289       if(GetPrivateProfileString("Messages", "ERROR_CREATE_TEMP_DIR", "",
00290                                  szECreateTempDir, sizeof(szECreateTempDir), 
00291                                  szFileIniUninstall))
00292       {
00293         wsprintf(szBuf, szECreateTempDir, szTempDir);
00294         PrintError(szBuf, ERROR_CODE_HIDE);
00295       }
00296       return(1);
00297     }
00298     RemoveBackSlash(szTempDir);
00299   }
00300 
00301   ugUninstall.bVerbose = FALSE;
00302   ugUninstall.bUninstallFiles = TRUE;
00303   ugUninstall.bSharedInst = FALSE;
00304 
00305   return(0);
00306 }
00307 
00308 /* Function to remove quotes from a string */
00309 void RemoveQuotes(LPSTR lpszSrc, LPSTR lpszDest, int iDestSize)
00310 {
00311   char *lpszBegin;
00312 
00313   if(lstrlen(lpszSrc) > iDestSize)
00314     return;
00315 
00316   if(*lpszSrc == '\"')
00317     lpszBegin = &lpszSrc[1];
00318   else
00319     lpszBegin = lpszSrc;
00320 
00321   lstrcpy(lpszDest, lpszBegin);
00322 
00323   if(lpszDest[lstrlen(lpszDest) - 1] == '\"')
00324     lpszDest[lstrlen(lpszDest) - 1] = '\0';
00325 }
00326 
00327 /* Function to copy strings safely.
00328  *   returns the amount of memory required (including NULL byte) if there's not enough
00329  *   else, it returns 0 for success.
00330  */
00331 int MozCopyStr(LPSTR szSrc, LPSTR szDest, DWORD dwDestBufSize)
00332 {
00333   DWORD length = lstrlen(szSrc) + 1;
00334   strncpy(szDest, szSrc, dwDestBufSize);
00335   if(length > dwDestBufSize)
00336   {
00337     szDest[dwDestBufSize - 1] = '\0';
00338     return(length);
00339   }
00340   return(0);
00341 }
00342 
00343 /* Function to locate the first non space character in a string,
00344  * and return a pointer to it. */
00345 LPSTR GetFirstNonSpace(LPSTR lpszString)
00346 {
00347   char* p = lpszString;
00348   while (*p && isspace(*p))
00349     p = CharNext(p);
00350 
00351   if(*p == '\0')  // null means end of string
00352     return NULL;
00353 
00354   return p;
00355 }
00356 
00357 /* Function to locate the first space character in a string,
00358  * and return a pointer to it. */
00359 LPSTR GetFirstSpace(LPSTR lpszString)
00360 {
00361   char* p = lpszString;
00362   while (*p && !isspace(*p))
00363     p = CharNext(p);
00364 
00365   if (*p == '\0')  // null means end of string
00366     return NULL;
00367 
00368   return p;
00369 }
00370 
00371 /* Function to locate the first character c in lpszString,
00372  * and return a pointer to it. */
00373 LPSTR MozStrChar(LPSTR lpszString, char c)
00374 {
00375   char* p = lpszString;
00376   while (*p && (*p != c))
00377     p = CharNext(p);
00378 
00379   if (*p == '\0')  // null means end of string
00380     return NULL;
00381 
00382   return p;
00383 }
00384 
00385 /* Function to return the argument count given a command line input
00386  * format string */
00387 int GetArgC(LPSTR lpszCommandLine)
00388 {
00389   int   i;
00390   int   iArgCount;
00391   int   iStrLength;
00392   LPSTR lpszBeginStr;
00393   BOOL  bFoundQuote;
00394   BOOL  bFoundSpace;
00395 
00396   iArgCount    = 0;
00397   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
00398 
00399   if(lpszBeginStr == NULL)
00400     return(iArgCount);
00401 
00402   iStrLength   = lstrlen(lpszBeginStr);
00403   bFoundQuote  = FALSE;
00404   bFoundSpace  = TRUE;
00405 
00406   for(i = 0; i < iStrLength; i++)
00407   {
00408     if(lpszCommandLine[i] == '\"')
00409     {
00410       if(bFoundQuote == FALSE)
00411       {
00412         ++iArgCount;
00413         bFoundQuote = TRUE;
00414       }
00415       else
00416       {
00417         bFoundQuote = FALSE;
00418       }
00419     }
00420     else if(bFoundQuote == FALSE)
00421     {
00422       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
00423       {
00424         ++iArgCount;
00425         bFoundSpace = FALSE;
00426       }
00427       else if(isspace(lpszCommandLine[i]))
00428       {
00429         bFoundSpace = TRUE;
00430       }
00431     }
00432   }
00433 
00434   return(iArgCount);
00435 }
00436 
00437 /* Function to return a specific argument parameter from a given command line input
00438  * format string. */
00439 LPSTR GetArgV(LPSTR lpszCommandLine, int iIndex, LPSTR lpszDest, int iDestSize)
00440 {
00441   int   i;
00442   int   j;
00443   int   iArgCount;
00444   int   iStrLength;
00445   LPSTR lpszBeginStr;
00446   LPSTR lpszDestTemp;
00447   BOOL  bFoundQuote;
00448   BOOL  bFoundSpace;
00449 
00450   iArgCount    = 0;
00451   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
00452 
00453   if(lpszBeginStr == NULL)
00454     return(NULL);
00455 
00456   lpszDestTemp = (char *)calloc(iDestSize, sizeof(char));
00457   if(lpszDestTemp == NULL)
00458   {
00459     PrintError("Out of memory", ERROR_CODE_HIDE);
00460     exit(1);
00461   }
00462 
00463   ZeroMemory(lpszDest, iDestSize);
00464   iStrLength    = lstrlen(lpszBeginStr);
00465   bFoundQuote   = FALSE;
00466   bFoundSpace   = TRUE;
00467   j             = 0;
00468 
00469   for(i = 0; i < iStrLength; i++)
00470   {
00471     if(lpszCommandLine[i] == '\"')
00472     {
00473       if(bFoundQuote == FALSE)
00474       {
00475         ++iArgCount;
00476         bFoundQuote = TRUE;
00477       }
00478       else
00479       {
00480         bFoundQuote = FALSE;
00481       }
00482     }
00483     else if(bFoundQuote == FALSE)
00484     {
00485       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
00486       {
00487         ++iArgCount;
00488         bFoundSpace = FALSE;
00489       }
00490       else if(isspace(lpszCommandLine[i]))
00491       {
00492         bFoundSpace = TRUE;
00493       }
00494     }
00495 
00496     if((iIndex == (iArgCount - 1)) &&
00497       ((bFoundQuote == TRUE) || (bFoundSpace == FALSE) ||
00498       ((bFoundQuote == FALSE) && (lpszCommandLine[i] == '\"'))))
00499     {
00500       if(j < iDestSize)
00501       {
00502         lpszDestTemp[j] = lpszCommandLine[i];
00503         ++j;
00504       }
00505       else
00506       {
00507         lpszDestTemp[j] = '\0';
00508       }
00509     }
00510   }
00511 
00512   RemoveQuotes(lpszDestTemp, lpszDest, iDestSize);
00513   free(lpszDestTemp);
00514   return(lpszDest);
00515 }
00516 
00517 void SetUninstallRunMode(LPSTR szMode)
00518 {
00519   /* Check to see if mode has already been set.  If so,
00520    * then do not override it.
00521    */
00522   if(ugUninstall.mode != NOT_SET)
00523     return;
00524 
00525   if(lstrcmpi(szMode, "NORMAL") == 0)
00526     ugUninstall.mode = NORMAL;
00527   if(lstrcmpi(szMode, "AUTO") == 0)
00528     ugUninstall.mode = AUTO;
00529   if(lstrcmpi(szMode, "SILENT") == 0)
00530     ugUninstall.mode = SILENT;
00531   if(lstrcmpi(szMode, "SHOWICONS") == 0)
00532     ugUninstall.mode = SHOWICONS;
00533   if(lstrcmpi(szMode, "HIDEICONS") == 0)
00534     ugUninstall.mode = HIDEICONS;
00535   if(lstrcmpi(szMode, "SETDEFAULT") == 0)
00536     ugUninstall.mode = SETDEFAULT;
00537 }
00538 
00539 void RemoveBackSlash(LPSTR szInput)
00540 {
00541   int   iCounter;
00542   DWORD dwInputLen;
00543 
00544   if(szInput != NULL)
00545   {
00546     dwInputLen = lstrlen(szInput);
00547 
00548     for(iCounter = dwInputLen -1; iCounter >= 0 ; iCounter--)
00549     {
00550       if(szInput[iCounter] == '\\')
00551         szInput[iCounter] = '\0';
00552       else
00553         break;
00554     }
00555   }
00556 }
00557 
00558 void AppendBackSlash(LPSTR szInput, DWORD dwInputSize)
00559 {
00560   if(szInput != NULL)
00561   {
00562     if(*szInput == '\0')
00563     {
00564       if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
00565       {
00566         lstrcat(szInput, "\\");
00567       }
00568     }
00569     else if(szInput[strlen(szInput) - 1] != '\\')
00570     {
00571       if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
00572       {
00573         lstrcat(szInput, "\\");
00574       }
00575     }
00576   }
00577 }
00578 
00579 void RemoveSlash(LPSTR szInput)
00580 {
00581   int   iCounter;
00582   DWORD dwInputLen;
00583 
00584   if(szInput != NULL)
00585   {
00586     dwInputLen = lstrlen(szInput);
00587 
00588     for(iCounter = dwInputLen -1; iCounter >= 0 ; iCounter--)
00589     {
00590       if(szInput[iCounter] == '/')
00591         szInput[iCounter] = '\0';
00592       else
00593         break;
00594     }
00595   }
00596 }
00597 
00598 void AppendSlash(LPSTR szInput, DWORD dwInputSize)
00599 {
00600   if(szInput != NULL)
00601   {
00602     if(*szInput == '\0')
00603     {
00604       if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
00605       {
00606         lstrcat(szInput, "/");
00607       }
00608     }
00609     else if(szInput[strlen(szInput) - 1] != '/')
00610     {
00611       if(((DWORD)lstrlen(szInput) + 1) < dwInputSize)
00612       {
00613         lstrcat(szInput, "/");
00614       }
00615     }
00616   }
00617 }
00618 
00619 void ParsePath(LPSTR szInput, LPSTR szOutput, DWORD dwOutputSize, DWORD dwType)
00620 {
00621   int   iCounter;
00622   DWORD dwCounter;
00623   DWORD dwInputLen;
00624   BOOL  bFound;
00625 
00626   if((szInput != NULL) && (szOutput != NULL))
00627   {
00628     bFound        = FALSE;
00629     dwInputLen    = lstrlen(szInput);
00630     ZeroMemory(szOutput, dwOutputSize);
00631 
00632     if(dwInputLen < dwOutputSize)
00633     {
00634       switch(dwType)
00635       {
00636         case PP_FILENAME_ONLY:
00637           for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
00638           {
00639             if(szInput[iCounter] == '\\')
00640             {
00641               lstrcpy(szOutput, &szInput[iCounter + 1]);
00642               bFound = TRUE;
00643               break;
00644             }
00645           }
00646           if(bFound == FALSE)
00647             lstrcpy(szOutput, szInput);
00648 
00649           break;
00650 
00651         case PP_PATH_ONLY:
00652           for(iCounter = dwInputLen - 1; iCounter >= 0; iCounter--)
00653           {
00654             if(szInput[iCounter] == '\\')
00655             {
00656               lstrcpy(szOutput, szInput);
00657               szOutput[iCounter + 1] = '\0';
00658               bFound = TRUE;
00659               break;
00660             }
00661           }
00662           if(bFound == FALSE)
00663             lstrcpy(szOutput, szInput);
00664 
00665           break;
00666 
00667         case PP_ROOT_ONLY:
00668           if(szInput[1] == ':')
00669           {
00670             szOutput[0] = szInput[0];
00671             szOutput[1] = szInput[1];
00672             AppendBackSlash(szOutput, dwOutputSize);
00673           }
00674           else if(szInput[1] == '\\')
00675           {
00676             int iFoundBackSlash = 0;
00677             for(dwCounter = 0; dwCounter < dwInputLen; dwCounter++)
00678             {
00679               if(szInput[dwCounter] == '\\')
00680               {
00681                 szOutput[dwCounter] = szInput[dwCounter];
00682                 ++iFoundBackSlash;
00683               }
00684 
00685               if(iFoundBackSlash == 3)
00686                 break;
00687             }
00688 
00689             if(iFoundBackSlash != 0)
00690               AppendBackSlash(szOutput, dwOutputSize);
00691           }
00692           break;
00693       }
00694     }
00695   }
00696 }
00697 
00698 void DetermineOSVersion()
00699 {
00700   BOOL          bIsWin95Debute;
00701   char          szEMsg[MAX_BUF];
00702   OSVERSIONINFO osVersionInfo;
00703 
00704   ulOSType = 0;
00705   osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00706   if(!GetVersionEx(&osVersionInfo))
00707   {
00708     /* GetVersionEx() failed for some reason.  It's not fatal, but could cause
00709      * some complications during installation */
00710     if(GetPrivateProfileString("Messages", "ERROR_GETVERSION", "", szEMsg, sizeof(szEMsg), szFileIniUninstall))
00711       PrintError(szEMsg, ERROR_CODE_SHOW);
00712   }
00713 
00714   bIsWin95Debute  = IsWin95Debute();
00715   switch(osVersionInfo.dwPlatformId)
00716   {
00717     case VER_PLATFORM_WIN32_WINDOWS:
00718       ulOSType |= OS_WIN9x;
00719       if(osVersionInfo.dwMinorVersion == 0)
00720       {
00721         ulOSType |= OS_WIN95;
00722         if(bIsWin95Debute)
00723           ulOSType |= OS_WIN95_DEBUTE;
00724       }
00725       else
00726         ulOSType |= OS_WIN98;
00727       break;
00728 
00729     case VER_PLATFORM_WIN32_NT:
00730       ulOSType |= OS_NT;
00731       switch(osVersionInfo.dwMajorVersion)
00732       {
00733         case 3:
00734           ulOSType |= OS_NT3;
00735           break;
00736 
00737         case 4:
00738           ulOSType |= OS_NT4;
00739           break;
00740 
00741         default:
00742           ulOSType |= OS_NT5;
00743           switch(osVersionInfo.dwMinorVersion)
00744           {
00745             case 0:
00746               /* a minor version of 0 (major.minor.build) indicates Win2000 */
00747               ulOSType |= OS_NT50;
00748               break;
00749 
00750             case 1:
00751               /* a minor version of 1 (major.minor.build) indicates WinXP */
00752               ulOSType |= OS_NT51;
00753           break;
00754           }
00755         break;
00756       }
00757       break;
00758 
00759     default:
00760       if(GetPrivateProfileString("Messages", "ERROR_SETUP_REQUIREMENT", "", szEMsg, sizeof(szEMsg), szFileIniUninstall))
00761         PrintError(szEMsg, ERROR_CODE_HIDE);
00762 
00763       exit(1);
00764       break;
00765   }
00766 }
00767 
00768 HRESULT WinSpawn(LPSTR szClientName, LPSTR szParameters, LPSTR szCurrentDir, int iShowCmd, BOOL bWait)
00769 {
00770   SHELLEXECUTEINFO seInfo;
00771 
00772   seInfo.cbSize       = sizeof(SHELLEXECUTEINFO);
00773   seInfo.fMask        = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
00774   seInfo.hwnd         = hWndMain;
00775   seInfo.lpVerb       = NULL;
00776   seInfo.lpFile       = szClientName;
00777   seInfo.lpParameters = szParameters;
00778   seInfo.lpDirectory  = szCurrentDir;
00779   seInfo.nShow        = SW_SHOWNORMAL;
00780   seInfo.hInstApp     = 0;
00781   seInfo.lpIDList     = NULL;
00782   seInfo.lpClass      = NULL;
00783   seInfo.hkeyClass    = 0;
00784   seInfo.dwHotKey     = 0;
00785   seInfo.hIcon        = 0;
00786   seInfo.hProcess     = 0;
00787 
00788   if((ShellExecuteEx(&seInfo) != 0) && (seInfo.hProcess != NULL))
00789   {
00790     if(bWait)
00791     {
00792       for(;;)
00793       {
00794         if(WaitForSingleObject(seInfo.hProcess, 200) == WAIT_OBJECT_0)
00795           break;
00796 
00797         ProcessWindowsMessages();
00798       }
00799     }
00800     return(TRUE);
00801   }
00802   return(FALSE);
00803 }
00804 
00805 HRESULT InitDlgUninstall(diU *diDialog)
00806 {
00807   diDialog->bShowDialog = FALSE;
00808   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
00809     return(1);
00810   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
00811     return(1);
00812 
00813   return(0);
00814 }
00815 
00816 void DeInitDlgUninstall(diU *diDialog)
00817 {
00818   FreeMemory(&(diDialog->szTitle));
00819   FreeMemory(&(diDialog->szMessage0));
00820 }
00821 
00822 HRESULT InitUninstallGeneral()
00823 {
00824   ugUninstall.mode = NOT_SET;
00825 
00826   if((ugUninstall.szAppPath                 = NS_GlobalAlloc(MAX_BUF)) == NULL)
00827     return(1);
00828   if((ugUninstall.szLogPath                 = NS_GlobalAlloc(MAX_BUF)) == NULL)
00829     return(1);
00830   if((ugUninstall.szLogFilename             = NS_GlobalAlloc(MAX_BUF)) == NULL)
00831     return(1);
00832   if((ugUninstall.szCompanyName             = NS_GlobalAlloc(MAX_BUF)) == NULL)
00833     return(1);
00834   if((ugUninstall.szProductName             = NS_GlobalAlloc(MAX_BUF)) == NULL)
00835     return(1);
00836   if((ugUninstall.szWrKey                   = NS_GlobalAlloc(MAX_BUF)) == NULL)
00837     return(1);
00838   if((ugUninstall.szUserAgent               = NS_GlobalAlloc(MAX_BUF)) == NULL)
00839     return(1);
00840   if((ugUninstall.szDefaultComponent        = NS_GlobalAlloc(MAX_BUF)) == NULL)
00841     return(1);
00842   if((ugUninstall.szWrMainKey               = NS_GlobalAlloc(MAX_BUF)) == NULL)
00843     return(1);
00844   if((ugUninstall.szDescription             = NS_GlobalAlloc(MAX_BUF)) == NULL)
00845     return(1);
00846   if((ugUninstall.szUninstallKeyDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
00847     return(1);
00848   if((ugUninstall.szClientAppID             = NS_GlobalAlloc(MAX_BUF)) == NULL)
00849     return(1);
00850   if((ugUninstall.szClientAppPath           = NS_GlobalAlloc(MAX_BUF)) == NULL)
00851     return(1);
00852 
00853   return(0);
00854 }
00855 
00856 void DeInitUninstallGeneral()
00857 {
00858   FreeMemory(&(ugUninstall.szAppPath));
00859   FreeMemory(&(ugUninstall.szLogPath));
00860   FreeMemory(&(ugUninstall.szLogFilename));
00861   FreeMemory(&(ugUninstall.szDescription));
00862   FreeMemory(&(ugUninstall.szUninstallKeyDescription));
00863   FreeMemory(&(ugUninstall.szUserAgent));
00864   FreeMemory(&(ugUninstall.szDefaultComponent));
00865   FreeMemory(&(ugUninstall.szWrKey));
00866   FreeMemory(&(ugUninstall.szCompanyName));
00867   FreeMemory(&(ugUninstall.szProductName));
00868   FreeMemory(&(ugUninstall.szWrMainKey));
00869   FreeMemory(&(ugUninstall.szClientAppID));
00870   FreeMemory(&(ugUninstall.szClientAppPath));
00871   DeleteObject(ugUninstall.definedFont);
00872 }
00873 
00874 sil *CreateSilNode()
00875 {
00876   sil *silNode;
00877 
00878   if((silNode = NS_GlobalAlloc(sizeof(struct sInfoLine))) == NULL)
00879     exit(1);
00880 
00881   if((silNode->szLine = NS_GlobalAlloc(MAX_BUF)) == NULL)
00882     exit(1);
00883 
00884   silNode->ullLineNumber = 0;
00885   silNode->Next          = silNode;
00886   silNode->Prev          = silNode;
00887 
00888   return(silNode);
00889 }
00890 
00891 void SilNodeInsert(sil *silHead, sil *silTemp)
00892 {
00893   if(silHead == NULL)
00894   {
00895     silHead          = silTemp;
00896     silHead->Next    = silHead;
00897     silHead->Prev    = silHead;
00898   }
00899   else
00900   {
00901     silTemp->Next           = silHead;
00902     silTemp->Prev           = silHead->Prev;
00903     silHead->Prev->Next     = silTemp;
00904     silHead->Prev           = silTemp;
00905   }
00906 }
00907 
00908 void SilNodeDelete(sil *silTemp)
00909 {
00910   if(silTemp != NULL)
00911   {
00912     silTemp->Next->Prev = silTemp->Prev;
00913     silTemp->Prev->Next = silTemp->Next;
00914     silTemp->Next       = NULL;
00915     silTemp->Prev       = NULL;
00916 
00917     FreeMemory(&(silTemp->szLine));
00918     FreeMemory(&silTemp);
00919   }
00920 }
00921 
00922 BOOL IsWin95Debute()
00923 {
00924   HINSTANCE hLib;
00925   BOOL      bIsWin95Debute;
00926 
00927   bIsWin95Debute = FALSE;
00928   if((hLib = LoadLibraryEx("kernel32.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) != NULL)
00929   {
00930     if(((FARPROC)NS_GetDiskFreeSpaceEx = GetProcAddress(hLib, "GetDiskFreeSpaceExA")) == NULL)
00931     {
00932       (FARPROC)NS_GetDiskFreeSpace = GetProcAddress(hLib, "GetDiskFreeSpaceA");
00933       bIsWin95Debute = TRUE;
00934     }
00935 
00936     FreeLibrary(hLib);
00937   }
00938   return(bIsWin95Debute);
00939 }
00940 
00941 DWORD ParseCommandLine(LPSTR lpszCmdLine)
00942 {
00943   char  szArgVBuf[MAX_BUF];
00944   int   i;
00945   int   iArgC;
00946 
00947   i     = 0;
00948   iArgC = GetArgC(lpszCmdLine);
00949   while(i < iArgC)
00950   {
00951     GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
00952 
00953     if((lstrcmpi(szArgVBuf, "-ma") == 0) || (lstrcmpi(szArgVBuf, "/ma") == 0))
00954     {
00955       SetUninstallRunMode("AUTO");
00956     }
00957     else if((lstrcmpi(szArgVBuf, "-ms") == 0) || (lstrcmpi(szArgVBuf, "/ms") == 0))
00958     {
00959       SetUninstallRunMode("SILENT");
00960     }
00961     else if((lstrcmpi(szArgVBuf, "-ua") == 0) || (lstrcmpi(szArgVBuf, "/ua") == 0))
00962     {
00963       if((i + 1) < iArgC)
00964         GetArgV(lpszCmdLine, ++i, ugUninstall.szUserAgent, MAX_BUF);
00965     }
00966     else if((lstrcmpi(szArgVBuf, "-ss") == 0) || (lstrcmpi(szArgVBuf, "/ss") == 0))
00967     // Show Shortcuts
00968     {
00969       SetUninstallRunMode("SHOWICONS");
00970       if((i + 1) < iArgC)
00971         GetArgV(lpszCmdLine, ++i, ugUninstall.szDefaultComponent, MAX_BUF);
00972     }
00973     else if((lstrcmpi(szArgVBuf, "-hs") == 0) || (lstrcmpi(szArgVBuf, "/hs") == 0))
00974     // Hide Shortcuts
00975     {
00976       SetUninstallRunMode("HIDEICONS");
00977       if((i + 1) < iArgC)
00978         GetArgV(lpszCmdLine, ++i, ugUninstall.szDefaultComponent, MAX_BUF);
00979     }
00980     else if((lstrcmpi(szArgVBuf, "-sd") == 0) || (lstrcmpi(szArgVBuf, "/sd") == 0))
00981     // SetDefault
00982     {
00983       SetUninstallRunMode("SETDEFAULT");
00984       if((i + 1) < iArgC)
00985         GetArgV(lpszCmdLine, ++i, ugUninstall.szDefaultComponent, MAX_BUF);
00986     }
00987     else if((lstrcmpi(szArgVBuf, "-app") == 0) || (lstrcmpi(szArgVBuf, "/app") == 0))
00988     // Set the App ID
00989     {
00990       if((i + 1) < iArgC)
00991         GetArgV(lpszCmdLine, ++i, ugUninstall.szClientAppID, MAX_BUF);
00992     }
00993     else if((lstrcmpi(szArgVBuf, "-app_path") == 0) || (lstrcmpi(szArgVBuf, "/app_path") == 0))
00994     // Set the App Path
00995     {
00996       if((i + 1) < iArgC)
00997         GetArgV(lpszCmdLine, ++i, ugUninstall.szClientAppPath, MAX_BUF);
00998     }
00999     else if((lstrcmpi(szArgVBuf, "-reg_path") == 0) || (lstrcmpi(szArgVBuf, "/reg_path") == 0))
01000     // Set the alternative Windows registry path
01001     {
01002       if((i + 1) < iArgC)
01003         GetArgV(lpszCmdLine, ++i, ugUninstall.szWrMainKey, MAX_BUF);
01004     }
01005     else if((lstrcmpi(szArgVBuf, "-v") == 0) || (lstrcmpi(szArgVBuf, "/v") == 0))
01006     // Set Verbose
01007     {
01008       ugUninstall.bVerbose = TRUE;
01009     }
01010     else if(!lstrcmpi(szArgVBuf, "-mmi") || !lstrcmpi(szArgVBuf, "/mmi"))
01011     {
01012       gbAllowMultipleInstalls = TRUE;    
01013     }
01014     else if(!lstrcmpi(szArgVBuf, "-ppid") || !lstrcmpi(szArgVBuf, "/ppid"))
01015     {
01016       if((i + 1) < iArgC)
01017       {
01018         char buf[32];
01019         if (GetArgV(lpszCmdLine, ++i, buf, sizeof(buf)))
01020         {
01021           dwParentPID = (DWORD) atoi(buf);
01022         }
01023       }
01024     }
01025 
01026     ++i;
01027   }
01028   return(WIZ_OK);
01029 }
01030 
01031 int PreCheckInstance(char *szSection, char *szIniFile)
01032 {
01033   char  szBuf[MAX_BUF];
01034   char  szKey[MAX_BUF];
01035   char  szName[MAX_BUF];
01036   char  szParameter[MAX_BUF];
01037   char  szPath[MAX_BUF];
01038   char  szFile[MAX_BUF];
01039   char  *ptrName = NULL;
01040   HKEY  hkeyRoot;
01041   int   iRv = WIZ_OK;
01042   DWORD dwCounter = 0;
01043   BOOL  bContinue = TRUE;
01044   char  szExtraCmd[] = "Extra Cmd";
01045   char  szExtraCmdKey[MAX_BUF];
01046 
01047   do
01048   {
01049     /* Read the win reg key path */
01050     wsprintf(szExtraCmdKey, "%s%d Reg Key", szExtraCmd, dwCounter);
01051     GetPrivateProfileString(szSection,
01052                             szExtraCmdKey,
01053                             "",
01054                             szKey,
01055                             sizeof(szKey),
01056                             szIniFile);
01057     if(*szKey == '\0')
01058     {
01059       bContinue = FALSE;
01060       continue;
01061     }
01062 
01063     /* Read the win reg root key */
01064     wsprintf(szExtraCmdKey, "%s%d Reg Key Root", szExtraCmd, dwCounter);
01065     GetPrivateProfileString(szSection,
01066                             szExtraCmdKey,
01067                             "",
01068                             szBuf,
01069                             sizeof(szBuf),
01070                             szIniFile);
01071     if(*szBuf == '\0')
01072     {
01073       bContinue = FALSE;
01074       continue;
01075     }
01076     hkeyRoot = ParseRootKey(szBuf);
01077 
01078     /* Read the win reg name value */
01079     wsprintf(szExtraCmdKey, "%s%d Reg Name", szExtraCmd, dwCounter);
01080     GetPrivateProfileString(szSection,
01081                             szExtraCmdKey,
01082                             "",
01083                             szName,
01084                             sizeof(szName),
01085                             szIniFile);
01086     if(*szName == '\0')
01087       ptrName = NULL;
01088     else
01089       ptrName = szName;
01090 
01091     /* Read the parameter to use for quitting the browser's turbo mode */
01092     wsprintf(szExtraCmdKey, "%s%d Parameter", szExtraCmd, dwCounter);
01093     GetPrivateProfileString(szSection,
01094                             szExtraCmdKey,
01095                             "",
01096                             szParameter,
01097                             sizeof(szParameter),
01098                             szIniFile);
01099 
01100     /* Read the win reg key that contains the path to the browser */
01101     GetWinReg(hkeyRoot, szKey, ptrName, szFile, sizeof(szFile));
01102     ParsePath(szFile, szPath, sizeof(szPath), PP_PATH_ONLY);
01103 
01104     /* Make sure the file exists */
01105     if(FileExists(szFile))
01106     {
01107       // we've found a file, so let's execute it and stop.  No need to look
01108       // for other keys to parse.  We only want to do that if the file is
01109       // _not_ found.  This is for when we change the name of the browser
01110       // app file and still need to deal with locating it and calling
01111       // -kill on it. ie.
01112       //   previous name: netscp6.exe
01113       //   new name: netscp.exe
01114       // We only need to call one of them, not both.
01115       bContinue = FALSE;
01116 
01117       /* Run the file */
01118       WinSpawn(szFile, szParameter, szPath, SW_HIDE, WS_WAIT);
01119 
01120       /* Even though WinSpawn is suppose to wait for the app to finish, this
01121        * does not really work that way for trying to quit the browser when
01122        * it's in turbo mode, so we wait 2 secs for it to complete. */
01123       Delay(2);
01124     }
01125 
01126     ++dwCounter;
01127   } while(bContinue);
01128 
01129   return(iRv);
01130 }
01131 
01132 HRESULT GetCheckInstanceQuitMessage(char *aSection, char *aMessage, DWORD aMessageBufSize)
01133 {
01134   *aMessage = '\0';
01135   GetPrivateProfileString(aSection, "Message", "", aMessage, aMessageBufSize, szFileIniUninstall);
01136   return(WIZ_OK);
01137 }
01138 
01139 HRESULT ShowMessageAndQuitProcess(HWND aHwndFW, char *aMsgQuitProcess, char *aMsgWait, BOOL aCloseAllWindows, char *aProcessName, BOOL aForceQuit)
01140 {
01141   switch(ugUninstall.mode)
01142   {
01143     case NORMAL:
01144     {
01145       char msgTitleStr[MAX_BUF];
01146       GetPrivateProfileString("Messages", "MB_ATTENTION_STR", "", msgTitleStr, sizeof(msgTitleStr), szFileIniUninstall);
01147       MessageBox(hWndMain, aMsgQuitProcess, msgTitleStr, MB_ICONEXCLAMATION | MB_SETFOREGROUND);
01148       break;
01149     }
01150 
01151     case AUTO:
01152     {
01153       /* Setup mode is AUTO.  Show message, timeout, then auto close
01154        * all the windows associated with the process */
01155       ShowMessage(aMsgQuitProcess, TRUE);
01156       Delay(5);
01157       ShowMessage(aMsgQuitProcess, FALSE);
01158       break;
01159     }
01160 
01161     case SILENT:
01162       break;
01163   }
01164 
01165   if(aForceQuit)
01166   {
01167     assert(aProcessName);
01168     FindAndKillProcess(aProcessName, KP_KILL_PROCESS);
01169   }
01170   else
01171   {
01172     assert(aHwndFW);
01173     /* First try sending a WM_QUIT message to the window because this is the
01174      * preferred way to quit a process.  If it works, then we're good and
01175      * CloseAllWindowsOfWindowHandle() will have nothing to do.
01176      * If it doesn't work, then CloseAllWindowsOfWindowHandle will try to
01177      * quit the process. */
01178     SendMessageTimeout(aHwndFW, WM_QUIT, (WPARAM)1, (LPARAM)0, SMTO_NORMAL, WM_CLOSE_TIMEOUT_VALUE, NULL);
01179     if(aCloseAllWindows)
01180       CloseAllWindowsOfWindowHandle(aHwndFW, aMsgWait);
01181   }
01182   Delay(2);
01183   return(WIZ_OK);
01184 }
01185 
01186 HRESULT CheckInstances()
01187 {
01188   char  section[MAX_BUF];
01189   char  processName[MAX_BUF];
01190   char  className[MAX_BUF];
01191   char  windowName[MAX_BUF];
01192   char  closeAllWindows[MAX_BUF];
01193   char  message[MAX_BUF];
01194   char  msgTitleStr[MAX_BUF];
01195   char  prettyName[MAX_BUF];
01196   char  buf[MAX_BUF];
01197   char  msgWait[MAX_BUF];
01198   int   index;
01199   int   killProcessTries = 0;
01200   int   instanceOfFoundProcess = 0;
01201   BOOL  bContinue;
01202   BOOL  bCloseAllWindows;
01203   HWND  hwndFW;
01204   LPSTR szWN;
01205   LPSTR szCN;
01206   DWORD dwRv0;
01207   DWORD dwRv1;
01208 
01209   GetPrivateProfileString("Messages", "MB_ATTENTION_STR", "", msgTitleStr, sizeof(msgTitleStr), szFileIniUninstall);
01210   bContinue = TRUE;
01211   index    = -1;
01212   while(bContinue)
01213   {
01214     *className  = '\0';
01215     *windowName = '\0';
01216     *message    = '\0';
01217 
01218     wsprintf(section, "Check Instance%d", ++index);
01219     GetPrivateProfileString(section, "Process Name", "", processName, sizeof(processName), szFileIniUninstall);
01220     GetPrivateProfileString(section, "Pretty Name", "", prettyName, sizeof(prettyName), szFileIniUninstall);
01221     GetPrivateProfileString(section, "Message Wait", "", msgWait, sizeof(msgWait), szFileIniUninstall);
01222     GetPrivateProfileString(section, "Close All Process Windows", "", closeAllWindows, sizeof(closeAllWindows), szFileIniUninstall);
01223     if(lstrcmpi(closeAllWindows, "TRUE") == 0)
01224       bCloseAllWindows = TRUE;
01225     else
01226       bCloseAllWindows = FALSE;
01227 
01228     if(instanceOfFoundProcess != index)
01229     {
01230       killProcessTries = 0;
01231       instanceOfFoundProcess = index;
01232     }
01233 
01234     if((killProcessTries == 1) && (*processName != '\0'))
01235     {
01236       if(FindAndKillProcess(processName, KP_DO_NOT_KILL_PROCESS))
01237       {
01238         /* found process, display warning message, then kill process */
01239         GetPrivateProfileString("Messages", "MSG_FORCE_QUIT_PROCESS", "", message, sizeof(message), szFileIniUninstall);
01240         if(*message != '\0')
01241         {
01242           wsprintf(buf, message, prettyName, processName, prettyName, prettyName);
01243           ShowMessageAndQuitProcess(NULL, buf, msgWait, bCloseAllWindows, processName, CI_FORCE_QUIT_PROCESS);
01244           ++killProcessTries;
01245           instanceOfFoundProcess = index--;
01246         }
01247       }
01248       continue;
01249     }
01250     else if(killProcessTries == MAX_KILL_PROCESS_RETRIES)
01251     {
01252       GetPrivateProfileString("Messages", "MSG_FORCE_QUIT_PROCESS_FAILED", "", message, sizeof(message), szFileIniUninstall);
01253       if(*message != '\0')
01254       {
01255         wsprintf(buf, message, prettyName, processName, prettyName);
01256         switch(ugUninstall.mode)
01257         {
01258           case NORMAL:
01259             MessageBox(hWndMain, buf, msgTitleStr, MB_ICONEXCLAMATION | MB_SETFOREGROUND);
01260             break;
01261 
01262           case AUTO:
01263             /* Setup mode is AUTO.  Show message, timeout, then auto close
01264              * all the windows associated with the process */
01265             ShowMessage(buf, TRUE);
01266             Delay(5);
01267             ShowMessage(buf, FALSE);
01268             break;
01269 
01270           default:
01271             break;
01272         }
01273       }
01274 
01275       /* can't kill the process for some unknown reason.  Stop the installation. */
01276       return(TRUE);
01277     }
01278     else if((killProcessTries > 1) &&
01279             (killProcessTries < MAX_KILL_PROCESS_RETRIES) &&
01280             (*processName != '\0'))
01281     {
01282       if(FindAndKillProcess(processName, KP_KILL_PROCESS))
01283       {
01284         ++killProcessTries;
01285         instanceOfFoundProcess = index--;
01286       }
01287       continue;
01288     }
01289 
01290     dwRv0 = GetPrivateProfileString(section, "Class Name",  "", className,  sizeof(className), szFileIniUninstall);
01291     dwRv1 = GetPrivateProfileString(section, "Window Name", "", windowName, sizeof(windowName), szFileIniUninstall);
01292     if((dwRv0 == 0L) && (dwRv1 == 0L) && (*processName == '\0'))
01293     {
01294       bContinue = FALSE;
01295     }
01296     else if((*className != '\0') || (*windowName != '\0'))
01297     {
01298       if(*className == '\0')
01299         szCN = NULL;
01300       else
01301         szCN = className;
01302 
01303       if(*windowName == '\0')
01304         szWN = NULL;
01305       else
01306         szWN = windowName;
01307 
01308       /* If an instance is found, call PreCheckInstance first.
01309        * PreCheckInstance will try to disable the browser's
01310        * QuickLaunch feature. If the browser was in QuickLaunch
01311        * mode without any windows open, PreCheckInstance would
01312        * shutdown the browser, thus a second call to FindAndKillProcess
01313        * is required to see if the process is still around. */
01314       if((hwndFW = FindWindow(szCN, szWN)) != NULL)
01315         PreCheckInstance(section, szFileIniUninstall);
01316 
01317       if((hwndFW = FindWindow(szCN, szWN)) != NULL)
01318       {
01319         GetCheckInstanceQuitMessage(section, message, sizeof(message));
01320         if(*message != '\0')
01321         {
01322           ShowMessageAndQuitProcess(hwndFW, message, msgWait, bCloseAllWindows, processName, CI_CLOSE_PROCESS);
01323           ++killProcessTries;
01324           instanceOfFoundProcess = index--;
01325         }
01326         else
01327         {
01328           /* No message to display.  Assume cancel because we can't allow user to continue */
01329           return(TRUE);
01330         }
01331       }
01332     }
01333 
01334     if((killProcessTries == 0) && (*processName != '\0'))
01335     {
01336       /* The first attempt used FindWindow(), but sometimes the browser can be
01337        * in a state where there's no window open and still not fully shutdown.
01338        * In this case, we need to check for the process itself and kill it. */
01339       if(FindAndKillProcess(processName, KP_DO_NOT_KILL_PROCESS))
01340       {
01341         GetCheckInstanceQuitMessage(section, message, sizeof(message));
01342         if(*message != '\0')
01343         {
01344           ShowMessageAndQuitProcess(hwndFW, message, msgWait, bCloseAllWindows, processName, CI_FORCE_QUIT_PROCESS);
01345           ++killProcessTries;
01346           instanceOfFoundProcess = index--;
01347         }
01348         else
01349         {
01350           /* No message to display.  Assume cancel because we can't allow user to continue */
01351           return(TRUE);
01352         }
01353       }
01354     }
01355   }
01356 
01357   return(FALSE);
01358 }
01359 
01360 BOOL GetFileVersion(LPSTR szFile, verBlock *vbVersion)
01361 {
01362   UINT              uLen;
01363   UINT              dwLen;
01364   BOOL              bRv;
01365   DWORD             dwHandle;
01366   LPVOID            lpData;
01367   LPVOID            lpBuffer;
01368   VS_FIXEDFILEINFO  *lpBuffer2;
01369 
01370   vbVersion->ullMajor   = 0;
01371   vbVersion->ullMinor   = 0;
01372   vbVersion->ullRelease = 0;
01373   vbVersion->ullBuild   = 0;
01374   if(FileExists(szFile))
01375   {
01376     bRv    = TRUE;
01377     dwLen  = GetFileVersionInfoSize(szFile, &dwHandle);
01378     lpData = (LPVOID)malloc(sizeof(long)*dwLen);
01379     uLen   = 0;
01380 
01381     if(GetFileVersionInfo(szFile, dwHandle, dwLen, lpData) != 0)
01382     {
01383       if(VerQueryValue(lpData, "\\", &lpBuffer, &uLen) != 0)
01384       {
01385         lpBuffer2             = (VS_FIXEDFILEINFO *)lpBuffer;
01386         vbVersion->ullMajor   = HIWORD(lpBuffer2->dwFileVersionMS);
01387         vbVersion->ullMinor   = LOWORD(lpBuffer2->dwFileVersionMS);
01388         vbVersion->ullRelease = HIWORD(lpBuffer2->dwFileVersionLS);
01389         vbVersion->ullBuild   = LOWORD(lpBuffer2->dwFileVersionLS);
01390       }
01391     }
01392     free(lpData);
01393   }
01394   else
01395     /* File does not exist */
01396     bRv = FALSE;
01397 
01398   return(bRv);
01399 }
01400 
01401 void TranslateVersionStr(LPSTR szVersion, verBlock *vbVersion)
01402 {
01403   LPSTR szNum1 = NULL;
01404   LPSTR szNum2 = NULL;
01405   LPSTR szNum3 = NULL;
01406   LPSTR szNum4 = NULL;
01407 
01408   szNum1 = strtok(szVersion, ".");
01409   szNum2 = strtok(NULL,      ".");
01410   szNum3 = strtok(NULL,      ".");
01411   szNum4 = strtok(NULL,      ".");
01412 
01413   vbVersion->ullMajor   = _atoi64(szNum1);
01414   vbVersion->ullMinor   = _atoi64(szNum2);
01415   vbVersion->ullRelease = _atoi64(szNum3);
01416   vbVersion->ullBuild   = _atoi64(szNum4);
01417 }
01418 
01419 int CompareVersion(verBlock vbVersionOld, verBlock vbVersionNew)
01420 {
01421   if(vbVersionOld.ullMajor > vbVersionNew.ullMajor)
01422     return(4);
01423   else if(vbVersionOld.ullMajor < vbVersionNew.ullMajor)
01424     return(-4);
01425 
01426   if(vbVersionOld.ullMinor > vbVersionNew.ullMinor)
01427     return(3);
01428   else if(vbVersionOld.ullMinor < vbVersionNew.ullMinor)
01429     return(-3);
01430 
01431   if(vbVersionOld.ullRelease > vbVersionNew.ullRelease)
01432     return(2);
01433   else if(vbVersionOld.ullRelease < vbVersionNew.ullRelease)
01434     return(-2);
01435 
01436   if(vbVersionOld.ullBuild > vbVersionNew.ullBuild)
01437     return(1);
01438   else if(vbVersionOld.ullBuild < vbVersionNew.ullBuild)
01439     return(-1);
01440 
01441   /* the versions are all the same */
01442   return(0);
01443 }
01444 
01445 BOOL VerifyRestrictedAccess(void)
01446 {
01447   char  szSubKey[MAX_BUF];
01448   char  szSubKeyToTest[] = "Software\\%s - Test Key";
01449   BOOL  bRv;
01450   DWORD dwDisp = 0;
01451   DWORD dwErr;
01452   HKEY  hkRv;
01453 
01454   wsprintf(szSubKey, szSubKeyToTest, ugUninstall.szCompanyName);
01455   dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
01456                          szSubKey,
01457                          0,
01458                          NULL,
01459                          REG_OPTION_NON_VOLATILE,
01460                          KEY_WRITE,
01461                          NULL,
01462                          &hkRv,
01463                          &dwDisp);
01464   if(dwErr == ERROR_SUCCESS)
01465   {
01466     RegCloseKey(hkRv);
01467     switch(dwDisp)
01468     {
01469       case REG_CREATED_NEW_KEY:
01470         RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
01471         break;
01472 
01473       case REG_OPENED_EXISTING_KEY:
01474         break;
01475     }
01476     bRv = FALSE;
01477   }
01478   else
01479     bRv = TRUE;
01480 
01481   return(bRv);
01482 }
01483 
01484 BOOL CheckLegacy(HWND hDlg)
01485 {
01486   char      szSection[MAX_BUF];
01487   char      szFilename[MAX_BUF];
01488   char      szMessage[MAX_BUF];
01489   char      szIndex[MAX_BUF];
01490   char      szVersionNew[MAX_BUF];
01491   char      szDecryptedFilePath[MAX_BUF];
01492   int       iIndex;
01493   BOOL      bContinue;
01494   DWORD     dwRv0;
01495   DWORD     dwRv1;
01496   verBlock  vbVersionNew;
01497   verBlock  vbVersionOld;
01498 
01499   bContinue = TRUE;
01500   iIndex    = -1;
01501   while(bContinue)
01502   {
01503     ZeroMemory(szFilename,      sizeof(szFilename));
01504     ZeroMemory(szVersionNew,    sizeof(szVersionNew));
01505     ZeroMemory(szMessage,       sizeof(szMessage));
01506 
01507     ++iIndex;
01508     itoa(iIndex, szIndex, 10);
01509     lstrcpy(szSection, "Legacy Check");
01510     lstrcat(szSection, szIndex);
01511 
01512     dwRv0 = GetPrivateProfileString(szSection, "Filename", "", szFilename, MAX_BUF, szFileIniUninstall);
01513     dwRv1 = GetPrivateProfileString(szSection, "Version", "", szVersionNew, MAX_BUF, szFileIniUninstall);
01514     if(dwRv0 == 0L)
01515     {
01516       bContinue = FALSE;
01517     }
01518     else if(*szFilename != '\0')
01519     {
01520       GetPrivateProfileString(szSection, "Message", "", szMessage, MAX_BUF, szFileIniUninstall);
01521       if(*szMessage == '\0')
01522         /* no message string input. so just continue with the next check */
01523         continue;
01524 
01525       DecryptString(szDecryptedFilePath, szFilename);
01526       if((dwRv1 == 0L) || (*szVersionNew == '\0'))
01527       {
01528         if(FileExists(szDecryptedFilePath))
01529         {
01530           char szMBWarningStr[MAX_BUF];
01531 
01532           if(!GetPrivateProfileString("Messages", "MB_WARNING_STR", "",
01533                                       szMBWarningStr, sizeof(szMBWarningStr), 
01534                                       szFileIniUninstall))
01535             lstrcpy(szMBWarningStr, "Warning");
01536 
01537           if(MessageBox(hDlg, szMessage, szMBWarningStr, MB_ICONWARNING | MB_YESNO) == IDYES)
01538             return(TRUE);
01539         }
01540         /* file does not exist, so it's okay.  Continue with the next check */
01541         continue;
01542       }
01543 
01544       if(GetFileVersion(szDecryptedFilePath, &vbVersionOld))
01545       {
01546         TranslateVersionStr(szVersionNew, &vbVersionNew);
01547         if(CompareVersion(vbVersionOld, vbVersionNew) < 0)
01548         {
01549           char szMBWarningStr[MAX_BUF];
01550 
01551           if(!GetPrivateProfileString("Messages", "MB_WARNING_STR", "",
01552                                       szMBWarningStr, sizeof(szMBWarningStr), 
01553                                       szFileIniUninstall))
01554             lstrcpy(szMBWarningStr, "Warning");
01555 
01556           if(MessageBox(hDlg, szMessage, szMBWarningStr, MB_ICONWARNING | MB_YESNO) == IDYES)
01557             return(TRUE);
01558         }
01559       }
01560     }
01561   }
01562   /* returning TRUE means the user wants to go back and choose a different destination path
01563    * returning FALSE means the user is ignoring the warning
01564    */
01565   return(FALSE);
01566 }
01567 
01568 // This function looks up the path for the application being uninstalled, NOT the client
01569 //   app in a shared install environment.
01570 HRESULT GetAppPath()
01571 {
01572   char szTmpAppPath[MAX_BUF];
01573   char szKey[MAX_BUF];
01574   BOOL bRestrictedAccess;
01575   HKEY hkRoot;
01576 
01577   if(*ugUninstall.szUserAgent != '\0')
01578   {
01579     hkRoot = ugUninstall.hWrMainRoot;
01580     wsprintf(szKey, "%s\\%s\\Main", ugUninstall.szWrMainKey, ugUninstall.szUserAgent);
01581   }
01582   else
01583   {
01584     hkRoot = ugUninstall.hWrRoot;
01585     strcpy(szKey, ugUninstall.szWrKey);
01586   }
01587 
01588   bRestrictedAccess = VerifyRestrictedAccess();
01589   if(bRestrictedAccess)
01590     hkRoot = HKEY_CURRENT_USER;
01591 
01592   GetWinReg(hkRoot, szKey, "PathToExe", szTmpAppPath, sizeof(szTmpAppPath));
01593   if(FileExists(szTmpAppPath))
01594     lstrcpy(ugUninstall.szAppPath, szTmpAppPath);
01595 
01596   GetWinReg(hkRoot, szKey, "Install Directory", ugUninstall.szInstallPath, sizeof(ugUninstall.szInstallPath));
01597 
01598   return(0);
01599 }
01600 
01601 // For shared installs we maintain an app list, which is a glorified
01602 //   refcount of the apps which are using this version of the 
01603 //   shared app.  Processing the app list does two things:
01604 //
01605 //   1) Cleans up any registry entries for apps which are no longer
01606 //      installed.  The app list includes a representative file for
01607 //      each app.  If that file is not installed than the app is 
01608 //      assumed to have been removed from the system.
01609 //   2) Returns a count of the installed apps which depend upon this
01610 //      shared app.  If this app is not shared, there will be no app
01611 //      list so this will always return 0.
01612 DWORD CleanupAppList()
01613 {
01614   typedef struct siAppListStruct siAppList;
01615   struct siAppListStruct
01616   {
01617     char szAppID[MAX_BUF];
01618     siAppList *Next;
01619   };
01620 
01621   siAppList *siALHead;
01622   siAppList *siALPrev;
01623   siAppList *siALTmp;
01624 
01625   char      *szRv = NULL;
01626   char      szKey[MAX_BUF];
01627   char      szBuf[MAX_BUF];
01628   char      szDefaultApp[MAX_BUF_TINY];
01629   BOOL      bFoundDefaultApp;
01630   HKEY      hkResult;
01631   DWORD     dwIndex;
01632   DWORD     dwBufSize;
01633   DWORD     dwTotalSubKeys;
01634   DWORD     dwTotalValues;
01635   DWORD     dwAppCount;
01636   FILETIME  ftLastWriteFileTime;
01637 
01638   GetPrivateProfileString("General", "Default AppID", "", szDefaultApp, MAX_BUF_TINY, szFileIniUninstall);
01639   wsprintf(szKey, "%s\\%s\\AppList", ugUninstall.szWrMainKey, ugUninstall.szUserAgent);
01640   if(RegOpenKeyEx(ugUninstall.hWrMainRoot, szKey, 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
01641   {
01642     return(0);
01643   }
01644 
01645   siALHead = NULL;
01646   dwAppCount = 0;
01647   dwTotalSubKeys = 0;
01648   dwTotalValues  = 0;
01649   RegQueryInfoKey(hkResult, NULL, NULL, NULL, &dwTotalSubKeys, NULL, NULL, &dwTotalValues, NULL, NULL, NULL, NULL);
01650 
01651   for(dwIndex = 0; dwIndex < dwTotalSubKeys; dwIndex++)
01652   {
01653     dwBufSize = sizeof(szBuf);
01654     if(RegEnumKeyEx(hkResult, dwIndex, szBuf, &dwBufSize, NULL, NULL, NULL, &ftLastWriteFileTime) == ERROR_SUCCESS)
01655     {
01656       if((siALTmp = NS_GlobalAlloc(sizeof(struct siAppListStruct))) == NULL)
01657         exit(1);
01658       lstrcpy(siALTmp->szAppID, szBuf);
01659       siALTmp->Next = NULL;
01660 
01661       if(siALHead == NULL)
01662         siALHead = siALTmp; //New list, point the head at it.
01663       else
01664         siALPrev->Next = siALTmp;
01665 
01666       siALPrev = siALTmp;
01667     }
01668   }
01669   RegCloseKey(hkResult);
01670 
01671   siALTmp = siALHead;
01672   while(siALTmp != NULL)
01673   {
01674     if(lstrcmpi(siALTmp->szAppID, szDefaultApp) == 0)
01675       bFoundDefaultApp = TRUE;
01676 
01677     // ProcessAppItem returns the # of installations of the App
01678     dwAppCount = dwAppCount + ProcessAppItem(ugUninstall.hWrMainRoot, szKey, siALTmp->szAppID);
01679 
01680     siALPrev = siALTmp;
01681     siALTmp = siALTmp->Next;
01682     FreeMemory(&siALPrev);
01683   }
01684 
01685   if(dwAppCount == 0)
01686     RegDeleteKey(ugUninstall.hWrMainRoot, szKey);
01687 
01688   // If the Default App is not listed in AppList, then the shared app should not be in the 
01689   //   Windows Add/Remove Programs list either.
01690   if(!bFoundDefaultApp)
01691   {
01692     wsprintf(szKey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s (%s)",ugUninstall.szProductName, ugUninstall.szUserAgent);
01693     RegDeleteKey(ugUninstall.hWrMainRoot, szKey);
01694   }
01695 
01696   return(dwAppCount);
01697 }
01698 
01699 
01700 // Removes the app item if it is the app identified with the /app command-line option
01701 // If an app item is not installed this removes it from the app list.
01702 // Returns the # of installations of the app item found in the AppList.
01703 DWORD ProcessAppItem(HKEY hkRootKey, LPSTR szKeyAppList, LPSTR szAppID)
01704 {
01705   DWORD dwIndex = 1;
01706   const DWORD dwUpperLimit = 100;
01707   BOOL  bDefaultApp;
01708   char szBuf[MAX_BUF];
01709   char szKey[MAX_BUF];
01710   char szName[MAX_BUF];
01711   char szUninstKey[MAX_BUF];
01712 
01713   GetPrivateProfileString("General", "Default AppID", "", szBuf, sizeof(szBuf), szFileIniUninstall);
01714   bDefaultApp = (lstrcmpi(szAppID, szBuf) == 0);
01715 
01716   wsprintf(szKey, "%s\\%s", szKeyAppList, szAppID);
01717 
01718   if(lstrcmpi(szAppID, ugUninstall.szClientAppID) == 0) // This is the app that the user said 
01719   {                                                     // on the command-line to uninstall.
01720     if((ugUninstall.szClientAppPath[0] == '\0') || (bDefaultApp)) // If we didn't get an /app_path or this
01721     {                                                             // is the default app, just remove it.
01722       RegDeleteKey(hkRootKey, szKey);
01723       if(bDefaultApp)
01724       {
01725         wsprintf(szKey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\GRE (%s)", ugUninstall.szUserAgent);
01726         RegDeleteKey(hkRootKey, szKey);
01727       }
01728 
01729       return 0;
01730     }
01731 
01732     wsprintf(szName, "PathToExe%02d", dwIndex);
01733     while(WinRegNameExists(hkRootKey, szKey, szName) && // Since we got an /app_path we need to cycle
01734          (dwIndex < dwUpperLimit))                      // through the list looking for that instance.
01735     {
01736       GetWinReg(hkRootKey, szKey, szName, szBuf, sizeof(szBuf));
01737       if((lstrcmpi(szBuf, ugUninstall.szClientAppPath) == 0) || (!FileExists(szBuf)))
01738       {
01739         // RemovePathToExeXX() will delete the dwIndex Name and reorder
01740         // PathToExeXX so there are no gaps.
01741         RemovePathToExeXX(hkRootKey, szKey, dwIndex, dwUpperLimit);
01742       }
01743       else
01744         wsprintf(szName, "PathToExe%02d", ++dwIndex);
01745     }
01746 
01747     if(--dwIndex == 0)
01748       RegDeleteKey(hkRootKey, szKey);
01749 
01750     return dwIndex;
01751   }
01752 
01753   if(bDefaultApp) // The Default App does not have an installed file registered.  However, an entry in 
01754   {               // the Windows Add/Remove products list indicates that the Default App is installed
01755                   // and needs to be counted.
01756     wsprintf(szUninstKey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s (%s)",ugUninstall.szProductName, ugUninstall.szUserAgent);
01757     GetWinReg(hkRootKey, szUninstKey, "UninstallString", szBuf, sizeof(szBuf));
01758 
01759     if(szBuf[0] != '\0')
01760       return 1;
01761   }
01762 
01763   dwIndex = 1;
01764   wsprintf(szName, "PathToExe%02d", dwIndex);
01765   while(WinRegNameExists(hkRootKey, szKey, szName) && // Count the entries which can be verified by the
01766        (dwIndex < dwUpperLimit))                      // existence of the file pointed to by PathToExeXX
01767   {
01768     GetWinReg(hkRootKey, szKey, szName, szBuf, sizeof(szBuf));
01769     if(!FileExists(szBuf))    
01770     {
01771       // RemovePathToExeXX() will delete the dwIndex Name and reorder
01772       // PathToExeXX so there are no gaps.
01773       RemovePathToExeXX(hkRootKey, szKey, dwIndex, dwUpperLimit);
01774     }
01775     else
01776       wsprintf(szName, "PathToExe%02d", ++dwIndex);
01777   }
01778 
01779   if(--dwIndex == 0)
01780     RegDeleteKey(hkRootKey, szKey);
01781 
01782   return dwIndex;
01783 }
01784 
01785 void RemovePathToExeXX(HKEY hkRootKey, LPSTR szKey, DWORD dwIndex, const DWORD dwUpperLimit)
01786 {
01787   char szBuf[MAX_BUF_TINY];
01788   char szName[MAX_BUF_TINY];
01789   char szNextName[MAX_BUF_TINY];
01790 
01791   wsprintf(szName,     "PathToExe%02d", dwIndex++);
01792   wsprintf(szNextName, "PathToExe%02d", dwIndex);
01793   while(WinRegNameExists(hkRootKey, szKey, szNextName) && (dwIndex < dwUpperLimit))
01794   {
01795     GetWinReg(hkRootKey, szKey, szNextName, szBuf, sizeof(szBuf));
01796     SetWinReg(hkRootKey, szKey, szName, REG_SZ, szBuf, lstrlen(szBuf));
01797     lstrcpy(szName, szNextName);
01798     wsprintf(szNextName, "PathToExe%02d", ++dwIndex);
01799   }        
01800 
01801   DeleteWinRegValue(hkRootKey, szKey, szName);
01802 }
01803 
01804 /* Function: ReplacePrivateProfileStrCR()
01805  *
01806  *       in: LPSTR aInputOutputStr: In/out string to containing "\\n" to replace.
01807  *           
01808  *  purpose: To parse for and replace "\\n" string with "\n".  Strings stored
01809  *           in .ini files cannot contain "\n" because it's a key delimiter.
01810  *           To work around this limination, "\\n" chars can be used to
01811  *           represent '\n'.  This function will look for "\\n" and replace
01812  *           them with a true "\n".
01813  *           If it encounters a string of "\\\\n" (which looks like '\\n'),
01814  *           then this function will strip out the extra '\\' and just show
01815  *           "\\n";
01816  */
01817 void ReplacePrivateProfileStrCR(LPSTR aInputOutputStr)
01818 {
01819   LPSTR pSearch          = aInputOutputStr;
01820   LPSTR pSearchEnd       = aInputOutputStr + lstrlen(aInputOutputStr);
01821   LPSTR pPreviousSearch  = NULL;
01822 
01823   while (pSearch < pSearchEnd)
01824   {
01825     if (('\\' == *pSearch) || ('n' == *pSearch))
01826     {
01827       // found a '\\' or 'n'.  check to see if  the prefivous char is also a '\\'.
01828       if (pPreviousSearch && ('\\' == *pPreviousSearch))
01829       {
01830         if ('n' == *pSearch)
01831           *pSearch = '\n';
01832 
01833         memmove(pPreviousSearch, pSearch, pSearchEnd-pSearch+1);
01834 
01835         // our string is shorter now ...
01836         pSearchEnd -= pSearch - pPreviousSearch;
01837       }
01838     }
01839 
01840     pPreviousSearch = pSearch;
01841     pSearch = CharNext(pSearch);
01842   }
01843 }
01844 
01845 /* Function: IsPathWithinWindir()
01846  *       in: char *aTargetPath
01847  *      out: returns a BOOL type indicating whether the install path chosen
01848  *           by the user is within the %windir% or not.
01849  *  purpose: To see if aTargetPath is within the %windir% path.
01850  */
01851 BOOL IsPathWithinWindir(char *aTargetPath)
01852 {
01853   char    windir[MAX_PATH];
01854   char    targetPath[MAX_PATH];
01855   HRESULT rv;
01856 
01857   assert(aTargetPath);
01858 
01859   rv = GetWindowsDirectory(windir, sizeof(windir));
01860   assert(rv);
01861   MozCopyStr(aTargetPath, targetPath, sizeof(targetPath));
01862   RemoveBackSlash(targetPath);
01863   CharUpperBuff(targetPath, sizeof(targetPath));
01864   RemoveBackSlash(windir);
01865   CharUpperBuff(windir, sizeof(windir));
01866 
01867   if(strstr(targetPath, windir))
01868     return(TRUE);
01869 
01870   return(FALSE);
01871 }
01872 
01873 /* Function: VerifyAndDeleteInstallationFolder()
01874  *       in: none
01875  *      out: none
01876  *  purpose: To verify that the installation folder has been completely
01877  *           deleted, else prompt the user if they would like to delete
01878  *           the folder and it's left over contents.
01879  *           It will also check to make sure that the installation
01880  *           folder is not within the %windir% folder.  If it is,
01881  *           it will warn the user and not perform the deletion of the
01882  *           installation folder.
01883  */
01884 void VerifyAndDeleteInstallationFolder()
01885 {
01886   if(FileExists(ugUninstall.szInstallPath))
01887   {
01888     char buf[MAX_BUF];
01889     char msg[MAX_BUF];
01890     char msgBoxTitle[MAX_BUF];
01891     char installationPath[MAX_BUF];
01892 
01893     MozCopyStr(ugUninstall.szInstallPath, installationPath, sizeof(installationPath));
01894     RemoveBackSlash(installationPath);
01895 
01896     if(ugUninstall.mode == NORMAL)
01897     {
01898       GetPrivateProfileString("Messages", "MB_ATTENTION_STR", "", msgBoxTitle, sizeof(msgBoxTitle), szFileIniUninstall);
01899       GetPrivateProfileString("Messages", "MSG_DELETE_INSTALLATION_PATH", "", buf, sizeof(buf), szFileIniUninstall);
01900       ReplacePrivateProfileStrCR(buf);
01901       _snprintf(msg, sizeof(msg), buf, installationPath);
01902       msg[sizeof(msg) - 1] = '\0';
01903 
01904       /* Prompt user on if they want the completely remove the
01905        * installation folder */
01906       if(MessageBox(hWndMain, msg, msgBoxTitle, MB_ICONQUESTION | MB_YESNO) == IDYES)
01907       {
01908         if(IsPathWithinWindir(installationPath))
01909         {
01910           GetPrivateProfileString("Messages", "MSG_INSTALLATION_PATH_WITHIN_WINDIR",
01911               "", msg, sizeof(msg), szFileIniUninstall);
01912           MessageBox(hWndMain, msg, NULL, MB_ICONEXCLAMATION);
01913           return;
01914         }
01915 
01916         /* Remove the installation folder here */
01917         AppendBackSlash(installationPath, sizeof(installationPath));
01918         DirectoryRemove(installationPath, TRUE);
01919       }
01920     }
01921     else
01922     {
01923       /* If uninstall is running in !NORMAL mode, assume user wants to
01924        * completely delete the installation folder */
01925       AppendBackSlash(installationPath, sizeof(installationPath));
01926       DirectoryRemove(installationPath, TRUE);
01927     }
01928   }
01929 }
01930 
01931 HRESULT GetUninstallLogPath()
01932 {
01933   char szBuf[MAX_BUF];
01934   char szLogFolder[MAX_BUF];
01935   char szKey[MAX_BUF];
01936   char szWindowsUninstallKey[MAX_BUF];
01937   char szErrorMsg[MAX_BUF];
01938   char szEUninstallLogFolder[MAX_BUF];
01939   char szRootKey[MAX_BUF];
01940   BOOL bRestrictedAccess;
01941   HKEY hkRoot;
01942 
01943   if(*ugUninstall.szUserAgent != '\0')
01944   {
01945     hkRoot = ugUninstall.hWrMainRoot;
01946     lstrcpy(szKey, ugUninstall.szWrMainKey);
01947     AppendBackSlash(szKey, sizeof(szKey));
01948     lstrcat(szKey, ugUninstall.szUserAgent);
01949     AppendBackSlash(szKey, sizeof(szKey));
01950     lstrcat(szKey, "Uninstall");
01951   }
01952   else
01953   {
01954     hkRoot = ugUninstall.hWrRoot;
01955     strcpy(szKey, ugUninstall.szWrKey);
01956   }
01957 
01958   bRestrictedAccess = VerifyRestrictedAccess();
01959   if(bRestrictedAccess)
01960     hkRoot = HKEY_CURRENT_USER;
01961 
01962   GetWinReg(hkRoot, szKey, "Uninstall Log Folder",   szLogFolder, sizeof(szLogFolder));
01963   GetWinReg(hkRoot, szKey, "Description",            ugUninstall.szUninstallKeyDescription, MAX_BUF);
01964 
01965   if(!bRestrictedAccess)
01966   {
01967     lstrcpy(szWindowsUninstallKey, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
01968     lstrcat(szWindowsUninstallKey, ugUninstall.szUninstallKeyDescription);
01969     GetWinReg(HKEY_LOCAL_MACHINE, szWindowsUninstallKey, "DisplayName", ugUninstall.szDescription, MAX_BUF);
01970   }
01971 
01972   /* if the DisplayName was not found in the windows registry,
01973    * use the description read in from config.ini file */
01974   if(*ugUninstall.szDescription == '\0')
01975     lstrcpy(ugUninstall.szDescription, ugUninstall.szUninstallKeyDescription);
01976 
01977   if(FileExists(szLogFolder) == FALSE)
01978   {
01979     if(GetPrivateProfileString("Messages", "ERROR_UNINSTALL_LOG_FOLDER", "",
01980                                szEUninstallLogFolder, sizeof(szEUninstallLogFolder), 
01981                                szFileIniUninstall))
01982     {
01983       lstrcpy(szBuf, "\n\n    ");
01984 
01985       if(*szLogFolder == '\0')
01986       {
01987         GetStringRootKey(hkRoot, szRootKey, sizeof(szRootKey));
01988         lstrcat(szBuf, szRootKey);
01989         lstrcat(szBuf, "\\");
01990         lstrcat(szBuf, szKey);
01991         lstrcat(szBuf, "\\Uninstall Log Folder");
01992       }
01993       else
01994         lstrcat(szBuf, szLogFolder);
01995 
01996       lstrcat(szBuf, "\n");
01997       wsprintf(szErrorMsg, szEUninstallLogFolder, szBuf);
01998       PrintError(szErrorMsg, ERROR_CODE_SHOW);
01999     }
02000 
02001     return(1);
02002   }
02003   lstrcpy(ugUninstall.szLogPath, szLogFolder);
02004 
02005   return(0);
02006 }
02007 
02008 HRESULT ParseUninstallIni()
02009 {
02010   char szBuf[MAX_BUF];
02011   char szKeyCrypted[MAX_BUF];
02012   char szShowDialog[MAX_BUF];
02013   LOGFONT lf;
02014   char fontName[MAX_BUF];
02015   char fontSize[MAX_BUF];
02016   char charSet[MAX_BUF];
02017 
02018   lstrcpy(ugUninstall.szLogFilename, FILE_LOG_INSTALL);
02019 
02020   GetPrivateProfileString("General", "Shared Install", "", szBuf, MAX_BUF, szFileIniUninstall);
02021   ugUninstall.bSharedInst = (lstrcmpi(szBuf, "TRUE") == 0);
02022 
02023   /* get install Mode information */
02024   GetPrivateProfileString("General", "Run Mode", "", szBuf, MAX_BUF, szFileIniUninstall);
02025   SetUninstallRunMode(szBuf);
02026 
02027   if((ugUninstall.mode != SHOWICONS) && (ugUninstall.mode != HIDEICONS) && (ugUninstall.mode != SETDEFAULT))
02028     if(CheckInstances())
02029       return(1);
02030   if(InitDlgUninstall(&diUninstall))
02031     return(1);
02032  
02033   /* get product name description */
02034   GetPrivateProfileString("General", "Company Name", "", ugUninstall.szCompanyName, MAX_BUF, szFileIniUninstall);
02035   GetPrivateProfileString("General", "Product Name", "", ugUninstall.szProductName, MAX_BUF, szFileIniUninstall);
02036   GetPrivateProfileString("General", "Root Key",     "", szBuf, MAX_BUF, szFileIniUninstall);
02037   ugUninstall.hWrRoot = ParseRootKey(szBuf);
02038 
02039   GetPrivateProfileString("General", "Key",          "", szKeyCrypted, MAX_BUF, szFileIniUninstall);
02040   GetPrivateProfileString("General", "Decrypt Key",  "", szBuf, MAX_BUF, szFileIniUninstall);
02041   if(lstrcmpi(szBuf, "TRUE") == 0)
02042   {
02043     DecryptString(ugUninstall.szWrKey, szKeyCrypted);
02044   }
02045   else
02046     strcpy(ugUninstall.szWrKey, szKeyCrypted);
02047 
02048   RemoveBackSlash(ugUninstall.szWrKey);
02049 
02050   GetPrivateProfileString("General", "Main Root Key",    "", szBuf, MAX_BUF, szFileIniUninstall);
02051   ugUninstall.hWrMainRoot = ParseRootKey(szBuf);
02052 
02053   GetPrivateProfileString("General", "Main Key",         "", szKeyCrypted, MAX_BUF, szFileIniUninstall);
02054   GetPrivateProfileString("General", "Decrypt Main Key", "", szBuf, MAX_BUF, szFileIniUninstall);
02055 
02056   // If szWrMainKey is not null then it was set on the command-line and that is
02057   //    what we want to use.
02058   if(*ugUninstall.szWrMainKey == '\0') 
02059   {
02060     if(lstrcmpi(szBuf, "TRUE") == 0)
02061     {
02062       DecryptString(ugUninstall.szWrMainKey, szKeyCrypted);
02063     }
02064     else
02065       strcpy(ugUninstall.szWrMainKey, szKeyCrypted);
02066   }
02067 
02068   RemoveBackSlash(ugUninstall.szWrMainKey);
02069 
02070   /* Uninstall dialog */
02071   GetPrivateProfileString("Dialog Uninstall",       "Show Dialog",  "", szShowDialog,                 MAX_BUF, szFileIniUninstall);
02072   GetPrivateProfileString("Dialog Uninstall",       "Title",        "", diUninstall.szTitle,          MAX_BUF, szFileIniUninstall);
02073   GetPrivateProfileString("Dialog Uninstall",       "Message0",     "", diUninstall.szMessage0,       MAX_BUF, szFileIniUninstall);
02074   if(lstrcmpi(szShowDialog, "TRUE") == 0)
02075     diUninstall.bShowDialog = TRUE;
02076 
02077   switch(ugUninstall.mode)
02078   {
02079     case AUTO:
02080     case SILENT:
02081     case SHOWICONS:
02082     case HIDEICONS:
02083     case SETDEFAULT:
02084       gdwWhatToDo             = WTD_NO_TO_ALL;
02085       diUninstall.bShowDialog = FALSE;
02086       break;
02087   }
02088 
02089   /* get defined font */
02090   GetPrivateProfileString("Dialog Uninstall", "FONTNAME", "", fontName, MAX_BUF, szFileIniUninstall);
02091   GetPrivateProfileString("Dialog Uninstall", "FONTSIZE", "", fontSize, MAX_BUF, szFileIniUninstall);
02092   GetPrivateProfileString("Dialog Uninstall", "CHARSET", "", charSet, MAX_BUF, szFileIniUninstall);
02093   memset(&lf, 0, sizeof(lf));
02094   strcpy(lf.lfFaceName, fontName);
02095   lf.lfHeight = -MulDiv(atoi(fontSize), GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72);
02096   lf.lfCharSet = atoi(charSet);
02097   ugUninstall.definedFont = CreateFontIndirect( &lf ); 
02098 
02099   GetAppPath();
02100 
02101 
02102   if(ugUninstall.bSharedInst)
02103   {
02104     // Shared installations require a user agent.  Without one there is no way to know 
02105     //   what version of GRE to clean up so we can't do anything--including CleanupAppList()
02106     //   so don't change the order of the if statement.  
02107     //   (We should add UI warning the user when a required UserAgent is not supplied.)
02108     // CleanupAppList() returns the number of installations of apps dependant on this shared app.
02109     if((ugUninstall.szUserAgent[0] == '\0') || (CleanupAppList() != 0))
02110       ugUninstall.bUninstallFiles = FALSE;
02111   }
02112 
02113   return(GetUninstallLogPath());
02114 }
02115 
02116 void GetWinReg(HKEY hkRootKey, LPSTR szKey, LPSTR szName, LPSTR szReturnValue, DWORD dwReturnValueSize)
02117 {
02118   HKEY  hkResult;
02119   DWORD dwErr;
02120   DWORD dwSize;
02121   char  szBuf[MAX_BUF];
02122 
02123   ZeroMemory(szBuf, sizeof(szBuf));
02124   ZeroMemory(szReturnValue, dwReturnValueSize);
02125 
02126   if((dwErr = RegOpenKeyEx(hkRootKey, szKey, 0, KEY_READ, &hkResult)) == ERROR_SUCCESS)
02127   {
02128     dwSize = sizeof(szBuf);
02129     dwErr = RegQueryValueEx(hkResult, szName, 0, NULL, szBuf, &dwSize);
02130 
02131     if((*szBuf != '\0') && (dwErr == ERROR_SUCCESS))
02132       ExpandEnvironmentStrings(szBuf, szReturnValue, dwReturnValueSize);
02133     else
02134       *szReturnValue = '\0';
02135 
02136     RegCloseKey(hkResult);
02137   }
02138 }
02139 
02140 void SetWinReg(HKEY hkRootKey, LPSTR szKey, LPSTR szName, DWORD dwType, LPSTR szData, DWORD dwSize)
02141 {
02142   HKEY    hkResult;
02143   DWORD   dwErr;
02144   DWORD   dwDisp;
02145   char    szBuf[MAX_BUF];
02146 
02147   memset(szBuf, '\0', MAX_BUF);
02148 
02149   dwErr = RegOpenKeyEx(hkRootKey, szKey, 0, KEY_WRITE, &hkResult);
02150   if(dwErr != ERROR_SUCCESS)
02151     dwErr = RegCreateKeyEx(hkRootKey, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkResult, &dwDisp);
02152 
02153   if(dwErr == ERROR_SUCCESS)
02154   {
02155     dwErr = RegSetValueEx(hkResult, szName, 0, dwType, szData, dwSize);
02156 
02157     RegCloseKey(hkResult);
02158   }
02159 }
02160 
02161 void SetWinRegNumValue(HKEY hkRootKey, LPSTR szKey, LPSTR szName, DWORD dwData)
02162 {
02163   HKEY    hkResult;
02164   DWORD   dwErr;
02165   DWORD   dwDisp;
02166   DWORD   dwVal;
02167   DWORD   dwValSize;
02168 
02169   dwVal = dwData;
02170   dwValSize = sizeof(DWORD);
02171 
02172   dwErr = RegOpenKeyEx(hkRootKey, szKey, 0, KEY_WRITE, &hkResult);
02173   if(dwErr != ERROR_SUCCESS)
02174     dwErr = RegCreateKeyEx(hkRootKey, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkResult, &dwDisp);
02175 
02176   if(dwErr == ERROR_SUCCESS)
02177   {
02178     dwErr = RegSetValueEx(hkResult, szName, 0, REG_DWORD, (LPBYTE)&dwVal, dwValSize);
02179 
02180     RegCloseKey(hkResult);
02181   }
02182 }
02183 
02184 HRESULT DecryptVariable(LPSTR szVariable, DWORD dwVariableSize)
02185 {
02186   char szBuf[MAX_BUF];
02187   char szKey[MAX_BUF];
02188   char szName[MAX_BUF];
02189   char szValue[MAX_BUF];
02190 
02191   /* zero out the memory allocations */
02192   ZeroMemory(szBuf,       sizeof(szBuf));
02193   ZeroMemory(szKey,       sizeof(szKey));
02194   ZeroMemory(szName,      sizeof(szName));
02195   ZeroMemory(szValue,     sizeof(szValue));
02196 
02197   if(lstrcmpi(szVariable, "PROGRAMFILESDIR") == 0)
02198   {
02199     /* parse for the "c:\Program Files" directory */
02200     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", "ProgramFilesDir", szVariable, dwVariableSize);
02201   }
02202   else if(lstrcmpi(szVariable, "COMMONFILESDIR") == 0)
02203   {
02204     /* parse for the "c:\Program Files\Common Files" directory */
02205     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", "CommonFilesDir", szVariable, dwVariableSize);
02206   }
02207   else if(lstrcmpi(szVariable, "MEDIAPATH") == 0)
02208   {
02209     /* parse for the "c:\Winnt40\Media" directory */
02210     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", "MediaPath", szVariable, dwVariableSize);
02211   }
02212   else if(lstrcmpi(szVariable, "CONFIGPATH") == 0)
02213   {
02214     /* parse for the "c:\Windows\Config" directory */
02215     if(ulOSType & OS_WIN9x)
02216     {
02217       GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", "ConfigPath", szVariable, dwVariableSize);
02218     }
02219   }
02220   else if(lstrcmpi(szVariable, "DEVICEPATH") == 0)
02221   {
02222     /* parse for the "c:\Winnt40\INF" directory */
02223     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", "DevicePath", szVariable, dwVariableSize);
02224   }
02225   else if(lstrcmpi(szVariable, "COMMON_STARTUP") == 0)
02226   {
02227     /* parse for the "C:\WINNT40\Profiles\All Users\Start Menu\\Programs\\Startup" directory */
02228     if(ulOSType & OS_WIN9x)
02229     {
02230       GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Startup", szVariable, dwVariableSize);
02231     }
02232     else
02233     {
02234       GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Common Startup", szVariable, dwVariableSize);
02235     }
02236   }
02237   else if(lstrcmpi(szVariable, "COMMON_PROGRAMS") == 0)
02238   {
02239     /* parse for the "C:\WINNT40\Profiles\All Users\Start Menu\\Programs" directory */
02240     if(ulOSType & OS_WIN9x)
02241     {
02242       GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Programs", szVariable, dwVariableSize);
02243     }
02244     else
02245     {
02246       GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Common Programs", szVariable, dwVariableSize);
02247     }
02248   }
02249   else if(lstrcmpi(szVariable, "COMMON_STARTMENU") == 0)
02250   {
02251     /* parse for the "C:\WINNT40\Profiles\All Users\Start Menu" directory */
02252     if(ulOSType & OS_WIN9x)
02253     {
02254       GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Start Menu", szVariable, dwVariableSize);
02255     }
02256     else
02257     {
02258       GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Common Start Menu", szVariable, dwVariableSize);
02259     }
02260   }
02261   else if(lstrcmpi(szVariable, "COMMON_DESKTOP") == 0)
02262   {
02263     /* parse for the "C:\WINNT40\Profiles\All Users\Desktop" directory */
02264     if(ulOSType & OS_WIN9x)
02265     {
02266       GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Desktop", szVariable, dwVariableSize);
02267     }
02268     else
02269     {
02270       GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Common Desktop", szVariable, dwVariableSize);
02271     }
02272   }
02273   else if(lstrcmpi(szVariable, "PERSONAL_STARTUP") == 0)
02274   {
02275     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Start Menu\Programs\Startup" directory */
02276     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Startup", szVariable, dwVariableSize);
02277   }
02278   else if(lstrcmpi(szVariable, "PERSONAL_PROGRAMS") == 0)
02279   {
02280     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Start Menu\Programs" directory */
02281     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Programs", szVariable, dwVariableSize);
02282   }
02283   else if(lstrcmpi(szVariable, "PERSONAL_STARTMENU") == 0)
02284   {
02285     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Start Menu" directory */
02286     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Start Menu", szVariable, dwVariableSize);
02287   }
02288   else if(lstrcmpi(szVariable, "PERSONAL_DESKTOP") == 0)
02289   {
02290     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Desktop" directory */
02291     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Desktop", szVariable, dwVariableSize);
02292   }
02293   else if(lstrcmpi(szVariable, "PERSONAL_APPDATA") == 0)
02294   {
02295     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Application Data" directory */
02296     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "AppData", szVariable, dwVariableSize);
02297   }
02298   else if(lstrcmpi(szVariable, "PERSONAL_CACHE") == 0)
02299   {
02300     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Temporary Internet Files" directory */
02301     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Cache", szVariable, dwVariableSize);
02302   }
02303   else if(lstrcmpi(szVariable, "PERSONAL_COOKIES") == 0)
02304   {
02305     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Cookies" directory */
02306     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Cookies", szVariable, dwVariableSize);
02307   }
02308   else if(lstrcmpi(szVariable, "PERSONAL_FAVORITES") == 0)
02309   {
02310     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Favorites" directory */
02311     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Favorites", szVariable, dwVariableSize);
02312   }
02313   else if(lstrcmpi(szVariable, "PERSONAL_FONTS") == 0)
02314   {
02315     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Fonts" directory */
02316     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Fonts", szVariable, dwVariableSize);
02317   }
02318   else if(lstrcmpi(szVariable, "PERSONAL_HISTORY") == 0)
02319   {
02320     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\History" directory */
02321     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "History", szVariable, dwVariableSize);
02322   }
02323   else if(lstrcmpi(szVariable, "PERSONAL_NETHOOD") == 0)
02324   {
02325     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\NetHood" directory */
02326     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "NetHood", szVariable, dwVariableSize);
02327   }
02328   else if(lstrcmpi(szVariable, "PERSONAL_PERSONAL") == 0)
02329   {
02330     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Personal" directory */
02331     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Personal", szVariable, dwVariableSize);
02332   }
02333   else if(lstrcmpi(szVariable, "PERSONAL_PRINTHOOD") == 0)
02334   {
02335     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\PrintHood" directory */
02336     if(ulOSType & OS_NT)
02337     {
02338       GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "PrintHood", szVariable, dwVariableSize);
02339     }
02340   }
02341   else if(lstrcmpi(szVariable, "PERSONAL_RECENT") == 0)
02342   {
02343     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\Recent" directory */
02344     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Recent", szVariable, dwVariableSize);
02345   }
02346   else if(lstrcmpi(szVariable, "PERSONAL_SENDTO") == 0)
02347   {
02348     /* parse for the "C:\WINNT40\Profiles\%USERNAME%\SendTo" directory */
02349     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "SendTo", szVariable, dwVariableSize);
02350   }
02351   else if(lstrcmpi(szVariable, "PERSONAL_TEMPLATES") == 0)
02352   {
02353     /* parse for the "C:\WINNT40\ShellNew" directory */
02354     GetWinReg(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Templates", szVariable, dwVariableSize);
02355   }
02356   else if(lstrcmpi(szVariable, "WIZTEMP") == 0)
02357   {
02358     /* parse for the "c:\Temp" path */
02359     lstrcpy(szVariable, szTempDir);
02360     if(szVariable[strlen(szVariable) - 1] == '\\')
02361       szVariable[strlen(szVariable) - 1] = '\0';
02362   }
02363   else if(lstrcmpi(szVariable, "TEMP") == 0)
02364   {
02365     /* parse for the "c:\Temp" path */
02366     lstrcpy(szVariable, szOSTempDir);
02367     if(szVariable[strlen(szVariable) - 1] == '\\')
02368       szVariable[strlen(szVariable) - 1] = '\0';
02369   }
02370   else if(lstrcmpi(szVariable, "WINDISK") == 0)
02371   {
02372     /* Locate the drive that Windows is installed on, and only use the drive letter and the ':' character (C:). */
02373     if(GetWindowsDirectory(szBuf, MAX_BUF) == 0)
02374     {
02375       char szEGetWinDirFailed[MAX_BUF];
02376 
02377       if(GetPrivateProfileString("Messages", "ERROR_GET_WINDOWS_DIRECTORY_FAILED", "",
02378                                  szEGetWinDirFailed, sizeof(szEGetWinDirFailed), 
02379                                  szFileIniUninstall))
02380         PrintError(szEGetWinDirFailed, ERROR_CODE_SHOW);
02381 
02382       exit(1);
02383     }
02384     else
02385     {
02386       /* Copy the first 2 characters from the path..        */
02387       /* This is the drive letter and the ':' character for */
02388       /* where Windows is installed at.                     */
02389       memset(szVariable, '\0', MAX_BUF);
02390       szVariable[0] = szBuf[0];
02391       szVariable[1] = szBuf[1];
02392     }
02393   }
02394   else if(lstrcmpi(szVariable, "WINDIR") == 0)
02395   {
02396     /* Locate the "c:\Windows" directory */
02397     if(GetWindowsDirectory(szVariable, dwVariableSize) == 0)
02398     {
02399       char szEGetWinDirFailed[MAX_BUF];
02400 
02401       if(GetPrivateProfileString("Messages", "ERROR_GET_WINDOWS_DIRECTORY_FAILED", "",
02402                                  szEGetWinDirFailed, sizeof(szEGetWinDirFailed), 
02403                                  szFileIniUninstall))
02404         PrintError(szEGetWinDirFailed, ERROR_CODE_SHOW);
02405       exit(1);
02406     }
02407   }
02408   else if(lstrcmpi(szVariable, "WINSYSDIR") == 0)
02409   {
02410     /* Locate the "c:\Windows\System" (for Win95/Win98) or "c:\Windows\System32" (for NT) directory */
02411     if(GetSystemDirectory(szVariable, dwVariableSize) == 0)
02412     {
02413       char szEGetSysDirFailed[MAX_BUF];
02414 
02415       if(GetPrivateProfileString("Messages", "ERROR_GET_SYSTEM_DIRECTORY_FAILED", "",
02416                                  szEGetSysDirFailed, sizeof(szEGetSysDirFailed), 
02417                                  szFileIniUninstall))
02418         PrintError(szEGetSysDirFailed, ERROR_CODE_SHOW);
02419 
02420       exit(1);
02421     }
02422   }
02423   else if(lstrcmpi(szVariable, "JRE BIN PATH") == 0)
02424   {
02425     /* Locate the "c:\Program Files\JavaSoft\JRE\1.3\Bin" directory */
02426     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\javaw.Exe", NULL, szVariable, dwVariableSize);
02427     if(*szVariable == '\0')
02428       return(FALSE);
02429     else
02430     {
02431       ParsePath(szVariable, szBuf, MAX_BUF, PP_PATH_ONLY);
02432       lstrcpy(szVariable, szBuf);
02433     }
02434   }
02435   else if(lstrcmpi(szVariable, "JRE PATH") == 0)
02436   {
02437     /* Locate the "c:\Program Files\JavaSoft\JRE\1.3" directory */
02438     GetWinReg(HKEY_LOCAL_MACHINE, "Software\\JavaSoft\\Java Plug-in\\1.3", "JavaHome", szVariable, dwVariableSize);
02439     if(*szVariable == '\0')
02440       return(FALSE);
02441   }
02442   else if(lstrcmpi(szVariable, "UNINSTALL STARTUP PATH") == 0)
02443   {
02444     lstrcpy(szVariable, szUninstallDir);
02445   }
02446   else if(lstrcmpi(szVariable, "Product CurrentVersion") == 0)
02447   {
02448     char szKey[MAX_BUF];
02449 
02450     lstrcpy(szKey, "Software\\");
02451     lstrcat(szKey, ugUninstall.szCompanyName);
02452     lstrcat(szKey, "\\");
02453     lstrcat(szKey, ugUninstall.szProductName);
02454 
02455     /* parse for the current Netscape WinReg key */
02456     GetWinReg(HKEY_LOCAL_MACHINE, szKey, "CurrentVersion", szBuf, sizeof(szBuf));
02457 
02458     if(*szBuf == '\0')
02459       return(FALSE);
02460 
02461     wsprintf(szVariable, "Software\\%s\\%s\\%s", ugUninstall.szCompanyName, ugUninstall.szProductName, szBuf);
02462   }
02463   else if(lstrcmpi(szVariable, "Product WinRegKey") == 0)
02464   {
02465     char szKey[MAX_BUF];
02466 
02467     lstrcpy(szKey, "Software\\");
02468     lstrcat(szKey, ugUninstall.szCompanyName);
02469     lstrcat(szKey, "\\");
02470     lstrcat(szKey, ugUninstall.szProductName);
02471 
02472     wsprintf(szVariable, "Software\\%s\\%s", ugUninstall.szCompanyName, ugUninstall.szProductName);
02473   }
02474   else
02475     return(FALSE);
02476 
02477   return(TRUE);
02478 }
02479 
02480 HRESULT DecryptString(LPSTR szOutputStr, LPSTR szInputStr)
02481 {
02482   DWORD dwLenInputStr;
02483   DWORD dwCounter;
02484   DWORD dwVar;
02485   DWORD dwPrepend;
02486   char  szBuf[MAX_BUF];
02487   char  szVariable[MAX_BUF];
02488   char  szPrepend[MAX_BUF];
02489   char  szAppend[MAX_BUF];
02490   char  szResultStr[MAX_BUF];
02491   BOOL  bFoundVar;
02492   BOOL  bBeginParse;
02493   BOOL  bDecrypted;
02494 
02495   /* zero out the memory addresses */
02496   memset(szBuf,       '\0', MAX_BUF);
02497   memset(szVariable,  '\0', MAX_BUF);
02498   memset(szPrepend,   '\0', MAX_BUF);
02499   memset(szAppend,    '\0', MAX_BUF);
02500   memset(szResultStr, '\0', MAX_BUF);
02501 
02502   lstrcpy(szPrepend, szInputStr);
02503   dwLenInputStr = lstrlen(szInputStr);
02504   bBeginParse   = FALSE;
02505   bFoundVar     = FALSE;
02506 
02507   for(dwCounter = 0; dwCounter < dwLenInputStr; dwCounter++)
02508   {
02509     if((szInputStr[dwCounter] == ']') && bBeginParse)
02510       break;
02511 
02512     if(bBeginParse)
02513       szVariable[dwVar++] = szInputStr[dwCounter];
02514 
02515     if((szInputStr[dwCounter] == '[') && !bBeginParse)
02516     {
02517       dwVar        = 0;
02518       dwPrepend    = dwCounter;
02519       bBeginParse  = TRUE;
02520     }
02521   }
02522 
02523   if(dwCounter == dwLenInputStr)
02524     /* did not find anything to expand. */
02525     dwCounter = 0;
02526   else
02527   {
02528     bFoundVar = TRUE;
02529     ++dwCounter;
02530   }
02531 
02532   if(bFoundVar)
02533   {
02534     lstrcpy(szAppend, &szInputStr[dwCounter]);
02535 
02536     szPrepend[dwPrepend] = '\0';
02537 
02538     bDecrypted = DecryptVariable(szVariable, MAX_BUF);
02539     if(!bDecrypted)
02540     {
02541       /* Variable was not able to be decrypted. */
02542       /* Leave the variable as it was read in by adding the '[' and ']' */
02543       /* characters back to the variable. */
02544       lstrcpy(szBuf, "[");
02545       lstrcat(szBuf, szVariable);
02546       lstrcat(szBuf, "]");
02547       lstrcpy(szVariable, szBuf);
02548     }
02549 
02550     lstrcpy(szOutputStr, szPrepend);
02551     lstrcat(szOutputStr, szVariable);
02552     lstrcat(szOutputStr, szAppend);
02553 
02554     if(bDecrypted)
02555     {
02556       DecryptString(szResultStr, szOutputStr);
02557       lstrcpy(szOutputStr, szResultStr);
02558     }
02559   }
02560   else
02561     lstrcpy(szOutputStr, szInputStr);
02562 
02563   return(TRUE);
02564 }
02565 
02566 HRESULT FileExists(LPSTR szFile)
02567 {
02568   DWORD rv;
02569 
02570   if((rv = GetFileAttributes(szFile)) == -1)
02571   {
02572     return(FALSE);
02573   }
02574   else
02575   {
02576     return(rv);
02577   }
02578 }
02579 
02580 BOOL MakeUniquePath(LPSTR szPath)
02581 {
02582   int i, dwLen;
02583 
02584   dwLen = lstrlen(szPath);
02585   for(i = 1; i <= 999 && (FileExists(szPath) != FALSE); i++)
02586   {
02587     itoa(i, (szPath + dwLen), 10);
02588   }
02589   return !FileExists(szPath);
02590 }
02591 
02592 BOOL WinRegNameExists(HKEY hkRootKey, LPSTR szKey, LPSTR szName)
02593 {
02594   HKEY  hkResult;
02595   DWORD dwErr;
02596   DWORD dwSize;
02597   char  szBuf[MAX_BUF];
02598   BOOL  bNameExists = FALSE;
02599 
02600   szBuf[0] = '\0';
02601   if((dwErr = RegOpenKeyEx(hkRootKey, szKey, 0, KEY_READ, &hkResult)) == ERROR_SUCCESS)
02602   {
02603     dwSize = sizeof(szBuf);
02604     dwErr  = RegQueryValueEx(hkResult, szName, 0, NULL, szBuf, &dwSize);
02605 
02606     if((*szBuf != '\0') && (dwErr == ERROR_SUCCESS))
02607       bNameExists = TRUE;
02608 
02609     RegCloseKey(hkResult);
02610   }
02611 
02612   return(bNameExists);
02613 }
02614 
02615 void DeleteWinRegValue(HKEY hkRootKey, LPSTR szKey, LPSTR szName)
02616 {
02617   HKEY    hkResult;
02618   DWORD   dwErr;
02619 
02620   dwErr = RegOpenKeyEx(hkRootKey, szKey, 0, KEY_WRITE, &hkResult);
02621   if(dwErr == ERROR_SUCCESS)
02622   {
02623     if(*szName == '\0')
02624       dwErr = RegDeleteValue(hkResult, NULL);
02625     else
02626       dwErr = RegDeleteValue(hkResult, szName);
02627 
02628     RegCloseKey(hkResult);
02629   }
02630 }
02631 
02632 void DeInitialize()
02633 {
02634   DeInitDlgUninstall(&diUninstall);
02635 
02636   FreeMemory(&szTempDir);
02637   FreeMemory(&szOSTempDir);
02638   FreeMemory(&szUninstallDir);
02639   FreeMemory(&szEGlobalAlloc);
02640   FreeMemory(&szEDllLoad);
02641   FreeMemory(&szEStringLoad);
02642   FreeMemory(&szEStringNull);
02643   FreeMemory(&szFileIniUninstall);
02644   FreeMemory(&szFileIniDefaultsInfo);
02645 }
02646