tWin32 installer handling of directories and errors now much improved - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit b303528750c77ad6dad59ead543ac18f856e52eb
 (DIR) parent b3875bd825494c795438861554e458bd7976bb45
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Mon,  1 Oct 2001 17:53:35 +0000
       
       Win32 installer handling of directories and errors now much improved
       
       
       Diffstat:
         M win32/contid.h                      |       2 +-
         M win32/dialogs.rc                    |       6 +++---
         M win32/setup.c                       |     106 ++++++++++++++++++++-----------
         M win32/uninstall.c                   |      48 +++++++++++++++++++++++++------
         M win32/util.c                        |      89 ++++++++++++++++++++++++++-----
         M win32/util.h                        |       3 +++
       
       6 files changed, 192 insertions(+), 62 deletions(-)
       ---
 (DIR) diff --git a/win32/contid.h b/win32/contid.h
       t@@ -10,7 +10,7 @@
        #define ED_FOLDER   210
        #define LB_FOLDLIST 211
        #define CB_DESKTOP  212
       -#define ST_INSTDIR  213
       +#define ED_INSTDIR  213
        #define ST_DELSTAT  214
        #define ST_DELDONE  215
        #define BT_DELOK    216
 (DIR) diff --git a/win32/dialogs.rc b/win32/dialogs.rc
       t@@ -33,10 +33,10 @@ BEGIN
                PUSHBUTTON "Cancel", BT_CANCEL, 191, 143, 39, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
                LTEXT "dopewars will be installed into the directory given below.", -1, 22, 14, 195, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
                LTEXT "To install in this directory, select ""Next"".", -1, 22, 33, 195, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
       -        LTEXT "To install in a different directory, select ""Browse"" and select the desired location.", -1, 22, 51, 195, 18, WS_CHILD | WS_VISIBLE | WS_GROUP
       +        LTEXT "To install in a different directory, enter the new directory into the box below, using the ""Browse"" button if necessary.", -1, 22, 51, 195, 35, WS_CHILD | WS_VISIBLE | WS_GROUP
                GROUPBOX "Destination directory", 105, 22, 84, 195, 35, WS_CHILD | WS_VISIBLE | WS_TABSTOP
       -        LTEXT "", ST_INSTDIR, 28, 100, 142, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
       -        PUSHBUTTON "B&rowse...", BT_BROWSE, 171, 98, 39, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
       +        CONTROL "", ED_INSTDIR, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 27, 99, 142, 10
       +        PUSHBUTTON "B&rowse...", BT_BROWSE, 173, 98, 39, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
        END
        
        
 (DIR) diff --git a/win32/setup.c b/win32/setup.c
       t@@ -20,6 +20,27 @@ DialogType CurrentDialog;
        HINSTANCE hInst=NULL;
        
        DWORD WINAPI DoInstall(LPVOID lpParam);
       +static void GetWinText(char **text,HWND hWnd);
       +
       +BOOL CheckCreateDir(void) {
       +  char *instdir;
       +  GetWinText(&idata->installdir,GetDlgItem(mainDlg[DL_INSTALLDIR],ED_INSTDIR));
       +  instdir=idata->installdir;
       +  if (SetCurrentDirectory(instdir)) {
       +    return TRUE;
       +  } else {
       +    if (MessageBox(mainDlg[CurrentDialog],
       +                   "The install directory does not exist.\n"
       +                   "Create it?","Install Directory",MB_YESNO)==IDYES) {
       +      if (CreateWholeDirectory(instdir)) {
       +        return TRUE;
       +      } else {
       +        DisplayError("Could not create directory",FALSE,FALSE);
       +      }
       +    }
       +    return FALSE;
       +  }
       +}
        
        void ShowNewDialog(DialogType NewDialog) {
          RECT DeskRect,OurRect;
       t@@ -29,6 +50,10 @@ void ShowNewDialog(DialogType NewDialog) {
          DWORD threadID;
          if (NewDialog<0 || NewDialog>=DL_NUM) return;
        
       +  if (NewDialog > CurrentDialog && CurrentDialog==DL_INSTALLDIR) {
       +    if (!CheckCreateDir()) return;
       +  }
       +
          hWnd=mainDlg[NewDialog];
          if (GetWindowRect(hWnd,&OurRect) &&
              GetWindowRect(GetDesktopWindow(),&DeskRect)) {
       t@@ -46,44 +71,38 @@ void ShowNewDialog(DialogType NewDialog) {
          }
        }
        
       +int CALLBACK BrowseCallback(HWND hwnd,UINT msg,LPARAM lParam,LPARAM lpData) {
       +  switch(msg) {
       +    case BFFM_INITIALIZED:
       +      SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)idata->installdir);
       +      break;
       +  }
       +  return 0;
       +}
       +
        void SelectInstDir(HWND parent) {
          BROWSEINFO bi = { 0 };
          TCHAR path[MAX_PATH];
          LPITEMIDLIST pidl;
          IMalloc *imalloc=0;
        
       -  bi.lpszTitle = "Pick a directory";
       -  bi.pszDisplayName = path;
       -  bi.ulFlags = BIF_STATUSTEXT|BIF_RETURNONLYFSDIRS|BIF_DONTGOBELOWDOMAIN;
       -  pidl = SHBrowseForFolder(&bi);
       -  if (pidl) {
       -    if (SUCCEEDED(SHGetMalloc(&imalloc))) {
       -//    imalloc->free(pidl); imalloc->release();
       +  if (SUCCEEDED(SHGetMalloc(&imalloc))) {
       +    bi.lpszTitle = "Pick a directory";
       +    bi.pszDisplayName = path;
       +    bi.ulFlags = BIF_STATUSTEXT|BIF_RETURNONLYFSDIRS;
       +    bi.lpfn = BrowseCallback;
       +    pidl = SHBrowseForFolder(&bi);
       +    if (pidl) {
       +      if (SHGetPathFromIDList(pidl,path)) {
       +        bfree(idata->installdir);
       +        idata->installdir = bstrdup(path);
       +        SendDlgItemMessage(mainDlg[DL_INSTALLDIR],ED_INSTDIR,WM_SETTEXT,
       +                           0,(LPARAM)idata->installdir);
       +      }
       +      imalloc->lpVtbl->Free(imalloc,pidl);
            }
       +    imalloc->lpVtbl->Release(imalloc);
          }
       -/*OPENFILENAME ofn;
       -  char lpstrFile[200]="";
       -
       -  ofn.lStructSize = sizeof(OPENFILENAME);
       -  ofn.hwndOwner = parent;
       -  ofn.hInstance = hInst;
       -  ofn.lpstrFilter = NULL;
       -  ofn.lpstrCustomFilter = NULL;
       -  ofn.nMaxCustFilter = 0;
       -  ofn.nFilterIndex = 0;
       -  ofn.lpstrFile = lpstrFile;
       -  ofn.nMaxFile = 200;
       -  ofn.lpstrFileTitle = NULL;
       -  ofn.nMaxFileTitle = 0;
       -  ofn.lpstrInitialDir = NULL;
       -  ofn.lpstrTitle = NULL;
       -  ofn.Flags = OFN_HIDEREADONLY;
       -  ofn.lpstrDefExt = NULL;
       -  ofn.lCustData = 0;
       -  ofn.lpfnHook = NULL;
       -  ofn.lpTemplateName = NULL;
       -
       -  GetOpenFileName(&ofn);*/
        }
        
        void ConditionalExit(HWND hWnd) {
       t@@ -490,8 +509,10 @@ DWORD WINAPI DoInstall(LPVOID lpParam) {
        
          GetWinText(&idata->startmenudir,GetDlgItem(mainDlg[DL_SHORTCUTS],ED_FOLDER));
        
       -  CreateDirectory(idata->installdir,NULL);
       -  SetCurrentDirectory(idata->installdir);
       +  if (!SetCurrentDirectory(idata->installdir)) {
       +    DisplayError("Cannot access install directory",TRUE,TRUE);
       +  }
       +
          logf = CreateFile("install.log",GENERIC_WRITE,0,NULL,
                            CREATE_ALWAYS,0,NULL);
        
       t@@ -564,6 +585,7 @@ DWORD WINAPI DoInstall(LPVOID lpParam) {
        
          ShowWindow(GetDlgItem(mainDlg[DL_DOINSTALL],ST_COMPLETE),SW_SHOW);
          ShowWindow(GetDlgItem(mainDlg[DL_DOINSTALL],ST_EXIT),SW_SHOW);
       +  EnableWindow(GetDlgItem(mainDlg[DL_DOINSTALL],BT_FINISH),TRUE);
          return 0;
        }
        
       t@@ -571,6 +593,7 @@ void FillFolderList(void) {
          HANDLE findfile;
          WIN32_FIND_DATA finddata;
          bstr *str;
       +  char *startdir;
          HWND folderlist;
        
          folderlist = GetDlgItem(mainDlg[DL_SHORTCUTS],LB_FOLDLIST);
       t@@ -578,22 +601,29 @@ void FillFolderList(void) {
        
          str=bstr_new();
        
       -  bstr_assign_windir(str);
       -  bstr_appendpath(str,"Start Menu\\Programs\\*");
       +  startdir=GetStartMenuTopDir();
       +  bstr_assign(str,startdir);
       +  bfree(startdir);
       +  bstr_appendpath(str,"Programs\\*");
       +//MessageBox(NULL,str->text,NULL,MB_OK);
        
       +//MessageBox(NULL,"Finding first file",NULL,MB_OK);
          findfile = FindFirstFile(str->text,&finddata);
       -  if (findfile) {
       +  if (findfile!=INVALID_HANDLE_VALUE) {
            while(1) {
       +//MessageBox(NULL,finddata.cFileName,NULL,MB_OK);
              if (finddata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY &&
                  strcmp(finddata.cFileName,".")!=0 &&
                  strcmp(finddata.cFileName,"..")!=0) {
                SendMessage(folderlist,LB_ADDSTRING,0,(LPARAM)finddata.cFileName);
              }
       +//MessageBox(NULL,"Finding next file",NULL,MB_OK);
              if (!FindNextFile(findfile,&finddata)) break;
            }
            FindClose(findfile);
          }
          bstr_free(str,TRUE);
       +//MessageBox(NULL,"Find done",NULL,MB_OK);
        }
        
        int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
       t@@ -607,14 +637,18 @@ int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
        
          hInst = hInstance;
        
       +//MessageBox(NULL,"Registering class",NULL,MB_OK);
          if (!hPrevInstance) RegisterSepClass(hInstance);
        
       +//MessageBox(NULL,"Creating dialogs",NULL,MB_OK);
          for (i=0;i<DL_NUM;i++) {
            mainDlg[i] = CreateDialog(hInst,MAKEINTRESOURCE(i+1),NULL,MainDlgProc);
          }
        
          CheckDlgButton(mainDlg[DL_SHORTCUTS],CB_DESKTOP,BST_CHECKED);
       +  EnableWindow(GetDlgItem(mainDlg[DL_DOINSTALL],BT_FINISH),FALSE);
        
       +//MessageBox(NULL,"Filling folder list",NULL,MB_OK);
          FillFolderList();
        
          ShowWindow(GetDlgItem(mainDlg[DL_DOINSTALL],ST_COMPLETE),SW_HIDE);
       t@@ -624,7 +658,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
        
          SendDlgItemMessage(mainDlg[DL_SHORTCUTS],ED_FOLDER,WM_SETTEXT,
                             0,(LPARAM)idata->startmenudir);
       -  SendDlgItemMessage(mainDlg[DL_INSTALLDIR],ST_INSTDIR,WM_SETTEXT,
       +  SendDlgItemMessage(mainDlg[DL_INSTALLDIR],ED_INSTDIR,WM_SETTEXT,
                             0,(LPARAM)idata->installdir);
          
          licence=GetFirstFile(idata->instfiles,idata->totalsize);
 (DIR) diff --git a/win32/uninstall.c b/win32/uninstall.c
       t@@ -150,12 +150,17 @@ void DeleteFileList(InstFiles *listpt) {
        void DeleteLinkList(char *dir,InstLink *listpt) {
          bstr *str;
          str=bstr_new();
       -  SetCurrentDirectory(dir);
       -  for (;listpt;listpt=listpt->next) {
       -    bstr_assign(str,"Deleting link: ");
       -    bstr_append(str,listpt->linkfile);
       -    SendDlgItemMessage(mainDlg,ST_DELSTAT,WM_SETTEXT,0,(LPARAM)str->text);
       -    DeleteFile(listpt->linkfile);
       +  if (SetCurrentDirectory(dir)) {
       +    for (;listpt;listpt=listpt->next) {
       +      bstr_assign(str,"Deleting shortcut: ");
       +      bstr_append(str,listpt->linkfile);
       +      SendDlgItemMessage(mainDlg,ST_DELSTAT,WM_SETTEXT,0,(LPARAM)str->text);
       +      DeleteFile(listpt->linkfile);
       +    }
       +  } else {
       +    bstr_assign(str,"Could not find shortcut directory ");
       +    bstr_append(str,dir);
       +    DisplayError(str->text,TRUE,FALSE);
          }
          bstr_free(str,TRUE);
        }
       t@@ -197,7 +202,14 @@ DWORD WINAPI DoUninstall(LPVOID lpParam) {
        
          installdir=GetInstallDir(product);
        
       -  SetCurrentDirectory(installdir);
       +  if (!SetCurrentDirectory(installdir)) {
       +    str=bstr_new();
       +    bstr_assign(str,"Could not access install directory ");
       +    bstr_append(str,installdir);
       +    DisplayError(str->text,TRUE,TRUE);
       +/* Pointless to try to free the bstr, since DisplayError ends the process */
       +  }
       +
          fin = CreateFile("install.log",GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
        
          if (fin) {
       t@@ -216,10 +228,22 @@ DWORD WINAPI DoUninstall(LPVOID lpParam) {
        
            SetCurrentDirectory(desktop); /* Just make sure we're not in the install
                                             directory any more */
       -    RemoveDirectory(installdir);
       -    RemoveDirectory(startmenu);
        
            str=bstr_new();
       +    if (!RemoveWholeDirectory(installdir)) {
       +      bstr_assign(str,"Could not remove install directory:\n");
       +      bstr_append(str,installdir);
       +      bstr_append(str,"\nYou may wish to manually remove it later.");
       +      DisplayError(str->text,FALSE,FALSE);
       +    }
       +
       +    if (!RemoveWholeDirectory(startmenu)) {
       +      bstr_assign(str,"Could not remove Start Menu directory:\n");
       +      bstr_append(str,startmenu);
       +      bstr_append(str,"\nYou may wish to manually remove it later.");
       +      DisplayError(str->text,FALSE,FALSE);
       +    }
       +
            bstr_assign(str,UninstallKey);
            bstr_appendpath(str,product);
            RegDeleteKey(HKEY_LOCAL_MACHINE,str->text);
       t@@ -229,9 +253,15 @@ DWORD WINAPI DoUninstall(LPVOID lpParam) {
            FreeInstData(idata,TRUE);
          } else {
            bfree(product); bfree(installdir); /* Normally FreeInstData frees these */
       +    str=bstr_new();
       +    bstr_assign(str,"Could not read install.log from ");
       +    bstr_append(str,installdir);
       +    DisplayError(str->text,TRUE,TRUE);
       +/* Pointless to try to free the bstr, since DisplayError ends the process */
          }
          ShowWindow(GetDlgItem(mainDlg,ST_DELDONE),SW_SHOW);
          EnableWindow(GetDlgItem(mainDlg,BT_DELOK),TRUE);
       +  SetFocus(GetDlgItem(mainDlg,BT_DELOK));
          return 0;
        }
        
 (DIR) diff --git a/win32/util.c b/win32/util.c
       t@@ -1,6 +1,7 @@
        #include <windows.h>
        #include <stdio.h>
        #include <string.h>
       +#include <shlobj.h>
        #include "util.h"
        
        const char *UninstallKey=
       t@@ -192,8 +193,9 @@ void DisplayError(const char *errtext,BOOL addsyserr,BOOL fatal) {
          bstr_assign(str,errtext);
        
          if (addsyserr) {
       +    bstr_append(str,"; ");
            bstr_append_long(str,syserr);
       -    bstr_append_c(str,' ');
       +    bstr_append(str,": ");
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                          NULL,syserr,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
                          (LPTSTR)&lpMsgBuf,0,NULL);
       t@@ -330,13 +332,42 @@ void WriteFileList(HANDLE fout,InstFiles *listpt) {
          bstr_free(str,TRUE);
        }
        
       +static char *GetSpecialDir(int dirtype) {
       +  LPITEMIDLIST pidl;
       +  LPMALLOC pmalloc;
       +  char szDir[MAX_PATH];
       +  BOOL doneOK=FALSE;
       +
       +  if (SUCCEEDED(SHGetMalloc(&pmalloc))) {
       +    if (SUCCEEDED(SHGetSpecialFolderLocation(NULL,dirtype,&pidl))) {
       +      if (SHGetPathFromIDList(pidl,szDir)) doneOK=TRUE;
       +      pmalloc->lpVtbl->Free(pmalloc,pidl);
       +    }
       +    pmalloc->lpVtbl->Release(pmalloc);
       +  }
       +  return (doneOK ? bstrdup(szDir) : NULL);
       +}
       +
       +char *GetStartMenuTopDir(void) {
       +  return GetSpecialDir(CSIDL_STARTMENU);
       +}
       +
       +char *GetDesktopDir(void) {
       +  return GetSpecialDir(CSIDL_DESKTOPDIRECTORY);
       +}
       +
        char *GetStartMenuDir(InstData *idata) {
          bstr *str;
       -  char *retval;
       +  char *topdir,*retval;
       +
       +  topdir=GetStartMenuTopDir();
        
          str = bstr_new();
       -  bstr_assign_windir(str);
       -  bstr_appendpath(str,"Start Menu\\Programs");
       +  
       +  bstr_assign(str,topdir);
       +  bfree(topdir);
       +
       +  bstr_appendpath(str,"Programs");
          bstr_appendpath(str,idata->startmenudir);
        
          retval = str->text;
       t@@ -344,15 +375,47 @@ char *GetStartMenuDir(InstData *idata) {
          return retval;
        }
        
       -char *GetDesktopDir(void) {
       -  bstr *str;
       -  char *retval;
       +BOOL CreateWholeDirectory(char *path) {
       +  char *pt;
       +  if (!path) return FALSE;
        
       -  str = bstr_new();
       -  bstr_assign_windir(str);
       -  bstr_appendpath(str,"Desktop");
       +/* We may as well try the easy way first */
       +  if (CreateDirectory(path,NULL)) return TRUE;
        
       -  retval = str->text;
       -  bstr_free(str,FALSE);
       -  return retval;
       +  /* \\machine\share notation */
       +  if (strlen(path)>2 && path[0]=='\\' && path[1]=='\\') {
       +    pt=&path[2]; /* Skip initial "\\" */
       +  } else {
       +    pt=path;
       +  }
       +
       +  while (*pt && *pt!='\\') pt++;  /* Skip the first (root) '\' */
       +
       +  while (*pt) {
       +    pt++;
       +    if (*pt=='\\') {
       +      *pt='\0';
       +      if (!CreateDirectory(path,NULL)) {
       +        *pt='\\'; return FALSE;
       +      }
       +      *pt='\\';
       +    }
       +  }
       +  return CreateDirectory(path,NULL);
       +}
       +
       +BOOL RemoveWholeDirectory(char *path) {
       +  char *pt;
       +  BOOL retval;
       +  if (!path || !RemoveDirectory(path)) return FALSE;
       +
       +  for (pt=&path[strlen(path)-2];pt>path;pt--) {
       +    if (*pt=='\\') {
       +      *pt='\0';
       +      retval=RemoveDirectory(path);
       +      *pt='\\';
       +      if (!retval) break;
       +    }
       +  }
       +  return TRUE;
        }
 (DIR) diff --git a/win32/util.h b/win32/util.h
       t@@ -61,5 +61,8 @@ void FreeFileList(InstFiles *filelist,BOOL freepts);
        void FreeInstData(InstData *idata,BOOL freepts);
        void WriteLinkList(HANDLE fout,InstLink *listpt);
        void WriteFileList(HANDLE fout,InstFiles *listpt);
       +char *GetStartMenuTopDir(void);
        char *GetStartMenuDir(InstData *idata);
        char *GetDesktopDir(void);
       +BOOL CreateWholeDirectory(char *path);
       +BOOL RemoveWholeDirectory(char *path);