windowsdelphipermissionsdelphi-10-seattlecreate-directory

Cannot create Folder using System.SYSUTILS.ForceDirectories


More and more users complain that they cannot install/start my application.

What is the problem:

Using System.SYSUTILS.ForceDirectories(...) a directory structure is built consisting of 4 directories, which do not exist in the first place. This happens when the application starts for the first time. On some machines this seems to be impossible, because ForceDirectories() returns False.

I know exactly where the error occurs (the following is just a code snippet):

if ( not TDirectory.Exists(self.TempInstallPath) ) then
begin
    if (System.SYSUTILS.ForceDirectories(self.TempInstallPath)) then
      begin
        uGlobalFiles.DeleteDirectoryContents(self.TempInstallPath, self.GetLoggingFunc());
        if ( not self.copyDatabase(source) ) then
          raise TCopyDatabase_Exception.Create('Database could not be copied to: ' + sLineBreak + self.TempInstallPath);
      end
      else
      begin
        raise TPathCouldNotBeCreated_Exception.Create('adding a new directory failed with error: ' + sLineBreak + SysErrorMessage(GetLastError)
                + sLineBreak
                + 'destination folder: ' + self.TempInstallPath
                + sLineBreak
                + 'local user folder:' + self.LocaluserPath
                + sLineBreak
                + 'session time stamp:' + self.TimeStamp);
      end;
end;

Which path is used:

For good reason I decided on creating the paths and information in the Local AppData folder of the user. I get the value from the registry:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders

What I did so far: So far, I was not able to reproduce the exact error. I tried to take ownership from the user, but that shows a different error. Also messing around with special permissions in that directory - denying "create folder" etc - all to no avail.

Is there anything I am missing or that I can do in those cases?

Help is much appreciated, thanks a lot!

UPDATE1

Now I get the local user folder doing this:

function GetShellFolder(CSIDLFolder : integer) : string;
begin
SetLength(Result, MAX_PATH);
  SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, false);  // (CSIDL_LOCAL_APPDATA -- FOLDERID_LocalAppData)
  SetLength(Result, StrLen(PChar(Result)));
  if (Result <> '') then
    Result  := IncludeTrailingBackslash(Result);
end;

UPDATE2

Since I already used SysErrorMessage(GetLastError), I know the error message, which literally says that there is no error. I also know (from the customer) that the first folder (out of the 4 folders to create) was created as a hidden folder, the others were not created at all. She can create folders using the context menu, though.

UPDATE3

The change mentioned in UPDATE1 resolved the error. Since nothing was stored in the registry:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders

the program tried to write directly into C:\Program Files... (path of executable) where some users do not have permissions to write.

I accepted the solution of Andre Ruebel, but everybody who commented taught me something on the matter. Thanks to everybody.

UPDATE4

To sum it all up. The problem was indeed the way the local user path was extracted. In the case of this specific user, the registry key had no value. Therefore the data was copied to the installation directory, which lies under Program Files...

To make a long story short: The application data needs read/write access which the user is not privileged with, so the error occurred. Thanks again to all the answers, they lead me into the right direction.


Solution

  • use

    var
      P: array [0 .. max_path] of Char;
    begin
      SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, @P[0]);
    end;
    

    to get the Appdata directory. If the forcedirectories function fails, use

    SysErrorMessage(getlasterror)
    

    to get a meaningful error message.