winecfg: Also distinguish versions by product type.
[wine] / programs / winecfg / driveui.c
1 /*
2  * Drive management UI code
3  *
4  * Copyright 2003 Mark Westcott
5  * Copyright 2004 Chris Morgan
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  */
23
24 #include <stdio.h>
25
26 #define WIN32_LEAN_AND_MEAN
27 #define COBJMACROS
28
29 #include <windows.h>
30 #include <shellapi.h>
31 #include <objbase.h>
32 #include <shlguid.h>
33 #include <shlwapi.h>
34 #include <shlobj.h>
35
36 #include <wine/unicode.h>
37 #include <wine/debug.h>
38
39 #include "winecfg.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
43
44 #define BOX_MODE_DEVICE 1
45 #define BOX_MODE_NORMAL 2
46
47 static BOOL advanced = FALSE;
48 static BOOL updating_ui = FALSE;
49 static struct drive* current_drive;
50
51 static void update_controls(HWND dialog);
52
53 static DWORD driveui_msgbox (HWND parent, UINT messageId, DWORD flags)
54 {
55   WCHAR* caption = load_string (IDS_WINECFG_TITLE);
56   WCHAR* text = load_string (messageId);
57   DWORD result = MessageBoxW (parent, text, caption, flags);
58   HeapFree (GetProcessHeap(), 0, caption);
59   HeapFree (GetProcessHeap(), 0, text);
60   return result;
61 }
62
63 /**** listview helper functions ****/
64
65 /* clears the item at index in the listview */
66 static void lv_clear_curr_select(HWND dialog, int index)
67 {
68     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, 0, LVIS_SELECTED);
69 }
70
71 /* selects the item at index in the listview */
72 static void lv_set_curr_select(HWND dialog, int index)
73 {
74     /* no more than one item can be selected in our listview */
75     lv_clear_curr_select(dialog, -1);
76     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, LVIS_SELECTED, LVIS_SELECTED);
77 }
78
79 /* returns the currently selected item in the listview */
80 static int lv_get_curr_select(HWND dialog)
81 {
82     return SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
83 }
84
85 /* sets the item in the listview at item->iIndex */
86 static void lv_set_item(HWND dialog, LVITEMW *item)
87 {
88     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_SETITEMW, 0, (LPARAM) item);
89 }
90
91 /* sets specified item's text */
92 static void lv_set_item_text(HWND dialog, int item, int subItem, WCHAR *text)
93 {
94     LVITEMW lvItem;
95     if (item < 0 || subItem < 0) return;
96     lvItem.mask = LVIF_TEXT;
97     lvItem.iItem = item;
98     lvItem.iSubItem = subItem;
99     lvItem.pszText = text;
100     lvItem.cchTextMax = lstrlenW(lvItem.pszText);
101     lv_set_item(dialog, &lvItem);
102 }
103
104 /* inserts an item into the listview */
105 static void lv_insert_item(HWND dialog, LVITEMW *item)
106 {
107     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_INSERTITEMW, 0, (LPARAM) item);
108 }
109
110 /* retrieve the item at index item->iIndex */
111 static void lv_get_item(HWND dialog, LVITEMW *item)
112 {
113     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_GETITEMW, 0, (LPARAM) item);
114 }
115
116 static void set_advanced(HWND dialog)
117 {
118     int state;
119     WCHAR text[256];
120
121     if (advanced)
122     {
123         state = SW_NORMAL;
124         LoadStringW(GetModuleHandle(NULL), IDS_HIDE_ADVANCED, text, 256);
125     }
126     else
127     {
128         state = SW_HIDE;
129         LoadStringW(GetModuleHandle(NULL), IDS_SHOW_ADVANCED, text, 256);
130     }
131
132     ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
133     ShowWindow(GetDlgItem(dialog, IDC_STATIC_DEVICE), state);
134     ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
135     ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
136     ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
137     ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
138     ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
139     ShowWindow(GetDlgItem(dialog, IDC_COMBO_TYPE), state);
140     ShowWindow(GetDlgItem(dialog, IDC_STATIC_TYPE), state);
141
142     /* update the button text based on the state */
143     SetWindowTextW(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
144 }
145
146 struct drive_typemap {
147     unsigned int sCode;
148     UINT idDesc;
149 };
150
151 static const struct drive_typemap type_pairs[] = {
152   { DRIVE_UNKNOWN,    IDS_DRIVE_UNKNOWN   },
153   { DRIVE_FIXED,      IDS_DRIVE_FIXED     },
154   { DRIVE_REMOTE,     IDS_DRIVE_REMOTE    },
155   { DRIVE_REMOVABLE,  IDS_DRIVE_REMOVABLE },
156   { DRIVE_CDROM,      IDS_DRIVE_CDROM     }
157 };
158
159 #define DRIVE_TYPE_DEFAULT 0
160
161 static void enable_labelserial_box(HWND dialog, int mode)
162 {
163     WINE_TRACE("mode=%d\n", mode);
164
165     switch (mode)
166     {
167         case BOX_MODE_DEVICE:
168             /* FIXME: enable device editing */
169             disable(IDC_EDIT_DEVICE);
170             disable(IDC_BUTTON_BROWSE_DEVICE);
171             disable(IDC_EDIT_SERIAL);
172             disable(IDC_EDIT_LABEL);
173             break;
174
175         case BOX_MODE_NORMAL:
176             disable(IDC_EDIT_DEVICE);
177             disable(IDC_BUTTON_BROWSE_DEVICE);
178             enable(IDC_EDIT_SERIAL);
179             enable(IDC_EDIT_LABEL);
180             break;
181     }
182 }
183
184 static int fill_drives_list(HWND dialog)
185 {
186     int count = 0;
187     BOOL drivec_present = FALSE;
188     int i;
189     int prevsel = -1;
190
191     WINE_TRACE("\n");
192
193     updating_ui = TRUE;
194
195     prevsel = lv_get_curr_select(dialog); 
196
197     /* Clear the listbox */
198     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
199
200     for(i = 0; i < 26; i++)
201     {
202         LVITEMW item;
203         WCHAR *path;
204         char letter[4];
205
206         /* skip over any unused drives */
207         if (!drives[i].in_use)
208             continue;
209
210         if (drives[i].letter == 'C')
211             drivec_present = TRUE;
212
213         letter[0] = 'A' + i;
214         letter[1] = ':';
215         letter[2] = 0;
216
217         item.mask = LVIF_TEXT | LVIF_PARAM;
218         item.iItem = count;
219         item.iSubItem = 0;
220         item.pszText = strdupU2W(letter);
221         item.cchTextMax = lstrlenW(item.pszText);
222         item.lParam = (LPARAM) &drives[i];
223
224         lv_insert_item(dialog, &item);
225         HeapFree(GetProcessHeap(), 0, item.pszText);
226
227         path = strdupU2W(drives[i].unixpath);
228         lv_set_item_text(dialog, count, 1, path);
229         HeapFree(GetProcessHeap(), 0, path);
230
231         count++;
232     }
233
234     WINE_TRACE("loaded %d drives\n", count);
235
236     /* show the warning if there is no Drive C */
237     if (!drivec_present)
238         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
239     else
240         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
241
242     lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
243
244     updating_ui = FALSE;
245     return count;
246 }
247
248 static void on_options_click(HWND dialog)
249 {
250     if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
251         set_reg_key(config_key, "", "ShowDotFiles", "Y");
252     else
253         set_reg_key(config_key, "", "ShowDotFiles", "N");
254
255     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
256 }
257
258 static INT_PTR CALLBACK drivechoose_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
259 {
260     static int i, sel;
261     char c;
262     char drive[] = "X:";
263
264     switch(uMsg)
265     {
266     case WM_INITDIALOG:
267         {
268         ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
269         for( c = 'A'; c<= 'Z'; c++){
270             drive[0] = c;
271             if(!( mask & (1 << (c - 'A'))))
272                 SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_ADDSTRING, 0, (LPARAM) drive);
273         }
274         drive[0] = lParam;
275         SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_SELECTSTRING, 0, (LPARAM) drive);
276         return TRUE;
277         }
278     case WM_COMMAND:
279         if(HIWORD(wParam) != BN_CLICKED) break;
280         switch (LOWORD(wParam))
281         {
282         case IDOK:
283             i = SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETCURSEL, 0, 0);
284             if( i != CB_ERR){
285                 SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETLBTEXT, i, (LPARAM) drive);
286                 sel = drive[0];
287             } else
288                 sel = -1;
289             EndDialog(hwndDlg, sel);
290             return TRUE;
291         case IDCANCEL:
292             EndDialog(hwndDlg, -1);
293             return TRUE;
294         }
295     }
296     return FALSE;
297 }
298
299 static void on_add_click(HWND dialog)
300 {
301     /* we should allocate a drive letter automatically. We also need
302        some way to let the user choose the mapping point, for now we
303        will just force them to enter a path automatically, with / being
304        the default. In future we should be able to temporarily map /
305        then invoke the directory chooser dialog. */
306
307     char new = 'C'; /* we skip A and B, they are historically floppy drives */
308     ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
309     int i, c;
310     INT_PTR ret;
311
312     while (mask & (1 << (new - 'A')))
313     {
314         new++;
315         if (new > 'Z')
316         {
317             driveui_msgbox (dialog, IDS_DRIVE_LETTERS_EXCEEDED, MB_OK | MB_ICONEXCLAMATION);
318             return;
319         }
320     }
321
322
323     ret = DialogBoxParam(0, MAKEINTRESOURCE(IDD_DRIVECHOOSE), dialog, drivechoose_dlgproc, new);
324
325     if( ret == -1) return;
326     new = ret;
327
328     WINE_TRACE("selected drive letter %c\n", new);
329
330     if (new == 'C')
331     {
332         WCHAR label[64];
333         LoadStringW (GetModuleHandle (NULL), IDS_SYSTEM_DRIVE_LABEL, label,
334                      sizeof(label)/sizeof(label[0]));
335         add_drive(new, "../drive_c", NULL, label, 0, DRIVE_FIXED);
336     }
337     else add_drive(new, "/", NULL, NULL, 0, DRIVE_UNKNOWN);
338
339     fill_drives_list(dialog);
340
341     /* select the newly created drive */
342     mask = ~drive_available_mask(0);
343     c = 0;
344     for (i = 0; i < 26; i++)
345     {
346         if ('A' + i == new) break;
347         if ((1 << i) & mask) c++;
348     }
349     lv_set_curr_select(dialog, c);
350
351     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
352
353     update_controls(dialog);
354     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
355 }
356
357 static void on_remove_click(HWND dialog)
358 {
359     int itemIndex;
360     struct drive *drive;
361     LVITEMW item;
362
363     itemIndex = lv_get_curr_select(dialog);
364     if (itemIndex == -1) return; /* no selection */
365
366     item.mask = LVIF_PARAM;
367     item.iItem = itemIndex;
368     item.iSubItem = 0;
369
370     lv_get_item(dialog, &item);
371
372     drive = (struct drive *) item.lParam;
373
374     WINE_TRACE("unixpath: %s\n", drive->unixpath);
375
376     if (drive->letter == 'C')
377     {
378         DWORD result = driveui_msgbox (dialog, IDS_CONFIRM_DELETE_C, MB_YESNO | MB_ICONEXCLAMATION);
379         if (result == IDNO) return;
380     }
381
382     delete_drive(drive);
383
384     fill_drives_list(dialog);
385
386     itemIndex = itemIndex - 1;
387     if (itemIndex < 0) itemIndex = 0;
388     lv_set_curr_select(dialog, itemIndex);   /* previous item */
389
390     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
391
392     update_controls(dialog);
393     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
394 }
395
396 static void update_controls(HWND dialog)
397 {
398     static const WCHAR emptyW[1];
399     WCHAR *path;
400     unsigned int type;
401     char serial[16];
402     int i, selection = -1;
403     LVITEMW item;
404
405     updating_ui = TRUE;
406
407     i = lv_get_curr_select(dialog);
408     if (i == -1)
409     {
410         /* no selection? let's select something for the user. this will re-enter */
411         lv_set_curr_select(dialog, i);
412         return;
413     }
414
415     item.mask = LVIF_PARAM;
416     item.iItem = i;
417     item.iSubItem = 0;
418
419     lv_get_item(dialog, &item);
420     current_drive = (struct drive *) item.lParam;
421
422     WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);
423
424     /* path */
425     WINE_TRACE("set path control text to '%s'\n", current_drive->unixpath);
426     path = strdupU2W(current_drive->unixpath);
427     set_textW(dialog, IDC_EDIT_PATH, path);
428     HeapFree(GetProcessHeap(), 0, path);
429
430     /* drive type */
431     type = current_drive->type;
432     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);
433
434     for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++)
435     {
436         WCHAR driveDesc[64];
437         LoadStringW (GetModuleHandle (NULL), type_pairs[i].idDesc, driveDesc,
438             sizeof(driveDesc)/sizeof(driveDesc[0]));
439         SendDlgItemMessageW (dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)driveDesc);
440
441         if (type_pairs[i].sCode ==  type)
442         {
443             selection = i;
444         }
445     }
446
447     if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
448     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
449
450     EnableWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), (current_drive->letter != 'C') );
451     EnableWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), (current_drive->letter != 'C') );
452     EnableWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), (current_drive->letter != 'C') );
453     EnableWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), (current_drive->letter != 'C') );
454
455     /* removeable media properties */
456     set_textW(dialog, IDC_EDIT_LABEL, current_drive->label ? current_drive->label : emptyW);
457
458     /* set serial edit text */
459     sprintf( serial, "%X", current_drive->serial );
460     set_text(dialog, IDC_EDIT_SERIAL, serial);
461
462     set_text(dialog, IDC_EDIT_DEVICE, current_drive->device);
463
464     if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
465         enable_labelserial_box(dialog, BOX_MODE_DEVICE);
466     else
467         enable_labelserial_box(dialog, BOX_MODE_NORMAL);
468
469     updating_ui = FALSE;
470
471     return;
472 }
473
474 static void on_edit_changed(HWND dialog, WORD id)
475 {
476     if (updating_ui) return;
477
478     WINE_TRACE("edit id %d changed\n", id);
479
480     switch (id)
481     {
482         case IDC_EDIT_LABEL:
483         {
484             WCHAR *label = get_textW(dialog, id);
485             HeapFree(GetProcessHeap(), 0, current_drive->label);
486             current_drive->label = label;
487             current_drive->modified = TRUE;
488
489             WINE_TRACE("set label to %s\n", wine_dbgstr_w(current_drive->label));
490
491             /* enable the apply button  */
492             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
493             break;
494         }
495
496         case IDC_EDIT_PATH:
497         {
498             WCHAR *wpath;
499             char *path;
500             int lenW;
501
502             wpath = get_textW(dialog, id);
503             if( (lenW = WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, NULL, 0, NULL, NULL)) )
504             {
505                 path = HeapAlloc(GetProcessHeap(), 0, lenW);
506                 WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, path, lenW, NULL, NULL);
507             }
508             else
509             {
510                 path = NULL;
511                 wpath = strdupU2W("drive_c");
512             }
513
514             HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
515             current_drive->unixpath = path ? path : strdupA("drive_c");
516             current_drive->modified = TRUE;
517
518             WINE_TRACE("set path to %s\n", current_drive->unixpath);
519
520             lv_set_item_text(dialog, lv_get_curr_select(dialog), 1,
521                              wpath);
522             HeapFree(GetProcessHeap(), 0, wpath);
523
524             /* enable the apply button  */
525             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
526             break;
527         }
528
529         case IDC_EDIT_SERIAL:
530         {
531             char *serial;
532
533             serial = get_text(dialog, id);
534             current_drive->serial = serial ? strtoul( serial, NULL, 16 ) : 0;
535             HeapFree(GetProcessHeap(), 0, serial);
536             current_drive->modified = TRUE;
537
538             WINE_TRACE("set serial to %08X\n", current_drive->serial);
539
540             /* enable the apply button  */
541             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
542             break;
543         }
544
545         case IDC_EDIT_DEVICE:
546         {
547             char *device = get_text(dialog, id);
548             /* TODO: handle device if/when it makes sense to do so.... */
549             HeapFree(GetProcessHeap(), 0, device);
550             break;
551         }
552     }
553 }
554
555 BOOL browse_for_unix_folder(HWND dialog, WCHAR *pszPath)
556 {
557     static WCHAR wszUnixRootDisplayName[] = 
558         { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
559           'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
560     WCHAR pszChoosePath[FILENAME_MAX];
561     BROWSEINFOW bi = {
562         dialog,
563         NULL,
564         NULL,
565         pszChoosePath,
566         0,
567         NULL,
568         0,
569         0
570     };
571     IShellFolder *pDesktop;
572     LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
573     HRESULT hr;
574    
575     LoadStringW(GetModuleHandle(NULL), IDS_CHOOSE_PATH, pszChoosePath, FILENAME_MAX);
576     
577     hr = SHGetDesktopFolder(&pDesktop);
578     if (FAILED(hr)) return FALSE;
579
580     hr = IShellFolder_ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
581                                        &pidlUnixRoot, NULL);
582     if (FAILED(hr)) {
583         IShellFolder_Release(pDesktop);
584         return FALSE;
585     }
586
587     bi.pidlRoot = pidlUnixRoot;
588     pidlSelectedPath = SHBrowseForFolderW(&bi);
589     SHFree(pidlUnixRoot);
590     
591     if (pidlSelectedPath) {
592         STRRET strSelectedPath;
593         WCHAR *pszSelectedPath;
594         HRESULT hr;
595         
596         hr = IShellFolder_GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
597                                            &strSelectedPath);
598         IShellFolder_Release(pDesktop);
599         if (FAILED(hr)) {
600             SHFree(pidlSelectedPath);
601             return FALSE;
602         }
603
604         hr = StrRetToStrW(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
605         SHFree(pidlSelectedPath);
606         if (FAILED(hr)) return FALSE;
607
608         lstrcpyW(pszPath, pszSelectedPath);
609         
610         CoTaskMemFree(pszSelectedPath);
611         return TRUE;
612     }
613     return FALSE;
614 }
615
616 static void init_listview_columns(HWND dialog)
617 {
618     LVCOLUMNW listColumn;
619     RECT viewRect;
620     int width;
621     WCHAR column[64];
622
623     GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
624     width = (viewRect.right - viewRect.left) / 6 - 5;
625
626     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVELETTER, column,
627         sizeof(column)/sizeof(column[0]));
628     listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
629     listColumn.pszText = column;
630     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
631     listColumn.cx = width;
632
633     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
634
635     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVEMAPPING, column,
636         sizeof(column)/sizeof(column[0]));
637     listColumn.cx = viewRect.right - viewRect.left - width;
638     listColumn.pszText = column;
639     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
640
641     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
642 }
643
644 static void load_drive_options(HWND dialog)
645 {
646     if (!strcmp(get_reg_key(config_key, "", "ShowDotFiles", "N"), "Y"))
647         CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
648 }
649
650 INT_PTR CALLBACK
651 DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
652 {
653     int item;
654
655     switch (msg)
656     {
657         case WM_INITDIALOG:
658             init_listview_columns(dialog);
659             if (!load_drives())
660             {
661                 ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_SHOW );
662                 ShowWindow( GetDlgItem( dialog, IDC_LIST_DRIVES ), SW_HIDE );
663                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_ADD ), SW_HIDE );
664                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), SW_HIDE );
665                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_AUTODETECT ), SW_HIDE );
666                 ShowWindow( GetDlgItem( dialog, IDC_STATIC_PATH ), SW_HIDE );
667                 ShowWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), SW_HIDE );
668                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), SW_HIDE );
669                 ShowWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), SW_HIDE );
670                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED ), SW_HIDE );
671                 set_advanced(dialog);
672                 break;
673             }
674             ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_HIDE );
675             load_drive_options(dialog);
676
677             if (!drives[2].in_use)
678                 driveui_msgbox (dialog, IDS_NO_DRIVE_C, MB_OK | MB_ICONEXCLAMATION);
679
680             fill_drives_list(dialog);
681             update_controls(dialog);
682             /* put in non-advanced mode by default  */
683             set_advanced(dialog);
684             break;
685
686         case WM_SHOWWINDOW:
687             set_window_title(dialog);
688             break;
689
690         case WM_COMMAND:
691             switch (HIWORD(wParam))
692             {
693                 case EN_CHANGE:
694                     on_edit_changed(dialog, LOWORD(wParam));
695                     break;
696
697                 case BN_CLICKED:
698                     switch (LOWORD(wParam))
699                     {
700                         case IDC_SHOW_DOT_FILES:
701                             on_options_click(dialog);
702                         break;
703                     }
704                     break;
705
706                 case CBN_SELCHANGE:
707                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
708                     break;
709             }
710
711             switch (LOWORD(wParam))
712             {
713                 case IDC_BUTTON_ADD:
714                     if (HIWORD(wParam) != BN_CLICKED) break;
715                     on_add_click(dialog);
716                     break;
717
718                 case IDC_BUTTON_REMOVE:
719                     if (HIWORD(wParam) != BN_CLICKED) break;
720                     on_remove_click(dialog);
721                     break;
722
723                 case IDC_BUTTON_EDIT:
724                     if (HIWORD(wParam) != BN_CLICKED) break;
725                     item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
726                     SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
727                     break;
728
729                 case IDC_BUTTON_AUTODETECT:
730                     autodetect_drives();
731                     fill_drives_list(dialog);
732                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
733                     break;
734
735                 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
736                     advanced = !advanced;
737                     set_advanced(dialog);
738                     break;
739
740                 case IDC_BUTTON_BROWSE_PATH:
741                 {
742                     WCHAR szTargetPath[FILENAME_MAX];
743                     if (browse_for_unix_folder(dialog, szTargetPath)) 
744                         set_textW(dialog, IDC_EDIT_PATH, szTargetPath);
745                     break;
746                 }
747
748                 case IDC_COMBO_TYPE:
749                 {
750                     int mode = BOX_MODE_NORMAL;
751                     int selection;
752
753                     if (HIWORD(wParam) != CBN_SELCHANGE) break;
754
755                     selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
756
757                     if (selection >= 0 &&
758                         (type_pairs[selection].sCode == DRIVE_CDROM ||
759                          type_pairs[selection].sCode == DRIVE_REMOVABLE))
760                         mode = BOX_MODE_DEVICE;
761                     else
762                         mode = BOX_MODE_NORMAL;
763
764                     enable_labelserial_box(dialog, mode);
765
766                     current_drive->type = type_pairs[selection].sCode;
767                     current_drive->modified = TRUE;
768                     break;
769                 }
770
771             }
772             break;
773
774         case WM_NOTIFY:
775             switch (((LPNMHDR)lParam)->code)
776             {
777                 case PSN_KILLACTIVE:
778                     WINE_TRACE("PSN_KILLACTIVE\n");
779                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, FALSE);
780                     break;
781                 case PSN_APPLY:
782                     apply_drive_changes();
783                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
784                     break;
785                 case PSN_SETACTIVE:
786                     break;
787                 case LVN_ITEMCHANGED:
788                 {
789                     LPNMLISTVIEW lpnm = (LPNMLISTVIEW)lParam;
790                     if (!(lpnm->uOldState & LVIS_SELECTED) &&
791                          (lpnm->uNewState & LVIS_SELECTED))
792                     update_controls(dialog);
793                     break;
794                 }
795             }
796             break;
797     }
798
799     return FALSE;
800 }