Windows: use SHGetFolderPathW() for application data folder (#710)
See GitHub issue #710: "Fl_Preferences not stored on Windows 10" Summary: don't use the undocumented registry key "Shell Folders", use function SHGetFolderPathW() instead although this function is meanwhile deprecated (but available since Windows XP). Note: tested with 32-bit build running on Windows XP (works).
This commit is contained in:
parent
6aa6866d80
commit
5a4e7caa54
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Definition of Windows system driver for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2022 by Bill Spitzak and others.
|
||||
// Copyright 1998-2023 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
@ -39,6 +39,7 @@
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
// function pointer for the UuidCreate Function
|
||||
// RPC_STATUS RPC_ENTRY UuidCreate(UUID __RPC_FAR *Uuid);
|
||||
@ -845,72 +846,41 @@ void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer)
|
||||
char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, const char *vendor,
|
||||
const char *application)
|
||||
{
|
||||
# define FLPREFS_RESOURCE "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
|
||||
# define FLPREFS_RESOURCEW L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
|
||||
static char *filename = 0L;
|
||||
// make enough room for a UTF16 pathname
|
||||
if (!filename) filename = (char*)::malloc(2*FL_PATH_MAX);
|
||||
filename[0] = 0;
|
||||
filename[1] = 0;
|
||||
size_t appDataLen = strlen(vendor) + strlen(application) + 8;
|
||||
DWORD nn;
|
||||
LONG err;
|
||||
HKEY key;
|
||||
// make enough room for a UTF-16 pathname
|
||||
if (!filename) filename = (char*)::malloc(2 * FL_PATH_MAX);
|
||||
HRESULT res;
|
||||
|
||||
switch (root&Fl_Preferences::ROOT_MASK) {
|
||||
case Fl_Preferences::SYSTEM:
|
||||
err = RegOpenKeyW( HKEY_LOCAL_MACHINE, FLPREFS_RESOURCEW, &key );
|
||||
if (err == ERROR_SUCCESS) {
|
||||
nn = (DWORD) (FL_PATH_MAX - appDataLen);
|
||||
err = RegQueryValueExW( key, L"Common AppData", 0L, 0L,
|
||||
(BYTE*)filename, &nn );
|
||||
if ( err != ERROR_SUCCESS ) {
|
||||
filename[0] = 0;
|
||||
filename[1] = 0;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
break;
|
||||
case Fl_Preferences::USER:
|
||||
err = RegOpenKeyW( HKEY_CURRENT_USER, FLPREFS_RESOURCEW, &key );
|
||||
if (err == ERROR_SUCCESS) {
|
||||
nn = (DWORD) (FL_PATH_MAX - appDataLen);
|
||||
err = RegQueryValueExW( key, L"AppData", 0L,0L,
|
||||
(BYTE*)filename, &nn );
|
||||
if ( err != ERROR_SUCCESS ) {
|
||||
filename[0] = 0;
|
||||
filename[1] = 0;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!filename[1] && !filename[0]) {
|
||||
// Don't write data into some arbitrary directory! Just return NULL.
|
||||
//strcpy(filename, "C:\\FLTK");
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw
|
||||
|
||||
int appdata = CSIDL_APPDATA; // assume user preferences
|
||||
if ((root & Fl_Preferences::ROOT_MASK) == Fl_Preferences::SYSTEM)
|
||||
appdata = CSIDL_COMMON_APPDATA; // use system preferences
|
||||
|
||||
res = SHGetFolderPathW(NULL, // hwnd: Reserved!
|
||||
appdata, // csidl: User or common Application Data (Roaming)
|
||||
NULL, // hToken (unused)
|
||||
SHGFP_TYPE_CURRENT, // dwFlags: use current, potentially redirected path
|
||||
(LPWSTR)filename); // out: filename in Windows wide string encoding
|
||||
if (res != S_OK) {
|
||||
// don't write data into some arbitrary directory! Just return NULL.
|
||||
return 0L;
|
||||
} else {
|
||||
#if 0
|
||||
wchar_t *b = (wchar_t*)_wcsdup((wchar_t *)filename);
|
||||
#else
|
||||
// cygwin does not come with _wcsdup. Use malloc + wcscpy.
|
||||
// For implementation of wcsdup functionality See
|
||||
// - http://linenum.info/p/glibc/2.7/wcsmbs/wcsdup.c
|
||||
wchar_t *b = (wchar_t *)malloc((wcslen((wchar_t *)filename) + 1) * sizeof(wchar_t));
|
||||
wcscpy(b, (wchar_t *) filename);
|
||||
#endif
|
||||
// filename[fl_unicode2utf(b, wcslen((wchar_t*)b), filename)] = 0;
|
||||
unsigned len = fl_utf8fromwc(filename, (FL_PATH_MAX-1), b, (unsigned) wcslen(b));
|
||||
filename[len] = 0;
|
||||
free(b);
|
||||
}
|
||||
|
||||
// convert the path from Windows wide character (UTF-16) to UTF-8
|
||||
// FIXME: can this be simplified? Don't allocate/copy/move/free more than necessary!
|
||||
char *buf = NULL;
|
||||
wchar_to_utf8((wchar_t *)filename, buf); // allocates buf for conversion
|
||||
strcpy(filename, buf);
|
||||
free(buf);
|
||||
|
||||
// Make sure that the parameters are not NULL
|
||||
if ( (vendor==0L) || (vendor[0]==0) )
|
||||
vendor = "unknown";
|
||||
if ( (application==0L) || (application[0]==0) )
|
||||
application = "unknown";
|
||||
|
||||
// append vendor, application, and ".prefs", and convert '\' to '/'
|
||||
snprintf(filename + strlen(filename), FL_PATH_MAX - strlen(filename),
|
||||
"/%s/%s.prefs", vendor, application);
|
||||
for (char *s = filename; *s; s++) if (*s == '\\') *s = '/';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user