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.
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.