C++ - QSettings question - c++

Does Qt has something like QSettings, but for local scopes?
I am seeking for a data structure with the same methods, but not specific for APPLICATION.
I mean, I want to construct local (for example, exporting settings) settings from file (xml, for example) and use them in local scope - without polluting global application settings.
Is that possible (with QSettings or some other class)? How should I construct the object then?

You can use
void QSettings::setPath ( Format format, Scope scope, const QString & path )
to set the format (as specified in the doc)
QSettings::NativeFormat 0 Store the
settings using the most appropriate
storage format for the platform. On
Windows, this means the system
registry; on Mac OS X, this means the
CFPreferences API; on Unix, this means
textual configuration files in INI
format.
QSettings::IniFormat 1 Store the
settings in INI files.
QSettings::InvalidFormat
the scope:
QSettings::UserScope 0 Store settings
in a location specific to the current
user (e.g., in the user's home
directory).
QSettings::SystemScope 1 Store
settings in a global location, so that
all users on the same machine access
the same set of settings.
So if you are on Windows and want to write User-specific settings, you would use the IniFormat and the UserScope values and specify the path where you want to write your settings in the path variable.
Hope this helps.

You create a datastream and write the data into the file in member by member fashion.

Related

How to get a settings storage path in a cross-platform way in Qt?

My program needs to read/write a text (just a few lines) file with its settings to disk. To specify a path in code may work well on one platform, like windows, but if runs it on Linux, the path is not cross platform.
I am looking for a similar solution to QSettings that saves settings to different paths or has its native ways to handle this. Programmers don't need to do with the details. But the text file is not suitable to be saved as a value in QSettings.
No user interaction should be needed to obtain such path. The text file should persist across application restarts. It can't be a temporary file.
Is there an existing solution in Qt and what is the API that should be used?
The location of application-specific settings storage differs across platforms. Qt 5 provides a sensible solution via QStandardPaths.
Generally, you'd store per-user settings in QStandardPaths::writableLocation(QStandardPaths::AppDataLocation). If you wish the settings not to persist in the user's roaming profile on Windows, you can use QStandardPaths::AppLocalDataLocation, it has the meaning of AppDataLocation on non-Windows platforms.
Before you can use the standard paths, you must set your application name via QCoreApplication::setApplicationName, and your organization's name using setOrganizationName or setOrganizationDomain. The path will depend on these, so make sure they are unique for you. If you ever change them, you'll lose access to old settings, so make sure you stick with name and domain that makes sense for you.
The path is not guaranteed to exist. If it doesn't, you must create it yourself, e.g. using QDir::mkpath.
int main(int argc, char ** argv) {
QApplication app{argc, argv};
app.setOrganizationDomain("stackoverflow.com");
app.setApplicationName("Q32525196.A32535544");
auto path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (path.isEmpty()) qFatal("Cannot determine settings storage location");
QDir d{path};
if (d.mkpath(d.absolutePath()) && QDir::setCurrentPath(d.absolutePath())) {
qDebug() << "settings in" << QDir::currentPath();
QFile f{"settings.txt"};
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate))
f.write("Hello, World");
}
}
If you want to save some user related data, you can get user home directory path using QDir::homePath().
There is QDir to handle paths to dirs, QFileInfo for platform independent file information and QDir's homePath()
My proposal is to use these classes and use QDir::home() or QDir::homePath() to find a directory where to write to, since the user has write permissions in his homedir and it exists on each platform.
You can store file in application directory. Take a look at QCoreApplication::applicationDirPath().
From Qt documentation:
Returns the directory that contains the application executable.

WinRT Create File at Customized Path

I am writing some code to create a file from a Windows 8 app in an standard way, the code looks like below:
using namespace Windows::Storage;
StorageFolder^ folder = KnownFolders::DocumentsLibrary;
String ^filename = ref new String(L"file.txt");
auto createFile = folder->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting);
concurrency::create_task(createFile).wait;
Now instead of using DocumentsLibrary, I want to write thid file to an customized file path, like:
C:\Users\<username>\AppData\Local\ExampleApp\ExampleFolder
How should I change the code to be able to do this? Thanks!
WinRT can only access a few folders. You have a few standard libraries like Pictures, Music, etc (Documents requires elevated rights) and you have the application data folders that you can find under \AppData\Local\Packages\yourpackage.
Inside of this package folder you have two main folders to store data: LocalState and RoamingState. As the names convey: the former is to store data locally while the latter will synchronize its contents whenever possible (according to the rules you define).
You can access these folders using the C++ equivalent of Windows.Storage.ApplicationData.Current.LocalFolder and Windows.Storage.ApplicationData.Current.RoamingFolder.
What you can do though is request explicit access through a FilePicker but this will prompt the user a window where he should target the directory himself.

Save file settings in ini instead of registry

I'm new to MFC, once I create my first app, in myApp::InitInstance() . I have
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
Can I delete this and save settings to my own ini construct ?
Edit: After further testing, the solution below does not work if your app class is derived from CWinAppEx ! It does work if your app is directly derived from CWinApp.
To store values in an .ini file instead of the registry:
Omit the call to SetRegistryKey.
In your app class, set m_pszProfileName to the full path of your .ini file. The filename string must be allocated using malloc, because the framework will call free on it when your app shuts down. First free the existing value, then assign your new string:
free((void*)m_pszProfileName);
m_pszProfileName = ::_tcsdup(_T("C:\\somedir\\myini.ini"));
Call CWinApp::GetProfileInt, CWinApp::WriteProfileInt and similar functions as usual.
I strongly recommend using a path under APPDATA for storing your .ini file.
Yes you can. CWinApp::SetProfileXXX() does this for you, actually - but I wouldn't use these methods anymore in 2010, they were OK when ppl moved from .ini to the registry.
I am not sure if this is possible as a .ini file has only strings for your program. You can create an operating system script (.bat for windows, .sh for unix etc) and call it using system() call.
Use win32 APIs WriteProfileString (write to INI file) and GetProfileString (read from INI file)
For more help
ms-help://MS.MSDNQTR.v90.en/sysinfo/base/writeprofilestring.htm

Create registry entry to associate file extension with application in C++

I would like to know the cleanest way of registering a file extension with my C++ application so that when a data file associated with my program is double clicked, the application is opened and the filename is passed as a parameter to the application.
Currently, I do this through my wix installer, but there are some instances where the application will not be installed on ths user's computer, so I also need the option of creating the registry key through the application.
Additionally, will this also mean that if the application is removed, unused entries in the registry will be left lying around?
Your basic overview of the process is found in this MSDN article. The key parts are at the bottom of the list:
Register the ProgID
A ProgID (essentially, the file type registry key) is what contains your important file type properties, such as icon, description, and context menu items including applications used when the file is double clicked. Many extensions may have the same file type. That mapping is done in the next step:
Register the file name extension for the file type
Here, you set a registry value for your extension, setting that extension's file type to the ProgID you created in the previous step.
The minimum amount of work required to get a file to open with your application is setting/creating two registry keys. In this example .reg file, I create a file type (blergcorp.blergapp.v1) and associate a file extension (.blerg) with it.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command]
#="c:\path\to\app.exe \"%1\""
[HKEY_CURRENT_USER\Software\Classes\.blerg]
#="blergcorp.blergapp.v1"
Now, you probably want to accomplish this programmatically. To be absolutely kosher, you could check for the existence of these keys, and change your program behavior accordingly, especially if you're assuming control of some common file extension. However, the goal can be accomplished by setting those two keys using the SetValue function.
I'm not positive of the exact C++ syntax, but in C# the syntax looks something like this:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command", null, #"c:\path\to\app.exe \"%1\"");
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\.blerg", null, "blergcorp.blergapp.v1");
Of course you could manually open each sub key, manually create the ProgID and extension subkey, and then set the key value, but a nice thing about the SetValue function is that if the keys or values don't exist, they will automatically be created. Very handy.
Now, a quick word about which hive to use. Many file association examples online, including ones on MSDN, show these keys being set in HKEY_CLASSES_ROOT. I don't recommend doing this. That hive is a merged, virtual view of HKEY_LOCAL_MACHINE\Software\Classes (the system defaults) and HKEY_CURRENT_USER\Software\Classes (the per-user settings), and writes to any subkey in the hive are redirected to the same key in HKEY_LOCAL_MACHINE\Software\Classes. Now, there's no direct problem doing this, but you may run into this issue: If you write to HKCR (redirected to HKLM), and the user has specified the same keys with different values in HKCU, the HKCU values will take precedence. Therefore, your writes will succeed but you won't see any change, because HKEY_CURRENT_USER settings take precedence over HKEY_LOCAL_MACHINE settings.
Therefore, you should take this into consideration when designing your application. Now, on the flip side, you can write to only HKEY_CURRENT_USER, as my examples here show. However, that file association setting will only be loaded for the current user, and if your application has been installed for all users, your application won't launch when that other user opens the file in Windows.
That should be a decent primer for what you want to do. For further reading I suggest
Best Practices for File Association
File Types and File Association, especially
How File Associations Work
And see also my similar answer to a similar question:
Associating file extensions with a program
This is a two step process:
1. Define a program that would take care of extension: (unless you want to use existing one)
1.1 create a key in "HKCU\\Software\\Classes\\" for example
"Software\\Classes\\YourProgramName.file.ext"
1.2 create subkey "Software\\Classes\\YourProgramName.file.ext\\DefaultIcon"
1.2.1 set default value ("") to your application full path to get
icon from resources
1.3 create a subkey "Software\\Classes\\YourProgramName.file.ext\\Shell\\OperationName\\Command"
OperationName = for example Open, Print or Other
1.3.1 set default value ("") to your application full path +optional runtime params (filename)
2.Associate file extension with program.
2.1 create a key HKCU\\Software\\Classes\\.ext - here goes your extension
2.2 set default value to the program definition key
("YourProgramName.file.ext")
Below is part of the program written in c# which associate file extension. It is not c++ but i think it is simple enought to explain itself and AFAIK it is verv simmilar if not identical to the code in c++
1.
RegistryKey keyPFCTExt0 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc", true);
if (keyPFCTExt0 == null)
{
keyPFCTExt0 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc");
keyPFCTExt0.CreateSubKey("DefaultIcon");
RegistryKey keyPFCTExt0ext = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\DefaultIcon", true);
keyPFCTExt0ext.SetValue("", Application.ExecutablePath +",0");
keyPFCTExt0ext.Close();
keyPFCTExt0.CreateSubKey("Shell\\PFCT_Decrypt\\Command");
}
keyPFCTExt0.SetValue("", "PFCT.file.enc");
keyPFCTExt0.Close();
2.
RegistryKey keyPFCTExt1 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command", true);
if (keyPFCTExt1 == null)
keyPFCTExt1 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command");
keyPFCTExt1.SetValue("", Application.ExecutablePath + " !d %1"); //!d %1 are optional params, here !d string and full file path
keyPFCTExt1.Close();
I don't know why people keep saying that HKEY_CURRENT_USER\Software\Classes\<.ext>'s Default value (which will redirect you into another (software-created) class.
It does work, but it will be overridden by
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\<.ext>\UserChoice
And I believe Microsoft recommends the second practice- because it's what the built-in "open with" is doing. The value of Progid" key is equal to default value of HKEY_CURRENT_USER\Software\Classes\<.ext> in this case.
I found the following while trying to manipulate associations using C#:
hkcu\software\microsoft\windows\currentVersion\explorer\fileexts.reg\userchoice -> for user specific settings. The values in the openWithProgIds
key point to the keys in the hkcr.
hkcr\xfile\shell\open\muiVerb value or hkcr\xfile\shell\open\command\default value -> affects open handler. This is the value that contains the path to a program.
hkcr\ .x -> affects context menu (new x) among other things related to the menus.
I don't know the C++ code, but given these info you must be able to manipulate the registry using the registry API.

Qt4.4 how to get the user settings path

linux: $HOME/.config
windows: %APPDATA%
mac os: $HOME/.config
It can be set using http://qt-project.org/doc/qt-4.8/qsettings.html#setPath, but it seems as I am not able to retrieve it.
http://qt-project.org/doc/qt-4.8/qlibraryinfo.html#location QLibraryInfo::LibrariesPath returns the system wide settings dir, which is not what I want.
Any ideas, or do I have to code it separately for each platform?
€: I want to create a sub directory, and store files into it. (You may punish me if this is a bad idea)
This might not answer your question directly: if you want to store per-user persistent data, shouldn't you use QDesktopServices::storageLocation(QDesktopServices::DataLocation) instead?
This is a nasty workaround. First you create QSettings, then get its location.
QSettings cfg(QSettings::IniFormat, QSettings::UserScope,
"organization", "application");
QString config_dir = QFileInfo(cfg.fileName()).absolutePath() + "/";
Credits go to the Qt Centre forum.
QSettings stores the default config in the user AppData directory. See documentation for QSettings. Also this code instructs to store the config in the Ini file format.
this works on both qt 4 and qt 5
QApplication::setApplicationName("MyApp");
QApplication::setOrganizationName("Me");
QString homePath;
#if QT_VERSION >= 0x050000
homePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
#else
homePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
#endif
Why do you need to know the settings path? If you are going to put settings in it, you could use QSettings. I could see making a subdirectory to hold various settings, but it seems like the easiest way would be to use QSettings directly.
As far as I can tell, you can't retrieve the path. In the Qt source, src/corelib/io/qsettings.cpp, there is a function to get the path:
static QString getPath(QSettings::Format format, QSettings::Scope scope)
{
...
but it's not accessible from code using Qt. You can't copy it and use it either, because it uses internal Qt globals to store the path...
EDIT: A solution was posted, using QDesktopServices.storageLocation(QDesktopServices.DataLocation) but it doesn't do exactly what the question was asking for, i.e. if I set a custom path using QSettings.setPath() it doesn't reflect the change.
What platform are you at?
Might be related or not but in windows, the default is to write QSettings to the registry.
I read more into the question than there was as it was originally posted. It is clearer after the edits. Ok, so can't you use..
QString QSettings::fileName () const
Returns the path where settings are written to using this QSettings object are stored.
On Windows, if the format is QSettings::NativeFormat, the return value is a system registry path, not a file path.