2
0
Эх сурвалжийг харах

Change GetTempDir to use GetTempPath2 when available, else GetTempPath.

Previously, neither were used; environment variables were read directly.

We do lose the DirExists checks, which were based on Windows 95's
GetTempPath implementation. Now, if TMP points to a non-existent path,
the function will return that non-existent path instead of trying other
variables.
Jordan Russell 1 сар өмнө
parent
commit
a2668f33ad

+ 24 - 16
Projects/Src/Shared.CommonFunc.pas

@@ -746,23 +746,31 @@ end;
 
 function GetTempDir: String;
 { Returns fully qualified path of the temporary directory, with trailing
-  backslash. This does not use the Win32 function GetTempPath, due to platform
-  differences. }
-label 1;
+  backslash. }
+var
+  GetTempPathFunc: function(nBufferLength: DWORD; lpBuffer: LPWSTR): DWORD; stdcall;
+  Buf: array[0..MAX_PATH] of Char;
 begin
-  Result := GetEnv('TMP');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  Result := GetEnv('TEMP');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  { Like Windows 2000's GetTempPath, return USERPROFILE when TMP and TEMP
-    are not set }
-  Result := GetEnv('USERPROFILE');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  Result := GetWinDir;
-1:Result := AddBackslash(PathExpand(Result));
+  { When available, GetTempPath2 is preferred as it returns a private
+    directory (typically C:\Windows\SystemTemp) when running as SYSTEM }
+  GetTempPathFunc := GetProcAddress(GetModuleHandle(kernel32),
+    PAnsiChar('GetTempPath2W'));
+  if not Assigned(GetTempPathFunc) then
+    GetTempPathFunc := GetTempPathW;
+
+  const Res = GetTempPathFunc(SizeOf(Buf) div SizeOf(Buf[0]), Buf);
+  if (Res > 0) and (Res < SizeOf(Buf) div SizeOf(Buf[0])) then begin
+    { The docs say the returned path is fully qualified and ends with a
+      backslash, but let's be really sure! }
+    Result := AddBackslash(PathExpand(Buf));
+    Exit;
+  end;
+
+  { We don't expect GetTempPath to ever fail or claim a larger buffer is
+    needed (docs say maximum possible return value is MAX_PATH+1), but if it
+    does, raise an exception as this function has no return value for failure }
+  raise Exception.CreateFmt('GetTempDir: GetTempPath failed (%u, %u)',
+    [Res, GetLastError]);
 end;
 
 function StringChangeEx(var S: String; const FromStr, ToStr: String;

+ 1 - 0
whatsnew.htm

@@ -232,6 +232,7 @@ issigtool --key-file="MyKey.ispublickey" verify "MyProg.dll"</code></pre>
       <li><i>Fix:</i> Event function <tt>CurPageChanged</tt> is now always only triggered when the current page actually changes. Before it was called twice in a row for <tt>wpPreparing</tt> when the script had a <tt>PrepareToInstall</tt> event function which returned a non empty string to instruct Setup to stop.</li>
     </ul>
   </li>
+  <li>When available, Setup now retrieves the temporary directory path using the <tt>GetTempPath2</tt> API, which was first introduced in Windows 11 and later backported to Windows 10 and Windows Server 2016 via monthly updates. When running under the SYSTEM account, <tt>GetTempPath2</tt> returns a private directory (typically <tt>C:\Windows\SystemTemp</tt>), potentially enhancing security. On older versions of Windows or systems that haven't been updated, Setup falls back to the original <tt>GetTempPath</tt> API. (This change adds defense-in-depth; it does not address a known vulnerability.)</li>
   <li>Inno Setup 6.4.3 increased the maximum width of all task dialogs by about 50%, which helps to keep long paths from being truncated with ellipses. It now only does this if the task dialog's content actually contains a path.</li>
   <li>All official translations which still had an UTF-8 BOM had their BOM removed. Using a BOM in UTF-8 encoded files is not needed and not recommended since Inno Setup 6.3.0.</li>
   <li>Inno Setup is now built using Delphi 12.3 Athens instead of Delphi 12.1 Athens. Thanks to Ian Barker from Embarcadero for providing us with a license!</li>