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