2 * WineCfg configuration management
4 * Copyright 2002 Jaco Greeff
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2003 Mike Hearn
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * TODO: (in rough order of priority)
23 * - A mind bogglingly vast amount of stuff
25 * - Implement autodetect for drive configuration
26 * - Figure out whether we need the virtual vs real drive selection stuff at the top of the property page
27 * - Implement explicit mode vs instant-apply mode
28 * - AppDefaults handling
30 * - Make a list of prefs that have been dropped from the UI/should be eliminated
32 * - Settings migration code (from old configs)
33 * - Clean up resource.h, it's a bog
35 * Minor things that should be done someday:
36 * - Make the desktop size UI a combo box, with a Custom option, so it's more obvious what you might want to choose here
39 * - WineLook default fallback doesn't work
40 * - x11drv page triggers key writes on entry
49 #include <wine/debug.h>
51 WINE_DEFAULT_DEBUG_CHANNEL(winecfg
);
55 HKEY configKey
= NULL
;
58 int initialize(void) {
59 DWORD res
= RegCreateKey(HKEY_LOCAL_MACHINE
, WINE_KEY_ROOT
, &configKey
);
60 if (res
!= ERROR_SUCCESS
) {
61 WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res
);
68 /*****************************************************************************
69 * getConfigValue: Retrieves a configuration value from the registry
71 * char *subKey : the name of the config section
72 * char *valueName : the name of the config value
73 * char *defaultResult : if the key isn't found, return this value instead
75 * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result.
78 char *getConfigValue (char *subkey
, char *valueName
, char *defaultResult
)
85 WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey
, valueName
, defaultResult
);
87 res
= RegOpenKeyEx( configKey
, subkey
, 0, KEY_ALL_ACCESS
, &hSubKey
);
88 if(res
!= ERROR_SUCCESS
) {
89 if( res
==ERROR_FILE_NOT_FOUND
)
91 WINE_TRACE("Section key not present - using default\n");
92 return strdup(defaultResult
);
96 WINE_ERR("RegOpenKey failed on wine config key (res=%ld)\n", res
);
101 res
= RegQueryValueExA( hSubKey
, valueName
, NULL
, NULL
, NULL
, &dataLength
);
102 if( res
== ERROR_FILE_NOT_FOUND
) {
103 WINE_TRACE("Value not present - using default\n");
104 buffer
= strdup(defaultResult
);
106 } else if( res
!=ERROR_SUCCESS
) {
107 WINE_ERR("Couldn't query value's length (res=%ld)\n", res
);
111 buffer
= malloc(dataLength
);
114 WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength
);
118 RegQueryValueEx(hSubKey
, valueName
, NULL
, NULL
, (LPBYTE
)buffer
, &dataLength
);
122 RegCloseKey( hSubKey
);
128 /*****************************************************************************
129 * setConfigValue : Sets a configuration key in the registry. Section will be created if it doesn't already exist
131 * HKEY hCurrent : the registry key that the configuration is rooted at
132 * char *subKey : the name of the config section
133 * char *valueName : the name of the config value
134 * char *value : the value to set the configuration key to
136 * Returns 0 on success, non-zero otherwise
139 int setConfigValue (char *subkey
, char *valueName
, const char *value
) {
143 WINE_TRACE("subkey=%s, valueName=%s, value=%s\n", subkey
, valueName
, value
);
145 assert( subkey
!= NULL
);
146 assert( valueName
!= NULL
);
147 assert( value
!= NULL
);
149 res
= RegCreateKey(configKey
, subkey
, &key
);
150 if (res
!= ERROR_SUCCESS
) goto end
;
152 res
= RegSetValueEx(key
, valueName
, 0, REG_SZ
, value
, strlen(value
) + 1);
153 if (res
!= ERROR_SUCCESS
) goto end
;
157 if (key
) RegCloseKey(key
);
158 if (res
!= 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", valueName
, subkey
, value
, res
);
162 /* returns 0 on success, an HRESULT from the registry funtions otherwise */
163 HRESULT
doesConfigValueExist(char *subkey
, char *valueName
) {
167 WINE_TRACE("subkey=%s, valueName=%s - ", subkey
, valueName
);
169 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
171 WINE_TRACE("no: subkey does not exist\n");
175 hr
= RegQueryValueEx(key
, valueName
, NULL
, NULL
, NULL
, NULL
);
177 WINE_TRACE("no: key does not exist\n");
186 /* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */
187 HRESULT
removeConfigValue(char *subkey
, char *valueName
) {
190 WINE_TRACE("subkey=%s, valueName=%s\n", subkey
, valueName
);
192 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
193 if (hr
!= S_OK
) return hr
;
195 hr
= RegDeleteValue(key
, valueName
);
196 if (hr
!= ERROR_SUCCESS
) return hr
;
201 /* removes the requested configuration section (subkey) from the registry, assuming it exists */
202 /* this function might be slightly pointless, but in future we may wish to treat recursion specially etc, so we'll keep it for now */
203 HRESULT
removeConfigSection(char *section
) {
205 WINE_TRACE("section=%s\n", section
);
207 return hr
= RegDeleteKey(configKey
, section
);
211 /* ========================================================================= */
212 /* Transaction management code */
214 struct transaction
*tqhead
, *tqtail
;
215 int instantApply
= 1;
217 void destroyTransaction(struct transaction
*trans
) {
218 assert( trans
!= NULL
);
220 WINE_TRACE("destroying %p\n", trans
);
222 free(trans
->section
);
223 if (trans
->key
) free(trans
->key
);
224 if (trans
->newValue
) free(trans
->newValue
);
226 if (trans
->next
) trans
->next
->prev
= trans
->prev
;
227 if (trans
->prev
) trans
->prev
->next
= trans
->next
;
228 if (trans
== tqhead
) tqhead
= NULL
;
229 if (trans
== tqtail
) tqtail
= NULL
;
234 void addTransaction(char *section
, char *key
, enum transaction_action action
, char *newValue
) {
235 struct transaction
*trans
= calloc(sizeof(struct transaction
),1);
237 assert( section
!= NULL
);
238 if (action
== ACTION_SET
) assert( newValue
!= NULL
);
239 if (action
== ACTION_SET
) assert( key
!= NULL
);
241 trans
->section
= strdup(section
);
242 if (key
) trans
->key
= strdup(key
);
243 if (newValue
) trans
->newValue
= strdup(newValue
);
244 trans
->action
= action
;
246 if (tqtail
== NULL
) {
250 tqhead
->next
= trans
;
251 trans
->prev
= tqhead
;
256 processTransaction(trans
);
257 destroyTransaction(trans
);
261 void processTransaction(struct transaction
*trans
) {
262 if (trans
->action
== ACTION_SET
) {
263 WINE_TRACE("Setting %s\\%s to '%s'\n", trans
->section
, trans
->key
, trans
->newValue
);
264 setConfigValue(trans
->section
, trans
->key
, trans
->newValue
);
265 } else if (trans
->action
== ACTION_REMOVE
) {
267 WINE_TRACE("Removing %s\\%s\n", trans
->section
, trans
->key
);
268 removeConfigValue(trans
->section
, trans
->key
);
270 /* NULL key means remove that section entirely */
271 WINE_TRACE("Removing section %s\n", trans
->section
);
272 removeConfigSection(trans
->section
);
275 /* TODO: implement notifications here */
278 void processTransQueue(void)
281 while (tqtail
!= NULL
) {
282 struct transaction
*next
= tqtail
->next
;
283 processTransaction(tqtail
);
284 destroyTransaction(tqtail
);
289 /* ================================== utility functions ============================ */
291 /* returns a string with the window text of the dialog item. user is responsible for freeing the result */
292 char *getDialogItemText(HWND hDlg
, WORD controlID
) {
293 HWND item
= GetDlgItem(hDlg
, controlID
);
294 int len
= GetWindowTextLength(item
) + 1;
295 char *result
= malloc(len
);
296 if (GetWindowText(item
, result
, len
) == 0) return NULL
;