AppData / Similar for all OS : C++? - c++

I'm looking to store some "preferences" for my C++ application.
Under windows I know I have to use the "AppData" folder, but I need the equivalent for Linux and OsX.
Is there some library or portable way to get such information in C++ ?
Here is the code I use currently:
#ifdef VD_OS_WINDOWS
LPWSTR wszPath = NULL;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &wszPath);
_bstr_t bstrPath(wszPath);
std::string strPath((char*)bstrPath);
CoTaskMemFree(wszPath);
return strPath;
#else
char* path = getenv("XDG_CONFIG_HOME");
if (!path)
getenv("HOME") + ".local/share";
return string(path);
#endif
Thanks

If you happen to write a Qt application, there is the QSettings Class. The documentation says the following about this class:
The QSettings class provides persistent platform-independent application settings.
Users normally expect an application to remember its settings (window sizes and positions, options, etc.) across sessions. This information is often stored in the system registry on Windows, and in XML preferences files on Mac OS X. On Unix systems, in the absence of a standard, many applications (including the KDE applications) use INI text files.
This delivers IMHO the best "out-of-the-box" experience. And it's really platform independent.
An alternative would be boost::program_options or boost::property_tree. But the aim of these libraries is the data handling, not so much the storage. This means you would still need to detect the platform, and store the data in the correct location.

Historically on Linux the program stores its configuration data in a hidden file or folder (one beginning with a dot .) in the $HOME directory.
So something like:
$HOME/.my_prog_data.conf
or
$HOME/.my_prog_data/config.conf
In a more recent effort to clean up the $HOME directory nowadays programs tend to either use $HOME/.config or $HOME/.local/share rather than $HOME itself.

Related

Best way to clean up `QSettings` registry entries (Qt 5 on Windows)

Qt stores QSettings values in the windows registry: https://doc.qt.io/qt-5/qsettings.html
Users normally expect an application to remember its settings (window sizes and positions, options, etc.) across sessions. This information is often stored in the system registry on Windows, and in property list files on macOS and iOS. On Unix systems, in the absence of a standard, many applications (including the KDE applications) use INI text files.
I wish to delete those entries if I un-install my Qt App. Is there an easy way to do this, without explicitly deleting all values. I am asking about a Qt function to delete all values for my particular application.
If you initialise the QSettings object with the company and application name or using the default constructor, you can use the method clear()
Example:
QSettings settings;
settings.clear();
Alternatively, you can also try:
QSettings settings(QSettings::SystemScope, "Org", "App");
settings.clear();

GetOpenFileName open at default directory 'Computer' possible?

I'm using GetOpenFileName to open files in C++, is it possible to set the initial dir at "Computer" virtual location with lpstrInitialDir?
Thanks,
Lee.
This is not possible with GetOpenFileName because the location you wish to use is not part of the file system. Rather it is part of the wider shell namespace.
If you look at the documentation for GetOpenFileName you will see that it has been superseded (over 10 years ago in fact) by the Common Item Dialogs. Those dialogs do allow you to specify the initial folder as a shell item.
If you need to support legacy Windows older than Vista, where IFileDialog is not available, try specifying a Shell folder GUID. For example, the My Computer GUID is 20D04FE0-3AEA-1069-A2D8-08002B30309D. You can specify it like this:
ofn.lpstrInitialDir = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
However, it is worth noting that this method is almost doomed to fail on Windows 7 and later, due to behavioral changes
So, you are better off using IFileDialog on Vista and later instead.

Do Windows Shell APIs work with long Unicode paths?

I can't seem to find the answer to this in MSDN. I'm curious, if I have something like this:
LPITEMIDLIST pidl = NULL;
HRESULT hr = SHParseDisplayName(L"\\\\?\\C:\\Users\\Name\\Folder", NULL, &pidl, 0, NULL);
It fails with HRESULT set to E_INVALIDARG. The issue goes away if I supply the path as "C:\\Users\\Name\\Folder", which is limited only to MAX_PATH characters.
Are those Shell APIs not compatible with long Unicode paths?
Typically no, it is not supported. \\?\ is a feature of the lower level file I/O API, not the higher level Shell API. \\?\ does not represent a Shell namespace.
Update: For something like parsing a long file path into a PIDL, you may need to manually divide the path string into its individual pieces and use IShellFolder directly to parse each one into parent/child PIDLs recursively as needed. If nothing else, that will help you identify which subfolder breaks the parsing, then you can report that to the user: "sorry, Windows path length limitation reached, cannot work with files/folder underneath path XXX".
No, the Shell API functions are (in general) not compatible with long Unicode paths.
E.g. in the documentation of the inverse function of SHParseDisplayName, namely SHGetPathFromIDList, you find
pszPath [out]
Type: LPTSTR
The address of a buffer to receive the file system path. This buffer must be at least MAX_PATH characters in size.
And in general the documentation notes this path length restriction for each relevant function, but AFAICS it's not there as a higher level overall general statement.
From a development point of view it's only reasonable to create >MAX_PATH paths, or e.g. paths involving reserved names such as CON, if they will not be handled by an ordinary end-user, because Windows Explorer refuses to handle them.
(I checked just now. Windows 8.1 Explorer refuses silently to delete a folder named con. I think it should, because an ordinary end user will find it difficult to remove it.)
A power user can work around the shell's path length limitation, in order to e.g. delete or rename, by leveraging some bugs in the command interpreter, by using subst drives, by using DOS shortnames, by writing programs that call the API functions, and possibly other techniques (hopefully not by disk editing). But to the average end user such techniques are unknown. So when the average end user gets some undesired >MAX_PATH path, then that user is stuck with it.

C++ / Qt: track filesystem changes

I'm currently trying to implement a c++ program which monitors a folder on the filesystem. On initalizing the application, it scans the Directory and saves some meta information about it.
when something is chenged while the program is active, i can read changes to the folder (for examlpe changing the name of a folder or a file). But i can't track changes to the Directory while the program isn't running. Upon startup i would get
Removed folder X
Added folder Y
instead of
Renamed folder X to Y
is it possible to identify a directory in another way than it's path/name?
if yes, how would i gather that information in C++ / Qt ?
Rather than reinventing the wheel, you could just use the class QFileSystemWatcher which the Qt docs states: -
The QFileSystemWatcher class provides an interface for monitoring
files and directories for modifications
If you want the program to run all the time, then you may want to look at creating a service (in Windows) or daemon (Linux / OSX).
This is filesystem-specific, but generally yes this is possible. FAT is the main exception, I think. But you won't find code for this in the C++ Standard Library or Qt. It's just too unusual, so you'll need OS-specific code if not filesystem-specific.
Like TheDarkNight said, you need to use QFileSystemWatcher to avoid portability and so other problem.
But if you want to continue your approach:
In GNU/Linux land, you can check this with inode struct of directory (take care of symbolic link issue).
inode struct have an index for example you can get it on shell with:
ls -id /path/to/your/folder
There is an API to access inode. You can google inode struct linux for it.
In Windows garden, you can get file id when accessing handle in the struct BY_HANDLE_FILE_INFORMATION:
nFileIndexHigh
The high-order part of a unique identifier that is associated with a file.
For more information, see nFileIndexLow.
nFileIndexLow
The low-order part of a unique identifier that is associated with a file.

How to embed data in an application

I want to make an application, but the application will be using icons (bitmaps) for some of the menu buttons and other stuff. I want to keep my application as one simple, single standalone exe file which means I will somehow have to embed all of the icons into the application (EXE on windows) so I can load the bitmaps without having any external files.
Does anyone know how I can do this?
Just some other info:
I'm using wxWidgets, currently with MSVC and I would prefer a method that works cross compiler/cross platform if possible.
Thanks in advance!
You could used the XPM format for your bitmaps, as it's easy to embed in your code (which of course is going to be in the exe, right where you want it;-). As the docs say,
All wxWidgets platforms support XPMs
for small bitmaps and icons. You may
include the XPM inline as below, since
it's C code, or you can load it at
run-time
(the "as below" being a #include directive) -- so, you would be perfectly cross-compiler and cross-platform by adopting this approach with the "include" option.
For more info about the XPM format, see here. It's easy to find converters to XPM from other popular formats, of course.
Windows does have resource files.You could use that. Alternatively you could write a small utility that will convert your binary icon into a C constant array
eg:
const unsigned int my_icon[] = {0x12345678, 0x87654321, .... };
This could easily be done in perl and you can then access the icon with the variable my_icon.
Cause Linux has no platform solution for this you will have to create your own system anyway. So i would recommand against platform specific ways to add resources on windows and macosx.
You can use reswrap which comes with the FOX GUI Toolkit is a simple tool to convert any binary file into c char literals. If you compile with msvc you will soon find that large files with lot of large strings are poison for the compiler. I added about 900 icons for my project and it killed the compiler.
I currently work with a solution where i simply copy a binary archive at the end of the executable. Every platform today can give you the executable path and neither ELF, EXE or Mach-O files care if additional data is added at the end of an executable file.
We use this technique in our projects:
Use optipng ./image.png to optimize your png file.
Convert your binary image data to a text using png2wx Perl script.
Embed your image into the source code this way:
{
wxMemoryInputStream sm("\211PNG\r\n\032\n\000\000....", 116);
m_bitmap = wxBitmap( wxImage(sm) );
}
Do not forget to add the support for the PNG format in your wxApp::OnInit() function:
wxImage::AddHandler(new wxPNGHandler);
Here is the link to original tutorial.
Hope this will help!