Back to index

lightning-sunbird  0.9+nobinonly
uninstall.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  *   Darin Fisher <darin@meer.net>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "uninstall.h"
00042 #include "extra.h"
00043 #include "dialogs.h"
00044 #include "ifuncns.h"
00045 #include "parser.h"
00046 
00047 /* global variables */
00048 HINSTANCE       hInst;
00049 
00050 HANDLE          hAccelTable;
00051 
00052 HWND            hDlgUninstall;
00053 HWND            hDlgMessage;
00054 HWND            hWndMain;
00055 
00056 LPSTR           szEGlobalAlloc;
00057 LPSTR           szEStringLoad;
00058 LPSTR           szEDllLoad;
00059 LPSTR           szEStringNull;
00060 
00061 LPSTR           szClassName;
00062 LPSTR           szUninstallDir;
00063 LPSTR           szTempDir;
00064 LPSTR           szOSTempDir;
00065 LPSTR           szFileIniUninstall;
00066 LPSTR           szFileIniDefaultsInfo;
00067 LPSTR           gszSharedFilename;
00068 
00069 ULONG           ulOSType;
00070 DWORD           dwScreenX;
00071 DWORD           dwScreenY;
00072 
00073 DWORD           gdwWhatToDo;
00074 
00075 BOOL            gbAllowMultipleInstalls = FALSE;
00076 
00077 uninstallGen    ugUninstall;
00078 diU             diUninstall;
00079 
00080 DWORD           dwParentPID = 0;
00081 
00082 BOOL            gbUninstallCompleted = FALSE;
00083 
00084 /* Copy a file into a directory.  Write the path to the new file
00085  * into the result buffer (MAX_PATH in size). */
00086 static BOOL CopyTo(LPCSTR file, LPCSTR destDir, LPSTR result)
00087 {
00088   char leaf[MAX_BUF_TINY];
00089 
00090   ParsePath(file, leaf, sizeof(leaf), PP_FILENAME_ONLY);
00091   lstrcpy(result, destDir);
00092   lstrcat(result, "\\");
00093   lstrcat(result, leaf);
00094 
00095   return CopyFile(file, result, TRUE);
00096 }
00097 
00098 /* Spawn child process. */
00099 static BOOL SpawnProcess(LPCSTR exePath, LPCSTR cmdLine)
00100 {
00101   STARTUPINFO si = {sizeof(si), 0};
00102   PROCESS_INFORMATION pi = {0};
00103 
00104   BOOL ok = CreateProcess(exePath,
00105                           cmdLine,
00106                           NULL,  // no special security attributes
00107                           NULL,  // no special thread attributes
00108                           FALSE, // don't inherit filehandles
00109                           0,     // No special process creation flags
00110                           NULL,  // inherit my environment
00111                           NULL,  // use my current directory
00112                           &si,
00113                           &pi);
00114 
00115   if (ok) {
00116     CloseHandle(pi.hProcess);
00117     CloseHandle(pi.hThread);
00118   }
00119 
00120   return ok;
00121 }
00122 
00123 /* This function is called to ensure that the running executable is a copy of
00124  * the actual uninstaller.  If not, then this function copies the uninstaller
00125  * into a temporary directory and invokes the copy of itself.  This is done to
00126  * enable the uninstaller to remove itself. */
00127 static BOOL EnsureRunningAsCopy(LPCSTR cmdLine)
00128 {
00129   char uninstExe[MAX_PATH], uninstIni[MAX_PATH];
00130   char tempBuf[MAX_PATH], tempDir[MAX_PATH] = ""; 
00131   DWORD n;
00132 
00133   if (dwParentPID != 0)
00134   {
00135     HANDLE hParent;
00136     
00137     /* OpenProcess may return NULL if the parent process has already gone away.
00138      * If not, then wait for the parent process to exit.  NOTE: The process may
00139      * be signaled before it releases the executable image, so we sit in a loop
00140      * until OpenProcess returns NULL. */
00141     while ((hParent = OpenProcess(SYNCHRONIZE, FALSE, dwParentPID)) != NULL)
00142     {
00143       DWORD rv = WaitForSingleObject(hParent, 5000);
00144       CloseHandle(hParent);
00145       if (rv != WAIT_OBJECT_0)
00146         return FALSE;
00147       Sleep(50);  /* prevent burning CPU while waiting */
00148     }
00149 
00150     return TRUE;
00151   }
00152 
00153   /* otherwise, copy ourselves to a temp location and execute the copy. */
00154 
00155   /* make unique folder under the Temp folder */
00156   n = GetTempPath(sizeof(tempDir)-1, tempDir);
00157   if (n == 0 || n > sizeof(tempDir)-1)
00158     return FALSE;
00159   lstrcat(tempDir, "nstmp");
00160   if (!MakeUniquePath(tempDir) || !CreateDirectory(tempDir, NULL))
00161     return FALSE;
00162 
00163   if (!GetModuleFileName(hInst, tempBuf, sizeof(tempBuf)))
00164     return FALSE;
00165 
00166   /* copy exe file into temp folder */
00167   if (!CopyTo(tempBuf, tempDir, uninstExe))
00168   {
00169     RemoveDirectory(tempDir);
00170     return FALSE;
00171   }
00172 
00173   /* copy ini file into temp folder */
00174   ParsePath(tempBuf, uninstIni, sizeof(uninstIni), PP_PATH_ONLY); 
00175   lstrcat(uninstIni, FILE_INI_UNINSTALL);
00176 
00177   if (!CopyTo(uninstIni, tempDir, tempBuf))
00178   {
00179     DeleteFile(uninstExe);
00180     RemoveDirectory(tempDir);
00181     return FALSE;
00182   }
00183 
00184   /* schedule temp dir and contents to be deleted on reboot */
00185   DeleteOnReboot(uninstExe);
00186   DeleteOnReboot(tempBuf);
00187   DeleteOnReboot(tempDir);
00188 
00189   /* append -ppid command line flag  */
00190   _snprintf(tempBuf, sizeof(tempBuf), "\"%s\" %s /ppid %lu",
00191             uninstExe, cmdLine, GetCurrentProcessId());
00192 
00193   /* call CreateProcess */
00194   SpawnProcess(uninstExe, tempBuf);
00195 
00196   return FALSE;  /* exit this process */
00197 }
00198 
00199 /* Uninstall completed; show some UI... */
00200 static void OnUninstallComplete()
00201 {
00202   char exePath[MAX_PATH], buf[MAX_PATH];
00203 
00204   if (!(ugUninstall.szProductName && ugUninstall.szProductName[0]) ||
00205       !(ugUninstall.szUserAgent && ugUninstall.szUserAgent[0]))
00206     return;
00207 
00208   if (DialogBox(hInst, MAKEINTRESOURCE(DLG_MESSAGE_CHK), NULL,
00209       DlgProcComplete) != ID_YES_TO_ALL)
00210     return;
00211 
00212   /* find iexplore.exe.  we cannot use ShellExecute because the protocol
00213    * association (in HKEY_CLASSES_ROOT) may reference the app we just
00214    * uninstalled, which is a bug in and of itself. */
00215   GetWinReg(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\IE Setup\\Setup", "Path",
00216             exePath, sizeof(exePath));
00217   if (!exePath[0])
00218     return;
00219   lstrcat(exePath, "\\iexplore.exe");
00220 
00221   /* launch IE, and point it at the survey URL (whitespace in the product name
00222    * or user agent is okay) */
00223   _snprintf(buf, sizeof(buf),
00224             "\"%s\" \"https://survey.mozilla.com/1/%s/%s/exit.html\"", exePath,
00225             ugUninstall.szProductName, ugUninstall.szUserAgent);
00226   SpawnProcess(exePath, buf);
00227 }
00228 
00229 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
00230 {
00231   /***********************************************************************/
00232   /* HANDLE hInstance;       handle for this instance                    */
00233   /* HANDLE hPrevInstance;   handle for possible previous instances      */
00234   /* LPSTR  lpszCmdLine;     long pointer to exec command line           */
00235   /* int    nCmdShow;        Show code for main window display           */
00236   /***********************************************************************/
00237 
00238   MSG   msg;
00239   char  szBuf[MAX_BUF];
00240   int   iRv = WIZ_OK;
00241   HWND  hwndFW;
00242 
00243   if(!hPrevInstance)
00244   {
00245     hInst = GetModuleHandle(NULL);
00246     if(InitUninstallGeneral() || ParseCommandLine(lpszCmdLine))
00247     {
00248       PostQuitMessage(1);
00249     }
00250     else if((hwndFW = FindWindow(CLASS_NAME_UNINSTALL_DLG, NULL)) != NULL && !gbAllowMultipleInstalls)
00251     {
00252     /* Allow only one instance of setup to run.
00253      * Detect a previous instance of setup, bring it to the 
00254      * foreground, and quit current instance */
00255 
00256       ShowWindow(hwndFW, SW_RESTORE);
00257       SetForegroundWindow(hwndFW);
00258       iRv = WIZ_SETUP_ALREADY_RUNNING;
00259       PostQuitMessage(1);
00260     }
00261     else if(!EnsureRunningAsCopy(lpszCmdLine) || Initialize(hInst))
00262     {
00263       PostQuitMessage(1);
00264     }
00265     else if(!InitApplication(hInst))
00266     {
00267       char szEFailed[MAX_BUF];
00268 
00269       if(NS_LoadString(hInst, IDS_ERROR_FAILED, szEFailed, MAX_BUF) == WIZ_OK)
00270       {
00271         wsprintf(szBuf, szEFailed, "InitApplication().");
00272         PrintError(szBuf, ERROR_CODE_SHOW);
00273       }
00274       PostQuitMessage(1);
00275     }
00276     else if(ParseUninstallIni())
00277     {
00278       PostQuitMessage(1);
00279     }
00280     else if(ugUninstall.bUninstallFiles == TRUE)
00281     {
00282       if(diUninstall.bShowDialog == TRUE)
00283         hDlgUninstall = InstantiateDialog(hWndMain, DLG_UNINSTALL, diUninstall.szTitle, DlgProcUninstall);
00284       // Assumes that SHOWICONS, HIDEICONS, and SETDEFAULT never show dialogs
00285       else if((ugUninstall.mode == SHOWICONS) || (ugUninstall.mode == HIDEICONS))
00286         ParseDefaultsInfo();
00287       else if(ugUninstall.mode == SETDEFAULT)
00288         SetDefault();
00289       else
00290         ParseAllUninstallLogs();
00291     }
00292   }
00293 
00294   if((ugUninstall.bUninstallFiles == TRUE) && (diUninstall.bShowDialog == TRUE))
00295   {
00296     while(GetMessage(&msg, NULL, 0, 0))
00297     {
00298       if((!IsDialogMessage(hDlgUninstall, &msg)) && (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)))
00299       {
00300         TranslateMessage(&msg);
00301         DispatchMessage(&msg);
00302       }
00303     }
00304   }
00305 
00306   if(diUninstall.bShowDialog == TRUE && gbUninstallCompleted)
00307   {
00308     OnUninstallComplete();
00309   }
00310 
00311   /* garbage collection */
00312   DeInitUninstallGeneral();
00313   if(iRv != WIZ_SETUP_ALREADY_RUNNING)
00314     /* Do clean up before exiting from the application */
00315     DeInitialize();
00316 
00317   return(msg.wParam);
00318 } /*  End of WinMain */