driveui.c 24 KB

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