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 * - x11drv page triggers key writes on entry
46 #include <wine/debug.h>
48 WINE_DEFAULT_DEBUG_CHANNEL(winecfg
);
52 HKEY configKey
= NULL
;
55 int initialize(void) {
56 DWORD res
= RegCreateKey(HKEY_LOCAL_MACHINE
, WINE_KEY_ROOT
, &configKey
);
57 if (res
!= ERROR_SUCCESS
) {
58 WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res
);
65 /*****************************************************************************
66 * getConfigValue: Retrieves a configuration value from the registry
68 * const char *subKey : the name of the config section
69 * const char *valueName : the name of the config value
70 * const char *defaultResult : if the key isn't found, return this value instead
72 * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result.
75 char *getConfigValue (const char *subkey
, const char *valueName
, const char *defaultResult
)
82 WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey
, valueName
, defaultResult
);
84 res
= RegOpenKeyEx( configKey
, subkey
, 0, KEY_ALL_ACCESS
, &hSubKey
);
85 if(res
!= ERROR_SUCCESS
) {
86 if( res
==ERROR_FILE_NOT_FOUND
)
88 WINE_TRACE("Section key not present - using default\n");
89 return strdup(defaultResult
);
93 WINE_ERR("RegOpenKey failed on wine config key (res=%ld)\n", res
);
98 res
= RegQueryValueExA( hSubKey
, valueName
, NULL
, NULL
, NULL
, &dataLength
);
99 if( res
== ERROR_FILE_NOT_FOUND
) {
100 WINE_TRACE("Value not present - using default\n");
101 buffer
= strdup(defaultResult
);
103 } else if( res
!=ERROR_SUCCESS
) {
104 WINE_ERR("Couldn't query value's length (res=%ld)\n", res
);
108 buffer
= malloc(dataLength
);
111 WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength
);
115 RegQueryValueEx(hSubKey
, valueName
, NULL
, NULL
, (LPBYTE
)buffer
, &dataLength
);
119 RegCloseKey( hSubKey
);
125 /*****************************************************************************
126 * setConfigValue : Sets a configuration key in the registry. Section will be created if it doesn't already exist
128 * HKEY hCurrent : the registry key that the configuration is rooted at
129 * const char *subKey : the name of the config section
130 * const char *valueName : the name of the config value
131 * const char *value : the value to set the configuration key to
133 * Returns 0 on success, non-zero otherwise
135 * If *valueName or *value is NULL, an empty section will be created
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
);
145 res
= RegCreateKey(configKey
, subkey
, &key
);
146 if (res
!= ERROR_SUCCESS
) goto end
;
147 if (value
== NULL
|| valueName
== NULL
) goto end
;
149 res
= RegSetValueEx(key
, valueName
, 0, REG_SZ
, value
, strlen(value
) + 1);
150 if (res
!= ERROR_SUCCESS
) goto end
;
154 if (key
) RegCloseKey(key
);
155 if (res
!= 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", valueName
, subkey
, value
, res
);
159 /* returns 0 on success, an HRESULT from the registry funtions otherwise */
160 HRESULT
doesConfigValueExist(const char *subkey
, const char *valueName
) {
164 WINE_TRACE("subkey=%s, valueName=%s - ", subkey
, valueName
);
166 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
168 WINE_TRACE("no: subkey does not exist\n");
172 hr
= RegQueryValueEx(key
, valueName
, NULL
, NULL
, NULL
, NULL
);
174 WINE_TRACE("no: key does not exist\n");
183 /* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */
184 HRESULT
removeConfigValue(const char *subkey
, const char *valueName
) {
187 WINE_TRACE("subkey=%s, valueName=%s\n", subkey
, valueName
);
189 hr
= RegOpenKeyEx(configKey
, subkey
, 0, KEY_READ
, &key
);
190 if (hr
!= S_OK
) return hr
;
192 hr
= RegDeleteValue(key
, valueName
);
193 if (hr
!= ERROR_SUCCESS
) return hr
;
198 /* removes the requested configuration section (subkey) from the registry, assuming it exists */
199 /* this function might be slightly pointless, but in future we may wish to treat recursion specially etc, so we'll keep it for now */
200 HRESULT
removeConfigSection(char *section
) {
202 WINE_TRACE("section=%s\n", section
);
204 return hr
= RegDeleteKey(configKey
, section
);
208 /* ========================================================================= */
209 /* Transaction management code */
211 struct transaction
*tqhead
, *tqtail
;
212 int instantApply
= 1;
214 void destroyTransaction(struct transaction
*trans
) {
215 assert( trans
!= NULL
);
217 WINE_TRACE("destroying %p\n", trans
);
219 free(trans
->section
);
220 if (trans
->key
) free(trans
->key
);
221 if (trans
->newValue
) free(trans
->newValue
);
223 if (trans
->next
) trans
->next
->prev
= trans
->prev
;
224 if (trans
->prev
) trans
->prev
->next
= trans
->next
;
225 if (trans
== tqhead
) tqhead
= NULL
;
226 if (trans
== tqtail
) tqtail
= NULL
;
231 void addTransaction(const char *section
, const char *key
, enum transaction_action action
, const char *newValue
) {
232 struct transaction
*trans
= calloc(sizeof(struct transaction
),1);
234 assert( section
!= NULL
);
235 if (action
== ACTION_SET
) assert( newValue
!= NULL
);
236 if (action
== ACTION_SET
) assert( key
!= NULL
);
238 trans
->section
= strdup(section
);
239 if (key
) trans
->key
= strdup(key
);
240 if (newValue
) trans
->newValue
= strdup(newValue
);
241 trans
->action
= action
;
243 if (tqtail
== NULL
) {
247 tqhead
->next
= trans
;
248 trans
->prev
= tqhead
;
253 processTransaction(trans
);
254 destroyTransaction(trans
);
258 void processTransaction(struct transaction
*trans
) {
259 if (trans
->action
== ACTION_SET
) {
260 WINE_TRACE("Setting %s\\%s to '%s'\n", trans
->section
, trans
->key
, trans
->newValue
);
261 setConfigValue(trans
->section
, trans
->key
, trans
->newValue
);
262 } else if (trans
->action
== ACTION_REMOVE
) {
264 WINE_TRACE("Removing %s\\%s\n", trans
->section
, trans
->key
);
265 removeConfigValue(trans
->section
, trans
->key
);
267 /* NULL key means remove that section entirely */
268 WINE_TRACE("Removing section %s\n", trans
->section
);
269 removeConfigSection(trans
->section
);
272 /* TODO: implement notifications here */
275 void processTransQueue(void)
278 while (tqtail
!= NULL
) {
279 struct transaction
*next
= tqtail
->next
;
280 processTransaction(tqtail
);
281 destroyTransaction(tqtail
);
286 /* ================================== utility functions ============================ */
288 /* returns a string with the window text of the dialog item. user is responsible for freeing the result */
289 char *getDialogItemText(HWND hDlg
, WORD controlID
) {
290 HWND item
= GetDlgItem(hDlg
, controlID
);
291 int len
= GetWindowTextLength(item
) + 1;
292 char *result
= malloc(len
);
293 if (GetWindowText(item
, result
, len
) == 0) return NULL
;
297 void PRINTERROR(void)
301 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM
,
302 0, GetLastError(), MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),
303 (LPSTR
)&msg
, 0, NULL
);
304 WINE_TRACE("error: '%s'\n", msg
);