small cosmetic improvements
[swftools.git] / installer / installer.c
index 78f4fc3..d22efd5 100644 (file)
@@ -1,8 +1,8 @@
 /* installer.c
 
-   Part of the swftools installer (Main program).
+   Part of the rfx installer (Main program).
    
-   Copyright (c) 2004 Matthias Kramm <kramm@quiss.org> 
+   Copyright (c) 2004-2008 Matthias Kramm <kramm@quiss.org> 
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -31,8 +31,6 @@
 #endif
 #include "utils.h"
 
-#include "../config.h" //for swftools version
-
 static int config_forAllUsers = 0;
 static int config_createLinks = 0;
 static int config_createStartmenu = 1;
@@ -46,10 +44,13 @@ static char path_programfiles[MAX_PATH] = "\0";
 static char pathBuf[MAX_PATH];
 static int do_abort = 0;
 
+static char* pdf2swf_dir;
 static char* pdf2swf_path;
 
 static char registry_path[1024];
 
+static char elevated = 0;
+
 static char*install_path = "c:\\swftools\\";
 #define SOFTWARE_DOMAIN "quiss.org"
 #define SOFTWARE_NAME "SWFTools"
@@ -95,7 +96,7 @@ static filelist_t* readFileList(char*filename)
     fseek(fi, 0, SEEK_END);
     int len = ftell(fi);
     fseek(fi, 0, SEEK_SET);
-    char*data = malloc(len);
+    char*data = malloc(len+1);
     fread(data, len, 1, fi);
     fclose(fi);
     int t=0;
@@ -164,7 +165,7 @@ static void handleTemplateFile(const char*filename)
     fseek(fi, 0, SEEK_END);
     int len = ftell(fi);
     fseek(fi, 0, SEEK_SET);
-    char*file = malloc(len);
+    char*file = malloc(len+1);
     fread(file, len, 1, fi);
     fclose(fi);
     int l = strlen(install_path);
@@ -256,6 +257,21 @@ static char* getRegistryEntry(char*path)
     }
 }
 
+static int has_full_access = 0;
+static char hasFullAccess()
+{
+    /* find out whether we can write keys in HKEY_LOCAL_MACHINE */
+    HKEY hKey;
+    int ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0,
+                           KEY_CREATE_SUB_KEY, &hKey);
+    if(!ret) {
+        RegCloseKey(hKey);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
 void processMessages()
 {
     MSG msg;
@@ -362,7 +378,6 @@ BOOL CALLBACK PropertySheetFunc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM
     if(message == WM_INITDIALOG) {
        SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
 
-        config_forAllUsers = 0;
         SendDlgItemMessage(hwnd, IDC_ALLUSERS, BM_SETCHECK, config_forAllUsers, 0);
         SendDlgItemMessage(hwnd, IDC_CURRENTUSER, BM_SETCHECK, config_forAllUsers^1, 0);
     }
@@ -410,6 +425,23 @@ BOOL CALLBACK PropertySheetFunc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM
            return 0;
        }
     }
+    if(message == WM_NOTIFY && (((LPNMHDR)lParam)->code == PSN_SETACTIVE)) {
+        if(!elevated && !has_full_access) {
+            OSVERSIONINFO winverinfo;
+            memset(&winverinfo, 0, sizeof(OSVERSIONINFO));
+            winverinfo.dwOSVersionInfoSize = sizeof(winverinfo);
+            if (GetVersionEx(&winverinfo) && winverinfo.dwMajorVersion >= 5) {
+                /* we're on Vista, were asked to install for all users, but don't have
+                   priviledges to do so. Ask to spawn the process elevated. */
+                char exename[MAX_PATH];
+                GetModuleFileName(NULL, exename, sizeof(exename));
+                if((int)ShellExecute(0, "runas", exename, "elevated", NULL, SW_SHOWNORMAL)>32) {
+                    /* that worked- the second process will do the work */
+                    exit(0);
+                }
+            }
+        }
+    }
     return PropertySheetFuncCommon(hwnd, message, wParam, lParam, PSWIZB_BACK|PSWIZB_NEXT);
 }
 HWND statuswnd;
@@ -485,7 +517,8 @@ BOOL CALLBACK PropertySheetFunc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM
            print_space(buf, "Space available: ", available.QuadPart);
        } else {
            sprintf(buf, "Space available: [Error %d]", GetLastError());
-           if(GetLastError() == ERROR_FILE_NOT_FOUND && install_path[0] && install_path[1]==':') {
+           if((GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
+                && install_path[0] && install_path[1]==':') {
                /* installation directory does not yet exist */
                char path[3]={'c',':',0};
                path[0] = install_path[0];
@@ -501,7 +534,7 @@ BOOL CALLBACK PropertySheetFunc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM
        SetDlgItemText(hwnd, IDC_SPACE2, "");
        PropSheet_SetWizButtons(dialog, 0);
        SendMessage(dialog, PSM_CANCELTOCLOSE, 0, 0); //makes wine display a warning
-       SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
+       SetDlgItemText(hwnd, IDC_TITLE, "Installing...");
        statuswnd = hwnd;
        status_t status;
        status.status = PropertyArchiveStatus;
@@ -525,16 +558,21 @@ static HRESULT (WINAPI *f_SHGetSpecialFolderPath)(HWND hwnd, LPTSTR lpszPath, in
 
 BOOL CALLBACK PropertySheetFunc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
     if(message == WM_INITDIALOG) {
-       pdf2swf_path = concatPaths(install_path, "pdf2swf_gui.exe");
+       pdf2swf_dir = install_path; //concatPaths(install_path, "gpdf2swf");
+       pdf2swf_path = concatPaths(pdf2swf_dir, "gpdf2swf.exe");
        FILE*fi = fopen(pdf2swf_path, "rb");
        if(fi) {
            printf("a GUI program exists, creating desktop/startmenu links\n");
            config_createLinks = 1;
            fclose(fi);
+       } else {
+           config_createLinks = 0;
+           config_createStartmenu = 0;
+           config_createDesktop = 0;
        }
        if(!config_createLinks) {
-           SendDlgItemMessage(hwnd, IDC_STARTMENU, SW_HIDE, 0, 0);
-           SendDlgItemMessage(hwnd, IDC_DESKTOP, SW_HIDE, 0, 0);
+           SendDlgItemMessage(hwnd, IDC_STARTMENU, BN_DISABLE, 0, 0);
+           SendDlgItemMessage(hwnd, IDC_DESKTOP, BN_DISABLE, 0, 0);
        }
 
        SendDlgItemMessage(hwnd, IDC_STARTMENU, BM_SETCHECK, config_createStartmenu, 0);
@@ -543,13 +581,17 @@ BOOL CALLBACK PropertySheetFunc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM
     if(message == WM_COMMAND) {
        if((wParam&0xffff) == IDC_STARTMENU) {
            config_createStartmenu = SendDlgItemMessage(hwnd, IDC_STARTMENU, BM_GETCHECK, 0, 0);
-           config_createStartmenu^=1;
+           if(config_createLinks) {
+               config_createStartmenu^=1;
+           }
            SendDlgItemMessage(hwnd, IDC_STARTMENU, BM_SETCHECK, config_createStartmenu, 0);
            return 0;
        }
        if((wParam&0xffff) == IDC_DESKTOP) {
            config_createDesktop = SendDlgItemMessage(hwnd, IDC_DESKTOP, BM_GETCHECK, 0, 0);
-           config_createDesktop^=1;
+           if(config_createLinks) {
+               config_createDesktop^=1;
+           }
            SendDlgItemMessage(hwnd, IDC_DESKTOP, BM_SETCHECK, config_createDesktop, 0);
            return 0;
        }
@@ -583,7 +625,7 @@ BOOL CALLBACK PropertySheetFunc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM
            if(config_createDesktop && path_desktop[0]) {
                char* linkName = concatPaths(path_desktop, "pdf2swf.lnk");
                 printf("Creating desktop link %s -> %s\n", linkName, pdf2swf_path);
-               if(!CreateShortcut(pdf2swf_path, "pdf2swf", linkName, 0, 0, 0, install_path)) {
+               if(!CreateShortcut(pdf2swf_path, "pdf2swf", linkName, 0, 0, 0, pdf2swf_dir)) {
                    MessageBox(0, "Couldn't create desktop shortcut", INSTALLER_NAME, MB_OK);
                    return 1;
                }
@@ -591,8 +633,9 @@ BOOL CALLBACK PropertySheetFunc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM
            if(config_createStartmenu && path_startmenu[0]) {
                char* group = concatPaths(path_startmenu, "pdf2swf");
                CreateDirectory(group, 0);
+                addDir(group);
                char* linkName = concatPaths(group, "pdf2swf.lnk");
-               if(!CreateShortcut(pdf2swf_path, "pdf2swf", concatPaths(group, "pdf2swf.lnk"), 0, 0, 0, install_path) ||
+               if(!CreateShortcut(pdf2swf_path, "pdf2swf", concatPaths(group, "pdf2swf.lnk"), 0, 0, 0, pdf2swf_dir) ||
                   !CreateShortcut(uninstall_path, "uninstall", concatPaths(group, "uninstall.lnk"), 0, 0, 0, install_path)) {
                    MessageBox(0, "Couldn't create start menu entry", INSTALLER_NAME, MB_OK);
                    return 1;
@@ -612,10 +655,59 @@ BOOL CALLBACK PropertySheetFunc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM
 
 #ifdef DEINSTALL
 
+void findfiles(char*path, int*pos, char*data, int len, char del)
+{
+    WIN32_FIND_DATA findFileData;
+    HANDLE hFind = FindFirstFile(concatPaths(path, "*"), &findFileData);
+    if(hFind == INVALID_HANDLE_VALUE)
+       return;
+    do {
+       if(findFileData.cFileName[0] == '.' &&
+          (findFileData.cFileName[0] == '.' || findFileData.cFileName == '\0'))
+           continue;
+       char*f = concatPaths(path, findFileData.cFileName);
+       if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+           findfiles(f, pos, data, len, del);
+            /* always try to remove directories- if they are empty, this
+               will work, and they won't prevent superdirectory deletion later */
+            RemoveDirectory(f);
+       } else {
+           int l = strlen(f);
+
+           /* don't list the uninstaller as file- it's going to be removed *after*
+              everything else is done */
+           char*uninstaller="uninstall.exe";
+           int ll = strlen(uninstaller);
+           if(l>=ll) {
+               if(!strcasecmp(&f[l-ll],uninstaller)) {
+                   continue;
+               }
+           }
+
+           if(data) {
+               if(*pos+l <= len) {
+                   memcpy(&data[*pos], f, l);(*pos)+=l;
+                   data[(*pos)++] = '\r';
+                   data[(*pos)++] = '\n';
+                   data[(*pos)] = 0;
+               }
+           } else {
+               (*pos) += l+2;
+           }
+           if(del) {
+               DeleteFile(f);
+           }
+       }
+    } while(FindNextFile(hFind, &findFileData));
+    FindClose(hFind);
+}
+
+static char*extrafiles = 0;
+
 BOOL CALLBACK PropertySheetFunc5(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
     HWND dialog = GetParent(hwnd);
     if(message == WM_INITDIALOG) {
-       SetDlgItemText(hwnd, IDC_INFO, "Ready to deinstall");
+       SetDlgItemText(hwnd, IDC_INFO, "Ready to uninstall");
     }
     if(message == WM_NOTIFY && (((LPNMHDR)lParam)->code == PSN_WIZNEXT)) {
 
@@ -623,8 +715,10 @@ BOOL CALLBACK PropertySheetFunc5(HWND hwnd, UINT message, WPARAM wParam, LPARAM
        if(!list) {
            list = readFileList(concatPaths(install_path, "uninstall.ini"));
            if(!list) {
-               MessageBox(0, "Couldn't determine installed files list- did you run uninstall twice?", INSTALLER_NAME, MB_OK);
-               exit(-1);
+               //Don't abort. If there's still something there, it'll be catched by the "extra files"
+               //functionality later
+               //MessageBox(0, "Couldn't determine installed files list- did you run uninstall twice?", INSTALLER_NAME, MB_OK);
+               //exit(-1);
            }
        }
        filelist_t* l = list;
@@ -648,58 +742,26 @@ BOOL CALLBACK PropertySheetFunc5(HWND hwnd, UINT message, WPARAM wParam, LPARAM
            num++;l = l->next;
        }
 
+       int len = 0;
+       findfiles(install_path, &len, 0, 0, 0);
+       if(len) {
+           extrafiles = malloc(len);
+           int pos = 0;
+           findfiles(install_path, &pos, extrafiles, len, 0);
+       } else {
+           PropSheet_RemovePage(dialog, 1, 0);
+       }
        return 0;
     }
     return PropertySheetFuncCommon(hwnd, message, wParam, lParam, PSWIZB_BACK|PSWIZB_NEXT);
 }
 
-void findfiles(char*path, int*pos, char*data, int len, char del)
-{
-    WIN32_FIND_DATA findFileData;
-    HANDLE hFind = FindFirstFile(concatPaths(path, "*"), &findFileData);
-    if(hFind == INVALID_HANDLE_VALUE)
-       return;
-    do {
-       if(findFileData.cFileName[0] == '.' &&
-          (findFileData.cFileName[0] == '.' || findFileData.cFileName == '\0'))
-           continue;
-       char*f = concatPaths(path, findFileData.cFileName);
-       if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-           findfiles(f, pos, data, len, del);
-           if(del) {
-               RemoveDirectory(f);
-           }
-       } else {
-           int l = strlen(f);
-           if(data) {
-               if(*pos+l <= len) {
-                   memcpy(&data[*pos], f, l);(*pos)+=l;
-                   data[(*pos)++] = '\r';
-                   data[(*pos)++] = '\n';
-               }
-           } else {
-               (*pos) += l+2;
-           }
-           if(del) {
-               DeleteFile(f);
-           }
-       }
-    } while(FindNextFile(hFind, &findFileData));
-    FindClose(hFind);
-}
-
 BOOL CALLBACK PropertySheetFunc6(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
     if(message == WM_INITDIALOG) {
        SendDlgItemMessage(hwnd, IDC_DELETEEXTRA, BM_SETCHECK, config_deleteextra, 0);
-
-       int len = 0;
-
-       findfiles(install_path, &len, 0, 0, 0);
-       char*data = malloc(len);
-       int pos = 0;
-       findfiles(install_path, &pos, data, len, 0);
-
-       SetDlgItemText(hwnd, IDC_FILELIST, data);
+       if(extrafiles) {
+           SetDlgItemText(hwnd, IDC_FILELIST, extrafiles);
+       }
     }
     if(message == WM_COMMAND) {
        if((wParam&0xffff) == IDC_DELETEEXTRA) {
@@ -751,7 +813,22 @@ void runPropertySheet(HWND parent)
        {PropertySheetFunc7, IDD_DEINSTALLED},
 #endif
     };
+
     int num = sizeof(wpage)/sizeof(wpage[0]);
+
+#ifndef DEINSTALL
+    if(elevated) {
+        /* remove license.
+           TODO: remove installdir querying, too (pass installdir
+                 to second process) */
+        int t;
+        for(t=1;t<num;t++) {
+            wpage[t-1] = wpage[t];
+        }
+        num --;
+    }
+#endif
+
     HPROPSHEETPAGE pages[num];
     int t;
     for(t=0;t<num;t++) {
@@ -780,15 +857,28 @@ void runPropertySheet(HWND parent)
 static void remove_self()
 {
     char exename[MAX_PATH];
-    char batname[MAX_PATH];
+    char batdir[MAX_PATH];
+    char batfile[MAX_PATH];
+    char*batname;
     FILE *fp;
 
+    memset(batdir, 0, sizeof(batdir));
+
     GetModuleFileName(NULL, exename, sizeof(exename));
-    sprintf(batname, "%s.bat", exename);
+    GetTempPath(MAX_PATH, batdir);
+    sprintf(batfile, "%08x.bat", rand());
+
+    batname = concatPaths(batdir, batfile);
+
     fp = fopen(batname, "w");
+    if(!fp) {
+        return;
+    } 
+
     fprintf(fp, ":Repeat\n");
     fprintf(fp, "del \"%s\"\n", exename);
     fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
+    fprintf(fp, "rmdir \"%s\"\n", install_path);
     fprintf(fp, "del \"%s\"\n", batname);
     fclose(fp);
 
@@ -821,7 +911,7 @@ int WINAPI WinMain(HINSTANCE _me,HINSTANCE hPrevInst,LPSTR lpszArgs, int nWinMod
 
     install_path = getRegistryEntry(registry_path);
     if(!install_path || !install_path[0]) {
-       MessageBox(0, "Couldn't find software installation directory- did you run the deinstallation twice?", INSTALLER_NAME, MB_OK);
+       MessageBox(0, "Couldn't find software installation directory- did you run the uninstallation twice?", INSTALLER_NAME, MB_OK);
        return 1;
     }
 
@@ -853,6 +943,12 @@ int WINAPI WinMain(HINSTANCE _me,HINSTANCE hPrevInst,LPSTR lpszArgs, int nWinMod
 
     sprintf(registry_path, "Software\\%s\\%s\\InstallPath", SOFTWARE_DOMAIN, SOFTWARE_NAME);
 
+    if(lpszArgs && strstr(lpszArgs, "elevated")) {
+        elevated = 1;
+    }
+    has_full_access = hasFullAccess();
+    config_forAllUsers = has_full_access;
+
     HINSTANCE shell32 = LoadLibrary("shell32.dll");
     if(!shell32) {
        MessageBox(0, "Could not load shell32.dll", INSTALLER_NAME, MB_OK);