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
30 * - Settings migration code (from old configs)
31 * - Clean up resource.h, it's a bog
33 * Minor things that should be done someday:
34 * - Make the desktop size UI a combo box, with a Custom option, so it's more obvious what you might want to choose here
37 * - WineLook default fallback doesn't work
38 * - x11drv page triggers key writes on entry
47 #include <wine/debug.h>
49 WINE_DEFAULT_DEBUG_CHANNEL(winecfg
);
53 HKEY configKey
= NULL
;
56 int initialize(void) {
57 DWORD res
= RegCreateKey(HKEY_LOCAL_MACHINE
, WINE_KEY_ROOT
, &configKey
);
58 if (res
!= ERROR_SUCCESS
) {
59 WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res
);
66 /*****************************************************************************
67 * getConfigValue: Retrieves a configuration value from the registry
69 * const char *subKey : the name of the config section
70 * const char *valueName : the name of the config value
71 * const char *defaultResult : if the key isn't found, return this value instead
73 * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result.
76 char *getConfigValue (const char *subkey
, const char *valueName
, const char *defaultResult
)
83 WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey
, valueName
, defaultResult
);
85 res
= RegOpenKeyEx( configKey
, subkey
, 0, KEY_ALL_ACCESS
, &hSubKey
);
86 if(res
!= ERROR_SUCCESS
) {
87 if( res
==ERROR_FILE_NOT_FOUND
)
89 WINE_TRACE("Section key not present - using default\n");
90 return strdup(defaultResult
);
94 WINE_ERR("RegOpenKey failed on wine config key (res=%ld)\n", res
);
99 res
= RegQueryValueExA( hSubKey
, valueName
, NULL
, NULL
, NULL
, &dataLength
);
100 if( res
== ERROR_FILE_NOT_FOUND
) {
101 WINE_TRACE("Value not present - using default\n");
102 buffer
= strdup(defaultResult
);
104 } else if( res
!=ERROR_SUCCESS
) {
105 WINE_ERR("Couldn't query value's length (res=%ld)\n", res
);
109 buffer
= malloc(dataLength
);
112 WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength
);
116 RegQueryValueEx(hSubKey
, valueName
, NULL
, NULL
, (LPBYTE
)buffer
, &dataLength
);
120 RegCloseKey( hSubKey
);
126 /*****************************************************************************
127 * setConfigValue : Sets a configuration key in the registry. Section will be created if it doesn't already exist
129 * HKEY hCurrent : the registry key that the configuration is rooted at
130 * const char *subKey : the name of the config section
131 * const char *valueName : the name of the config value
132 * const char *value : the value to set the configuration key to
134 * Returns 0 on success, non-zero otherwise
137 int setConfigValue (const char *subkey
, const char *valueName
, const char *value
) {
141 WINE_TRACE("subkey=%s, valueName=%s, value=%s\n", subkey
, valueName
, value
);
143 assert( subkey
!= NULL
);
144 assert( valueName
!= NULL
);
145 assert( value
!= NULL
);
147 res
= RegCreateKey(configKey
, subkey
, &key
);
148 if (res
!= ERROR_SUCCESS
) goto end
;
150 res
= RegSetValueEx(key
, valueName
, 0, REG_SZ
, value
, strlen(value
) + 1);
151 if (res
!= ERROR_SUCCESS
) goto end
;
155 if (key
) RegCloseKey(key
);
156 if (res
!= 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", valueName
, subkey
, value
, res
);
160 /* returns 0 on success, an HRESULT from the registry funtions otherwise */
161 HRESULT
doesConfigValueExist(const char *subkey
, const char *valueName
) {
165 WINE_TRACE("subkey=%s, valueName=%s - ", subkey
, valueName
);
167 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
169 WINE_TRACE("no: subkey does not exist\n");
173 hr
= RegQueryValueEx(key
, valueName
, NULL
, NULL
, NULL
, NULL
);
175 WINE_TRACE("no: key does not exist\n");
184 /* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */
185 HRESULT
removeConfigValue(const char *subkey
, const char *valueName
) {
188 WINE_TRACE("subkey=%s, valueName=%s\n", subkey
, valueName
);
190 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
191 if (hr
!= S_OK
) return hr
;
193 hr
= RegDeleteValue(key
, valueName
);
194 if (hr
!= ERROR_SUCCESS
) return hr
;
199 /* removes the requested configuration section (subkey) from the registry, assuming it exists */
200 /* this function might be slightly pointless, but in future we may wish to treat recursion specially etc, so we'll keep it for now */
201 HRESULT
removeConfigSection(char *section
) {
203 WINE_TRACE("section=%s\n", section
);
205 return hr
= RegDeleteKey(configKey
, section
);
209 /* ========================================================================= */
210 /* Transaction management code */
212 struct transaction
*tqhead
, *tqtail
;
213 int instantApply
= 1;
215 void destroyTransaction(struct transaction
*trans
) {
216 assert( trans
!= NULL
);
218 WINE_TRACE("destroying %p\n", trans
);
220 free(trans
->section
);
221 if (trans
->key
) free(trans
->key
);
222 if (trans
->newValue
) free(trans
->newValue
);
224 if (trans
->next
) trans
->next
->prev
= trans
->prev
;
225 if (trans
->prev
) trans
->prev
->next
= trans
->next
;
226 if (trans
== tqhead
) tqhead
= NULL
;
227 if (trans
== tqtail
) tqtail
= NULL
;
232 void addTransaction(const char *section
, const char *key
, enum transaction_action action
, const char *newValue
) {
233 struct transaction
*trans
= calloc(sizeof(struct transaction
),1);
235 assert( section
!= NULL
);
236 if (action
== ACTION_SET
) assert( newValue
!= NULL
);
237 if (action
== ACTION_SET
) assert( key
!= NULL
);
239 trans
->section
= strdup(section
);
240 if (key
) trans
->key
= strdup(key
);
241 if (newValue
) trans
->newValue
= strdup(newValue
);
242 trans
->action
= action
;
244 if (tqtail
== NULL
) {
248 tqhead
->next
= trans
;
249 trans
->prev
= tqhead
;
254 processTransaction(trans
);
255 destroyTransaction(trans
);
259 void processTransaction(struct transaction
*trans
) {
260 if (trans
->action
== ACTION_SET
) {
261 WINE_TRACE("Setting %s\\%s to '%s'\n", trans
->section
, trans
->key
, trans
->newValue
);
262 setConfigValue(trans
->section
, trans
->key
, trans
->newValue
);
263 } else if (trans
->action
== ACTION_REMOVE
) {
265 WINE_TRACE("Removing %s\\%s\n", trans
->section
, trans
->key
);
266 removeConfigValue(trans
->section
, trans
->key
);
268 /* NULL key means remove that section entirely */
269 WINE_TRACE("Removing section %s\n", trans
->section
);
270 removeConfigSection(trans
->section
);
273 /* TODO: implement notifications here */
276 void processTransQueue(void)
279 while (tqtail
!= NULL
) {
280 struct transaction
*next
= tqtail
->next
;
281 processTransaction(tqtail
);
282 destroyTransaction(tqtail
);
287 /* ================================== utility functions ============================ */
289 /* returns a string with the window text of the dialog item. user is responsible for freeing the result */
290 char *getDialogItemText(HWND hDlg
, WORD controlID
) {
291 HWND item
= GetDlgItem(hDlg
, controlID
);
292 int len
= GetWindowTextLength(item
) + 1;
293 char *result
= malloc(len
);
294 if (GetWindowText(item
, result
, len
) == 0) return NULL
;