tCheck for admin rights added to Win32 installer; error handling cleaned up; option to install in user's own Start Menu or the "all users" Start Menu added - 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 ed7fb9cd1a09f667ebc6fb3fcd07a684bca1d1aa
 (DIR) parent dc982dd81a76f2a8fcc599bdfe23552a230638de
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Sun,  3 Feb 2002 20:20:07 +0000
       
       Check for admin rights added to Win32 installer; error handling cleaned up;
       option to install in user's own Start Menu or the "all users" Start Menu added
       
       
       Diffstat:
         M ChangeLog                           |       1 +
         M TODO                                |       1 -
         M win32/contid.h                      |       2 ++
         M win32/dialogs.rc                    |       6 ++++--
         M win32/setup.c                       |     143 +++++++++++++++++++++++--------
         M win32/uninstall.c                   |       2 +-
         M win32/util.c                        |      34 ++++++++++++++++++++++++++-----
         M win32/util.h                        |      10 ++++++++--
       
       8 files changed, 154 insertions(+), 45 deletions(-)
       ---
 (DIR) diff --git a/ChangeLog b/ChangeLog
       t@@ -12,6 +12,7 @@ cvs
            - Keyboard shortcuts for menu items in Windows client
            - Default buttons (ENTER -> "OK") for Windows client
            - RPM build/make install can now be run as non-superuser
       +    - Win32 install for current user/all users
            - Code cleanups
        
        1.5.2   16-10-2001
 (DIR) diff --git a/TODO b/TODO
       t@@ -1,4 +1,3 @@
       -- Win32 install for current user/all users
        - Test code under Win98
        - Document new server interface
        - Admin of running NT Service servers
 (DIR) diff --git a/win32/contid.h b/win32/contid.h
       t@@ -14,3 +14,5 @@
        #define ST_DELSTAT  214
        #define ST_DELDONE  215
        #define BT_DELOK    216
       +#define RB_ALLUSERS 217
       +#define RB_ONEUSER  218
 (DIR) diff --git a/win32/dialogs.rc b/win32/dialogs.rc
       t@@ -8,8 +8,10 @@ BEGIN
                PUSHBUTTON "&Next >", BT_NEXT, 144, 143, 39, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
                PUSHBUTTON "Cancel", BT_CANCEL, 191, 143, 39, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP
                LTEXT "Welcome to the dopewars-1.5.3 installation program.\nThis program will install dopewars-1.5.3 on your computer.", -1, 22, 14, 195, 17, WS_CHILD | WS_VISIBLE | WS_GROUP
       -        LTEXT "Use the ""Back"" and ""Next"" buttons at the bottom of the dialog to control the installation. You can quit at any time using the ""Cancel"" button.", -1, 22, 51, 195, 25, WS_CHILD | WS_VISIBLE | WS_GROUP
       -        LTEXT "Newer versions of this program, when available, can be obtained from the dopewars website, http://dopewars.sf.net/", -1, 22, 94, 195, 18, WS_CHILD | WS_VISIBLE | WS_GROUP
       +        LTEXT "Use the ""Back"" and ""Next"" buttons at the bottom of the dialog to control the installation. You can quit at any time using the ""Cancel"" button.", -1, 22, 50, 195, 25, WS_CHILD | WS_VISIBLE | WS_GROUP
       +        LTEXT "Newer versions of this program, when available, can be obtained from the dopewars website, http://dopewars.sf.net/", -1, 22, 84, 195, 18, WS_CHILD | WS_VISIBLE | WS_GROUP
       +        CONTROL "Install for &all users (requires admin rights)", RB_ALLUSERS, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 28, 108, 110, 8
       +        CONTROL "Install for &current user only", RB_ONEUSER, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 28, 120, 108, 8
        END
        2 DIALOG 17, 40, 239, 162
        STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 (DIR) diff --git a/win32/setup.c b/win32/setup.c
       t@@ -40,24 +40,31 @@ HWND mainDlg[DL_NUM];
        DialogType CurrentDialog;
        HINSTANCE hInst=NULL;
        char *oldversion=NULL;
       +BOOL services_supported, have_admin_rights, install_all_users;
        
        DWORD WINAPI DoInstall(LPVOID lpParam);
        static void GetWinText(char **text,HWND hWnd);
       +static void FillFolderList(void);
        
       -/* Returns TRUE if this operating system version supports NT Services */
       -BOOL ServicesSupported(void) {
       +/* Does this OS version support NT services? If so, do we have the 
       + * necessary (administrator) rights to use them?
       + */
       +void ServiceCheck(BOOL *hasServices, BOOL *isAdmin) {
          SC_HANDLE scManager;
        
       -  scManager = OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT);
       +  scManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
          if (scManager) {
       +    *hasServices = *isAdmin = TRUE;
            CloseServiceHandle(scManager);
          } else if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) {
       -    return FALSE;
       +    *hasServices = *isAdmin = FALSE;
       +  } else {
       +    *hasServices = TRUE;
       +    *isAdmin = FALSE;
          } 
       -  return TRUE;
        }
        
       -void InstallService(InstData *idata) {
       +BOOL InstallService(InstData *idata) {
          SC_HANDLE scManager,scService;
          HKEY key;
          bstr *str;
       t@@ -65,13 +72,13 @@ void InstallService(InstData *idata) {
          NTService *service;
        
          service = idata->service;
       -  if (!service) return;
       +  if (!service) return FALSE;
        
       -  scManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
       +  scManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
        
          if (!scManager) {
            DisplayError("Cannot connect to service manager",TRUE,FALSE);
       -    return;
       +    return FALSE;
          }
        
          str = bstr_new();
       t@@ -85,7 +92,7 @@ void InstallService(InstData *idata) {
          if (!scService) {
            DisplayError("Cannot create service",TRUE,FALSE);
            bstr_free(str,TRUE);
       -    return;
       +    return FALSE;
          }
        
          bstr_assign(str,keyprefix);
       t@@ -99,6 +106,7 @@ void InstallService(InstData *idata) {
        
          CloseServiceHandle(scService);
          CloseServiceHandle(scManager);
       +  return TRUE;
        }
        
        BOOL CheckCreateDir(void) {
       t@@ -117,7 +125,7 @@ BOOL CheckCreateDir(void) {
              if (CreateWholeDirectory(instdir)) {
                return TRUE;
              } else {
       -        DisplayError("Could not create directory",FALSE,FALSE);
       +        DisplayError("Could not create directory",TRUE,FALSE);
              }
            }
            return FALSE;
       t@@ -132,8 +140,20 @@ void ShowNewDialog(DialogType NewDialog) {
          DWORD threadID;
          if (NewDialog<0 || NewDialog>=DL_NUM) return;
        
       -  if (NewDialog > CurrentDialog && CurrentDialog==DL_INSTALLDIR) {
       -    if (!CheckCreateDir()) return;
       +  if (NewDialog > CurrentDialog) {
       +    switch(CurrentDialog) {
       +    case DL_INSTALLDIR:
       +      if (!CheckCreateDir()) return;
       +      break;
       +    case DL_INTRO:
       +      install_all_users = (services_supported
       +                           && IsDlgButtonChecked(mainDlg[DL_INTRO],
       +                                                 RB_ALLUSERS)==BST_CHECKED);
       +      FillFolderList();
       +      break;
       +    default:
       +      break;
       +    }
          }
        
          hWnd=mainDlg[NewDialog];
       t@@ -253,13 +273,13 @@ LPVOID GetResource(LPCTSTR resname,LPCTSTR restype) {
          LPVOID respt;
        
          hrsrc = FindResource(NULL,resname,restype);
       -  if (!hrsrc) DisplayError("Could not find resource: ",TRUE,TRUE);
       +  if (!hrsrc) DisplayError("Could not find resource",TRUE,TRUE);
        
          hglobal = LoadResource(NULL,hrsrc);
       -  if (!hglobal) DisplayError("Could not load resource: ",TRUE,TRUE);
       +  if (!hglobal) DisplayError("Could not load resource",TRUE,TRUE);
        
          respt = LockResource(hglobal);
       -  if (!respt) DisplayError("Could not lock resource: ",TRUE,TRUE);
       +  if (!respt) DisplayError("Could not lock resource",TRUE,TRUE);
        
          return respt;
        }
       t@@ -277,6 +297,7 @@ InstData *ReadInstData() {
          pt=instdata;
        
          idata = bmalloc(sizeof(InstData));
       +  idata->flags = 0;
          idata->service = NULL;
          idata->totalsize = atol(pt);
          pt += strlen(pt)+1;
       t@@ -515,16 +536,19 @@ void SetupShortcuts(HANDLE fout) {
          char *startmenu,*desktop;
          BOOL dodesktop;
        
       -  startmenu = GetStartMenuDir(idata);
       +  startmenu = GetStartMenuDir(install_all_users, idata);
          desktop = GetDesktopDir();
        
          dodesktop=(IsDlgButtonChecked(mainDlg[DL_SHORTCUTS],CB_DESKTOP)==BST_CHECKED);
        
          if (startmenu) {
       -    CreateDirectory(startmenu,NULL);
       -
       -    CreateLinks(startmenu,idata->startmenu);
       -    WriteLinkList(fout,idata->startmenu);
       +    if (CreateDirectory(startmenu,NULL)) {
       +      CreateLinks(startmenu,idata->startmenu);
       +      WriteLinkList(fout,idata->startmenu);
       +    } else {
       +      DisplayError("Could not create Start Menu directory",TRUE,FALSE);
       +      WriteLinkList(fout,NULL);
       +    }
          } else {
            WriteLinkList(fout,NULL);
          }
       t@@ -564,7 +588,7 @@ void SetupUninstall() {
          bstr_appendpath(str,idata->product);
          
          if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,str->text,0,NULL,0,
       -                     KEY_ALL_ACCESS,NULL,&key,&disp)==ERROR_SUCCESS) {
       +                     KEY_WRITE,NULL,&key,&disp)==ERROR_SUCCESS) {
            RegSetValueEx(key,"DisplayName",0,REG_SZ,idata->product,
                          strlen(idata->product));
            bstr_assign_windir(str);
       t@@ -576,7 +600,7 @@ void SetupUninstall() {
            RegSetValueEx(key,"InstallDirectory",0,REG_SZ,str->text,str->length);
            RegCloseKey(key);
          } else {
       -    DisplayError("Cannot create registry key: ",TRUE,FALSE);
       +    DisplayError("Cannot create registry key for uninstall",TRUE,FALSE);
          }
        
          bstr_assign_windir(str);
       t@@ -587,11 +611,11 @@ void SetupUninstall() {
          bstr_appendpath(uninstexe,"uninstall.exe");
        
          if (!MoveFile(uninstexe->text,str->text)) {
       -    DisplayError("Unable to create uninstall program: ",TRUE,FALSE);
       +    DisplayError("Unable to create uninstall program",TRUE,FALSE);
          }
          DeleteFile(uninstexe->text);
        
       -  startmenu = GetStartMenuDir(idata);
       +  startmenu = GetStartMenuDir(install_all_users, idata);
          bstr_assign(link,startmenu);
          bstr_appendpath(link,"Uninstall ");
          bstr_append(link,idata->product);
       t@@ -636,7 +660,7 @@ void StartRemoveOldVersion(char *oldversion,InstData *idata,
            DeleteFileList(old->instfiles,hwnd,idata->keepfiles);
            DeleteFileList(old->extrafiles,hwnd,idata->keepfiles);
        
       -    startmenu = GetStartMenuDir(old);
       +    startmenu = GetStartMenuDir(old->flags & IF_ALLUSERS, old);
            desktop = GetDesktopDir();
            DeleteLinkList(startmenu,old->startmenu,hwnd);
            DeleteLinkList(desktop,old->desktop,hwnd);
       t@@ -682,7 +706,7 @@ void FinishRemoveOldVersion(char *oldversion,InstData *idata,
        
          if (strcmp(idata->startmenudir,oldidata->startmenudir)!=0) {
            SetCurrentDirectory(desktop); /* Make sure we're not in the menu dir */
       -    startmenu = GetStartMenuDir(oldidata);
       +    startmenu = GetStartMenuDir(oldidata->flags & IF_ALLUSERS, oldidata);
            if (!RemoveWholeDirectory(startmenu)) {
              bstr_assign(str,"Could not remove old Start Menu directory:\n");
              bstr_append(str,startmenu);
       t@@ -707,7 +731,7 @@ void FinishRemoveOldVersion(char *oldversion,InstData *idata,
        DWORD WINAPI DoInstall(LPVOID lpParam) {
          HANDLE fout,logf,fin;
          DWORD bytes_written,fileleft;
       -  BOOL skipfile;
       +  BOOL skipfile, service_installed;
          char *inbuf,*outbuf;
          int status,count;
          z_stream z;
       t@@ -807,14 +831,34 @@ DWORD WINAPI DoInstall(LPVOID lpParam) {
        
          FinishRemoveOldVersion(oldversion,idata,oldidata);
        
       -  InstallService(idata);
       +  if (services_supported) {
       +    service_installed = InstallService(idata);
       +  } else {
       +    service_installed = FALSE; 
       +  }
       +
       +  if (service_installed) {
       +    MessageBox(mainDlg[CurrentDialog],
       +               "The dopewars server has been installed as an NT Service, "
       +               "and configured\nfor manual startup. To start or stop this "
       +               "service, or to configure it to run\nautomatically when "
       +               "you turn on your computer, see the \"Services\" application\n"
       +               "from Control Panel. You can also run an interactive server "
       +               "by using\nthe \"dopewars server\" shortcut from the desktop "
       +               "and/or Start Menu.","Service Installed",MB_OK);
       +  }
        
          CoInitialize(NULL);
          SetupShortcuts(logf);
          SetupUninstall();
          CoUninitialize();
        
       -  WriteServiceDetails(logf,idata->service);
       +  WriteServiceDetails(logf,service_installed ? idata->service : NULL);
       +
       +  if (install_all_users) {
       +    idata->flags |= IF_ALLUSERS;
       +  }
       +  WriteInstFlags(logf, idata->flags);
        
          CloseHandle(logf);
        
       t@@ -836,9 +880,11 @@ void FillFolderList(void) {
          folderlist = GetDlgItem(mainDlg[DL_SHORTCUTS],LB_FOLDLIST);
          if (!folderlist) return;
        
       +  SendMessage(folderlist,LB_RESETCONTENT,0,0);
       +
          str=bstr_new();
        
       -  startdir=GetStartMenuTopDir();
       +  startdir=GetStartMenuTopDir(install_all_users);
          bstr_assign(str,startdir);
          bfree(startdir);
          bstr_appendpath(str,"Programs\\*");
       t@@ -858,6 +904,17 @@ void FillFolderList(void) {
          bstr_free(str,TRUE);
        }
        
       +BOOL CheckAdminRights(void) {
       +  return (!services_supported || have_admin_rights ||
       +          MessageBox(NULL,
       +                     "To successfully install all components of this "
       +                     "program Administrator\nrights are required, and you "
       +                     "do not appear to have them. Do you want\nto attempt "
       +                     "to continue the installation anyway?",
       +                     "Administrator rights not found",
       +                     MB_YESNO | MB_DEFBUTTON2)==IDYES);
       +}
       +
        BOOL CheckExistingInstall(InstData *idata) {
          bstr *str;
          char *sep,*prodname,*prodversion;
       t@@ -924,6 +981,22 @@ BOOL CheckExistingInstall(InstData *idata) {
          return retval;
        }
        
       +BOOL SetDefaultInstall(void) {
       +  HWND dlg;
       +
       +  dlg = mainDlg[DL_INTRO];
       +
       +  if (services_supported) {
       +    CheckRadioButton(dlg, RB_ALLUSERS, RB_ONEUSER,
       +                     have_admin_rights ? RB_ALLUSERS : RB_ONEUSER);
       +  } else {
       +    ShowWindow(GetDlgItem(dlg, RB_ALLUSERS), SW_HIDE);
       +    ShowWindow(GetDlgItem(dlg, RB_ONEUSER), SW_HIDE);
       +  }
       +
       +  return have_admin_rights;
       +}
       +
        int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
                             LPSTR lpszCmdParam,int nCmdShow) {
          MSG msg;
       t@@ -941,11 +1014,13 @@ int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
            mainDlg[i] = CreateDialog(hInst,MAKEINTRESOURCE(i+1),NULL,MainDlgProc);
          }
        
       +  ServiceCheck(&services_supported,&have_admin_rights);
       +
       +  install_all_users = SetDefaultInstall();
       +
          CheckDlgButton(mainDlg[DL_SHORTCUTS],CB_DESKTOP,BST_CHECKED);
          EnableWindow(GetDlgItem(mainDlg[DL_DOINSTALL],BT_FINISH),FALSE);
        
       -  FillFolderList();
       -
          ShowWindow(GetDlgItem(mainDlg[DL_DOINSTALL],ST_COMPLETE),SW_HIDE);
          ShowWindow(GetDlgItem(mainDlg[DL_DOINSTALL],ST_EXIT),SW_HIDE);
        
       t@@ -966,7 +1041,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
        
          for (i=0;i<DL_NUM;i++) SetGuiFont(mainDlg[i]);
        
       -  if (CheckExistingInstall(idata)) {
       +  if (CheckAdminRights() && CheckExistingInstall(idata)) {
            CurrentDialog=DL_NUM;
            ShowNewDialog(DL_INTRO);
        
 (DIR) diff --git a/win32/uninstall.c b/win32/uninstall.c
       t@@ -70,7 +70,7 @@ DWORD WINAPI DoUninstall(LPVOID lpParam) {
            DeleteFileList(idata->instfiles,delstat,NULL);
            DeleteFileList(idata->extrafiles,delstat,NULL);
        
       -    startmenu = GetStartMenuDir(idata);
       +    startmenu = GetStartMenuDir(idata->flags & IF_ALLUSERS, idata);
            desktop = GetDesktopDir();
            DeleteLinkList(startmenu,idata->startmenu,delstat);
            DeleteLinkList(desktop,idata->desktop,delstat);
 (DIR) diff --git a/win32/util.c b/win32/util.c
       t@@ -323,6 +323,16 @@ void FreeInstData(InstData *idata,BOOL freepts) {
          bfree(idata);
        }
        
       +void WriteInstFlags(HANDLE fout, InstFlags flags) {
       +  DWORD bytes_written;
       +  char str[3];
       +
       +  str[0] = (char)flags;
       +  if (!WriteFile(fout,str,1,&bytes_written,NULL)) {
       +    printf("Write error\n");
       +  }
       +}
       +
        void WriteServiceDetails(HANDLE fout,NTService *service) {
          DWORD bytes_written;
          char str[]="";
       t@@ -412,19 +422,19 @@ static char *GetSpecialDir(int dirtype) {
          return (doneOK ? bstrdup(szDir) : NULL);
        }
        
       -char *GetStartMenuTopDir(void) {
       -  return GetSpecialDir(CSIDL_STARTMENU);
       +char *GetStartMenuTopDir(BOOL AllUsers) {
       +  return GetSpecialDir(AllUsers ? CSIDL_COMMON_STARTMENU : CSIDL_STARTMENU);
        }
        
        char *GetDesktopDir(void) {
          return GetSpecialDir(CSIDL_DESKTOPDIRECTORY);
        }
        
       -char *GetStartMenuDir(InstData *idata) {
       +char *GetStartMenuDir(BOOL AllUsers, InstData *idata) {
          bstr *str;
          char *topdir,*retval;
        
       -  topdir=GetStartMenuTopDir();
       +  topdir=GetStartMenuTopDir(AllUsers);
        
          str = bstr_new();
          
       t@@ -563,6 +573,18 @@ InstLink *ReadLinkList(HANDLE fin) {
          return first;
        }
        
       +InstFlags ReadInstFlags(HANDLE fin) {
       +  DWORD bytes_read;
       +  char buf[3];
       +
       +  buf[0] = 0;
       +  if (!ReadFile(fin,buf,1,&bytes_read,NULL)) {
       +    printf("Read error\n");
       +  }
       +
       +  return (InstFlags)buf[0];
       +}
       +
        NTService *ReadServiceDetails(HANDLE fin) {
          NTService *service=NULL;
          char *name,*disp,*desc,*exe;
       t@@ -645,12 +667,14 @@ InstData *ReadOldInstData(HANDLE fin,char *product,char *installdir) {
        
          idata->instfiles = ReadFileList(fin);
          idata->extrafiles = ReadFileList(fin);
       +  idata->keepfiles = NULL;
        
          idata->startmenu = ReadLinkList(fin);
          idata->desktop = ReadLinkList(fin);
        
          idata->service = ReadServiceDetails(fin);
       -  idata->keepfiles = ReadFileList(fin);
       +
       +  idata->flags = ReadInstFlags(fin);
        
          return idata;
        }
 (DIR) diff --git a/win32/util.h b/win32/util.h
       t@@ -46,6 +46,10 @@ typedef struct _NTService {
          char *exe;
        } NTService;
        
       +typedef enum {
       +  IF_ALLUSERS = 1
       +} InstFlags;
       +
        typedef struct _InstData {
          char *product;
          char *installdir,*startmenudir;
       t@@ -56,6 +60,7 @@ typedef struct _InstData {
          InstFiles *keepfiles;
          InstLink *startmenu;
          InstLink *desktop;
       +  InstFlags flags;
        } InstData;
        
        extern const char *UninstallKey;
       t@@ -93,10 +98,11 @@ void AddServiceDetails(char *servicename,char *servicedisp,
                               NTService **service);
        void FreeServiceDetails(NTService *service,BOOL freepts);
        void WriteServiceDetails(HANDLE fout,NTService *service);
       +void WriteInstFlags(HANDLE fout, InstFlags flags);
        void WriteLinkList(HANDLE fout,InstLink *listpt);
        void WriteFileList(HANDLE fout,InstFiles *listpt);
       -char *GetStartMenuTopDir(void);
       -char *GetStartMenuDir(InstData *idata);
       +char *GetStartMenuTopDir(BOOL AllUsers);
       +char *GetStartMenuDir(BOOL AllUsers, InstData *idata);
        char *GetDesktopDir(void);
        BOOL CreateWholeDirectory(char *path);
        BOOL RemoveWholeDirectory(char *path);