Add windows version registry entries.
[wine] / programs / winecfg / appdefaults.c
1 /*
2  * WineCfg app settings tabsheet
3  *
4  * Copyright 2004 Robert van Herk
5  * Copyright 2004 Chris Morgan
6  * Copyright 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #define NONAMELESSUNION
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 static const struct
36 {
37     const char *szVersion;
38     const char *szDescription;
39     DWORD       dwMajorVersion;
40     DWORD       dwMinorVersion;
41     DWORD       dwBuildNumber;
42     DWORD       dwPlatformId;
43     const char *szCSDVersion;
44     WORD        wServicePackMajor;
45     WORD        wServicePackMinor;
46     const char *szProductType;
47 } win_versions[] =
48 {
49     { "win2003", "Windows 2003",   5,  2, 0xECE, VER_PLATFORM_WIN32_NT, "Service Pack 1", 1, 0, "ServerNT"},
50     { "winxp",   "Windows XP",     5,  1, 0xA28, VER_PLATFORM_WIN32_NT, "Service Pack 2", 2, 0, "WinNT"},
51     { "win2k",   "Windows 2000",   5,  0, 0x893, VER_PLATFORM_WIN32_NT, "Service Pack 4", 4, 0, "WinNT"},
52     { "winme",   "Windows ME",     4, 90, 0xBB8, VER_PLATFORM_WIN32_WINDOWS, " ", 0, 0, ""},
53     { "win98",   "Windows 98",     4, 10, 0x8AE, VER_PLATFORM_WIN32_WINDOWS, " A ", 0, 0, ""},
54     { "win95",   "Windows 95",     4,  0, 0x3B6, VER_PLATFORM_WIN32_WINDOWS, "", 0, 0, ""},
55     { "nt40",    "Windows NT 4.0", 4,  0, 0x565, VER_PLATFORM_WIN32_NT, "Service Pack 6a", 6, 0, "WinNT"},
56     { "nt351",   "Windows NT 3.5", 3, 51, 0x421, VER_PLATFORM_WIN32_NT, "Service Pack 2", 0, 0, "WinNT"},
57     { "win31",   "Windows 3.1",    2, 10,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""},
58     { "win30",   "Windows 3.0",    3,  0,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""},
59     { "win20",   "Windows 2.0",    2,  0,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""}
60 };
61
62 #define NB_VERSIONS (sizeof(win_versions)/sizeof(win_versions[0]))
63
64 static void update_comboboxes(HWND dialog)
65 {
66   int i;
67
68   char *winver;
69   
70   /* retrieve the registry values */
71   winver = get_reg_key(config_key, keypath(""), "Version", "");
72
73   /* empty winver means use automatic mode (ie the builtin dll linkage heuristics)  */
74   WINE_TRACE("winver is %s\n", *winver != '\0' ? winver : "null (automatic mode)");
75
76   /* normalize the version strings */
77   if (*winver != '\0')
78   {
79       for (i = 0; i < NB_VERSIONS; i++)
80       {
81         if (!strcasecmp (win_versions[i].szVersion, winver))
82         {
83           SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, (WPARAM) (i + 1), 0);
84           WINE_TRACE("match with %s\n", win_versions[i].szVersion);
85         }
86       }
87   }
88   else /* no explicit setting */
89   {
90     WINE_TRACE("setting winver combobox to automatic/default\n");
91     SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, 0, 0);
92   }
93
94   HeapFree(GetProcessHeap(), 0, winver);
95 }
96
97 static void
98 init_comboboxes (HWND dialog)
99 {
100   int i;
101
102   SendDlgItemMessage(dialog, IDC_WINVER, CB_RESETCONTENT, 0, 0);
103
104   /* add the default entries (automatic) which correspond to no setting  */
105   if (current_app)
106   {
107       SendDlgItemMessage(dialog, IDC_WINVER, CB_ADDSTRING, 0, (LPARAM) "Use global settings");
108   }
109   else
110   {
111       SendDlgItemMessage(dialog, IDC_WINVER, CB_ADDSTRING, 0, (LPARAM) "Automatically detect required version");
112   }
113
114     for (i = 0; i < NB_VERSIONS; i++)
115     {
116       SendDlgItemMessage (dialog, IDC_WINVER, CB_ADDSTRING,
117                           0, (LPARAM) win_versions[i].szDescription);
118     }
119 }
120
121 static void add_listview_item(HWND listview, const char *text, void *association)
122 {
123   LVITEM item;
124
125   ZeroMemory(&item, sizeof(LVITEM));
126
127   item.mask = LVIF_TEXT | LVIF_PARAM;
128   item.pszText = (char*) text;
129   item.cchTextMax = strlen(text);
130   item.lParam = (LPARAM) association;
131   item.iItem = ListView_GetItemCount(listview);
132
133   ListView_InsertItem(listview, &item);
134 }
135
136 /* Called when the application is initialized (cannot reinit!)  */
137 static void init_appsheet(HWND dialog)
138 {
139   HWND listview;
140   HKEY key;
141   int i;
142   DWORD size;
143   char appname[1024];
144
145   WINE_TRACE("()\n");
146
147   listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
148
149   /* we use the lparam field of the item so we can alter the presentation later and not change code
150    * for instance, to use the tile view or to display the EXEs embedded 'display name' */
151   add_listview_item(listview, "Default Settings", NULL);
152
153   /* because this list is only populated once, it's safe to bypass the settings list here  */
154   if (RegOpenKey(config_key, "AppDefaults", &key) == ERROR_SUCCESS)
155   {
156       i = 0;
157       size = sizeof(appname);
158       while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
159       {
160           add_listview_item(listview, appname, strdupA(appname));
161
162           i++;
163           size = sizeof(appname);
164       }
165
166       RegCloseKey(key);
167   }
168
169   init_comboboxes(dialog);
170   
171   /* Select the default settings listview item  */
172   {
173       LVITEM item;
174       
175       ZeroMemory(&item, sizeof(item));
176       
177       item.mask = LVIF_STATE;
178       item.iItem = 0;
179       item.state = LVIS_SELECTED | LVIS_FOCUSED;
180       item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
181
182       ListView_SetItem(listview, &item);
183   }
184   
185 }
186
187 /* there has to be an easier way than this  */
188 static int get_listview_selection(HWND listview)
189 {
190   int count = ListView_GetItemCount(listview);
191   int i;
192   
193   for (i = 0; i < count; i++)
194   {
195     if (ListView_GetItemState(listview, i, LVIS_SELECTED)) return i;
196   }
197
198   return -1;
199 }
200
201
202 /* called when the user selects a different application */
203 static void on_selection_change(HWND dialog, HWND listview)
204 {
205   LVITEM item;
206   char *oldapp = current_app;
207
208   WINE_TRACE("()\n");
209
210   item.iItem = get_listview_selection(listview);
211   item.mask = LVIF_PARAM;
212
213   WINE_TRACE("item.iItem=%d\n", item.iItem);
214   
215   if (item.iItem == -1) return;
216   
217   ListView_GetItem(listview, &item);
218
219   current_app = (char *) item.lParam;
220
221   if (current_app)
222   {
223       WINE_TRACE("current_app is now %s\n", current_app);
224       enable(IDC_APP_REMOVEAPP);
225   }
226   else
227   {
228       WINE_TRACE("current_app=NULL, editing global settings\n");
229       /* focus will never be on the button in this callback so it's safe  */
230       disable(IDC_APP_REMOVEAPP);
231   }
232
233   /* reset the combo boxes if we changed from/to global/app-specific  */
234
235   if ((oldapp && !current_app) || (!oldapp && current_app))
236       init_comboboxes(dialog);
237   
238   update_comboboxes(dialog);
239
240   set_window_title(dialog);
241 }
242
243 static BOOL list_contains_file(HWND listview, char *filename)
244 {
245   LVFINDINFO find_info = { LVFI_STRING, filename, 0, {0, 0}, 0 };
246   int index;
247
248   index = ListView_FindItem(listview, -1, &find_info);
249
250   return (index != -1);
251 }
252
253 static void on_add_app_click(HWND dialog)
254 {
255   char filetitle[MAX_PATH];
256   char file[MAX_PATH];
257
258   OPENFILENAME ofn = { sizeof(OPENFILENAME),
259                        0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL,
260                        0, NULL, 0, "c:\\", "Select a Windows executable file",
261                        OFN_SHOWHELP | OFN_HIDEREADONLY, 0, 0, NULL, 0, NULL };
262
263   ofn.lpstrFileTitle = filetitle;
264   ofn.lpstrFileTitle[0] = '\0';
265   ofn.nMaxFileTitle = sizeof(filetitle);
266   ofn.lpstrFile = file;
267   ofn.lpstrFile[0] = '\0';
268   ofn.nMaxFile = sizeof(file);
269
270   if (GetOpenFileName(&ofn))
271   {
272       HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
273       int count = ListView_GetItemCount(listview);
274       char* new_app;
275       
276       new_app = strdupA(filetitle);
277
278       if (list_contains_file(listview, new_app))
279           return;
280       
281       WINE_TRACE("adding %s\n", new_app);
282       
283       add_listview_item(listview, new_app, new_app);
284
285       ListView_SetItemState(listview, count, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
286
287       SetFocus(listview);
288   }
289   else WINE_TRACE("user cancelled\n");
290 }
291
292 static void on_remove_app_click(HWND dialog)
293 {
294     HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
295     int selection = get_listview_selection(listview);
296     char *section = keypath(""); /* AppDefaults\\whatever.exe\\ */
297
298     WINE_TRACE("selection=%d, section=%s\n", selection, section);
299     
300     assert( selection != 0 ); /* user cannot click this button when "default settings" is selected  */
301
302     section[strlen(section)] = '\0'; /* remove last backslash  */
303     set_reg_key(config_key, section, NULL, NULL); /* delete the section  */
304     ListView_DeleteItem(listview, selection);
305     ListView_SetItemState(listview, selection - 1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
306
307     SetFocus(listview);
308     
309     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);        
310 }
311
312 static void on_winver_change(HWND dialog)
313 {
314     int selection = SendDlgItemMessage(dialog, IDC_WINVER, CB_GETCURSEL, 0, 0);
315
316     if (selection == 0)
317     {
318         WINE_TRACE("automatic/default selected so removing current setting\n");
319         set_reg_key(config_key, keypath(""), "Version", NULL);
320     }
321     else
322     {
323         WINE_TRACE("setting Version key to value '%s'\n", win_versions[selection - 1].szVersion);
324         set_reg_key(config_key, keypath(""), "Version", win_versions[selection - 1].szVersion);
325     }
326     /* global version only */
327     if (!current_app && selection != 0)
328     {
329         static const char szKey9x[] = "Software\\Microsoft\\Windows\\CurrentVersion";
330         static const char szKeyNT[] = "Software\\Microsoft\\Windows NT\\CurrentVersion";
331         static const char szKeyProdNT[] = "System\\CurrentControlSet\\Control\\ProductOptions";
332         static const char szKeyWindNT[] = "System\\CurrentControlSet\\Control\\Windows";
333         char Buffer[40];
334
335         switch (win_versions[selection-1].dwPlatformId)
336         {
337         case VER_PLATFORM_WIN32_WINDOWS:
338             snprintf(Buffer, sizeof(Buffer), "%ld.%ld.%ld", win_versions[selection-1].dwMajorVersion,
339                      win_versions[selection-1].dwMinorVersion, win_versions[selection-1].dwBuildNumber);
340             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", Buffer);
341             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", win_versions[selection-1].szCSDVersion);
342
343             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", NULL);
344             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", NULL);
345             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", NULL);
346             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", NULL);
347             set_reg_key(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion", NULL);
348             break;
349
350         case VER_PLATFORM_WIN32_NT:
351             snprintf(Buffer, sizeof(Buffer), "%ld.%ld", win_versions[selection-1].dwMajorVersion,
352                      win_versions[selection-1].dwMinorVersion);
353             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", Buffer);
354             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", win_versions[selection-1].szCSDVersion);
355             snprintf(Buffer, sizeof(Buffer), "%ld", win_versions[selection-1].dwBuildNumber);
356             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", Buffer);
357             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", win_versions[selection-1].szProductType);
358             set_reg_key_dword(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion",
359                               MAKEWORD( win_versions[selection-1].wServicePackMinor,
360                                         win_versions[selection-1].wServicePackMajor ));
361
362             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", NULL);
363             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", NULL);
364             break;
365
366         case VER_PLATFORM_WIN32s:
367             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", NULL);
368             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", NULL);
369             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", NULL);
370             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", NULL);
371             set_reg_key(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion", NULL);
372             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", NULL);
373             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", NULL);
374             break;
375         }
376     }
377
378     /* enable the apply button  */
379     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
380 }
381
382 INT_PTR CALLBACK
383 AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
384 {
385   switch (uMsg)
386   {
387     case WM_INITDIALOG:
388         init_appsheet(hDlg);
389         break;
390
391     case WM_SHOWWINDOW:
392         set_window_title(hDlg);
393         break;
394
395     case WM_NOTIFY:
396       switch (((LPNMHDR)lParam)->code)
397       {
398         case LVN_ITEMCHANGED:
399             on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW));
400             break;
401         case PSN_APPLY:
402             apply();
403             SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
404             break;
405       }
406       
407       break;
408     
409     case WM_COMMAND:
410       switch(HIWORD(wParam))
411       {
412         case CBN_SELCHANGE:
413           switch(LOWORD(wParam))
414           {
415             case IDC_WINVER:
416               on_winver_change(hDlg);
417               break;
418           }
419         case BN_CLICKED:
420           switch(LOWORD(wParam))
421           {
422             case IDC_APP_ADDAPP:
423               on_add_app_click(hDlg);
424               break;
425             case IDC_APP_REMOVEAPP:
426               on_remove_app_click(hDlg);
427               break;
428           }
429           break;
430       }
431
432       break;
433   }
434   
435   return 0;
436 }