I am trying to make a windows application. In this application, some files get modified as a user add or delete an entry. I saved these files on the application folder itself.
But After making binary file I installed it, As I try to add a entry it get crashed.
So, I figured out the issue. The windows doesn't allow to modified files inside C:\Program Files.
So, I installed it in other drive and it works. It solved my issue temporarily but I want to know how other application works in windows.
Where do those applications save their data?
I am not talking about some data which get saved in "Documents" but something which is essential need to modified every time user makes change like theme, formates.
No user access is allowed to the "program folder", and that's for good: it is a system folder, and it should only be accessed for system related operations (like installing or uninstalling a program).
There are many places where "program data" can be stored depending on the situation, and QStandardPaths provides access to their paths, according to the category location. What you might be interested in are:
ConfigLocation: Returns a directory location where user-specific configuration files should be written. This may be either a generic value or application-specific, and the returned path is never empty.
AppDataLocation: Returns a directory location where persistent application data can be stored. This is an application-specific directory.
AppLocalDataLocation: As the previous one, but Windows specific.
AppConfigLocation: Returns a directory location where user-specific configuration files should be written. This is an application-specific directory, and the returned path is never empty.
Those paths (along with the others listed in the documentation) can be accessed using the following static methods:
standardLocations(locationType): returns a list of paths for the requested location type, in order of priority (the first is usually the preferred one);
writableLocation(locationType): returns the preferred path for which write access is allowed (usually the first of the standardLocations());
If you need to store the user configuration, you can use QStandardPaths.writableLocation(AppConfigLocation), while if you have some user-specific internal data that is used by the application (email database, document templates, etc) QStandardPaths.writableLocation(AppLocalDataLocation) should be a good choice.
In both cases, those paths may not exist, so you need to ensure that and eventually create them, possibly by using QDir(path):
dataPath = QtCore.QStandardPaths.writableLocation(AppLocalDataLocation)
dataPathDir = QtCore.QDir(dataPath)
if not dataPathDir.exists():
# create the directory (including parent directories if they don't exist);
# that the argument of mkpath is relative to the QDir's object path, so
# using '.' means that it will create the actual dataPath
dataPathDir.mkpath('.')
Note that for all of the above (especially the last 3) it's required that you correctly set both the organizationName and the applicationName.
Related
I'm developing a Windows application that targets Windows XP.
My app needs to resolve symbolic links to files and folders. To check whether the target exists, I can use CreateFile for symbolic links to files. But after I searched Google and MSDN for a whole day, I found that if I need to get the handle of a directory, I need to use the flag FILE_FLAG_BACKUP_SEMANTICS. This requires my application to request higher privileges. I know many users are not happy with this behavior, so I need to find another way to check whether the target of a directory symbolic link exists.
I have also read Symbolic Link Effects on File Systems Functions. The other functions I can use to test for the existence of a file or directory all check the symbolic link itself, not its target. I have tried some functions like _access_s. They also only check the symbolic link itself.
So my question is whether there is any way to check whether the target of a directory symbolic link exists without requiring higher privileges.
I could use CreateFile for symbolic file to get the file handle and
then check the file is exist or not.
If FILE_FLAG_OPEN_REPARSE_POINT is not specified in call CreateFile and you get file handle this mean that symbolic link/mount point target is exist. so already not need check something. if call fail because target not exist last error will be ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND (may be also ERROR_BAD_PATHNAME)
about FILE_FLAG_BACKUP_SEMANTICS - this is very bad design of CreateFile api. this api internal call NtCreateFile. the FILE_FLAG_BACKUP_SEMANTICS mapped to FILE_OPEN_FOR_BACKUP_INTENT CreateOptions flag. this flag checked inside IopCheckBackupRestorePrivilege
This function will determine if the caller is asking for any accesses
that may be satisfied by Backup or Restore privileges, and if so,
perform the privilege checks. If the privilege checks succeed, then
the appropriate bits will be moved out of the RemainingDesiredAccess
field in the AccessState structure and placed into the
PreviouslyGrantedAccess field.
Note that access is not denied if the caller does not have either or both of the privileges, since he may be granted the desired access via
the security descriptor on the object.
so even if caller have not either or both of the Backup or Restore privileges this not create problems.
but NtCreateFile have the next 2 options: FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE - this let specify are we want create/open file or directory. if we (potential) create new item - we need specify are we want create directory (FILE_DIRECTORY_FILE must be set) or not directory (FILE_NON_DIRECTORY_FILE, but by default assume this case - so optional). when we open file - both this flags is optional - if we not specify both - this mean that we not care are we open file or directory. if we care about this - need specify one of this flags.
but if look to CreateFile visible that not exist option which explicity mapped to FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE. the CreateFile use for this .. FILE_FLAG_BACKUP_SEMANTICS option. this is very not logical from my view, but as is. when FILE_FLAG_BACKUP_SEMANTICS not set CreateFile pass FILE_NON_DIRECTORY_FILE option for NtCreateFile. when it set - pass FILE_OPEN_FOR_BACKUP_INTENT and not pass FILE_NON_DIRECTORY_FILE. this allow you open file or directory. and no option for set FILE_DIRECTORY_FILE - because this CreatrFile can not create new directory.
so instead have separate option for FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE, CreateFile abuse FILE_FLAG_BACKUP_SEMANTICS wich have double sense here
TPath.GetTempFileName (which wraps the WinAPI GetTempFileName) replies "The directory name is invalid" when called from an application run by a user who is logged into a domain.
if they use a login that isn't using the domain, it works.
The customer having a problem is in another country and I am also not familiar with how a domain controller's configuration could be changed to avoid this problem.
I assume that since my application is the one that isn't working correctly, I should be getting a temporary file name in a different way.
"run as administrator" doesn't help.
I have directed them to ensure they have full control over the folders mentioned in the TEMP & TMP system environment variables and apparently they do but it still gives the same error.
My application as a Win32 Delphi desktop application but since Windows is the source of the error, I assume this information to be of limited usefulness.
Windows 10 is the OS.
TPath.GetTempFileName calls TPath.GetTempPath at the very beginning but does not check it before calling Winapi.Windows.GetTempFileName using the returned path.
It is very likely that the call to TPath.GetTempPath returns an empty or invalid path.
MSDN says:
The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
The path specified by the TMP environment variable.
The path specified by the TEMP environment variable.
The path specified by the USERPROFILE environment variable.
The Windows directory.
If it would return the Windows directory, the call wouldn't fail with the said message. So, probably, there is a wrong path in one of those three environment variables.
Your customer should check these variables and validate them, in terms of existence.
You say, that the paths are "apparently" okay.
Experience taught me to doubt what customers say they checked... You could make a call to TPath.GetTempPath on your own before calling TPath.GetTempFileName to check if it exists. Alternatively you can call it in case of failure as part of handling the raised exception and add the path to the error message.
WebStorm (and I assume IntelliJ), caches a lot of information in a directory called .WebstormXX under the user directory in Windows.
The documentation states that the data is saved here :
<SYSTEM DRIVE>\Users\<USER ACCOUNT NAME>\.<PRODUCT><VERSION>
I would like to NOT have this data stored here because my network user space is miniscule compared to what is required for the cache directory.
Can I define my .WebstormXX to be for example directly on my C drive?
In <WebstormLocation>/bin/idea.properties you can find the properties:
idea.config.path=${user.home}/.WebStorm/config
idea.system.path=${user.home}/.WebStorm/system
These are commented out by default and are found at the top of idea.properties; Uncommenting and redefining them is all you need to do.
Ensure you use forward slashes when defining a new directory.
I'm trying to save a CFPropertyList to a location in the user's home folder. Using the code below I'm getting errorCode = -10 (unknown error).
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("~/testfile.txt"), kCFURLPOSIXPathStyle, false );
SInt32 errorCode;
Boolean status = CFURLWriteDataAndPropertiesToResource(fileURL, xmlData, NULL, &errorCode);
If I change the path to something like "/testfile.txt" without the '~' then everything works. How can one save a property list to the current user's home folder? Must one obtain the user's name first and include it in the path such as /users/toffler/testfile.txt?
With Foundation, you can call the NSHomeDirectory function to get the absolute path to the user's home directory. You can then use the path-manipulation methods of NSString or of NSURL, or the equivalent function for CFURL, to tack a sub-path onto that.
However, please don't put files into the top level of my Home folder unless I, as the user, tell you to.
If you want to save a file at the user's request, run a save panel, and then save it where the user told you to.
If you want to save a preferences file, you probably should be using NSUserDefaults or CFPreferences, instead of handling plists yourself.
If you have some other reason to save a user-specific file, it should generally go into either the chewable items folder, the Caches folder, or the Preferences folder. The two functions that I linked to are the easiest ways to access those two of those three folders; the harder way, and the only one that works on all three, is the FSFindFolder function. Unlike most of the Folder Manager, FSFindFolder is not deprecated and is available in 64-bit.
Updates from the year 2012
Nowadays, you should use URLs, not paths. NSFileManager has a method for getting a URL to a desired directory.
Stapling paths (or file URLs) together does not work in a sandboxed application, because you don't have authorization to access the path you just made up. You need to get the path (or URL) from a system API, whether it's NSFileManager, NSSavePanel, or something else.
For saving and restoring file references, use NSURL's security-scoped bookmarks feature.
NSUserDefaults and CFPreferences work as expected in a sandbox.
The Folder Manager is now fully deprecated as of 10.8.
Polluting the user's Home folder is still bad manners.
Automatic ~ expansion is a feature of the shell.
If you are using Cocoa/Foundation, you can use the NSString methods
- (NSString *)stringByAbbreviatingWithTildeInPath;
- (NSString *)stringByExpandingTildeInPath;
otherwise, you'll have to write some code yourself to do this. Getting the user's login name and constructing the path /Users/login-name/ is not the correct way to do this. (While most users will have their home directory here, some will not.)
I used to be able to launch a locally installed helper application by registering a given mime-type in the Windows registry. This enabled me to allow users to be able to click once on a link to the current install of our internal browser application. This worked fine in Internet Explorer 5 (most of the time) and Firefox but now does not work in Internet Explorer 7.
The filename passed to my shell/open/command is not the full physical path to the downloaded install package. The path parameter I am handed by IE is
"C:\Document and Settings\chq-tomc\Local Settings\Temporary Internet Files\
EIPortal_DEV_2_0_5_4[1].expd"
This unfortunately does not resolve to the physical file when calling FileExists() or when attempting to create a TFileStream object.
The physical path is missing the Internet Explorer hidden caching sub-directory for Temporary Internet Files of "Content.IE5\ALBKHO3Q" whose absolute path would be expressed as
"C:\Document and Settings\chq-tomc\Local Settings\Temporary Internet Files\
Content.IE5\ALBKHO3Q\EIPortal_DEV_2_0_5_4[1].expd"
Yes, the sub-directories are randomly generated by IE and that should not be a concern so long as IE passes the full path to my helper application, which it unfortunately is not doing.
Installation of the mime helper application is not a concern. It is installed/updated by a global login script for all 10,000+ users worldwide. The mime helper is only invoked when the user clicks on an internal web page with a link to an installation of our Desktop browser application. That install is served back with a mime-type of "application/x-expeditors". The registration of the ".expd" / "application/x-expeditors" mime-type looks like this.
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.expd]
#="ExpeditorsInstaller"
"Content Type"="application/x-expeditors"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller]
"EditFlags"=hex:00,00,01,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell\open]
#=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell\open\command]
#="\"C:\\projects\\desktop2\\WebInstaller\\WebInstaller.exe\" \"%1\""
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MIME\Database\Content Type\application/x-expeditors]
"Extension"=".expd"
I had considered enumerating all of a user's IE cache entries but I would be concerned with how long it may take to examine them all or that I may end up finding an older cache entry before the current entry I am looking for. However, the bracketed filename suffix "[n]" may be the unique key.
I have tried wininet method GetUrlCacheEntryInfo but that requires the URL, not the virtual path handed over by IE.
My hope is that there is a Shell function that given a virtual path will hand back the physical path.
I believe the sub-directories created by IE are randomly generated, so you won't be able guarantee that it will be named the same every time, and the problem I see with the registry method is that it only works when the file is still in the cache...emptying the cache would purge the file requiring yet another installation.
Would it not be better to install this helper into application data?
I'm not sure about this but perhaps this may lead you in the right direction: try using URL cache functions from the wininet DLL: FindFirstUrlCacheEntry, FindNextUrlCacheEntry, FindCloseUrlCache for enumeration and when you locate an entry whose local file name matches the given path maybe you can use RetrieveUrlCacheEntryFile to retrieve the file.
I am using a similar system with the X-Appl browser to display WAML web applications and it works perfectly. Maybe you should have a look at how they managed to do it.
It looks like iexplore is passing the shell namespace "name" of the file rather than the filesystem name.
I dont think there is a documented way to be passed a shell item id on the command line - explorer does it to itself, but there are marshaling considerations as shell item ids are (pointers to) binary data structures that are only valid in a single process.
What I might try doing is:
1. Call SHGetDesktopFolder which will return the root IShellFolder object of the shell namespace.
2. Call the IShellFolder::ParseDisplayName to turn the name you are given back into a shell item id list.
3. Try the IShellFolder::GetDisplayNameOF with the SHGDN_FORPARSING flag - which, frankly, feels like w'eve just gone in a complete circle and are back where we started. Because I think its this API thats ultimately responsible for returning the "wrong" filesystem relative path.
Some follow-up to close out this question.
Turned out the real issue was how I was creating the file handle using TFileStream. I changed to open with fmOpenRead or fmShareDenyWrite which solved what turned out to be a file locking issue.
srcFile := TFileStream.Create(physicalFilename, fmOpenRead or fmShareDenyWrite);