Ver Fonte

Delay-load ole32.dll in WinDirs.

Rika Ichinose há 2 anos atrás
pai
commit
f96700f7db
1 ficheiros alterados com 36 adições e 81 exclusões
  1. 36 81
      rtl/win/windirs.pp

+ 36 - 81
rtl/win/windirs.pp

@@ -294,13 +294,8 @@ const
     (CSIDL: CSIDL_PROFILES;                 FOLDERID: @FOLDERID_UserProfiles)
   );
 
-// CoTaskMemFree is required for the use of SHGetKnownFolderPath function.
-// CoTaskMemFree function signature was copied from ActiveX unit.
-procedure CoTaskMemFree(_para1:PVOID); stdcall; external 'ole32.dll' name 'CoTaskMemFree';
-
 type
   KNOWNFOLDERID = TGUID;
-  PWSTR = PWideChar;
 
 type
   // HRESULT SHGetFolderPath(
@@ -324,17 +319,16 @@ type
   // DLL: Shell32.dll (version 6.0.6000 or later)
   // OS: Windows Vista / Server 2008 and newer
   TSHGetKnownFolderPathW = function(const rfid: KNOWNFOLDERID; dwFlags: DWORD;
-    hToken: THandle; out ppszPath: PWSTR): HRESULT; stdcall;
-
-const
-  SSHGetFolderPathW = 'SHGetFolderPathW';
-  SSHGetKnownFolderPathW = 'SHGetKnownFolderPath';
-  SLibName = 'shell32.dll';
+    hToken: THandle; out ppszPath: LPWSTR): HRESULT; stdcall;
 
 var
   _SHGetFolderPathW : TSHGetFolderPathW = nil;
   _SHGetKnownFolderPathW: TSHGetKnownFolderPathW = nil;
-  DLLHandle: THandle = 0;
+  // CoTaskMemFree is required for the use of SHGetKnownFolderPath function.
+  // CoTaskMemFree function signature was copied from ActiveX unit.
+  _CoTaskMemFree: procedure(_para1:PVOID); stdcall; = nil;
+  Shell32DLLHandle: THandle = 0;
+  Ole32DLLHandle: THandle = 0;
 
 {
   Taken from sysutils
@@ -371,36 +365,17 @@ end;
 }
 
 procedure InitDLL;
-var
-  DLLPath: UnicodeString;
-begin
-  if DLLHandle = 0 then
-  begin
-    // Load DLL using a full path, in order to prevent spoofing (Mantis #18185)
-    DLLPath := GetWindowsSystemDirectoryUnicode;
-    if Length(DLLPath) > 0 then
-    begin
-      DLLPath := IncludeTrailingPathDelimiter(DLLPath) + SLibName;
-      DLLHandle := LoadLibraryW(PWideChar(DLLPath));
-      if DLLHandle <> 0 then
-      begin
-        Pointer(_SHGetFolderPathW) := GetProcAddress(DLLHandle, SSHGetFolderPathW);
-        Pointer(_SHGetKnownFolderPathW) := GetProcAddress(DLLHandle, SSHGetKnownFolderPathW);
-      end;
-    end;
-  end;
-  // At least one of SHGetFolderPath or SHGetKnownFolderPath functions is required
-  if (@_SHGetFolderPathW = nil) and (@_SHGetKnownFolderPathW = nil) then
-    runError(6); // raise Exception.Create('Could not locate '+SSHGetFolderPathW+' / '+SSHGetKnownFolderPathW+' functions');
-end;
-
-procedure FinitDLL;
 begin
-  if DLLHandle <> 0 then
-  begin
-    FreeLibrary(DLLHandle);
-    DLLHandle := 0;
-  end;
+  if Shell32DLLHandle <> 0 then
+    exit;
+  { Btw, contrary to Mantis #18185 these DLLs are “Known DLLs” so relative paths won’t check the app folder.
+    (And even if they did, so what: wrong app.exe can be spoofed just as well as wrong shell32.dll). }
+  Shell32DLLHandle := LoadLibraryW('shell32.dll');
+  Pointer(_SHGetFolderPathW) := GetProcAddress(Shell32DLLHandle, 'SHGetFolderPathW');
+  Pointer(_SHGetKnownFolderPathW) := GetProcAddress(Shell32DLLHandle, 'SHGetKnownFolderPath');
+
+  Ole32DLLHandle := LoadLibraryW('ole32.dll');
+  Pointer(_CoTaskMemFree) := GetProcAddress(Ole32DLLHandle, 'CoTaskMemFree');
 end;
 
 function GetWindowsSystemDirectoryUnicode: UnicodeString;
@@ -408,13 +383,12 @@ var
   Buffer: array [0..MAX_PATH] of WideChar;
   CharCount: Integer;
 begin
-  CharCount := GetSystemDirectoryW(@Buffer[0], MAX_PATH);
+  CharCount := GetSystemDirectoryW(@Buffer[0], Length(Buffer));
   // CharCount is length in TCHARs not including the terminating null character.
   // If result did not fit, CharCount will be bigger than buffer size.
-  if (CharCount > 0) and (CharCount < MAX_PATH) then
-    Result := StrPas(Buffer)
-  else
-    Result := '';
+  if CharCount > High(Buffer) then
+    CharCount := 0;
+  SetString(Result, PWideChar(Buffer), CharCount);
 end;
 
 function GetWindowsSystemDirectory: String;
@@ -429,29 +403,21 @@ var
 begin
   InitDLL;
   Result := '';
-  if @_SHGetFolderPathW = nil then
-  begin
-    if ConvertCSIDLtoFOLDERID(ID, FOLDERID) then
-      Result := GetWindowsSpecialDirUnicode(FOLDERID, CreateIfNotExists);
-  end
-  else
-  begin
-    if CreateIfNotExists then
-      ID := ID or CSIDL_FLAG_CREATE;
-    if _SHGetFolderPathW(0, ID, 0, 0, @Buffer[0]) = S_OK then
-      Result := IncludeTrailingPathDelimiter(StrPas(Buffer));
-  end;
+  if CreateIfNotExists then
+    ID := ID or CSIDL_FLAG_CREATE;
+  if _SHGetFolderPathW(0, ID, 0, 0, @Buffer[0]) = S_OK then
+    Result := IncludeTrailingPathDelimiter(StrPas(Buffer));
 end;
 
 function GetWindowsSpecialDirUnicode(const GUID: TGUID; CreateIfNotExists: Boolean = True): UnicodeString;
 var
   Flags: DWORD;
-  Path: PWSTR;
+  Path: LPWSTR;
   CSIDL: Integer;
 begin
   InitDLL;
   Result := '';
-  if @_SHGetKnownFolderPathW = nil then
+  if _SHGetKnownFolderPathW = nil then
   begin
     if ConvertFOLDERIDtoCSIDL(GUID, CSIDL) then
       Result := GetWindowsSpecialDirUnicode(CSIDL, CreateIfNotExists);
@@ -465,7 +431,7 @@ begin
     if _SHGetKnownFolderPathW(GUID, Flags, 0, Path) = S_OK then
     begin
       Result := StrPas(Path);
-      CoTaskMemFree(Path);
+      _CoTaskMemFree(Path);
     end;
   end;
 end;
@@ -486,19 +452,11 @@ var
 begin
   Result := False;
   for I := Low(CSIDLtoFOLDERID) to High(CSIDLtoFOLDERID) do
-  begin
     if CSIDLtoFOLDERID[I].CSIDL = CSIDL then
     begin
-      if CSIDLtoFOLDERID[I].FOLDERID <> nil then
-      begin
-        FOLDERID := CSIDLtoFOLDERID[I].FOLDERID^;
-        Result := True;
-        Break;
-      end
-      else
-        Break;
+      FOLDERID := CSIDLtoFOLDERID[I].FOLDERID^;
+      Exit(True);
     end;
-  end;
 end;
 
 function ConvertFOLDERIDtoCSIDL(const FOLDERID: TGUID; out CSIDL: Integer): Boolean;
@@ -507,21 +465,18 @@ var
 begin
   Result := False;
   for I := Low(CSIDLtoFOLDERID) to High(CSIDLtoFOLDERID) do
-  begin
-    if CSIDLtoFOLDERID[I].FOLDERID <> nil then
+    if IsEqualGUID(CSIDLtoFOLDERID[I].FOLDERID^, FOLDERID) then
     begin
-      if IsEqualGUID(CSIDLtoFOLDERID[I].FOLDERID^, FOLDERID) then
-      begin
-        CSIDL := CSIDLtoFOLDERID[I].CSIDL;
-        Result := True;
-        Break;
-      end;
+      CSIDL := CSIDLtoFOLDERID[I].CSIDL;
+      Exit(True);
     end;
-  end;
 end;
 
 finalization
-  FinitDLL;
+  if Shell32DLLHandle <> 0 then
+    FreeLibrary(Shell32DLLHandle);
+  if Ole32DLLHandle <> 0 then
+    FreeLibrary(Ole32DLLHandle);
 
 end.