programs: Use WIN32_LEAN_AND_MEAN in some more places.
[wine] / programs / winecfg / libraries.c
1 /*
2  * WineCfg libraries tabsheet
3  *
4  * Copyright 2004 Robert van Herk
5  * Copyright 2004 Mike Hearn
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #define NONAMELESSUNION
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26 #include <commdlg.h>
27 #include <wine/debug.h>
28 #include <stdio.h>
29 #include <assert.h>
30 #include "winecfg.h"
31 #include "resource.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
34
35 enum dllmode
36 {
37         BUILTIN_NATIVE,
38         NATIVE_BUILTIN,
39         BUILTIN,
40         NATIVE,
41         DISABLE,
42         UNKNOWN /* Special value indicating an erronous DLL override mode */
43 };
44
45 struct dll
46 {
47         char *name;
48         enum dllmode mode;
49 };
50
51 /* Convert a registry string to a dllmode */
52 static enum dllmode string_to_mode(char *in)
53 {
54     int i, j, len;
55     char *out;
56     enum dllmode res;
57
58     len = strlen(in);
59     out = HeapAlloc(GetProcessHeap(), 0, len);
60
61     /* remove the spaces */
62     for (i = j = 0; i <= len; ++i) {
63         if (in[i] != ' ') {
64             out[j++] = in[i];
65         }
66     }
67
68     /* parse the string */
69     res = UNKNOWN;
70     if (strcmp(out, "builtin,native") == 0) res = BUILTIN_NATIVE;
71     if (strcmp(out, "native,builtin") == 0) res = NATIVE_BUILTIN;
72     if (strcmp(out, "builtin") == 0) res = BUILTIN;
73     if (strcmp(out, "native") == 0) res = NATIVE;
74     if (strcmp(out, "") == 0) res = DISABLE;
75
76     HeapFree(GetProcessHeap(), 0, out);
77     return res;
78 }
79
80 /* Convert a dllmode to a registry string. */
81 static const char* mode_to_string(enum dllmode mode)
82 {
83     switch( mode )
84     {
85         case NATIVE: return "native";
86         case BUILTIN: return "builtin";
87         case NATIVE_BUILTIN: return "native,builtin";
88         case BUILTIN_NATIVE: return "builtin,native";
89         case DISABLE: return "";
90         default: assert(FALSE); return "";
91     }
92 }
93
94 /* Convert a dllmode to a pretty string for display. TODO: use translations. */
95 static const char* mode_to_label(enum dllmode mode)
96 {
97     WINE_FIXME("translate me\n");
98     return mode_to_string(mode);
99 }
100
101 /* Convert a control id (IDC_ constant) to a dllmode */
102 static enum dllmode id_to_mode(DWORD id)
103 {
104     switch( id )
105     {
106         case IDC_RAD_BUILTIN: return BUILTIN;
107         case IDC_RAD_NATIVE: return NATIVE;
108         case IDC_RAD_NATIVE_BUILTIN: return NATIVE_BUILTIN;
109         case IDC_RAD_BUILTIN_NATIVE: return BUILTIN_NATIVE;
110         case IDC_RAD_DISABLE: return DISABLE;
111         default: assert( FALSE ); return 0; /* should not be reached  */
112     }
113 }
114
115 /* Convert a dllmode to a control id (IDC_ constant) */
116 static DWORD mode_to_id(enum dllmode mode)
117 {
118     switch( mode )
119     {
120         case BUILTIN: return IDC_RAD_BUILTIN;
121         case NATIVE: return IDC_RAD_NATIVE;
122         case NATIVE_BUILTIN: return IDC_RAD_NATIVE_BUILTIN;
123         case BUILTIN_NATIVE: return IDC_RAD_BUILTIN_NATIVE;
124         case DISABLE: return IDC_RAD_DISABLE;
125         default: assert( FALSE ); return 0; /* should not be reached  */
126     }
127 }
128
129 static void set_controls_from_selection(HWND dialog)
130 {
131     /* FIXME: display/update some information about the selected dll (purpose, recommended loadorder) maybe? */
132 }
133
134 static void clear_settings(HWND dialog)
135 {
136     int count = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0);
137     int i;
138
139     WINE_TRACE("count=%d\n", count);
140     
141     for (i = 0; i < count; i++)
142     {
143         struct dll *dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, 0, 0);
144         
145         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, 0, 0);
146         
147         HeapFree(GetProcessHeap(), 0, dll->name);
148         HeapFree(GetProcessHeap(), 0, dll);
149     }
150 }
151
152 static void load_library_settings(HWND dialog)
153 {
154     char **overrides = enumerate_values(config_key, keypath("DllOverrides"));
155     char **p;
156     int sel, count = 0;
157
158     sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
159
160     WINE_TRACE("sel=%d\n", sel);
161
162     clear_settings(dialog);
163     
164     if (!overrides || *overrides == NULL)
165     {
166         set_controls_from_selection(dialog);
167         disable(IDC_DLLS_EDITDLL);
168         disable(IDC_DLLS_REMOVEDLL);
169         HeapFree(GetProcessHeap(), 0, overrides);
170         return;
171     }
172
173     enable(IDC_DLLS_EDITDLL);
174     enable(IDC_DLLS_REMOVEDLL);
175     
176     for (p = overrides; *p != NULL; p++)
177     {
178         int index;
179         char *str, *value;
180         const char *label;
181         struct dll *dll;
182
183         value = get_reg_key(config_key, keypath("DllOverrides"), *p, NULL);
184
185         label = mode_to_label(string_to_mode(value));
186         
187         str = HeapAlloc(GetProcessHeap(), 0, strlen(*p) + 2 + strlen(label) + 2);
188         strcpy(str, *p);
189         strcat(str, " (");
190         strcat(str, label);
191         strcat(str, ")");
192
193         dll = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dll));
194         dll->name = *p;
195         dll->mode = string_to_mode(value);
196
197         index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_ADDSTRING, (WPARAM) -1, (LPARAM) str);
198         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETITEMDATA, index, (LPARAM) dll);
199
200         HeapFree(GetProcessHeap(), 0, str);
201
202         count++;
203     }
204
205     HeapFree(GetProcessHeap(), 0, overrides);
206
207     /* restore the previous selection, if possible  */
208     if (sel >= count - 1) sel = count - 1;
209     else if (sel == -1) sel = 0;
210     
211     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, sel, 0);
212
213     set_controls_from_selection(dialog);
214 }
215
216 /* Called when the application is initialized (cannot reinit!)  */
217 static void init_libsheet(HWND dialog)
218 {
219     /* clear the add dll controls  */
220     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 1, (LPARAM) "");
221     disable(IDC_DLLS_ADDDLL);
222 }
223
224 static void on_add_combo_change(HWND dialog)
225 {
226     char buffer[1024];
227
228     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
229
230     if (strlen(buffer))
231         enable(IDC_DLLS_ADDDLL)
232     else
233         disable(IDC_DLLS_ADDDLL);
234 }
235
236 static void set_dllmode(HWND dialog, DWORD id)
237 {
238     enum dllmode mode;
239     struct dll *dll;
240     int sel;
241     const char *str;
242
243     mode = id_to_mode(id);
244
245     sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
246     if (sel == -1) return;
247     
248     dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
249
250     str = mode_to_string(mode);
251     WINE_TRACE("Setting %s to %s\n", dll->name, str);
252     
253     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
254     set_reg_key(config_key, keypath("DllOverrides"), dll->name, str);
255
256     load_library_settings(dialog);  /* ... and refresh  */
257 }
258
259 static void on_add_click(HWND dialog)
260 {
261     static const char dotDll[] = ".dll";
262     char buffer[1024], *ptr;
263
264     ZeroMemory(buffer, sizeof(buffer));
265
266     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
267     if (lstrlenA(buffer) >= sizeof(dotDll))
268     {
269         ptr = buffer + lstrlenA(buffer) - sizeof(dotDll) + 1;
270         if (!lstrcmpiA(ptr, dotDll))
271         {
272             WINE_TRACE("Stripping dll extension\n");
273             *ptr = '\0';
274         }
275     }
276     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 0, (LPARAM) "");
277     disable(IDC_DLLS_ADDDLL);
278     
279     WINE_TRACE("Adding %s as native, builtin", buffer);
280     
281     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
282     set_reg_key(config_key, keypath("DllOverrides"), buffer, "native,builtin");
283
284     load_library_settings(dialog);
285
286     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SELECTSTRING, (WPARAM) 0, (LPARAM) buffer);
287
288     set_controls_from_selection(dialog);
289 }
290
291 static INT_PTR CALLBACK loadorder_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
292 {
293     static WORD sel;
294
295     switch(uMsg) 
296     {
297     case WM_INITDIALOG:
298         CheckRadioButton(hwndDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, lParam);
299         sel = lParam;
300         return TRUE;
301
302     case WM_COMMAND:
303         if(HIWORD(wParam) != BN_CLICKED) break;
304         switch (LOWORD(wParam))
305         {
306         case IDC_RAD_BUILTIN:
307         case IDC_RAD_NATIVE:
308         case IDC_RAD_BUILTIN_NATIVE:
309         case IDC_RAD_NATIVE_BUILTIN:
310         case IDC_RAD_DISABLE:
311             sel = LOWORD(wParam);
312             return TRUE;
313         case IDOK:
314             EndDialog(hwndDlg, sel);
315             return TRUE;
316         case IDCANCEL:
317             EndDialog(hwndDlg, wParam);
318             return TRUE;
319         }
320     }
321     return FALSE;
322 }
323
324 static void on_edit_click(HWND hwnd)
325 {
326     INT_PTR ret; 
327     int index = SendDlgItemMessage(hwnd, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
328     struct dll *dll;
329     DWORD id;
330
331     /* if no override is selected the edit button should be disabled... */
332     assert(index != -1);
333
334     dll = (struct dll *) SendDlgItemMessage(hwnd, IDC_DLLS_LIST, LB_GETITEMDATA, index, 0);
335     id = mode_to_id(dll->mode);
336     
337     ret = DialogBoxParam(0, MAKEINTRESOURCE(IDD_LOADORDER), hwnd, loadorder_dlgproc, id);
338     
339     if(ret != IDCANCEL)
340         set_dllmode(hwnd, ret);
341 }
342
343 static void on_remove_click(HWND dialog)
344 {
345     int sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
346     struct dll *dll;
347
348     if (sel == LB_ERR) return;
349     
350     dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
351     
352     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, sel, 0);
353
354     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
355     set_reg_key(config_key, keypath("DllOverrides"), dll->name, NULL);
356
357     HeapFree(GetProcessHeap(), 0, dll->name);
358     HeapFree(GetProcessHeap(), 0, dll);
359
360     if (SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0) > 0)
361         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, max(sel - 1, 0), 0);
362     else
363     {
364         disable(IDC_DLLS_EDITDLL);
365         disable(IDC_DLLS_REMOVEDLL);
366     }
367
368     set_controls_from_selection(dialog);
369 }
370
371 INT_PTR CALLBACK
372 LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
373 {
374         switch (uMsg)
375         {
376         case WM_INITDIALOG:
377                 init_libsheet(hDlg);
378                 break;
379         case WM_SHOWWINDOW:
380                 set_window_title(hDlg);
381                 break;
382         case WM_NOTIFY:
383                 switch (((LPNMHDR)lParam)->code) {
384                 case PSN_SETACTIVE:
385                     load_library_settings(hDlg);
386                     break;
387                 }
388                 break;
389         case WM_COMMAND:
390                 switch(HIWORD(wParam)) {
391
392                     /* FIXME: when the user hits enter in the DLL combo box we should invoke the add
393                      * add button, rather than the propsheet OK button. But I don't know how to do that!
394                      */
395                     
396                 case CBN_EDITCHANGE:
397                         if(LOWORD(wParam) == IDC_DLLCOMBO)
398                         {
399                             on_add_combo_change(hDlg);
400                             break;
401                         }
402
403                 case BN_CLICKED:
404                         switch(LOWORD(wParam)) {
405                         case IDC_DLLS_ADDDLL:
406                             on_add_click(hDlg);
407                             break;
408                         case IDC_DLLS_EDITDLL:
409                             on_edit_click(hDlg);
410                             break;
411                         case IDC_DLLS_REMOVEDLL:
412                             on_remove_click(hDlg);
413                             break;
414                         }
415                         break;
416                 case LBN_SELCHANGE:
417                         set_controls_from_selection(hDlg);
418                         break;
419                 }
420                 break;
421         }
422
423         return 0;
424 }