1 2; 3;Inno Setup Extensions Knowledge Base 4;Article 44 - Native ISX procedures for PATH modification 5;http://www13.brinkster.com/vincenzog/isxart.asp?idart=44 6;Author: Thomas Vedel 7; 8 9[Code] 10 11// Version log: 12// 03/31/2003: Initial release (thv@lr.dk) 13 14const 15 // Modification method 16 pmAddToBeginning = $1; // Add dir to beginning of Path 17 pmAddToEnd = $2; // Add dir to end of Path 18 pmAddAllways = $4; // Add also if specified dir is already included in existing path 19 pmAddOnlyIfDirExists = $8; // Add only if specified dir actually exists 20 pmRemove = $10; // Remove dir from path 21 pmRemoveSubdirsAlso = $20; // Remove dir and all subdirs from path 22 23 // Scope 24 psCurrentUser = 1; // Modify path for current user 25 psAllUsers = 2; // Modify path for all users 26 27 // Error results 28 mpOK = 0; // No errors 29 mpMissingRights = -1; // User has insufficient rights 30 mpAutoexecNoWriteacc = -2; // Autoexec can not be written (may be readonly) 31 mpBothAddAndRemove = -3; // User has specified that dir should both be removed from and added to path 32 33 34{ Helper procedure: Split a path environment variable into individual dirnames } 35procedure SplitPath(Path: string; var Dirs: TStringList); 36var 37 pos: integer; 38 s: string; 39begin 40 Dirs.Clear; 41 s := ''; 42 pos := 1; 43 while (pos<=Length(Path)) do 44 begin 45 if (Path[pos]<>';') then 46 s := s + Path[pos]; 47 if ((Path[pos]=';') or (pos=Length(Path))) then 48 begin 49 s := Trim(s); 50 s := RemoveQuotes(s); 51 s := Trim(s); 52 if (s <> '') then 53 Dirs.Add(s); 54 s := ''; 55 end; 56 Pos := Pos + 1; 57 end; 58end; // procedure SplitPath 59 60 61{ Helper procedure: Concatenate individual dirnames into a path environment variable } 62procedure ConcatPath(Dirs: TStringList; Quotes: boolean; var Path: string); 63var 64 Index, MaxIndex: integer; 65 s: string; 66begin 67 MaxIndex := Dirs.Count-1; 68 Path := ''; 69 for Index := 0 to MaxIndex do 70 begin 71 s := Dirs.Strings[Index]; 72 if ((Quotes) and (pos(' ',s) > 0)) then 73 s := AddQuotes(s); 74 Path := Path + s; 75 if (Index < MaxIndex) then 76 Path := Path + ';' 77 end; 78end; // procedure ConcatPath 79 80 81{ Helper function: Modifies path environment string } 82procedure ModifyPathString(OldPath, DirName: string; Method: integer; Quotes: boolean; var ResultPath: string); 83var 84 Dirs: TStringList; 85 DirNotInPath: Boolean; 86 i: integer; 87begin 88 // Create Dirs variable 89 Dirs := TStringList.Create; 90 91 // Remove quotes form DirName 92 DirName := Trim(DirName); 93 DirName := RemoveQuotes(DirName); 94 DirName := Trim(DirName); 95 96 // Split old path in individual directory names 97 SplitPath(OldPath, Dirs); 98 99 // Check if dir is allready in path 100 DirNotInPath := True; 101 for i:=Dirs.Count-1 downto 0 do 102 begin 103 if (uppercase(Dirs.Strings[i]) = uppercase(DirName)) then 104 DirNotInPath := False; 105 end; 106 107 // Should dir be removed from existing Path? 108 if ((Method and (pmRemove or pmRemoveSubdirsAlso)) > 0) then 109 begin 110 for i:=Dirs.Count-1 downto 0 do 111 begin 112 if (((Method and pmRemoveSubdirsAlso) > 0) and (pos(uppercase(DirName)+'\', uppercase(Dirs.Strings[i])) = 1)) or 113 (((Method and (pmRemove) or (pmRemoveSubdirsAlso)) > 0) and (uppercase(DirName) = uppercase(Dirs.Strings[i]))) 114 then 115 Dirs.Delete(i); 116 end; 117 end; 118 119 // Should dir be added to existing Path? 120 if ((Method and (pmAddToBeginning or pmAddToEnd)) > 0) then 121 begin 122 // Add dir to path 123 if (((Method and pmAddAllways) > 0) or DirNotInPath) then 124 begin 125 // Dir is not in path allready or should be added anyway 126 if (((Method and pmAddOnlyIfDirExists) = 0) or (DirExists(DirName))) then 127 begin 128 // Dir actually exsists or should be added anyway 129 if ((Method and pmAddToBeginning) > 0) then 130 Dirs.Insert(0, DirName) 131 else 132 Dirs.Append(DirName); 133 end; 134 end; 135 end; 136 137 // Concatenate directory names into one single path variable 138 ConcatPath(Dirs, Quotes, ResultPath); 139 // Finally free Dirs object 140 Dirs.Free; 141end; // ModifyPathString 142 143 144{ Helper function: Modify path on Windows 9x } 145function ModifyPath9x(DirName: string; Method: integer): integer; 146var 147 AutoexecLines: TStringList; 148 ActualLine: String; 149 PathLineNos: TStringList; 150 FirstPathLineNo: Integer; 151 OldPath, ResultPath: String; 152 LineNo, CharNo, Index: integer; 153 154 TempString: String; 155begin 156 // Expect everything to be OK 157 result := mpOK; 158 159 // Create stringslists 160 AutoexecLines := TStringList.Create; 161 PathLineNos := TStringList.Create; 162 163 // Read existing path 164 OldPath := ''; 165 LoadStringFromFile('c:\Autoexec.bat', TempString); 166 AutoexecLines.Text := TempString; 167 PathLineNos.Clear; 168 // Read Autoexec line by line 169 for LineNo := 0 to AutoexecLines.Count - 1 do begin 170 ActualLine := AutoexecLines.Strings[LineNo]; 171 // Check if line starts with "PATH=" after first stripping spaces and other "fill-chars" 172 if Pos('=', ActualLine) > 0 then 173 begin 174 for CharNo := Pos('=', ActualLine)-1 downto 1 do 175 if (ActualLine[CharNo]=' ') or (ActualLine[CharNo]=#9) then 176 Delete(ActualLine, CharNo, 1); 177 if Pos('@', ActualLine) = 1 then 178 Delete(ActualLine, 1, 1); 179 if (Pos('PATH=', uppercase(ActualLine))=1) or (Pos('SETPATH=', uppercase(ActualLine))=1) then 180 begin 181 // Remove 'PATH=' and add path to "OldPath" variable 182 Delete(ActualLine, 1, pos('=', ActualLine)); 183 // Check if an earlier PATH variable is referenced, but there has been no previous PATH defined in Autoexec 184 if (pos('%PATH%',uppercase(ActualLine))>0) and (PathLineNos.Count=0) then 185 OldPath := ExpandConstant('{win}') + ';' + ExpandConstant('{win}')+'\COMMAND'; 186 if (pos('%PATH%',uppercase(ActualLine))>0) then 187 begin 188 ActualLine := Copy(ActualLine, 1, pos('%PATH%',uppercase(ActualLine))-1) + 189 OldPath + 190 Copy(ActualLine, pos('%PATH%',uppercase(ActualLine))+6, Length(ActualLine)); 191 end; 192 OldPath := ActualLine; 193 194 // Update list of line numbers holding path variables 195 PathLineNos.Add(IntToStr(LineNo)); 196 end; 197 end; 198 end; 199 200 // Save first line number in Autoexec.bat which modifies path environment variable 201 if PathLineNos.Count > 0 then 202 FirstPathLineNo := StrToInt(PathLineNos.Strings[0]) 203 else 204 FirstPathLineNo := 0; 205 206 // Modify path 207 ModifyPathString(OldPath, DirName, Method, True, ResultPath); 208 209 // Write Modified path back to Autoexec.bat 210 // First delete all existing path references from Autoexec.bat 211 Index := PathLineNos.Count-1; 212 while (Index>=0) do 213 begin 214 AutoexecLines.Delete(StrToInt(PathLineNos.Strings[Index])); 215 Index := Index-1; 216 end; 217 // Then insert new path variable into Autoexec.bat 218 AutoexecLines.Insert(FirstPathLineNo, '@PATH='+ResultPath); 219 // Delete old Autoexec.bat from disk 220 if not DeleteFile('c:\Autoexec.bat') then 221 result := mpAutoexecNoWriteAcc; 222 Sleep(500); 223 // And finally write Autoexec.bat back to disk 224 if not (result=mpAutoexecNoWriteAcc) then 225 SaveStringToFile('c:\Autoexec.bat', AutoexecLines.Text, false); 226 227 // Free stringlists 228 PathLineNos.Free; 229 AutoexecLines.Free; 230end; // ModifyPath9x 231 232 233{ Helper function: Modify path on Windows NT, 2000 and XP } 234function ModifyPathNT(DirName: string; Method, Scope: integer): integer; 235var 236 RegRootKey: integer; 237 RegSubKeyName: string; 238 RegValueName: string; 239 OldPath, ResultPath: string; 240 OK: boolean; 241begin 242 // Expect everything to be OK 243 result := mpOK; 244 245 // Initialize registry key and value names to reflect if changes should be global or local to current user only 246 case Scope of 247 psCurrentUser: 248 begin 249 RegRootKey := HKEY_CURRENT_USER; 250 RegSubKeyName := 'Environment'; 251 RegValueName := 'Path'; 252 end; 253 psAllUsers: 254 begin 255 RegRootKey := HKEY_LOCAL_MACHINE; 256 RegSubKeyName := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; 257 RegValueName := 'Path'; 258 end; 259 end; 260 261 // Read current path value from registry 262 OK := RegQueryStringValue(RegRootKey, RegSubKeyName, RegValueName, OldPath); 263 if not OK then 264 begin 265 result := mpMissingRights; 266 Exit; 267 end; 268 269 // Modify path 270 ModifyPathString(OldPath, DirName, Method, False, ResultPath); 271 272 // Write new path value to registry 273 if not RegWriteStringValue(RegRootKey, RegSubKeyName, RegValueName, ResultPath) then 274 begin 275 result := mpMissingRights; 276 Exit; 277 278 end; 279end; // ModifyPathNT 280 281 282{ Main function: Modify path } 283function ModifyPath(Path: string; Method, Scope: integer): integer; 284begin 285 // Check if both add and remove has been specified (= error!) 286 if (Method and (pmAddToBeginning or pmAddToEnd) and (pmRemove or pmRemoveSubdirsAlso)) > 0 then 287 begin 288 result := mpBothAddAndRemove; 289 Exit; 290 end; 291 292 // Perform directory constant expansion 293 Path := ExpandConstantEx(Path, ' ', ' '); 294 295 // Test if Win9x 296 if InstallOnThisVersion('4,0','0,0') = irInstall then 297 ModifyPath9x(Path, Method); 298 299 // Test if WinNT, 2000 or XP 300 if InstallOnThisVersion('0,4','0,0') = irInstall then 301 ModifyPathNT(Path, Method, Scope); 302end; // ModifyPath 303