From 0af614e77ba46736f4f875eb202f454fc02fd609 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Tue, 28 Sep 2004 03:55:16 +0000 Subject: [PATCH] - rewrite the transaction system to be based on a settings overlay, to have a nicer API, and to actually work (always a bonus) - change the libraries page to be based on a listbox rather than a treeview, clean up and shrink the code - add accelerator keys to the libraries page, focus management - make the window title reflect what the user is currently editing - remove bogus root warning - remove some unused control IDs in resource.h - start converting the x11drv dialog to kernel_style from javaStyle - bugfixing --- programs/winecfg/En.rc | 22 +- programs/winecfg/appdefaults.c | 78 +-- programs/winecfg/audio.c | 12 +- programs/winecfg/drive.c | 8 +- programs/winecfg/libraries.c | 1025 ++++++++++++++++------------------------ programs/winecfg/main.c | 4 - programs/winecfg/resource.h | 17 +- programs/winecfg/winecfg.c | 850 ++++++++++++++++++++------------- programs/winecfg/winecfg.h | 61 +-- programs/winecfg/x11drvdlg.c | 94 ++-- 10 files changed, 1067 insertions(+), 1104 deletions(-) rewrite programs/winecfg/libraries.c (87%) rewrite programs/winecfg/winecfg.c (62%) diff --git a/programs/winecfg/En.rc b/programs/winecfg/En.rc index 0029f37dd59..769eb14af2c 100644 --- a/programs/winecfg/En.rc +++ b/programs/winecfg/En.rc @@ -84,20 +84,18 @@ STYLE WS_CHILD | WS_DISABLED FONT 8, "MS Shell Dlg" BEGIN GROUPBOX "DLL Overrides",IDC_STATIC,8,4,244,240 - LTEXT "Libraries can be specified individually to be either builtin or native. A DLL entry specified as ""*"" pertains to all DLLs not specified explicitly." + LTEXT "Dynamic Link Libraries can be specified individually to be either builtin (provided by Wine) or native (taken from Windows or provided by the application)." , IDC_STATIC,15,17,228,32 - CONTROL "DLL Overrides", IDC_TREE_DLLS, "SysTreeView32", WS_BORDER | WS_TABSTOP | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_HASBUTTONS, 15,50,142,187 + LISTBOX IDC_DLLS_LIST,15,50,142,187,WS_BORDER | WS_TABSTOP | WS_VSCROLL LTEXT "Load order:",IDC_STATIC,163,50,37,8 - CONTROL "Builtin (Wine)",IDC_RAD_BUILTIN,"Button", BS_AUTORADIOBUTTON | WS_GROUP,163,65,75,10 - CONTROL "Native (Windows)",IDC_RAD_NATIVE,"Button", BS_AUTORADIOBUTTON,163,80,75,10 - CONTROL "Builtin, Native",IDC_RAD_BUILTIN_NATIVE,"Button", BS_AUTORADIOBUTTON,163,95,75,10 - CONTROL "Native, Builtin",IDC_RAD_NATIVE_BUILTIN,"Button", BS_AUTORADIOBUTTON,163,110,75,10 - CONTROL "Disable",IDC_RAD_DISABLE,"Button", BS_AUTORADIOBUTTON,163,125,75,10 - PUSHBUTTON "Add application...",IDC_DLLS_ADDAPP,163,144,82,14 - PUSHBUTTON "Remove application",IDC_DLLS_REMOVEAPP, 163,164,82,14 - PUSHBUTTON "Add DLL override for:",IDC_DLLS_ADDDLL, 163,184,82,14 - COMBOBOX IDC_DLLLIST,163,204,82,14,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | CBS_SORT | CBS_LOWERCASE - PUSHBUTTON "Remove DLL override",IDC_DLLS_REMOVEDLL,163,224,82,14 + CONTROL "&Builtin (Wine)",IDC_RAD_BUILTIN,"Button", BS_AUTORADIOBUTTON | WS_GROUP,163,65,75,10 + CONTROL "&Native (Windows)",IDC_RAD_NATIVE,"Button", BS_AUTORADIOBUTTON,163,80,75,10 + CONTROL "Bui<in then Native",IDC_RAD_BUILTIN_NATIVE,"Button", BS_AUTORADIOBUTTON,163,95,75,10 + CONTROL "Nati&ve then Builtin",IDC_RAD_NATIVE_BUILTIN,"Button", BS_AUTORADIOBUTTON,163,110,75,10 + CONTROL "&Disable",IDC_RAD_DISABLE,"Button", BS_AUTORADIOBUTTON,163,125,75,10 + PUSHBUTTON "&Add DLL override for:",IDC_DLLS_ADDDLL, 163,184,82,14 + COMBOBOX IDC_DLLCOMBO,163,204,82,14,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | CBS_SORT | CBS_LOWERCASE + PUSHBUTTON "&Remove DLL override",IDC_DLLS_REMOVEDLL,163,224,82,14 END IDD_SYSTEMCFG DIALOG DISCARDABLE 0, 0, 260, 250 diff --git a/programs/winecfg/appdefaults.c b/programs/winecfg/appdefaults.c index e0b24ee8953..610bdaca785 100644 --- a/programs/winecfg/appdefaults.c +++ b/programs/winecfg/appdefaults.c @@ -40,23 +40,21 @@ static void update_comboboxes(HWND dialog) char *winver, *dosver; /* retrieve the registry values */ - winver = getConfigValue(keypath("Version"), "Windows", NULL); - dosver = getConfigValue(keypath("Version"), "DOS", NULL); + winver = get(keypath("Version"), "Windows", ""); + dosver = get(keypath("Version"), "DOS", ""); - /* NULL winver/dosver means use automatic mode (ie the builtin dll linkage heuristics) */ + /* empty winver/dosver means use automatic mode (ie the builtin dll linkage heuristics) */ - WINE_TRACE("winver is %s\n", winver ? winver : "null (automatic mode)"); - WINE_TRACE("dosver is %s\n", dosver ? dosver : "null (automatic mode)"); + WINE_TRACE("winver is %s\n", *winver != '\0' ? winver : "null (automatic mode)"); + WINE_TRACE("dosver is %s\n", *dosver != '\0' ? dosver : "null (automatic mode)"); /* normalize the version strings */ - if (winver && strlen(winver)) + if (*winver != '\0') { if ((pVer = getWinVersions ())) { - WINE_TRACE("Windows version\n"); for (i = 0; *pVer->szVersion || *pVer->szDescription; i++, pVer++) { - WINE_TRACE("pVer->szVersion == %s\n", pVer->szVersion); if (!strcasecmp (pVer->szVersion, winver)) { SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, (WPARAM) (i + 1), 0); @@ -71,14 +69,12 @@ static void update_comboboxes(HWND dialog) SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, 0, 0); } - if (dosver && strlen(dosver)) + if (*dosver != '\0') { if ((pVer = getDOSVersions ())) { - WINE_TRACE("DOS version\n"); for (i = 0; *pVer->szVersion || *pVer->szDescription; i++, pVer++) { - WINE_TRACE("pVer->szVersion == %s\n", pVer->szVersion); if (!strcasecmp (pVer->szVersion, dosver)) { SendDlgItemMessage (dialog, IDC_DOSVER, CB_SETCURSEL, @@ -93,9 +89,9 @@ static void update_comboboxes(HWND dialog) WINE_TRACE("setting dosver combobox to automatic/default\n"); SendDlgItemMessage (dialog, IDC_DOSVER, CB_SETCURSEL, 0, 0); } - - if (winver) free(winver); - if (dosver) free(dosver); + + HeapFree(GetProcessHeap(), 0, winver); + HeapFree(GetProcessHeap(), 0, dosver); } void @@ -153,6 +149,7 @@ static void add_listview_item(HWND listview, char *text, void *association) ListView_InsertItem(listview, &item); } +/* Called when the application is initialized (cannot reinit!) */ static void init_appsheet(HWND dialog) { HWND listview; @@ -160,22 +157,21 @@ static void init_appsheet(HWND dialog) int i; DWORD size; char appname[1024]; - FILETIME ft; WINE_TRACE("()\n"); - + listview = GetDlgItem(dialog, IDC_APP_LISTVIEW); /* we use the lparam field of the item so we can alter the presentation later and not change code * for instance, to use the tile view or to display the EXEs embedded 'display name' */ add_listview_item(listview, "Default Settings", NULL); - - /* do the application specific stuff, then add the default item last */ - if (RegOpenKey(configKey, "AppDefaults", &key) == ERROR_SUCCESS) + + /* because this list is only populated once, it's safe to bypass the settings list here */ + if (RegOpenKey(config_key, "AppDefaults", &key) == ERROR_SUCCESS) { i = 0; size = sizeof(appname); - while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS) + while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { add_listview_item(listview, appname, strdup(appname)); @@ -218,12 +214,13 @@ static int get_listview_selection(HWND listview) return -1; } + /* called when the user selects a different application */ static void on_selection_change(HWND dialog, HWND listview) { LVITEM item; char *oldapp = currentApp; - + WINE_TRACE("()\n"); item.iItem = get_listview_selection(listview); @@ -253,6 +250,8 @@ static void on_selection_change(HWND dialog, HWND listview) init_comboboxes(dialog); update_comboboxes(dialog); + + set_window_title(dialog); } static void on_add_app_click(HWND dialog) @@ -295,14 +294,14 @@ static void on_remove_app_click(HWND dialog) { HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW); int selection = get_listview_selection(listview); - char *section = keypath(""); + char *section = keypath(""); /* AppDefaults\\whatever.exe\\ */ WINE_TRACE("selection=%d, section=%s\n", selection, section); assert( selection != 0 ); /* user cannot click this button when "default settings" is selected */ section[strlen(section)] = '\0'; /* remove last backslash */ - addTransaction(section, NULL, ACTION_REMOVE, NULL); + set(section, NULL, NULL); /* delete the section */ ListView_DeleteItem(listview, selection); SetFocus(listview); @@ -316,13 +315,16 @@ static void on_winver_change(HWND dialog) if (selection == 0) { WINE_TRACE("automatic/default selected so removing current setting\n"); - addTransaction(keypath("Version"), "Windows", ACTION_REMOVE, NULL); + set(keypath("Version"), "Windows", NULL); } else { WINE_TRACE("setting Version\\Windows key to value '%s'\n", ver[selection - 1].szVersion); - addTransaction(keypath("Version"), "Windows", ACTION_SET, ver[selection - 1].szVersion); + set(keypath("Version"), "Windows", ver[selection - 1].szVersion); } + + /* enable the apply button */ + SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0); } static void on_dosver_change(HWND dialog) @@ -333,13 +335,16 @@ static void on_dosver_change(HWND dialog) if (selection == 0) { WINE_TRACE("automatic/default selected so removing current setting\n"); - addTransaction(keypath("Version"), "DOS", ACTION_REMOVE, NULL); + set(keypath("Version"), "DOS", NULL); } else { WINE_TRACE("setting Version\\DOS key to value '%s'\n", ver[selection - 1].szVersion); - addTransaction(keypath("Version"), "DOS", ACTION_SET, ver[selection - 1].szVersion); + set(keypath("Version"), "DOS", ver[selection - 1].szVersion); } + + /* enable the apply button */ + SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0); } INT_PTR CALLBACK @@ -348,17 +353,25 @@ AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) switch (uMsg) { case WM_INITDIALOG: - init_appsheet(hDlg); - break; + init_appsheet(hDlg); + break; + + case WM_SHOWWINDOW: + set_window_title(hDlg); + break; case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { case LVN_ITEMCHANGED: - on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW)); - break; + on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW)); + break; + case PSN_APPLY: + apply(); + SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); + break; } + break; case WM_COMMAND: @@ -383,6 +396,7 @@ AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) } break; } + break; } diff --git a/programs/winecfg/audio.c b/programs/winecfg/audio.c index 39ee3f6d503..ff564693187 100644 --- a/programs/winecfg/audio.c +++ b/programs/winecfg/audio.c @@ -55,7 +55,8 @@ void selectAudioDriver(HWND hDlg, char *drivername) { if (!strcmp (pAudioDrv->szDriver, drivername)) { - addTransaction("Winmm", "Drivers", ACTION_SET, pAudioDrv->szDriver); + set("Winmm", "Drivers", (char *) pAudioDrv->szDriver); + SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM) hDlg, 0); /* enable apply button */ SendDlgItemMessage(hDlg, IDC_AUDIO_DRIVER, CB_SETCURSEL, (WPARAM) i, 0); } @@ -66,7 +67,7 @@ void selectAudioDriver(HWND hDlg, char *drivername) void initAudioDlg (HWND hDlg) { - char *curAudioDriver = getConfigValue("Winmm", "Drivers", "winealsa.drv"); + char *curAudioDriver = get("Winmm", "Drivers", "winealsa.drv"); const AUDIO_DRIVER *pAudioDrv = NULL; int i; @@ -175,13 +176,18 @@ AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) break; } break; - + + case WM_SHOWWINDOW: + set_window_title(hDlg); + break; + case WM_NOTIFY: switch(((LPNMHDR)lParam)->code) { case PSN_KILLACTIVE: SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); break; case PSN_APPLY: + apply(); SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); break; case PSN_SETACTIVE: diff --git a/programs/winecfg/drive.c b/programs/winecfg/drive.c index 94db811ae3c..965807241e0 100644 --- a/programs/winecfg/drive.c +++ b/programs/winecfg/drive.c @@ -212,14 +212,13 @@ int refreshDriveDlg (HWND dialog) ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE); /* disable or enable controls depending on whether we are editing global vs app specific config */ - if (appSettings == EDITING_GLOBAL) { + if (currentApp) { WINE_TRACE("enabling controls\n"); enable(IDC_LIST_DRIVES); enable(IDC_BUTTON_ADD); enable(IDC_BUTTON_REMOVE); enable(IDC_BUTTON_EDIT); enable(IDC_BUTTON_AUTODETECT); - } else { WINE_TRACE("disabling controls\n"); disable(IDC_LIST_DRIVES); @@ -1016,6 +1015,11 @@ DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_INITDIALOG: onDriveInitDialog(); break; + + case WM_SHOWWINDOW: + set_window_title(hDlg); + break; + case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_LIST_DRIVES: diff --git a/programs/winecfg/libraries.c b/programs/winecfg/libraries.c dissimilarity index 87% index 3d5da0bc4bb..d3caaa19d6a 100644 --- a/programs/winecfg/libraries.c +++ b/programs/winecfg/libraries.c @@ -1,619 +1,406 @@ -/* - * WineCfg libraries tabsheet - * - * Copyright 2004 Robert van Herk - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#define NONAMELESSUNION -#include -#include -#include -#include -#include "winecfg.h" -#include "resource.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winecfg); - -typedef enum _DLGMODE -{ - DLL, - APP, - GLOBAL, -} DLGMODE; - -typedef enum _DLLMODE { - BUILTIN_NATIVE, - NATIVE_BUILTIN, - BUILTIN, - NATIVE, - DISABLE, - UNKNOWN /*Special value indicating an erronous DLL override mode*/ -} DLLMODE; - -static void removeSpaces(char* in, char* out) -{ - int i,j; - j = 0; - for (i = 0; i < strlen(in); i++) - { - if (in[i] != ' ') - { - out[j] = in[i]; - j++; - } - } - out[j] = 0; -} - -static DLLMODE Str2DLLMode(char* c) -{ - /*Parse a string into a DLLMode*/ - char* d = HeapAlloc(GetProcessHeap(), 0, sizeof(c)); - removeSpaces(c,d); - if (strcmp (d, "builtin,native") == 0) { - return BUILTIN_NATIVE; - } else - if (strcmp (d, "native,builtin") == 0) { - return NATIVE_BUILTIN; - } else - if (strcmp (d, "native") == 0){ - return NATIVE; - } else - if (strcmp (d, "builtin") == 0) { - return BUILTIN; - } else - if (strcmp (d, "") == 0) { - return DISABLE; - } else - return UNKNOWN; -} - -static char* DLLMode2Str(DLLMODE mode) -{ - char* res; - switch (mode) { - case NATIVE: - res = "native"; - break; - case BUILTIN: - res = "builtin"; - break; - case NATIVE_BUILTIN: - res = "native, builtin"; - break; - case BUILTIN_NATIVE: - res = "builtin, native"; - break; - case DISABLE: - res = ""; - break; - default: - res = "unknown"; - } - return strdup(res); -} - -typedef struct _DLLOVERRIDE -{ - char* lpcKey; /*The actual dll name*/ - DLLMODE mode; -} DLLOVERRIDE, *LPDLLOVERRIDE; - -static LPDLLOVERRIDE CreateDLLOverride(char* lpcKey) -{ - LPDLLOVERRIDE out = HeapAlloc(GetProcessHeap(),0,sizeof(DLLOVERRIDE)); - out->lpcKey = strdup (lpcKey); - return out; -} - -static VOID FreeDLLOverride(LPDLLOVERRIDE ldo) -{ - if (ldo->lpcKey) - free(ldo->lpcKey); - HeapFree(GetProcessHeap(),0,ldo); -} - -typedef struct _APPL -{ - BOOL isGlobal; - char* lpcApplication; - char* lpcSection; /*Registry section*/ -} APPL, *LPAPPL; - -static LPAPPL CreateAppl(BOOL isGlobal, char* application, char* section) -{ - LPAPPL out; - out = HeapAlloc(GetProcessHeap(),0,sizeof(APPL)); - out->lpcApplication = strdup(application); - out->lpcSection = strdup(section); - out->isGlobal = isGlobal; - return out; -} - -static VOID FreeAppl(LPAPPL lpAppl) -{ - if (lpAppl->lpcApplication) - free(lpAppl->lpcApplication); /* The strings were strdup-ped, so we use "free" */ - if (lpAppl->lpcSection) - free(lpAppl->lpcSection); - HeapFree(GetProcessHeap(),0,lpAppl); -} - -typedef struct _ITEMTAG -{ - LPAPPL lpAppl; - LPDLLOVERRIDE lpDo; -} ITEMTAG, *LPITEMTAG; - -static LPITEMTAG CreateItemTag() -{ - LPITEMTAG out; - out = HeapAlloc(GetProcessHeap(),0,sizeof(ITEMTAG)); - out->lpAppl = 0; - out->lpDo = 0; - return out; -} - -static VOID FreeItemTag(LPITEMTAG lpit) -{ - if (lpit->lpAppl) - FreeAppl(lpit->lpAppl); - if (lpit->lpDo) - FreeDLLOverride(lpit->lpDo); - HeapFree(GetProcessHeap(),0,lpit); -} - -static VOID UpdateDLLList(HWND hDlg, char* dll) -{ - /*Add if it isn't already in*/ - if (SendDlgItemMessage(hDlg, IDC_DLLLIST, CB_FINDSTRING, 1, (LPARAM) dll) == CB_ERR) - SendDlgItemMessage(hDlg,IDC_DLLLIST,CB_ADDSTRING,0,(LPARAM) dll); -} - -static VOID LoadLibrarySettings(LPAPPL appl /*DON'T FREE, treeview will own this*/, HWND hDlg, HWND hwndTV) -{ - HKEY key; - int i; - DWORD size; - DWORD readSize; - char name [255]; - char read [255]; - LPITEMTAG lpIt; - TVINSERTSTRUCT tis; - HTREEITEM hParent; - LPDLLOVERRIDE lpdo; - - WINE_TRACE("opening %s\n", appl->lpcSection); - if (RegOpenKey (configKey, appl->lpcSection, &key) == ERROR_SUCCESS) - { - i = 0; - size = 255; - readSize = 255; - - lpIt = CreateItemTag(); - lpIt->lpAppl = appl; - - tis.hParent = NULL; - tis.hInsertAfter = TVI_LAST; - tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; - tis.u.item.pszText = appl->lpcApplication; - tis.u.item.lParam = (LPARAM)lpIt; - hParent = TreeView_InsertItem(hwndTV,&tis); - tis.hParent = hParent; - - while (RegEnumValue(key, i, name, &size, NULL, NULL, read, &readSize) == ERROR_SUCCESS) - { - WINE_TRACE("Reading value %s, namely %s\n", name, read); - - lpIt = CreateItemTag(); - lpdo = CreateDLLOverride(name); - lpIt->lpDo = lpdo; - tis.u.item.lParam = (LPARAM)lpIt; - tis.u.item.pszText = name; - - lpdo->mode = Str2DLLMode(read); - - TreeView_InsertItem(hwndTV,&tis); - UpdateDLLList(hDlg, name); - i ++; size = 255; readSize = 255; - } - RegCloseKey(key); - } -} - -static VOID SetEnabledDLLControls(HWND dialog, DLGMODE dlgmode) -{ - if (dlgmode == DLL) { - enable(IDC_RAD_BUILTIN); - enable(IDC_RAD_NATIVE); - enable(IDC_RAD_BUILTIN_NATIVE); - enable(IDC_RAD_NATIVE_BUILTIN); - enable(IDC_RAD_DISABLE); - enable(IDC_DLLS_REMOVEDLL); - } else { - disable(IDC_RAD_BUILTIN); - disable(IDC_RAD_NATIVE); - disable(IDC_RAD_BUILTIN_NATIVE); - disable(IDC_RAD_NATIVE_BUILTIN); - disable(IDC_RAD_DISABLE); - disable(IDC_DLLS_REMOVEDLL); - } - - if (dlgmode == APP) { - enable(IDC_DLLS_REMOVEAPP); - } - else { - disable(IDC_DLLS_REMOVEAPP); - } -} - -static VOID OnInitLibrariesDlg(HWND hDlg) -{ - HWND hwndTV; - LPAPPL lpAppl; - HKEY applKey; - int i; - DWORD size; - char appl [255]; - char lpcKey [255]; - FILETIME ft; - - hwndTV = GetDlgItem(hDlg,IDC_TREE_DLLS); - lpAppl = CreateAppl(TRUE,"Global DLL Overrides", "DllOverrides"); - LoadLibrarySettings(lpAppl, hDlg, hwndTV); - - /*And now the application specific stuff:*/ - if (RegOpenKey(configKey, "AppDefaults", &applKey) == ERROR_SUCCESS) { - i = 0; - size = 255; - while (RegEnumKeyEx(applKey, i, appl, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS) - { - sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", appl); - lpAppl = CreateAppl(FALSE,appl, lpcKey); - LoadLibrarySettings(lpAppl, hDlg, hwndTV); - i++; size = 255; - } - RegCloseKey(applKey); - } - - SetEnabledDLLControls(hDlg, GLOBAL); -} - -static VOID OnTreeViewChangeItem(HWND hDlg, HWND hTV) -{ - TVITEM ti; - LPITEMTAG lpit; - int buttonId; - - ti.mask = TVIF_PARAM; - ti.hItem = TreeView_GetSelection(hTV); - if (TreeView_GetItem (hTV, &ti)) - { - lpit = (LPITEMTAG) ti.lParam; - if (lpit->lpDo) - { - WINE_TRACE("%s\n", lpit->lpDo->lpcKey); - buttonId = IDC_RAD_BUILTIN; - switch (lpit->lpDo->mode) - { - case NATIVE: - buttonId = IDC_RAD_NATIVE; - break; - case BUILTIN: - buttonId = IDC_RAD_BUILTIN; - break; - case NATIVE_BUILTIN: - buttonId = IDC_RAD_NATIVE_BUILTIN; - break; - case BUILTIN_NATIVE: - buttonId = IDC_RAD_BUILTIN_NATIVE; - break; - case DISABLE: - buttonId = IDC_RAD_DISABLE; - break; - case UNKNOWN: - buttonId = -1; - break; - } - CheckRadioButton(hDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, buttonId); - SetEnabledDLLControls(hDlg, DLL); - } else { - if (lpit->lpAppl) - { - if (lpit->lpAppl->isGlobal == TRUE) - SetEnabledDLLControls(hDlg, GLOBAL); - else - SetEnabledDLLControls(hDlg, APP); - } - } - } -} - -static VOID SetDLLMode(HWND hDlg, DLLMODE mode) -{ - HWND hTV; - TVITEM ti; - LPITEMTAG lpit; - char* cMode; - TVITEM tiPar; - LPITEMTAG lpitPar; - - hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); - ti.mask = TVIF_PARAM; - ti.hItem = TreeView_GetSelection(hTV); - if (TreeView_GetItem (hTV, &ti)) - { - lpit = (LPITEMTAG) ti.lParam; - if (lpit->lpDo) - { - lpit->lpDo->mode = mode; - cMode = DLLMode2Str (mode); - /*Find parent, so we can read registry section*/ - tiPar.mask = TVIF_PARAM; - tiPar.hItem = TreeView_GetParent(hTV, ti.hItem); - if (TreeView_GetItem(hTV,&tiPar)) - { - lpitPar = (LPITEMTAG) tiPar.lParam; - if (lpitPar->lpAppl) - { - addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_SET, cMode); - } - } - free(cMode); - } - } -} - -static VOID OnBuiltinClick(HWND hDlg) -{ - SetDLLMode(hDlg, BUILTIN); -} - -static VOID OnNativeClick(HWND hDlg) -{ - SetDLLMode(hDlg, NATIVE); -} - -static VOID OnBuiltinNativeClick(HWND hDlg) -{ - SetDLLMode(hDlg, BUILTIN_NATIVE); -} - -static VOID OnNativeBuiltinClick(HWND hDlg) -{ - SetDLLMode(hDlg, NATIVE_BUILTIN); -} - -static VOID OnDisableClick(HWND hDlg) -{ - SetDLLMode(hDlg, DISABLE); -} - -static VOID OnTreeViewDeleteItem(NMTREEVIEW* nmt) -{ - FreeItemTag((LPITEMTAG)(nmt->itemOld.lParam)); -} - -static VOID OnAddDLLClick(HWND hDlg) -{ - HWND hTV; - TVITEM ti; - LPITEMTAG lpit; - LPITEMTAG lpitNew; - TVITEM childti; - char dll [255]; - BOOL doAdd; - TVINSERTSTRUCT tis; - - hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); - ti.mask = TVIF_PARAM; - ti.hItem = TreeView_GetSelection(hTV); - if (TreeView_GetItem (hTV, &ti)) - { - lpit = (LPITEMTAG) ti.lParam; - if (lpit->lpDo) { /*Is this a DLL override (that is: a subitem), then find the parent*/ - ti.hItem = TreeView_GetParent(hTV, ti.hItem); - if (TreeView_GetItem(hTV,&ti)) { - lpit = (LPITEMTAG) ti.lParam; - } else return; - } - } else return; - /*Now we should have an parent item*/ - if (lpit->lpAppl) - { - lpitNew = CreateItemTag(); - SendDlgItemMessage(hDlg,IDC_DLLLIST,WM_GETTEXT,(WPARAM)255, (LPARAM) dll); - if (strlen(dll) > 0) { - /*Is the dll already in the list? If so, don't do it*/ - doAdd = TRUE; - childti.mask = TVIF_PARAM; - if ((childti.hItem = TreeView_GetNextItem(hTV, ti.hItem, TVGN_CHILD))) { - /*Retrieved first child*/ - while (TreeView_GetItem (hTV, &childti)) - { - if (strcmp(((LPITEMTAG)childti.lParam)->lpDo->lpcKey,dll) == 0) { - doAdd = FALSE; - break; - } - childti.hItem = TreeView_GetNextItem(hTV, childti.hItem, TVGN_NEXT); - } - } - if (doAdd) - { - lpitNew->lpDo = CreateDLLOverride(dll); - lpitNew->lpDo->mode = NATIVE; - tis.hInsertAfter = TVI_LAST; - tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; - tis.u.item.pszText = dll; - tis.u.item.lParam = (LPARAM)lpitNew; - tis.hParent = ti.hItem; - TreeView_InsertItem(hTV,&tis); - UpdateDLLList(hDlg, dll); - addTransaction(lpit->lpAppl->lpcSection, dll, ACTION_SET, "native"); - } else MessageBox(hDlg, "A DLL with that name is already in this list...", "", MB_OK | MB_ICONINFORMATION); - } - } else return; -} - -static VOID OnRemoveDLLClick(HWND hDlg) -{ - HWND hTV; - TVITEM ti; - LPITEMTAG lpit; - TVITEM tiPar; - LPITEMTAG lpitPar; - - hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); - ti.mask = TVIF_PARAM; - ti.hItem = TreeView_GetSelection(hTV); - if (TreeView_GetItem (hTV, &ti)) { - lpit = (LPITEMTAG) ti.lParam; - if (lpit->lpDo) - { - /*Find parent for section*/ - tiPar.mask = TVIF_PARAM; - tiPar.hItem = TreeView_GetParent(hTV, ti.hItem); - if (TreeView_GetItem(hTV,&tiPar)) - { - lpitPar = (LPITEMTAG) tiPar.lParam; - if (lpitPar->lpAppl) - { - addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_REMOVE, NULL); - TreeView_DeleteItem(hTV,ti.hItem); - } - } - } - } -} - -static VOID OnAddApplicationClick(HWND hDlg) -{ - char szFileTitle [255]; - char szFile [255]; - char lpcKey [255]; - - TVINSERTSTRUCT tis; - LPITEMTAG lpit; - OPENFILENAME ofn = { sizeof(OPENFILENAME), - 0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL, - 0, NULL, 0, NULL, NULL, - OFN_SHOWHELP, 0, 0, NULL, 0, NULL }; - - ofn.lpstrFileTitle = szFileTitle; - ofn.lpstrFileTitle[0] = '\0'; - ofn.nMaxFileTitle = sizeof(szFileTitle); - ofn.lpstrFile = szFile; - ofn.lpstrFile[0] = '\0'; - ofn.nMaxFile = sizeof(szFile); - - if (GetOpenFileName(&ofn)) - { - tis.hParent = NULL; - tis.hInsertAfter = TVI_LAST; - tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; - tis.u.item.pszText = szFileTitle; - lpit = CreateItemTag(); - sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", szFileTitle); - lpit->lpAppl = CreateAppl(FALSE,szFileTitle,lpcKey); - tis.u.item.lParam = (LPARAM)lpit; - TreeView_InsertItem(GetDlgItem(hDlg,IDC_TREE_DLLS), &tis); - setConfigValue(lpcKey,NULL,NULL); - } -} - -static VOID OnRemoveApplicationClick(HWND hDlg) -{ - HWND hTV; - TVITEM ti; - LPITEMTAG lpit; - - hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); - ti.mask = TVIF_PARAM; - ti.hItem = TreeView_GetSelection(hTV); - if (TreeView_GetItem (hTV, &ti)) { - lpit = (LPITEMTAG) ti.lParam; - if (lpit->lpAppl) - { - addTransaction(lpit->lpAppl->lpcSection, NULL, ACTION_REMOVE, NULL); - TreeView_DeleteItem(hTV,ti.hItem); - } - } -} - -INT_PTR CALLBACK -LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - OnInitLibrariesDlg(hDlg); - break; - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case TVN_SELCHANGED: { - switch(LOWORD(wParam)) { - case IDC_TREE_DLLS: - OnTreeViewChangeItem(hDlg, GetDlgItem(hDlg,IDC_TREE_DLLS)); - break; - } - } - break; - case TVN_DELETEITEM: - OnTreeViewDeleteItem ((LPNMTREEVIEW)lParam); - break; - } - break; - case WM_COMMAND: - switch(HIWORD(wParam)) { - case BN_CLICKED: - switch(LOWORD(wParam)) { - case IDC_RAD_BUILTIN: - OnBuiltinClick(hDlg); - break; - case IDC_RAD_NATIVE: - OnNativeClick(hDlg); - break; - case IDC_RAD_BUILTIN_NATIVE: - OnBuiltinNativeClick(hDlg); - break; - case IDC_RAD_NATIVE_BUILTIN: - OnNativeBuiltinClick(hDlg); - break; - case IDC_RAD_DISABLE: - OnDisableClick(hDlg); - break; - case IDC_DLLS_ADDAPP: - OnAddApplicationClick(hDlg); - break; - case IDC_DLLS_REMOVEAPP: - OnRemoveApplicationClick(hDlg); - break; - case IDC_DLLS_ADDDLL: - OnAddDLLClick(hDlg); - break; - case IDC_DLLS_REMOVEDLL: - OnRemoveDLLClick(hDlg); - break; - } - break; - } - break; - } - - return 0; -} +/* + * WineCfg libraries tabsheet + * + * Copyright 2004 Robert van Herk + * Copyright 2004 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define NONAMELESSUNION +#include +#include +#include +#include +#include +#include "winecfg.h" +#include "resource.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winecfg); + +enum dllmode +{ + BUILTIN_NATIVE, + NATIVE_BUILTIN, + BUILTIN, + NATIVE, + DISABLE, + UNKNOWN /* Special value indicating an erronous DLL override mode */ +}; + +struct dll +{ + char *name; + enum dllmode mode; +}; + +static enum dllmode parse_override(char *in) +{ + int i, j; + char *out; + + out = HeapAlloc(GetProcessHeap(), 0, strlen(in)); + + /* remove the spaces */ + j = 0; + for (i = 0; i < strlen(in); i++) + { + if (in[i] != ' ') + { + out[j] = in[i]; + j++; + } + } + out[j] = 0; + + /* parse the string */ + if (strcmp(out, "builtin,native") == 0) return BUILTIN_NATIVE; + else if (strcmp(out, "native,builtin") == 0) return NATIVE_BUILTIN; + else if (strcmp(out, "native") == 0) return NATIVE; + else if (strcmp(out, "builtin") == 0) return BUILTIN; + else if (strcmp(out, "") == 0) return DISABLE; + + return UNKNOWN; +} + +/* this is used to convert a dllmode to a human readable string. we should read from the translations here */ +static char* mode_to_label(enum dllmode mode) +{ + char* res; + + switch (mode) { + case NATIVE: + res = "native"; + break; + case BUILTIN: + res = "builtin"; + break; + case NATIVE_BUILTIN: + res = "native, builtin"; + break; + case BUILTIN_NATIVE: + res = "builtin, native"; + break; + case DISABLE: + res = "disabled"; + break; + default: + res = "unknown/invalid"; + break; + } + + return res; +} + +static void set_controls_from_selection(HWND dialog) +{ + int index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0); + struct dll *dll; + DWORD id; + int i; + + if (index == -1) /* no selection */ + { + for (i = IDC_RAD_BUILTIN; i <= IDC_RAD_DISABLE; i++) + disable(i); + + CheckRadioButton(dialog, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, -1); + + return; + } + + /* enable the controls */ + for (i = IDC_RAD_BUILTIN; i <= IDC_RAD_DISABLE; i++) + enable(i); + + dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, index, 0); + + switch (dll->mode) + { + case NATIVE: + id = IDC_RAD_NATIVE; + break; + case BUILTIN: + id = IDC_RAD_BUILTIN; + break; + case NATIVE_BUILTIN: + id = IDC_RAD_NATIVE_BUILTIN; + break; + case BUILTIN_NATIVE: + id = IDC_RAD_BUILTIN_NATIVE; + break; + case DISABLE: + id = IDC_RAD_DISABLE; + break; + + case UNKNOWN: + default: + id = -1; + break; + } + + CheckRadioButton(dialog, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, id); +} + + +static void clear_settings(HWND dialog) +{ + int count = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0); + int i; + + WINE_TRACE("count=%d\n", count); + + for (i = 0; i < count; i++) + { + struct dll *dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, 0, 0); + + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, 0, 0); + + HeapFree(GetProcessHeap(), 0, dll->name); + HeapFree(GetProcessHeap(), 0, dll); + } +} + +static void load_library_settings(HWND dialog) +{ + char **overrides = enumerate_values(keypath("DllOverrides")); + char **p; + int sel, count = 0; + + sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0); + + WINE_TRACE("sel=%d\n", sel); + + clear_settings(dialog); + + if (!overrides || *overrides == NULL) + { + set_controls_from_selection(dialog); + disable(IDC_DLLS_REMOVEDLL); + HeapFree(GetProcessHeap(), 0, overrides); + return; + } + + enable(IDC_DLLS_REMOVEDLL); + + for (p = overrides; *p != NULL; p++) + { + int index; + char *str, *value, *label; + struct dll *dll; + + value = get(keypath("DllOverrides"), *p, NULL); + + label = mode_to_label(parse_override(value)); + + str = HeapAlloc(GetProcessHeap(), 0, strlen(*p) + 2 + strlen(label) + 2); + strcpy(str, *p); + strcat(str, " ("); + strcat(str, label); + strcat(str, ")"); + + dll = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dll)); + dll->name = *p; + dll->mode = parse_override(value); + + index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_ADDSTRING, (WPARAM) -1, (LPARAM) str); + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETITEMDATA, index, (LPARAM) dll); + + HeapFree(GetProcessHeap(), 0, str); + + count++; + } + + HeapFree(GetProcessHeap(), 0, overrides); + + /* restore the previous selection, if possible */ + if (sel >= count - 1) sel = count - 1; + else if (sel == -1) sel = 0; + + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, sel, 0); + + set_controls_from_selection(dialog); +} + +/* Called when the application is initialized (cannot reinit!) */ +static void init_libsheet(HWND dialog) +{ + /* clear the add dll controls */ + SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 1, (LPARAM) ""); + disable(IDC_DLLS_ADDDLL); +} + + +static void on_add_combo_change(HWND dialog) +{ + char buffer[1024]; + + SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer); + + if (strlen(buffer)) + enable(IDC_DLLS_ADDDLL) + else + disable(IDC_DLLS_ADDDLL); +} + +static void set_dllmode(HWND dialog, DWORD id) +{ + enum dllmode mode; + struct dll *dll; + int sel; + char *str; + +#define CONVERT(s) case IDC_RAD_##s: mode = s; break; + + switch (id) + { + CONVERT( BUILTIN ); + CONVERT( NATIVE ); + CONVERT( BUILTIN_NATIVE ); + CONVERT( NATIVE_BUILTIN ); + CONVERT( DISABLE ); + + default: assert( FALSE ); /* should not be reached */ + } + +#undef CONVERT + + sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0); + if (sel == -1) return; + + dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0); + + switch (mode) + { + case BUILTIN: str = "builtin"; break; + case NATIVE: str = "native"; break; + case BUILTIN_NATIVE: str = "builtin, native"; break; + case NATIVE_BUILTIN: str = "native, builtin"; break; + case DISABLE: str = ""; break; + default: assert( FALSE ); /* unreachable */ + } + WINE_TRACE("Setting %s to %s\n", dll->name, str); + + set(keypath("DllOverrides"), dll->name, str); + + load_library_settings(dialog); /* ... and refresh */ +} + +static void on_add_click(HWND dialog) +{ + char buffer[1024]; + + ZeroMemory(buffer, sizeof(buffer)); + + SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer); + + SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 0, (LPARAM) ""); + disable(IDC_DLLS_ADDDLL); + + WINE_TRACE("Adding %s as native, builtin", buffer); + + set(keypath("DllOverrides"), buffer, "native,builtin"); + + load_library_settings(dialog); + + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SELECTSTRING, (WPARAM) 0, (LPARAM) buffer); + + set_controls_from_selection(dialog); +} + +static void on_remove_click(HWND dialog) +{ + int sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0); + struct dll *dll; + + if (sel == LB_ERR) return; + + dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0); + + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, sel, 0); + + set(keypath("DllOverrides"), dll->name, NULL); + + HeapFree(GetProcessHeap(), 0, dll->name); + HeapFree(GetProcessHeap(), 0, dll); + + if (SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0) > 0) + SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, max(sel - 1, 0), 0); + else + disable(IDC_DLLS_REMOVEDLL); + + set_controls_from_selection(dialog); +} + +INT_PTR CALLBACK +LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + init_libsheet(hDlg); + break; + case WM_SHOWWINDOW: + set_window_title(hDlg); + break; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_SETACTIVE: + load_library_settings(hDlg); + break; + } + break; + case WM_COMMAND: + switch(HIWORD(wParam)) { + + /* FIXME: when the user hits enter in the DLL combo box we should invoke the add + * add button, rather than the propsheet OK button. But I don't know how to do that! + */ + + case CBN_EDITCHANGE: + if(LOWORD(wParam) == IDC_DLLCOMBO) + { + on_add_combo_change(hDlg); + break; + } + + case BN_CLICKED: + switch(LOWORD(wParam)) { + case IDC_RAD_BUILTIN: + case IDC_RAD_NATIVE: + case IDC_RAD_BUILTIN_NATIVE: + case IDC_RAD_NATIVE_BUILTIN: + case IDC_RAD_DISABLE: + set_dllmode(hDlg, LOWORD(wParam)); + break; + + case IDC_DLLS_ADDDLL: + on_add_click(hDlg); + break; + case IDC_DLLS_REMOVEDLL: + on_remove_click(hDlg); + break; + } + break; + case LBN_SELCHANGE: + set_controls_from_selection(hDlg); + break; + } + break; + } + + return 0; +} diff --git a/programs/winecfg/main.c b/programs/winecfg/main.c index 40319f6ae0f..6277dad2d0f 100644 --- a/programs/winecfg/main.c +++ b/programs/winecfg/main.c @@ -217,10 +217,6 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrev, LPSTR szCmdLine, int nShow) WINE_ERR("initialization failed, aborting\n"); ExitProcess(1); } - - /* is the user running as root? */ - if(getuid() == 0) - MessageBox(NULL, "It is not advisable to run wine as root. Doing so may compromise the security of your computer. Please run wine as a normal user.", "", MB_OK); /* * The next 3 lines should be all that is needed diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h index 5112774a8a6..2a90a880c14 100644 --- a/programs/winecfg/resource.h +++ b/programs/winecfg/resource.h @@ -53,26 +53,17 @@ #define IDC_DESKTOP_BY 1026 #define IDC_XDGA 1027 #define IDC_XSHM 1028 + +/* dll editing */ #define IDC_RAD_BUILTIN 1029 #define IDC_RAD_NATIVE 1030 #define IDC_RAD_BUILTIN_NATIVE 1031 #define IDC_RAD_NATIVE_BUILTIN 1032 #define IDC_RAD_DISABLE 1033 -#define IDC_TREE_DLLS 1034 -#define IDC_DLLS_ADDAPP 8000 +#define IDC_DLLS_LIST 1034 #define IDC_DLLS_ADDDLL 8001 -#define IDC_DLLS_REMOVEAPP 8002 #define IDC_DLLS_REMOVEDLL 8003 -#define IDC_DLLLIST 8004 -#define IDC_RADIO_DEFAULT_BUILTIN 1033 -#define IDC_RADIO_DEFAULT_NATIVE 1034 -#define IDC_RADIO_VIRTUAL 1035 -#define IDC_EDIT_VIRTUAL 1036 -#define IDC_BUTTON_VIRTUAL 1037 -#define IDC_RADIO_REAL 1038 -#define IDC_EDIT_REAL 1039 -#define IDC_BUTTON_REAL 1040 -#define IDC_BUTTON_FOLDERS 1041 +#define IDC_DLLCOMBO 8004 /* drive editing */ #define IDC_LIST_DRIVES 1042 diff --git a/programs/winecfg/winecfg.c b/programs/winecfg/winecfg.c dissimilarity index 62% index e7a6b4ab8e9..2e56c3d7929 100644 --- a/programs/winecfg/winecfg.c +++ b/programs/winecfg/winecfg.c @@ -1,328 +1,522 @@ -/* - * WineCfg configuration management - * - * Copyright 2002 Jaco Greeff - * Copyright 2003 Dimitrie O. Paun - * Copyright 2003-2004 Mike Hearn - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: (in rough order of priority) - * - A mind bogglingly vast amount of stuff - * - * - Implement autodetect for drive configuration - * - Figure out whether we need the virtual vs real drive selection stuff at the top of the property page - * - Implement explicit mode vs instant-apply mode - * - DLL editing - * - Multimedia page - * - Settings migration code (from old configs) - * - Clean up resource.h, it's a bog - * - * Minor things that should be done someday: - * - Make the desktop size UI a combo box, with a Custom option, so it's more obvious what you might want to choose here - * - * BUGS: - * - x11drv page triggers key writes on entry - * - */ - -#include -#include -#include -#include -#include -#include - -WINE_DEFAULT_DEBUG_CHANNEL(winecfg); - -#include "winecfg.h" - -HKEY configKey = NULL; - - -int initialize(void) { - DWORD res = RegCreateKey(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, &configKey); - if (res != ERROR_SUCCESS) { - WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res); - return 1; - } - return 0; -} - - -/***************************************************************************** - * getConfigValue: Retrieves a configuration value from the registry - * - * const char *subKey : the name of the config section - * const char *valueName : the name of the config value - * const char *defaultResult : if the key isn't found, return this value instead - * - * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result. - * - */ -char *getConfigValue (const char *subkey, const char *valueName, const char *defaultResult) -{ - char *buffer = NULL; - DWORD dataLength; - HKEY hSubKey = NULL; - DWORD res; - - WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey, valueName, defaultResult); - - res = RegOpenKeyEx( configKey, subkey, 0, KEY_ALL_ACCESS, &hSubKey ); - if(res != ERROR_SUCCESS) { - if( res==ERROR_FILE_NOT_FOUND ) - { - WINE_TRACE("Section key not present - using default\n"); - return defaultResult ? strdup(defaultResult) : NULL; - } - else - { - WINE_ERR("RegOpenKey failed on wine config key (res=%ld)\n", res); - } - goto end; - } - - res = RegQueryValueExA( hSubKey, valueName, NULL, NULL, NULL, &dataLength); - if( res == ERROR_FILE_NOT_FOUND ) { - WINE_TRACE("Value not present - using default\n"); - buffer = defaultResult ? strdup(defaultResult) : NULL; - goto end; - } else if( res!=ERROR_SUCCESS ) { - WINE_ERR("Couldn't query value's length (res=%ld)\n", res ); - goto end; - } - - buffer = malloc(dataLength); - if( buffer==NULL ) - { - WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength ); - goto end; - } - - RegQueryValueEx(hSubKey, valueName, NULL, NULL, (LPBYTE)buffer, &dataLength); - -end: - if( hSubKey!=NULL ) - RegCloseKey( hSubKey ); - - return buffer; - -} - -/***************************************************************************** - * setConfigValue : Sets a configuration key in the registry. Section - * will be created if it doesn't already exist - * - * HKEY hCurrent : the registry key that the configuration is rooted at - * const char *subKey : the name of the config section - * const char *valueName : the name of the config value - * const char *value : the value to set the configuration key to - * - * Returns 0 on success, non-zero otherwise - * - * If *valueName or *value is NULL, an empty section will be created - */ -int setConfigValue (const char *subkey, const char *valueName, const char *value) { - DWORD res = 1; - HKEY key = NULL; - - WINE_TRACE("subkey=%s, valueName=%s, value=%s\n", subkey, valueName, value); - - assert( subkey != NULL ); - - res = RegCreateKey(configKey, subkey, &key); - if (res != ERROR_SUCCESS) goto end; - if (value == NULL || valueName == NULL) goto end; - - res = RegSetValueEx(key, valueName, 0, REG_SZ, value, strlen(value) + 1); - if (res != ERROR_SUCCESS) goto end; - - res = 0; -end: - if (key) RegCloseKey(key); - if (res != 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", valueName, subkey, value, res); - return res; -} - -/* returns 0 on success, an HRESULT from the registry funtions otherwise */ -HRESULT doesConfigValueExist(const char *subkey, const char *valueName) { - HRESULT hr; - HKEY key; - - WINE_TRACE("subkey=%s, valueName=%s - ", subkey, valueName); - - hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key); - if (hr != S_OK) { - WINE_TRACE("no: subkey does not exist\n"); - return hr; - } - - hr = RegQueryValueEx(key, valueName, NULL, NULL, NULL, NULL); - if (hr != S_OK) { - WINE_TRACE("no: key does not exist\n"); - return hr; - } - - RegCloseKey(key); - WINE_TRACE("yes\n"); - return S_OK; -} - -/* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */ -HRESULT removeConfigValue(const char *subkey, const char *valueName) { - HRESULT hr; - HKEY key; - WINE_TRACE("subkey=%s, valueName=%s\n", subkey, valueName); - - hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key); - if (hr != S_OK) return hr; - - hr = RegDeleteValue(key, valueName); - if (hr != ERROR_SUCCESS) return hr; - - return S_OK; -} - -/* removes the requested configuration section (subkey) from the registry, assuming it exists */ -/* this function might be slightly pointless, but in future we may wish to treat recursion specially etc, so we'll keep it for now */ -HRESULT removeConfigSection(char *section) { - HRESULT hr; - WINE_TRACE("section=%s\n", section); - - return hr = RegDeleteKey(configKey, section); -} - - -/* ========================================================================= */ -/* Transaction management code */ - -struct transaction *tqhead, *tqtail; -int instantApply = 1; - -void destroyTransaction(struct transaction *trans) { - assert( trans != NULL ); - - WINE_TRACE("destroying %p\n", trans); - - free(trans->section); - if (trans->key) free(trans->key); - if (trans->newValue) free(trans->newValue); - - if (trans->next) trans->next->prev = trans->prev; - if (trans->prev) trans->prev->next = trans->next; - if (trans == tqhead) tqhead = NULL; - if (trans == tqtail) tqtail = NULL; - - free(trans); -} - -void addTransaction(const char *section, const char *key, enum transaction_action action, const char *newValue) { - struct transaction *trans = calloc(sizeof(struct transaction),1); - - assert( section != NULL ); - if (action == ACTION_SET) assert( newValue != NULL ); - if (action == ACTION_SET) assert( key != NULL ); - - trans->section = strdup(section); - if (key) trans->key = strdup(key); - if (newValue) trans->newValue = strdup(newValue); - trans->action = action; - - if (tqtail == NULL) { - tqtail = trans; - tqhead = tqtail; - } else { - tqhead->next = trans; - trans->prev = tqhead; - tqhead = trans; - } - - if (instantApply) { - processTransaction(trans); - destroyTransaction(trans); - } -} - -void processTransaction(struct transaction *trans) { - if (trans->action == ACTION_SET) { - WINE_TRACE("Setting %s\\%s to '%s'\n", trans->section, trans->key, trans->newValue); - setConfigValue(trans->section, trans->key, trans->newValue); - } else if (trans->action == ACTION_REMOVE) { - if (trans->key) { - WINE_TRACE("Removing %s\\%s\n", trans->section, trans->key); - removeConfigValue(trans->section, trans->key); - } else { - /* NULL key means remove that section entirely */ - WINE_TRACE("Removing section %s\n", trans->section); - removeConfigSection(trans->section); - } - } - /* TODO: implement notifications here */ -} - -void processTransQueue(void) -{ - WINE_TRACE("\n"); - while (tqtail != NULL) { - struct transaction *next = tqtail->next; - processTransaction(tqtail); - destroyTransaction(tqtail); - tqtail = next; - } -} - -/* ================================== utility functions ============================ */ - -char *currentApp = NULL; /* the app we are currently editing, or NULL if editing global */ - -/* returns a registry key path suitable for passing to addTransaction */ -char *keypath(char *section) -{ - static char *result = NULL; - - if (result) release(result); - - if (currentApp) - { - result = alloc(strlen("AppDefaults\\") + strlen(currentApp) + 2 /* \\ */ + strlen(section) + 1 /* terminator */); - sprintf(result, "AppDefaults\\%s\\%s", currentApp, section); - } - else - { - result = strdupA(section); - } - - return result; -} - -/* returns a string with the window text of the dialog item. user is responsible for freeing the result */ -char *getDialogItemText(HWND hDlg, WORD controlID) { - HWND item = GetDlgItem(hDlg, controlID); - int len = GetWindowTextLength(item) + 1; - char *result = malloc(len); - if (GetWindowText(item, result, len) == 0) return NULL; - return result; -} - -void PRINTERROR(void) -{ - LPSTR msg; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - 0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), - (LPSTR)&msg, 0, NULL); - WINE_TRACE("error: '%s'\n", msg); -} +/* + * WineCfg configuration management + * + * Copyright 2002 Jaco Greeff + * Copyright 2003 Dimitrie O. Paun + * Copyright 2003-2004 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +WINE_DEFAULT_DEBUG_CHANNEL(winecfg); + +#include "winecfg.h" + +HKEY config_key = NULL; + + + +/* this is called from the WM_SHOWWINDOW handlers of each tab page. + * + * it's a nasty hack, necessary because the property sheet insists on resetting the window title + * to the title of the tab, which is utterly useless. dropping the property sheet is on the todo list. + */ +void set_window_title(HWND dialog) +{ + char *newtitle; + + /* update the window title */ + if (currentApp) + { + char *template = "Wine Configuration for %s"; + newtitle = HeapAlloc(GetProcessHeap(), 0, strlen(template) + strlen(currentApp) + 1); + sprintf(newtitle, template, currentApp); + } + else + { + newtitle = strdupA("Wine Configuration"); + } + + WINE_TRACE("setting title to %s\n", newtitle); + SendMessage(GetParent(dialog), PSM_SETTITLE, 0, (LPARAM) newtitle); + HeapFree(GetProcessHeap(), 0, newtitle); +} + + +/** + * getkey: Retrieves a configuration value from the registry + * + * char *subkey : the name of the config section + * char *name : the name of the config value + * char *default : if the key isn't found, return this value instead + * + * Returns a buffer holding the value if successful, NULL if + * not. Caller is responsible for releasing the result. + * + */ +static char *getkey (char *subkey, char *name, char *def) +{ + LPBYTE buffer = NULL; + DWORD len; + HKEY hSubKey = NULL; + DWORD res; + + WINE_TRACE("subkey=%s, name=%s, def=%s\n", subkey, name, def); + + res = RegOpenKeyEx(config_key, subkey, 0, KEY_READ, &hSubKey); + if (res != ERROR_SUCCESS) + { + if (res == ERROR_FILE_NOT_FOUND) + { + WINE_TRACE("Section key not present - using default\n"); + return def ? strdupA(def) : NULL; + } + else + { + WINE_ERR("RegOpenKey failed on wine config key (res=%ld)\n", res); + } + goto end; + } + + res = RegQueryValueExA(hSubKey, name, NULL, NULL, NULL, &len); + if (res == ERROR_FILE_NOT_FOUND) + { + WINE_TRACE("Value not present - using default\n"); + buffer = def ? strdupA(def) : NULL; + goto end; + } else if (res != ERROR_SUCCESS) + { + WINE_ERR("Couldn't query value's length (res=%ld)\n", res); + goto end; + } + + buffer = HeapAlloc(GetProcessHeap(), 0, len + 1); + + RegQueryValueEx(hSubKey, name, NULL, NULL, buffer, &len); + + WINE_TRACE("buffer=%s\n", buffer); +end: + if (hSubKey) RegCloseKey(hSubKey); + + return buffer; +} + +/** + * setkey: convenience wrapper to set a key/value pair + * + * const char *subKey : the name of the config section + * const char *valueName : the name of the config value + * const char *value : the value to set the configuration key to + * + * Returns 0 on success, non-zero otherwise + * + * If valueName or value is NULL, an empty section will be created + */ +int setkey(const char *subkey, const char *name, const char *value) { + DWORD res = 1; + HKEY key = NULL; + + WINE_TRACE("subkey=%s: name=%s, value=%s\n", subkey, name, value); + + assert( subkey != NULL ); + + res = RegCreateKey(config_key, subkey, &key); + if (res != ERROR_SUCCESS) goto end; + if (name == NULL || value == NULL) goto end; + + res = RegSetValueEx(key, name, 0, REG_SZ, value, strlen(value) + 1); + if (res != ERROR_SUCCESS) goto end; + + res = 0; +end: + if (key) RegCloseKey(key); + if (res != 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", name, subkey, value, res); + return res; +} + +/* removes the requested value from the registry, however, does not + * remove the section if empty. Returns S_OK (0) on success. + */ +static HRESULT remove_value(const char *subkey, const char *name) +{ + HRESULT hr; + HKEY key; + + WINE_TRACE("subkey=%s, name=%s\n", subkey, name); + + hr = RegOpenKeyEx(config_key, subkey, 0, KEY_READ, &key); + if (hr != S_OK) return hr; + + hr = RegDeleteValue(key, name); + if (hr != ERROR_SUCCESS) return hr; + + return S_OK; +} + +/* removes the requested subkey from the registry, assuming it exists */ +static HRESULT remove_path(char *section) { + WINE_TRACE("section=%s\n", section); + + return RegDeleteKey(config_key, section); +} + + +/* ========================================================================= */ + +/* This code exists for the following reasons: + * + * - It makes working with the registry easier + * - By storing a mini cache of the registry, we can more easily implement + * cancel/revert and apply. The 'settings list' is an overlay on top of + * the actual registry data that we can write out at will. + * + * Rather than model a tree in memory, we simply store each absolute (rooted + * at the config key) path. + * + */ + +struct setting +{ + struct list entry; + char *path; /* path in the registry rooted at the config key */ + char *name; /* name of the registry value */ + char *value; /* contents of the registry value. if null, this means a deletion */ +}; + +struct list *settings; + +static void free_setting(struct setting *setting) +{ + assert( setting != NULL ); + + WINE_TRACE("destroying %p\n", setting); + + assert( setting->path && setting->name ); + + HeapFree(GetProcessHeap(), 0, setting->path); + HeapFree(GetProcessHeap(), 0, setting->name); + if (setting->value) HeapFree(GetProcessHeap(), 0, setting->value); + + list_remove(&setting->entry); + + HeapFree(GetProcessHeap(), 0, setting); +} + +/** + * Returns the contents of the value at path. If not in the settings + * list, it will be fetched from the registry - failing that, the + * default will be used. + * + * If already in the list, the contents as given there will be + * returned. You are expected to HeapFree the result. + */ +char *get(char *path, char *name, char *def) +{ + struct list *cursor; + struct setting *s; + char *val; + + WINE_TRACE("path=%s, name=%s, def=%s\n", path, name, def); + + /* check if it's in the list */ + LIST_FOR_EACH( cursor, settings ) + { + s = LIST_ENTRY(cursor, struct setting, entry); + + if (strcasecmp(path, s->path) != 0) continue; + if (strcasecmp(name, s->name) != 0) continue; + + WINE_TRACE("found %s:%s in settings list, returning %s\n", path, name, s->value); + return strdupA(s->value); + } + + /* no, so get from the registry */ + val = getkey(path, name, def); + + WINE_TRACE("returning %s\n", val); + + return val; +} + +/** + * Used to set a registry key. + * + * path is rooted at the config key, ie use "Version" or + * "AppDefaults\\fooapp.exe\\Version". You can use keypath() + * to get such a string. + * + * name is the value name, it must not be null (you cannot create + * empty groups, sorry ...) + * + * value is what to set the value to, or NULL to delete it. + * + * These values will be copied when necessary. + */ +void set(char *path, char *name, char *value) +{ + struct list *cursor; + struct setting *s; + + assert( path != NULL ); + assert( name != NULL ); + + WINE_TRACE("path=%s, name=%s, value=%s\n", path, name, value); + + /* firstly, see if we already set this setting */ + LIST_FOR_EACH( cursor, settings ) + { + struct setting *s = LIST_ENTRY(cursor, struct setting, entry); + + if (strcasecmp(s->path, path) != 0) continue; + if (strcasecmp(s->name, name) != 0) continue; + + /* yes, we have already set it, so just replace the content and return */ + if (s->value) HeapFree(GetProcessHeap(), 0, s->value); + s->value = value ? strdupA(value) : NULL; + + return; + } + + /* otherwise add a new setting for it */ + s = HeapAlloc(GetProcessHeap(), 0, sizeof(struct setting)); + s->path = strdupA(path); + s->name = strdupA(name); + s->value = value ? strdupA(value) : NULL; + + list_add_tail(settings, &s->entry); +} + +/** + * enumerates the value names at the given path, taking into account + * the changes in the settings list. + * + * you are expected to HeapFree each element of the array, which is null + * terminated, as well as the array itself. + */ +char **enumerate_values(char *path) +{ + HKEY key; + DWORD res, i = 0; + char **values = NULL; + int valueslen = 0; + struct list *cursor; + + res = RegOpenKeyEx(config_key, path, 0, KEY_READ, &key); + if (res == ERROR_SUCCESS) + { + while (TRUE) + { + char name[1024]; + DWORD namesize = sizeof(name); + BOOL removed = FALSE; + + /* find out the needed size, allocate a buffer, read the value */ + if ((res = RegEnumValue(key, i, name, &namesize, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS) + break; + + WINE_TRACE("name=%s\n", name); + + /* check if this value name has been removed in the settings list */ + LIST_FOR_EACH( cursor, settings ) + { + struct setting *s = LIST_ENTRY(cursor, struct setting, entry); + if (strcasecmp(s->path, path) != 0) continue; + if (strcasecmp(s->name, name) != 0) continue; + + if (!s->value) + { + WINE_TRACE("this key has been removed, so skipping\n"); + removed = TRUE; + break; + } + } + + if (removed) /* this value was deleted by the user, so don't include it */ + { + HeapFree(GetProcessHeap(), 0, name); + i++; + continue; + } + + /* grow the array if necessary, add buffer to it, iterate */ + if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1)); + else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*)); + + values[valueslen++] = strdupA(name); + WINE_TRACE("valueslen is now %d\n", valueslen); + i++; + } + } + else + { + WINE_WARN("failed opening registry key %s, res=0x%lx\n", path, res); + } + + WINE_TRACE("adding settings in list but not registry\n"); + + /* now we have to add the values that aren't in the registry but are in the settings list */ + LIST_FOR_EACH( cursor, settings ) + { + struct setting *setting = LIST_ENTRY(cursor, struct setting, entry); + BOOL found = FALSE; + + if (strcasecmp(setting->path, path) != 0) continue; + + if (!setting->value) continue; + + for (i = 0; i < valueslen; i++) + { + if (strcasecmp(setting->name, values[i]) == 0) + { + found = TRUE; + break; + } + } + + if (found) continue; + + WINE_TRACE("%s in list but not registry\n", setting->name); + + /* otherwise it's been set by the user but isn't in the registry */ + if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1)); + else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*)); + + values[valueslen++] = strdupA(setting->name); + } + + WINE_TRACE("adding null terminator\n"); + if (values) + { + values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1)); + values[valueslen] = NULL; + } + + RegCloseKey(key); + + return values; +} + +/** + * returns true if the given key/value pair exists in the registry or + * has been written to. + */ +BOOL exists(char *path, char *name) +{ + char *val = get(path, name, NULL); + + if (val) + { + HeapFree(GetProcessHeap(), 0, val); + return TRUE; + } + + return FALSE; +} + +static void process_setting(struct setting *s) +{ + if (s->value) + { + WINE_TRACE("Setting %s:%s to '%s'\n", s->path, s->name, s->value); + setkey(s->path, s->name, s->value); + } + else + { + /* NULL name means remove that path/section entirely */ + if (s->path && s->name) remove_value(s->path, s->name); + else if (s->path && !s->name) remove_path(s->path); + } +} + +void apply(void) +{ + if (list_empty(settings)) return; /* we will be called for each page when the user clicks OK */ + + WINE_TRACE("()\n"); + + while (!list_empty(settings)) + { + struct setting *s = (struct setting *) list_head(settings); + process_setting(s); + free_setting(s); + } +} + +/* ================================== utility functions ============================ */ + +char *currentApp = NULL; /* the app we are currently editing, or NULL if editing global */ + +/* returns a registry key path suitable for passing to addTransaction */ +char *keypath(char *section) +{ + static char *result = NULL; + + if (result) HeapFree(GetProcessHeap(), 0, result); + + if (currentApp) + { + result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + strlen(currentApp) + 2 /* \\ */ + strlen(section) + 1 /* terminator */); + sprintf(result, "AppDefaults\\%s\\%s", currentApp, section); + } + else + { + result = strdupA(section); + } + + return result; +} + +/* returns a string with the window text of the dialog item. user is responsible for freeing the result */ +char *getDialogItemText(HWND hDlg, WORD controlID) { + HWND item = GetDlgItem(hDlg, controlID); + int len = GetWindowTextLength(item) + 1; + char *result = malloc(len); + if (GetWindowText(item, result, len) == 0) return NULL; + return result; +} + +void PRINTERROR(void) +{ + LPSTR msg; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPSTR)&msg, 0, NULL); + WINE_TRACE("error: '%s'\n", msg); +} + +int initialize(void) { + DWORD res = RegCreateKey(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, &config_key); + + if (res != ERROR_SUCCESS) { + WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res); + return 1; + } + + /* we could probably just have the list as static data */ + settings = HeapAlloc(GetProcessHeap(), 0, sizeof(struct list)); + list_init(settings); + + return 0; +} diff --git a/programs/winecfg/winecfg.h b/programs/winecfg/winecfg.h index 1bef221d9fd..548634f581b 100644 --- a/programs/winecfg/winecfg.h +++ b/programs/winecfg/winecfg.h @@ -45,30 +45,21 @@ } #define WRITEME(owner) MessageBox(owner, "Write me!", "", MB_OK | MB_ICONEXCLAMATION); - -/* Transaction management */ -enum transaction_action { - ACTION_SET, - ACTION_REMOVE -}; - -struct transaction { - char *section; - char *key; - char *newValue; - enum transaction_action action; - struct transaction *next, *prev; -}; -extern struct transaction *tqhead, *tqtail; - -extern int instantApply; /* non-zero means apply all changes instantly */ +extern char *currentApp; /* NULL means editing global settings */ -#define EDITING_GLOBAL 0 -#define EDITING_APP 1 -extern int appSettings; /* non-zero means we are editing appdefault settings */ +/* Use get and set to alter registry settings. The changes made through set + won't be committed to the registry until process_all_settings is called, + however get will still return accurate information. -extern char *currentApp; /* NULL means editing global settings */ + You are expected to release the result of get. The parameters to set will + be copied, so release them too when necessary. + */ +void set(char *path, char *name, char *value); +char *get(char *path, char *name, char *def); +BOOL exists(char *path, char *name); +void apply(void); +char **enumerate_values(char *path); /* returns a string of the form "AppDefaults\\appname.exe\\section", or just "section" if * the user is editing the global settings. @@ -77,31 +68,11 @@ extern char *currentApp; /* NULL means editing global settings */ */ char *keypath(char *section); -/* Commits a transaction to the registry */ -void processTransaction(struct transaction *trans); - -/* Processes every pending transaction in the queue, removing them as it works from head to tail */ -void processTransQueue(); - -/* Adds a transaction to the head of the queue. If we're using instant apply, this calls processTransaction - * action can be either: - * ACTION_SET -> this transaction will change a registry key, newValue is the replacement value - * ACTION_REMOVE -> this transaction will remove a registry key. In this case, newValue is ignored. - */ -void addTransaction(const char *section, const char *key, enum transaction_action action, const char *newValue); - -/* frees the transaction structure, all fields, and removes it from the queue if in it */ -void destroyTransaction(struct transaction *trans); - /* Initializes the transaction system */ int initialize(void); -extern HKEY configKey; +extern HKEY config_key; -/* don't use these directly! */ -int setConfigValue (const char *subkey, const char *valueName, const char *value); -char *getConfigValue (const char *subkey, const char *valueName, const char *defaultResult); -HRESULT doesConfigValueExist (const char *subkey, const char *valueName); -HRESULT removeConfigValue (const char *subkey, const char *valueName); +void set_window_title(HWND dialog); /* Graphics */ @@ -125,14 +96,12 @@ INT_PTR CALLBACK AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara char *getDialogItemText(HWND hDlg, WORD controlID); #define disable(id) EnableWindow(GetDlgItem(dialog, id), 0); #define enable(id) EnableWindow(GetDlgItem(dialog, id), 1); -#define alloc(size) HeapAlloc(GetProcessHeap(), 0, size); -#define release(ptr) HeapFree(GetProcessHeap(), 0, ptr); void PRINTERROR(void); /* WINE_TRACE() the plaintext error message from GetLastError() */ /* returns a string in the win32 heap */ static inline char *strdupA(char *s) { - char *r = alloc(strlen(s)); + char *r = HeapAlloc(GetProcessHeap(), 0, strlen(s)); return strcpy(r, s); } diff --git a/programs/winecfg/x11drvdlg.c b/programs/winecfg/x11drvdlg.c index 8003944f636..7a34edafb7c 100644 --- a/programs/winecfg/x11drvdlg.c +++ b/programs/winecfg/x11drvdlg.c @@ -36,19 +36,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(winecfg); #define RES_MAXLEN 5 /* the maximum number of characters in a screen dimension. 5 digits should be plenty, what kind of crazy person runs their screen >10,000 pixels across? */ -int updatingUI; +int updating_ui; -int appSettings = EDITING_GLOBAL; /* start by editing global */ - -void updateGUIForDesktopMode(HWND dialog) { +void update_gui_for_desktop_mode(HWND dialog) { WINE_TRACE("\n"); - updatingUI = TRUE; + updating_ui = TRUE; /* do we have desktop mode enabled? */ - if (doesConfigValueExist(keypath("x11drv"), "Desktop") == S_OK) { + if (exists(keypath("x11drv"), "Desktop")) + { CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_CHECKED); - /* enable the controls */ + enable(IDC_DESKTOP_WIDTH); enable(IDC_DESKTOP_HEIGHT); enable(IDC_DESKTOP_SIZE); @@ -57,9 +56,10 @@ void updateGUIForDesktopMode(HWND dialog) { SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_WIDTH), "640"); SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), "480"); } - else { + else + { CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_UNCHECKED); - /* disable the controls */ + disable(IDC_DESKTOP_WIDTH); disable(IDC_DESKTOP_HEIGHT); disable(IDC_DESKTOP_SIZE); @@ -69,22 +69,22 @@ void updateGUIForDesktopMode(HWND dialog) { SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), ""); } - updatingUI = FALSE; + updating_ui = FALSE; } /* pokes the win32 api to setup the dialog from the config struct */ void initGraphDlg (HWND hDlg) { - static const char default_desktop[] = "640x480"; + static char *default_desktop = "640x480"; char *buf; char *bufindex; - updateGUIForDesktopMode(hDlg); + update_gui_for_desktop_mode(hDlg); - updatingUI = TRUE; + updating_ui = TRUE; /* desktop size */ - buf = getConfigValue(keypath("x11drv"), "Desktop", default_desktop); + buf = get(keypath("x11drv"), "Desktop", default_desktop); bufindex = strchr(buf, 'x'); if(!bufindex) /* handle invalid "Desktop" values */ { @@ -96,7 +96,7 @@ void initGraphDlg (HWND hDlg) bufindex++; SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), buf); SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), bufindex); - free(buf); + HeapFree(GetProcessHeap(), 0, buf); SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "8 bit"); @@ -104,7 +104,7 @@ void initGraphDlg (HWND hDlg) SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "24 bit"); SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "32 bit"); /* is this valid? */ - buf = getConfigValue(keypath("x11drv"), "ScreenDepth", "24"); + buf = get(keypath("x11drv"), "ScreenDepth", "24"); if (strcmp(buf, "8") == 0) SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_SETCURSEL, 0, 0); else if (strcmp(buf, "16") == 0) @@ -115,36 +115,34 @@ void initGraphDlg (HWND hDlg) SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_SETCURSEL, 3, 0); else WINE_ERR("Invalid screen depth read from registry (%s)\n", buf); - free(buf); + HeapFree(GetProcessHeap(), 0, buf); SendDlgItemMessage(hDlg, IDC_DESKTOP_WIDTH, EM_LIMITTEXT, RES_MAXLEN, 0); SendDlgItemMessage(hDlg, IDC_DESKTOP_HEIGHT, EM_LIMITTEXT, RES_MAXLEN, 0); - buf = getConfigValue(keypath("x11drv"), "DXGrab", "Y"); + buf = get(keypath("x11drv"), "DXGrab", "Y"); if (IS_OPTION_TRUE(*buf)) CheckDlgButton(hDlg, IDC_DX_MOUSE_GRAB, BST_CHECKED); else CheckDlgButton(hDlg, IDC_DX_MOUSE_GRAB, BST_UNCHECKED); - free(buf); + HeapFree(GetProcessHeap(), 0, buf); - buf = getConfigValue(keypath("x11drv"), "DesktopDoubleBuffered", "Y"); + buf = get(keypath("x11drv"), "DesktopDoubleBuffered", "Y"); if (IS_OPTION_TRUE(*buf)) CheckDlgButton(hDlg, IDC_DOUBLE_BUFFER, BST_CHECKED); else CheckDlgButton(hDlg, IDC_DOUBLE_BUFFER, BST_UNCHECKED); - free(buf); + HeapFree(GetProcessHeap(), 0, buf); - updatingUI = FALSE; + updating_ui = FALSE; } - - void setFromDesktopSizeEdits(HWND hDlg) { - char *width = malloc(RES_MAXLEN+1); - char *height = malloc(RES_MAXLEN+1); - char *newStr = malloc((RES_MAXLEN*2) + 2); + char *width = HeapAlloc(GetProcessHeap(), 0, RES_MAXLEN+1); + char *height = HeapAlloc(GetProcessHeap(), 0, RES_MAXLEN+1); + char *new = HeapAlloc(GetProcessHeap(), 0, (RES_MAXLEN*2) + 2); - if (updatingUI) return; + if (updating_ui) goto end; WINE_TRACE("\n"); @@ -154,12 +152,13 @@ void setFromDesktopSizeEdits(HWND hDlg) { if (strcmp(width, "") == 0) strcpy(width, "640"); if (strcmp(height, "") == 0) strcpy(height, "480"); - sprintf(newStr, "%sx%s", width, height); - addTransaction(keypath("x11drv"), "Desktop", ACTION_SET, newStr); - - free(width); - free(height); - free(newStr); + sprintf(new, "%sx%s", width, height); + set(keypath("x11drv"), "Desktop", new); + +end: + HeapFree(GetProcessHeap(), 0, width); + HeapFree(GetProcessHeap(), 0, height); + HeapFree(GetProcessHeap(), 0, new); } void onEnableDesktopClicked(HWND hDlg) { @@ -169,9 +168,9 @@ void onEnableDesktopClicked(HWND hDlg) { setFromDesktopSizeEdits(hDlg); } else { /* it was just checked, so remove the config values */ - addTransaction(keypath("x11drv"), "Desktop", ACTION_REMOVE, NULL); + set(keypath("x11drv"), "Desktop", NULL); } - updateGUIForDesktopMode(hDlg); + update_gui_for_desktop_mode(hDlg); } void onScreenDepthChanged(HWND hDlg) { @@ -179,26 +178,26 @@ void onScreenDepthChanged(HWND hDlg) { char *spaceIndex = strchr(newvalue, ' '); WINE_TRACE("newvalue=%s\n", newvalue); - if (updatingUI) return; + if (updating_ui) return; *spaceIndex = '\0'; - addTransaction(keypath("x11drv"), "ScreenDepth", ACTION_SET, newvalue); + set(keypath("x11drv"), "ScreenDepth", newvalue); free(newvalue); } void onDXMouseGrabClicked(HWND hDlg) { if (IsDlgButtonChecked(hDlg, IDC_DX_MOUSE_GRAB) == BST_CHECKED) - addTransaction(keypath("x11drv"), "DXGrab", ACTION_SET, "Y"); + set(keypath("x11drv"), "DXGrab", "Y"); else - addTransaction(keypath("x11drv"), "DXGrab", ACTION_SET, "N"); + set(keypath("x11drv"), "DXGrab", "N"); } void onDoubleBufferClicked(HWND hDlg) { if (IsDlgButtonChecked(hDlg, IDC_DOUBLE_BUFFER) == BST_CHECKED) - addTransaction(keypath("x11drv"), "DesktopDoubleBuffered", ACTION_SET, "Y"); + set(keypath("x11drv"), "DesktopDoubleBuffered", "Y"); else - addTransaction(keypath("x11drv"), "DesktopDoubleBuffered", ACTION_SET, "N"); + set(keypath("x11drv"), "DesktopDoubleBuffered", "N"); } INT_PTR CALLBACK @@ -207,17 +206,21 @@ GraphDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) switch (uMsg) { case WM_INITDIALOG: break; - + + case WM_SHOWWINDOW: + set_window_title(hDlg); + break; + case WM_COMMAND: switch(HIWORD(wParam)) { case EN_CHANGE: { SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); - if ( ((LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT)) && !updatingUI ) + if ( ((LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT)) && !updating_ui ) setFromDesktopSizeEdits(hDlg); break; } case BN_CLICKED: { - if (updatingUI) break; + if (updating_ui) break; switch(LOWORD(wParam)) { case IDC_ENABLE_DESKTOP: onEnableDesktopClicked(hDlg); break; case IDC_DX_MOUSE_GRAB: onDXMouseGrabClicked(hDlg); break; @@ -243,6 +246,7 @@ GraphDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) break; } case PSN_APPLY: { + apply(); SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); break; } -- 2.11.4.GIT