Replace SUBLANG_DEFAULT with the specific SUBLANG_XXX constant for languages that...
[wine] / programs / winecfg / winecfg.c
1 /*
2  * WineCfg configuration management
3  *
4  * Copyright 2002 Jaco Greeff
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2003-2004 Mike Hearn
7  *
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.
12  *
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.
17  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * TODO:
23  *  - Use unicode
24  *  - Icons in listviews/icons
25  *  - Better add app dialog, scan c: for EXE files and add to list in background
26  *  - Use [GNOME] HIG style groupboxes rather than win32 style (looks nicer, imho)
27  *
28  */
29
30 #define WIN32_LEAN_AND_MEAN
31
32 #include <assert.h>
33 #include <stdio.h>
34 #include <limits.h>
35 #include <windows.h>
36 #include <winreg.h>
37 #include <wine/debug.h>
38 #include <wine/list.h>
39
40 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
41
42 #include "winecfg.h"
43 #include "resource.h"
44
45 HKEY config_key = NULL;
46 HMENU hPopupMenus = 0;
47
48
49 /* this is called from the WM_SHOWWINDOW handlers of each tab page.
50  *
51  * it's a nasty hack, necessary because the property sheet insists on resetting the window title
52  * to the title of the tab, which is utterly useless. dropping the property sheet is on the todo list.
53  */
54 void set_window_title(HWND dialog)
55 {
56     WCHAR newtitle[256];
57
58     /* update the window title  */
59     if (current_app)
60     {
61         WCHAR apptitle[256];
62         LoadStringW (GetModuleHandle(NULL), IDS_WINECFG_TITLE_APP, apptitle,
63             sizeof(apptitle)/sizeof(apptitle[0]));
64         wsprintfW (newtitle, apptitle, current_app);
65     }
66     else
67     {
68         LoadStringW (GetModuleHandle(NULL), IDS_WINECFG_TITLE, newtitle,
69             sizeof(newtitle)/sizeof(newtitle[0]));
70     }
71
72     WINE_TRACE("setting title to %s\n", wine_dbgstr_w (newtitle));
73     SendMessageW (GetParent(dialog), PSM_SETTITLEW, 0, (LPARAM) newtitle);
74 }
75
76
77 WCHAR* load_string (UINT id)
78 {
79     WCHAR buf[1024];
80     int len;
81     WCHAR* newStr;
82
83     LoadStringW (GetModuleHandle (NULL), id, buf, sizeof(buf)/sizeof(buf[0]));
84
85     len = lstrlenW (buf);
86     newStr = HeapAlloc (GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR));
87     memcpy (newStr, buf, len * sizeof (WCHAR));
88     newStr[len] = 0;
89     return newStr;
90 }
91
92 /**
93  * get_config_key: Retrieves a configuration value from the registry
94  *
95  * char *subkey : the name of the config section
96  * char *name : the name of the config value
97  * char *default : if the key isn't found, return this value instead
98  *
99  * Returns a buffer holding the value if successful, NULL if
100  * not. Caller is responsible for releasing the result.
101  *
102  */
103 static char *get_config_key (HKEY root, const char *subkey, const char *name, const char *def)
104 {
105     LPSTR buffer = NULL;
106     DWORD len;
107     HKEY hSubKey = NULL;
108     DWORD res;
109
110     WINE_TRACE("subkey=%s, name=%s, def=%s\n", subkey, name, def);
111
112     res = RegOpenKey(root, subkey, &hSubKey);
113     if (res != ERROR_SUCCESS)
114     {
115         if (res == ERROR_FILE_NOT_FOUND)
116         {
117             WINE_TRACE("Section key not present - using default\n");
118             return def ? strdupA(def) : NULL;
119         }
120         else
121         {
122             WINE_ERR("RegOpenKey failed on wine config key (res=%d)\n", res);
123         }
124         goto end;
125     }
126
127     res = RegQueryValueExA(hSubKey, name, NULL, NULL, NULL, &len);
128     if (res == ERROR_FILE_NOT_FOUND)
129     {
130         WINE_TRACE("Value not present - using default\n");
131         buffer = def ? strdupA(def) : NULL;
132         goto end;
133     } else if (res != ERROR_SUCCESS)
134     {
135         WINE_ERR("Couldn't query value's length (res=%d)\n", res);
136         goto end;
137     }
138
139     buffer = HeapAlloc(GetProcessHeap(), 0, len + 1);
140
141     RegQueryValueEx(hSubKey, name, NULL, NULL, (LPBYTE) buffer, &len);
142
143     WINE_TRACE("buffer=%s\n", buffer);
144 end:
145     if (hSubKey && hSubKey != root) RegCloseKey(hSubKey);
146
147     return buffer;
148 }
149
150 /**
151  * set_config_key: convenience wrapper to set a key/value pair
152  *
153  * const char *subKey : the name of the config section
154  * const char *valueName : the name of the config value
155  * const char *value : the value to set the configuration key to
156  *
157  * Returns 0 on success, non-zero otherwise
158  *
159  * If valueName or value is NULL, an empty section will be created
160  */
161 static int set_config_key(HKEY root, const char *subkey, const char *name, const void *value, DWORD type) {
162     DWORD res = 1;
163     HKEY key = NULL;
164
165     WINE_TRACE("subkey=%s: name=%s, value=%p, type=%d\n", subkey, name, value, type);
166
167     assert( subkey != NULL );
168
169     if (subkey[0])
170     {
171         res = RegCreateKey(root, subkey, &key);
172         if (res != ERROR_SUCCESS) goto end;
173     }
174     else key = root;
175     if (name == NULL || value == NULL) goto end;
176
177     switch (type)
178     {
179         case REG_SZ: res = RegSetValueEx(key, name, 0, REG_SZ, value, strlen(value) + 1); break;
180         case REG_DWORD: res = RegSetValueEx(key, name, 0, REG_DWORD, value, sizeof(DWORD)); break;
181     }
182     if (res != ERROR_SUCCESS) goto end;
183
184     res = 0;
185 end:
186     if (key && key != root) RegCloseKey(key);
187     if (res != 0) WINE_ERR("Unable to set configuration key %s in section %s, res=%d\n", name, subkey, res);
188     return res;
189 }
190
191 /* removes the requested value from the registry, however, does not
192  * remove the section if empty. Returns S_OK (0) on success.
193  */
194 static HRESULT remove_value(HKEY root, const char *subkey, const char *name)
195 {
196     HRESULT hr;
197     HKEY key;
198
199     WINE_TRACE("subkey=%s, name=%s\n", subkey, name);
200
201     hr = RegOpenKey(root, subkey, &key);
202     if (hr != S_OK) return hr;
203
204     hr = RegDeleteValue(key, name);
205     if (hr != ERROR_SUCCESS) return hr;
206
207     return S_OK;
208 }
209
210 /* removes the requested subkey from the registry, assuming it exists */
211 static LONG remove_path(HKEY root, char *section) {
212     HKEY branch_key;
213     DWORD max_sub_key_len;
214     DWORD subkeys;
215     DWORD curr_len;
216     LONG ret = ERROR_SUCCESS;
217     long int i;
218     char *buffer;
219
220     WINE_TRACE("section=%s\n", section);
221
222     if ((ret = RegOpenKey(root, section, &branch_key)) != ERROR_SUCCESS)
223         return ret;
224
225     /* get size information and resize the buffers if necessary */
226     if ((ret = RegQueryInfoKey(branch_key, NULL, NULL, NULL,
227                                &subkeys, &max_sub_key_len,
228                                NULL, NULL, NULL, NULL, NULL, NULL
229                               )) != ERROR_SUCCESS)
230         return ret;
231
232     curr_len = strlen(section);
233     buffer = HeapAlloc(GetProcessHeap(), 0, max_sub_key_len + curr_len + 1);
234     strcpy(buffer, section);
235
236     buffer[curr_len] = '\\';
237     for (i = subkeys - 1; i >= 0; i--)
238     {
239         DWORD buf_len = max_sub_key_len - curr_len - 1;
240
241         ret = RegEnumKeyEx(branch_key, i, buffer + curr_len + 1,
242                            &buf_len, NULL, NULL, NULL, NULL);
243         if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA &&
244             ret != ERROR_NO_MORE_ITEMS)
245             break;
246         else
247             remove_path(root, buffer);
248     }
249     HeapFree(GetProcessHeap(), 0, buffer);
250     RegCloseKey(branch_key);
251
252     return RegDeleteKey(root, section);
253 }
254
255
256 /* ========================================================================= */
257
258 /* This code exists for the following reasons:
259  *
260  * - It makes working with the registry easier
261  * - By storing a mini cache of the registry, we can more easily implement
262  *   cancel/revert and apply. The 'settings list' is an overlay on top of
263  *   the actual registry data that we can write out at will.
264  *
265  * Rather than model a tree in memory, we simply store each absolute (rooted
266  * at the config key) path.
267  *
268  */
269
270 struct setting
271 {
272     struct list entry;
273     HKEY root;    /* the key on which path is rooted */
274     char *path;   /* path in the registry rooted at root  */
275     char *name;   /* name of the registry value. if null, this means delete the key  */
276     char *value;  /* contents of the registry value. if null, this means delete the value  */
277     DWORD type;   /* type of registry value. REG_SZ or REG_DWORD for now */
278 };
279
280 struct list *settings;
281
282 static void free_setting(struct setting *setting)
283 {
284     assert( setting != NULL );
285     assert( setting->path );
286
287     WINE_TRACE("destroying %p: %s\n", setting, setting->path);
288     
289     HeapFree(GetProcessHeap(), 0, setting->path);
290     HeapFree(GetProcessHeap(), 0, setting->name);
291     HeapFree(GetProcessHeap(), 0, setting->value);
292
293     list_remove(&setting->entry);
294
295     HeapFree(GetProcessHeap(), 0, setting);
296 }
297
298 /**
299  * Returns the contents of the value at path. If not in the settings
300  * list, it will be fetched from the registry - failing that, the
301  * default will be used.
302  *
303  * If already in the list, the contents as given there will be
304  * returned. You are expected to HeapFree the result.
305  */
306 char *get_reg_key(HKEY root, const char *path, const char *name, const char *def)
307 {
308     struct list *cursor;
309     struct setting *s;
310     char *val;
311
312     WINE_TRACE("path=%s, name=%s, def=%s\n", path, name, def);
313
314     /* check if it's in the list */
315     LIST_FOR_EACH( cursor, settings )
316     {
317         s = LIST_ENTRY(cursor, struct setting, entry);
318
319         if (root != s->root) continue;
320         if (strcasecmp(path, s->path) != 0) continue;
321         if (!s->name) continue;
322         if (strcasecmp(name, s->name) != 0) continue;
323
324         WINE_TRACE("found %s:%s in settings list, returning %s\n", path, name, s->value);
325         return s->value ? strdupA(s->value) : NULL;
326     }
327
328     /* no, so get from the registry */
329     val = get_config_key(root, path, name, def);
330
331     WINE_TRACE("returning %s\n", val);
332
333     return val;
334 }
335
336 /**
337  * Used to set a registry key.
338  *
339  * path is rooted at the config key, ie use "Version" or
340  * "AppDefaults\\fooapp.exe\\Version". You can use keypath()
341  * to get such a string.
342  *
343  * name is the value name, or NULL to delete the path.
344  *
345  * value is what to set the value to, or NULL to delete it.
346  *
347  * type is REG_SZ or REG_DWORD.
348  *
349  * These values will be copied when necessary.
350  */
351 static void set_reg_key_ex(HKEY root, const char *path, const char *name, const void *value, DWORD type)
352 {
353     struct list *cursor;
354     struct setting *s;
355
356     assert( path != NULL );
357
358     WINE_TRACE("path=%s, name=%s, value=%p\n", path, name, value);
359
360     /* firstly, see if we already set this setting  */
361     LIST_FOR_EACH( cursor, settings )
362     {
363         struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
364
365         if (root != s->root) continue;
366         if (strcasecmp(s->path, path) != 0) continue;
367         if ((s->name && name) && strcasecmp(s->name, name) != 0) continue;
368
369         /* are we attempting a double delete? */
370         if (!s->name && !name) return;
371
372         /* do we want to undelete this key? */
373         if (!s->name && name) s->name = strdupA(name);
374
375         /* yes, we have already set it, so just replace the content and return  */
376         HeapFree(GetProcessHeap(), 0, s->value);
377         s->type = type;
378         switch (type)
379         {
380             case REG_SZ:
381                 s->value = value ? strdupA(value) : NULL;
382                 break;
383             case REG_DWORD:
384                 s->value = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
385                 memcpy( s->value, value, sizeof(DWORD) );
386                 break;
387         }
388
389         /* are we deleting this key? this won't remove any of the
390          * children from the overlay so if the user adds it again in
391          * that session it will appear to undelete the settings, but
392          * in reality only the settings actually modified by the user
393          * in that session will be restored. we might want to fix this
394          * corner case in future by actually deleting all the children
395          * here so that once it's gone, it's gone.
396          */
397         if (!name) s->name = NULL;
398
399         return;
400     }
401
402     /* otherwise add a new setting for it  */
403     s = HeapAlloc(GetProcessHeap(), 0, sizeof(struct setting));
404     s->root  = root;
405     s->path  = strdupA(path);
406     s->name  = name  ? strdupA(name)  : NULL;
407     s->type  = type;
408     switch (type)
409     {
410         case REG_SZ:
411             s->value = value ? strdupA(value) : NULL;
412             break;
413         case REG_DWORD:
414             s->value = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
415             memcpy( s->value, value, sizeof(DWORD) );
416             break;
417     }
418
419     list_add_tail(settings, &s->entry);
420 }
421
422 void set_reg_key(HKEY root, const char *path, const char *name, const char *value)
423 {
424     set_reg_key_ex(root, path, name, value, REG_SZ);
425 }
426
427 void set_reg_key_dword(HKEY root, const char *path, const char *name, DWORD value)
428 {
429     set_reg_key_ex(root, path, name, &value, REG_DWORD);
430 }
431
432 /**
433  * enumerates the value names at the given path, taking into account
434  * the changes in the settings list.
435  *
436  * you are expected to HeapFree each element of the array, which is null
437  * terminated, as well as the array itself.
438  */
439 char **enumerate_values(HKEY root, char *path)
440 {
441     HKEY key;
442     DWORD res, i = 0;
443     char **values = NULL;
444     int valueslen = 0;
445     struct list *cursor;
446
447     res = RegOpenKey(root, path, &key);
448     if (res == ERROR_SUCCESS)
449     {
450         while (TRUE)
451         {
452             char name[1024];
453             DWORD namesize = sizeof(name);
454             BOOL removed = FALSE;
455
456             /* find out the needed size, allocate a buffer, read the value  */
457             if ((res = RegEnumValue(key, i, name, &namesize, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS)
458                 break;
459
460             WINE_TRACE("name=%s\n", name);
461
462             /* check if this value name has been removed in the settings list  */
463             LIST_FOR_EACH( cursor, settings )
464             {
465                 struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
466                 if (strcasecmp(s->path, path) != 0) continue;
467                 if (strcasecmp(s->name, name) != 0) continue;
468
469                 if (!s->value)
470                 {
471                     WINE_TRACE("this key has been removed, so skipping\n");
472                     removed = TRUE;
473                     break;
474                 }
475             }
476
477             if (removed)            /* this value was deleted by the user, so don't include it */
478             {
479                 HeapFree(GetProcessHeap(), 0, name);
480                 i++;
481                 continue;
482             }
483
484             /* grow the array if necessary, add buffer to it, iterate  */
485             if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
486             else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*));
487
488             values[valueslen++] = strdupA(name);
489             WINE_TRACE("valueslen is now %d\n", valueslen);
490             i++;
491         }
492     }
493     else
494     {
495         WINE_WARN("failed opening registry key %s, res=0x%x\n", path, res);
496     }
497
498     WINE_TRACE("adding settings in list but not registry\n");
499
500     /* now we have to add the values that aren't in the registry but are in the settings list */
501     LIST_FOR_EACH( cursor, settings )
502     {
503         struct setting *setting = LIST_ENTRY(cursor, struct setting, entry);
504         BOOL found = FALSE;
505
506         if (strcasecmp(setting->path, path) != 0) continue;
507
508         if (!setting->value) continue;
509
510         for (i = 0; i < valueslen; i++)
511         {
512             if (strcasecmp(setting->name, values[i]) == 0)
513             {
514                 found = TRUE;
515                 break;
516             }
517         }
518
519         if (found) continue;
520
521         WINE_TRACE("%s in list but not registry\n", setting->name);
522
523         /* otherwise it's been set by the user but isn't in the registry */
524         if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
525         else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*));
526
527         values[valueslen++] = strdupA(setting->name);
528     }
529
530     WINE_TRACE("adding null terminator\n");
531     if (values)
532     {
533         values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
534         values[valueslen] = NULL;
535     }
536
537     RegCloseKey(key);
538
539     return values;
540 }
541
542 /**
543  * returns true if the given key/value pair exists in the registry or
544  * has been written to.
545  */
546 BOOL reg_key_exists(HKEY root, const char *path, const char *name)
547 {
548     char *val = get_reg_key(root, path, name, NULL);
549
550     if (val)
551     {
552         HeapFree(GetProcessHeap(), 0, val);
553         return TRUE;
554     }
555
556     return FALSE;
557 }
558
559 static void process_setting(struct setting *s)
560 {
561     if (s->value)
562     {
563         WINE_TRACE("Setting %s:%s to '%s'\n", s->path, s->name, s->value);
564         set_config_key(s->root, s->path, s->name, s->value, s->type);
565     }
566     else
567     {
568         /* NULL name means remove that path/section entirely */
569         if (s->path && s->name) remove_value(s->root, s->path, s->name);
570         else if (s->path && !s->name) remove_path(s->root, s->path);
571     }
572 }
573
574 void apply(void)
575 {
576     if (list_empty(settings)) return; /* we will be called for each page when the user clicks OK */
577
578     WINE_TRACE("()\n");
579
580     while (!list_empty(settings))
581     {
582         struct setting *s = (struct setting *) list_head(settings);
583         process_setting(s);
584         free_setting(s);
585     }
586 }
587
588 /* ================================== utility functions ============================ */
589
590 WCHAR* current_app = NULL; /* the app we are currently editing, or NULL if editing global */
591
592 /* returns a registry key path suitable for passing to addTransaction  */
593 char *keypath(const char *section)
594 {
595     static char *result = NULL;
596
597     HeapFree(GetProcessHeap(), 0, result);
598
599     if (current_app)
600     {
601         result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + lstrlenW(current_app)*2 + 2 /* \\ */ + strlen(section) + 1 /* terminator */);
602         wsprintf(result, "AppDefaults\\%ls", current_app);
603         if (section[0]) sprintf( result + strlen(result), "\\%s", section );
604     }
605     else
606     {
607         result = strdupA(section);
608     }
609
610     return result;
611 }
612
613 void PRINTERROR(void)
614 {
615         LPSTR msg;
616
617         FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
618                        0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
619                        (LPSTR)&msg, 0, NULL);
620
621         /* eliminate trailing newline, is this a Wine bug? */
622         *(strrchr(msg, '\r')) = '\0';
623         
624         WINE_TRACE("error: '%s'\n", msg);
625 }
626
627 int initialize(HINSTANCE hInstance)
628 {
629     DWORD res = RegCreateKey(HKEY_CURRENT_USER, WINE_KEY_ROOT, &config_key);
630
631     if (res != ERROR_SUCCESS) {
632         WINE_ERR("RegOpenKey failed on wine config key (%d)\n", res);
633         return 1;
634     }
635
636     /* load any menus */
637     hPopupMenus = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_WINECFG));
638
639     /* we could probably just have the list as static data  */
640     settings = HeapAlloc(GetProcessHeap(), 0, sizeof(struct list));
641     list_init(settings);
642
643     return 0;
644 }