2 * Drive management UI code
4 * Copyright 2003 Mark Westcott
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Chris Morgan
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.
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.
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
25 /* - Support for devices(not sure what this means) */
26 /* - Various autodetections */
37 #include <wine/debug.h>
48 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
50 typedef struct drive_entry_s
61 static BOOL updatingUI = FALSE;
62 static drive_entry_t* editDriveEntry;
63 static int lastSel = 0; /* the last drive selected in the property sheet */
64 drive_entry_t drives[26]; /* one for each drive letter */
66 int getDrive(char letter)
68 return (toupper(letter) - 'A');
71 BOOL addDrive(char letter, char *targetpath, char *label, char *serial, uint type)
73 if(drives[getDrive(letter)].in_use)
76 WINE_TRACE("letter == '%c', unixpath == '%s', label == '%s', serial == '%s', type == %d\n",
77 letter, targetpath, label, serial, type);
79 drives[getDrive(letter)].letter = toupper(letter);
80 drives[getDrive(letter)].unixpath = strdup(targetpath);
81 drives[getDrive(letter)].label = strdup(label);
82 drives[getDrive(letter)].serial = strdup(serial);
83 drives[getDrive(letter)].type = type;
84 drives[getDrive(letter)].in_use = TRUE;
89 /* frees up the memory associated with a drive and returns the */
90 /* pNext of the given drive entry */
91 void freeDrive(drive_entry_t *pDrive)
93 free(pDrive->unixpath);
97 pDrive->in_use = FALSE;
100 void setDriveLabel(drive_entry_t *pDrive, char *label)
102 WINE_TRACE("pDrive->letter '%c', label = '%s'\n", pDrive->letter, label);
104 pDrive->label = strdup(label);
107 void setDriveSerial(drive_entry_t *pDrive, char *serial)
109 WINE_TRACE("pDrive->letter '%c', serial = '%s'\n", pDrive->letter, serial);
110 free(pDrive->serial);
111 pDrive->serial = strdup(serial);
114 void setDrivePath(drive_entry_t *pDrive, char *path)
116 WINE_TRACE("pDrive->letter '%c', path = '%s'\n", pDrive->letter, path);
117 free(pDrive->unixpath);
118 pDrive->unixpath = strdup(path);
121 BOOL copyDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
125 WINE_TRACE("pDst already in use\n");
129 if(!pSrc->unixpath) WINE_TRACE("!pSrc->unixpath\n");
130 if(!pSrc->label) WINE_TRACE("!pSrc->label\n");
131 if(!pSrc->serial) WINE_TRACE("!pSrc->serial\n");
133 pDst->unixpath = strdup(pSrc->unixpath);
134 pDst->label = strdup(pSrc->label);
135 pDst->serial = strdup(pSrc->serial);
136 pDst->type = pSrc->type;
142 BOOL moveDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
144 WINE_TRACE("pSrc->letter == %c, pDst->letter == %c\n", pSrc->letter, pDst->letter);
146 if(!copyDrive(pSrc, pDst))
148 WINE_TRACE("copyDrive failed\n");
156 int refreshDriveDlg (HWND dialog)
159 int doesDriveCExist = FALSE;
166 /* Clear the listbox */
167 SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_RESETCONTENT, 0, 0);
169 for(i = 0; i < 26; i++)
175 /* skip over any unused drives */
176 if(!drives[i].in_use)
179 if(drives[i].letter == 'C')
180 doesDriveCExist = TRUE;
182 titleLen = snprintf(title, 0, "Drive %c:\\ %s", 'A' + i,
184 titleLen++; /* add a byte for the trailing null */
186 title = malloc(titleLen);
188 /* the %s in the item label will be replaced by the drive letter, so -1, then
189 -2 for the second %s which will be expanded to the label, finally + 1 for terminating #0 */
190 snprintf(title, titleLen, "Drive %c:\\ %s", 'A' + i,
193 WINE_TRACE("title is '%s'\n", title);
195 /* the first SendMessage call adds the string and returns the index, the second associates that index with it */
196 itemIndex = SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_ADDSTRING ,(WPARAM) -1, (LPARAM) title);
197 SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_SETITEMDATA, itemIndex, (LPARAM) &drives[i]);
203 WINE_TRACE("loaded %d drives\n", driveCount);
204 SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETSEL, TRUE, lastSel);
206 /* show the warning if there is no Drive C */
207 if (!doesDriveCExist)
208 ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
210 ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
212 /* disable or enable controls depending on whether we are editing global vs app specific config */
213 if (appSettings == EDITING_GLOBAL) {
214 WINE_TRACE("enabling controls\n");
215 enable(IDC_LIST_DRIVES);
216 enable(IDC_BUTTON_ADD);
217 enable(IDC_BUTTON_REMOVE);
218 enable(IDC_BUTTON_EDIT);
219 enable(IDC_BUTTON_AUTODETECT);
222 WINE_TRACE("disabling controls\n");
223 disable(IDC_LIST_DRIVES);
224 disable(IDC_BUTTON_ADD);
225 disable(IDC_BUTTON_REMOVE);
226 disable(IDC_BUTTON_EDIT);
227 disable(IDC_BUTTON_AUTODETECT);
235 /******************************************************************************/
236 /* The Drive Editing Dialog */
237 /******************************************************************************/
238 #define DRIVE_MASK_BIT(B) 1<<(toupper(B)-'A')
245 static code_desc_pair type_pairs[] = {
246 {DRIVE_FIXED, "Local hard disk"},
247 {DRIVE_REMOTE, "Network share" },
248 {DRIVE_REMOVABLE, "Floppy disk"},
249 {DRIVE_CDROM, "CD-ROM"}
251 #define DRIVE_TYPE_DEFAULT 1
254 void fill_drive_droplist(long mask, char currentLetter, HWND hDlg)
260 char sName[4] = "A:";
262 for( i=0, count=0, selection=-1, next_letter=-1; i <= 'Z'-'A'; ++i ) {
263 if( mask & DRIVE_MASK_BIT('A'+i) ) {
267 index = SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName );
269 if( toupper(currentLetter) == 'A' + i ) {
273 if( i >= 2 && next_letter == -1){ /*default drive is first one of C-Z */
281 if( selection == -1 ) {
282 selection = next_letter;
285 SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0 );
288 #define BOX_MODE_CD_ASSIGN 1
289 #define BOX_MODE_CD_AUTODETECT 2
290 #define BOX_MODE_NONE 3
291 #define BOX_MODE_NORMAL 4
292 void enable_labelserial_box(HWND dialog, int mode)
294 WINE_TRACE("mode=%d\n", mode);
296 case BOX_MODE_CD_ASSIGN:
297 /* enable(IDC_RADIO_AUTODETECT); */
298 enable(IDC_RADIO_ASSIGN);
299 disable(IDC_EDIT_DEVICE);
300 disable(IDC_BUTTON_BROWSE_DEVICE);
301 enable(IDC_EDIT_SERIAL);
302 enable(IDC_EDIT_LABEL);
303 enable(IDC_STATIC_SERIAL);
304 enable(IDC_STATIC_LABEL);
307 case BOX_MODE_CD_AUTODETECT:
308 /* enable(IDC_RADIO_AUTODETECT); */
309 enable(IDC_RADIO_ASSIGN);
310 enable(IDC_EDIT_DEVICE);
311 enable(IDC_BUTTON_BROWSE_DEVICE);
312 disable(IDC_EDIT_SERIAL);
313 disable(IDC_EDIT_LABEL);
314 disable(IDC_STATIC_SERIAL);
315 disable(IDC_STATIC_LABEL);
319 disable(IDC_RADIO_AUTODETECT);
320 disable(IDC_RADIO_ASSIGN);
321 disable(IDC_EDIT_DEVICE);
322 disable(IDC_BUTTON_BROWSE_DEVICE);
323 disable(IDC_EDIT_SERIAL);
324 disable(IDC_EDIT_LABEL);
325 disable(IDC_STATIC_SERIAL);
326 disable(IDC_STATIC_LABEL);
329 case BOX_MODE_NORMAL:
330 disable(IDC_RADIO_AUTODETECT);
331 enable(IDC_RADIO_ASSIGN);
332 disable(IDC_EDIT_DEVICE);
333 disable(IDC_BUTTON_BROWSE_DEVICE);
334 enable(IDC_EDIT_SERIAL);
335 enable(IDC_EDIT_LABEL);
336 enable(IDC_STATIC_SERIAL);
337 enable(IDC_STATIC_LABEL);
342 /* This function produces a mask for each drive letter that isn't currently used. Each bit of the long result
343 * represents a letter, with A being the least significant bit, and Z being the most significant.
345 * To calculate this, we loop over each letter, and see if we can get a drive entry for it. If so, we
346 * set the appropriate bit. At the end, we flip each bit, to give the desired result.
348 * The letter parameter is always marked as being available. This is so the edit dialog can display the
349 * currently used drive letter alongside the available ones.
351 long drive_available_mask(char letter)
359 for(i = 0; i < 26; i++)
361 if(!drives[i].in_use) continue;
362 result |= (1 << (toupper(drives[i].letter) - 'A'));
366 if (letter) result |= DRIVE_MASK_BIT(letter);
368 WINE_TRACE( "finished drive letter loop with %lx\n", result );
372 void advancedDriveEditDialog(HWND hDlg, BOOL showAdvanced)
374 #define ADVANCED_DELTA 120
377 static BOOL got_initial_ok_position = FALSE;
379 static RECT windowpos; /* we only use the height of this rectangle */
380 static BOOL got_initial_window_position = FALSE;
382 static RECT current_window;
388 if(!got_initial_ok_position)
391 GetWindowRect(GetDlgItem(hDlg, ID_BUTTON_OK), &okpos);
394 ScreenToClient(hDlg, &pt);
395 okpos.right+= (pt.x - okpos.left);
396 okpos.bottom+= (pt.y - okpos.top);
399 got_initial_ok_position = TRUE;
402 if(!got_initial_window_position)
404 GetWindowRect(hDlg, &windowpos);
405 got_initial_window_position = TRUE;
412 text = "Hide Advanced";
416 offset = ADVANCED_DELTA;
417 text = "Show Advanced";
420 ShowWindow(GetDlgItem(hDlg, IDC_STATIC_TYPE), state);
421 ShowWindow(GetDlgItem(hDlg, IDC_COMBO_TYPE), state);
422 ShowWindow(GetDlgItem(hDlg, IDC_BOX_LABELSERIAL), state);
423 ShowWindow(GetDlgItem(hDlg, IDC_RADIO_AUTODETECT), state);
424 ShowWindow(GetDlgItem(hDlg, IDC_RADIO_ASSIGN), state);
425 ShowWindow(GetDlgItem(hDlg, IDC_EDIT_LABEL), state);
426 ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DEVICE), state);
427 ShowWindow(GetDlgItem(hDlg, IDC_STATIC_LABEL), state);
428 ShowWindow(GetDlgItem(hDlg, IDC_BUTTON_BROWSE_DEVICE), state);
429 SetWindowPos(GetDlgItem(hDlg, ID_BUTTON_OK),
431 okpos.left, okpos.top - offset, okpos.right - okpos.left,
432 okpos.bottom - okpos.top,
435 /* resize the parent window */
436 GetWindowRect(hDlg, ¤t_window);
441 windowpos.right - windowpos.left,
442 windowpos.bottom - windowpos.top - offset,
445 /* update the button text based on the state */
446 SetWindowText(GetDlgItem(hDlg, IDC_BUTTON_SHOW_HIDE_ADVANCED),
451 void refreshDriveEditDialog(HWND dialog) {
457 int i, selection = -1;
464 fill_drive_droplist( drive_available_mask( editDriveEntry->letter ), editDriveEntry->letter, dialog );
467 path = editDriveEntry->unixpath;
469 WINE_TRACE("set path control text to '%s'\n", path);
470 SetWindowText(GetDlgItem(dialog, IDC_EDIT_PATH), path);
471 } else WINE_WARN("no Path field?\n");
474 type = editDriveEntry->type;
476 for(i = 0; i < sizeof(type_pairs)/sizeof(code_desc_pair); i++) {
477 SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0,
478 (LPARAM) type_pairs[i].sDesc);
479 if(type_pairs[i].sCode == type){
484 if( selection == -1 ) selection = DRIVE_TYPE_DEFAULT;
485 SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
486 } else WINE_WARN("no Type field?\n");
489 /* removeable media properties */
490 label = editDriveEntry->label;
492 SendDlgItemMessage(dialog, IDC_EDIT_LABEL, WM_SETTEXT, 0,(LPARAM)label);
493 } else WINE_WARN("no Label field?\n");
495 /* set serial edit text */
496 serial = editDriveEntry->serial;
498 SendDlgItemMessage(dialog, IDC_EDIT_SERIAL, WM_SETTEXT, 0,(LPARAM)serial);
499 } else WINE_WARN("no Serial field?\n");
501 /* TODO: get the device here to put into the edit box */
502 device = "Not implemented yet";
504 SendDlgItemMessage(dialog, IDC_EDIT_DEVICE, WM_SETTEXT, 0,(LPARAM)device);
505 } else WINE_WARN("no Device field?\n");
507 selection = IDC_RADIO_ASSIGN;
508 if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE)) {
511 selection = IDC_RADIO_AUTODETECT;
512 enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT);
515 selection = IDC_RADIO_ASSIGN;
516 enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
521 enable_labelserial_box(dialog, BOX_MODE_NORMAL);
522 selection = IDC_RADIO_ASSIGN;
525 CheckRadioButton( dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection );
532 /* storing the drive propsheet HWND here is a bit ugly, but the simplest solution for now */
533 static HWND driveDlgHandle;
535 void onEditChanged(HWND hDlg, WORD controlID) {
536 WINE_TRACE("controlID=%d\n", controlID);
538 case IDC_EDIT_LABEL: {
539 char *label = getDialogItemText(hDlg, controlID);
540 if(!label) label = strdup("");
541 setDriveLabel(editDriveEntry, label);
542 refreshDriveDlg(driveDlgHandle);
543 if (label) free(label);
546 case IDC_EDIT_PATH: {
547 char *path = getDialogItemText(hDlg, controlID);
548 if (!path) path = strdup("fake_windows"); /* default to assuming fake_windows in the .wine directory */
549 WINE_TRACE("got path from control of '%s'\n", path);
550 setDrivePath(editDriveEntry, path);
554 case IDC_EDIT_SERIAL: {
555 char *serial = getDialogItemText(hDlg, controlID);
556 if(!serial) serial = strdup("");
557 setDriveSerial(editDriveEntry, serial);
558 if (serial) free (serial);
561 case IDC_EDIT_DEVICE: {
562 char *device = getDialogItemText(hDlg,controlID);
563 /* TODO: handle device if/when it makes sense to do so.... */
564 if (device) free(device);
565 refreshDriveDlg(driveDlgHandle);
571 /* edit a drive entry */
572 INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
575 static BOOL advanced = FALSE;
579 EndDialog(hDlg, wParam);
582 case WM_INITDIALOG: {
583 enable_labelserial_box(hDlg, BOX_MODE_NORMAL);
584 advancedDriveEditDialog(hDlg, advanced);
585 editDriveEntry = (drive_entry_t*)lParam;
586 refreshDriveEditDialog(hDlg);
590 switch (LOWORD(wParam)) {
592 if (HIWORD(wParam) != CBN_SELCHANGE) break;
593 selection = SendDlgItemMessage( hDlg, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
594 if( selection == 2 || selection == 3 ) { /* cdrom or floppy */
595 if (IsDlgButtonChecked(hDlg, IDC_RADIO_AUTODETECT))
596 enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT);
598 enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN);
601 enable_labelserial_box( hDlg, BOX_MODE_NORMAL );
603 editDriveEntry->type = type_pairs[selection].sCode;
606 case IDC_COMBO_LETTER: {
607 int item = SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETCURSEL, 0, 0);
609 SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETLBTEXT, item, (LPARAM) &newLetter);
611 if (HIWORD(wParam) != CBN_SELCHANGE) break;
612 if (newLetter == editDriveEntry->letter) break;
614 WINE_TRACE("changing drive letter to %c\n", newLetter);
615 moveDrive(editDriveEntry, &drives[getDrive(newLetter)]);
616 editDriveEntry = &drives[getDrive(newLetter)];
617 refreshDriveDlg(driveDlgHandle);
621 case IDC_BUTTON_BROWSE_PATH:
625 case IDC_RADIO_AUTODETECT: {
627 WINE_FIXME("Implement autodetection\n");
628 enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT);
629 refreshDriveDlg(driveDlgHandle);
633 case IDC_RADIO_ASSIGN:
636 edit = getDialogItemText(hDlg, IDC_EDIT_LABEL);
637 if(!edit) edit = strdup("");
638 setDriveLabel(editDriveEntry, edit);
641 serial = getDialogItemText(hDlg, IDC_EDIT_SERIAL);
642 if(!serial) serial = strdup("");
643 setDriveSerial(editDriveEntry, serial);
646 /* TODO: we don't have a device at this point */
647 /* setDriveValue(editWindowLetter, "Device", NULL); */
648 enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN);
649 refreshDriveDlg(driveDlgHandle);
653 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
654 advanced = (advanced == TRUE) ? FALSE : TRUE; /* toggle state */
655 advancedDriveEditDialog(hDlg, advanced);
659 EndDialog(hDlg, wParam);
663 if (HIWORD(wParam) == EN_CHANGE) onEditChanged(hDlg, LOWORD(wParam));
669 void onAddDriveClicked(HWND hDlg) {
670 /* we should allocate a drive letter automatically. We also need some way to let the user choose the mapping point,
671 for now we will just force them to enter a path automatically, with / being the default. In future we should
672 be able to temporarily map / then invoke the directory chooser dialog. */
674 char newLetter = 'C'; /* we skip A and B, they are historically floppy drives */
675 long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
677 while (mask & (1 << (newLetter - 'A'))) {
679 if (newLetter > 'Z') {
680 MessageBox(NULL, "You cannot add any more drives.\n\nEach drive must have a letter, from A to Z, so you cannot have more than 26", "", MB_OK | MB_ICONEXCLAMATION);
684 WINE_TRACE("allocating drive letter %c\n", newLetter);
686 if(newLetter == 'C') {
687 addDrive(newLetter, "fake_windows", "System Drive", "", DRIVE_FIXED);
689 addDrive(newLetter, "/", "", "", DRIVE_FIXED);
692 refreshDriveDlg(driveDlgHandle);
694 DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) &(drives[getDrive(newLetter)]));
697 void onDriveInitDialog(void)
706 /* setup the drives array */
707 pDevices = (char*)malloc(512);
708 ret = GetLogicalDriveStrings(512, pDevices);
710 /* make all devices unused */
711 for(i = 0; i < 26; i++)
713 drives[i].letter = 'A' + i;
714 drives[i].in_use = FALSE;
721 CHAR volumeNameBuffer[512];
723 CHAR serialNumberString[256];
724 DWORD maxComponentLength;
725 DWORD fileSystemFlags;
726 CHAR fileSystemName[128];
730 char targetpath[256];
732 *pDevices = toupper(*pDevices);
734 WINE_TRACE("pDevices == '%s'\n", pDevices);
736 volumeNameBuffer[0] = 0;
738 retval = GetVolumeInformation(pDevices,
740 sizeof(volumeNameBuffer),
745 sizeof(fileSystemName));
748 WINE_TRACE("GetVolumeInformation() for '%s' failed, setting serialNumber to 0\n", pDevices);
753 WINE_TRACE("serialNumber: '0x%lX'\n", serialNumber);
755 /* build rootpath for GetDriveType() */
756 strncpy(rootpath, pDevices, sizeof(rootpath));
757 pathlen = strlen(rootpath);
758 /* ensure that we have a backslash on the root path */
759 if((rootpath[pathlen - 1] != '\\') &&
760 (pathlen < sizeof(rootpath)))
762 rootpath[pathlen] = '\\';
763 rootpath[pathlen + 1] = 0;
766 strncpy(simplepath, pDevices, 2); /* QueryDosDevice() requires no trailing backslash */
768 QueryDosDevice(simplepath, targetpath, sizeof(targetpath));
770 snprintf(serialNumberString, sizeof(serialNumberString), "%lX", serialNumber);
771 WINE_TRACE("serialNumberString: '%s'\n", serialNumberString);
772 addDrive(*pDevices, targetpath, volumeNameBuffer, serialNumberString, GetDriveType(rootpath));
774 ret-=strlen(pDevices);
775 pDevices+=strlen(pDevices);
777 /* skip over any nulls */
778 while((*pDevices == 0) && (ret))
787 WINE_TRACE("found %d drives\n", i);
793 void applyDriveChanges(void)
797 CHAR targetpath[256];
799 CHAR volumeNameBuffer[512];
801 DWORD maxComponentLength;
802 DWORD fileSystemFlags;
803 CHAR fileSystemName[128];
809 /* add each drive and remove as we go */
810 for(i = 0; i < 26; i++)
812 defineDevice = FALSE;
814 snprintf(devicename, sizeof(devicename), "%c:", 'A' + i);
817 if(QueryDosDevice(devicename, targetpath, sizeof(targetpath)))
822 /* if we found a drive and have a drive then compare things */
823 if(foundDrive && drives[i].in_use)
825 char newSerialNumberText[256];
827 volumeNameBuffer[0] = 0;
829 WINE_TRACE("drives[i].letter: '%c'\n", drives[i].letter);
831 snprintf(devicename, sizeof(devicename), "%c:\\", 'A' + i);
832 retval = GetVolumeInformation(devicename,
834 sizeof(volumeNameBuffer),
839 sizeof(fileSystemName));
842 WINE_TRACE(" GetVolumeInformation() for '%s' failed\n", devicename);
843 WINE_TRACE(" Skipping this drive\n");
845 continue; /* skip this drive */
848 snprintf(newSerialNumberText, sizeof(newSerialNumberText), "%lX", serialNumber);
850 WINE_TRACE(" current path: '%s', new path: '%s'\n",
851 targetpath, drives[i].unixpath);
852 WINE_TRACE(" current label: '%s', new label: '%s'\n",
853 volumeNameBuffer, drives[i].label);
854 WINE_TRACE(" current serial: '%s', new serial: '%s'\n",
855 newSerialNumberText, drives[i].serial);
857 /* compare to what we have */
858 /* do we have the same targetpath? */
859 if(strcmp(drives[i].unixpath, targetpath) ||
860 strcmp(drives[i].label, volumeNameBuffer) ||
861 strcmp(drives[i].serial, newSerialNumberText))
864 WINE_TRACE(" making changes to drive '%s'\n", devicename);
867 WINE_TRACE(" no changes to drive '%s'\n", devicename);
869 } else if(foundDrive && !drives[i].in_use)
871 /* remove this drive */
872 if(!DefineDosDevice(DDD_REMOVE_DEFINITION, devicename, drives[i].unixpath))
874 WINE_ERR("unable to remove devicename of '%s', targetpath of '%s'\n",
875 devicename, drives[i].unixpath);
879 WINE_TRACE("removed devicename of '%s', targetpath of '%s'\n",
880 devicename, drives[i].unixpath);
882 } else if(drives[i].in_use) /* foundDrive must be false from the above check */
887 /* adding and modifying are the same steps */
895 char driveValue[256];
897 /* define this drive */
898 /* DefineDosDevice() requires that NO trailing slash be present */
899 snprintf(devicename, sizeof(devicename), "%c:", 'A' + i);
900 if(!DefineDosDevice(DDD_RAW_TARGET_PATH, devicename, drives[i].unixpath))
902 WINE_ERR(" unable to define devicename of '%s', targetpath of '%s'\n",
903 devicename, drives[i].unixpath);
907 WINE_TRACE(" added devicename of '%s', targetpath of '%s'\n",
908 devicename, drives[i].unixpath);
910 /* SetVolumeLabel() requires a trailing slash */
911 snprintf(devicename, sizeof(devicename), "%c:\\", 'A' + i);
912 if(!SetVolumeLabel(devicename, drives[i].label))
914 WINE_ERR("unable to set volume label for devicename of '%s', label of '%s'\n",
915 devicename, drives[i].label);
919 WINE_TRACE(" set volume label for devicename of '%s', label of '%s'\n",
920 devicename, drives[i].label);
924 /* Set the drive type in the registry */
925 if(drives[i].type == DRIVE_FIXED)
927 else if(drives[i].type == DRIVE_REMOTE)
928 typeText = "network";
929 else if(drives[i].type == DRIVE_REMOVABLE)
931 else /* must be DRIVE_CDROM */
935 snprintf(driveValue, sizeof(driveValue), "%c:", toupper(drives[i].letter));
937 retval = RegOpenKey(HKEY_LOCAL_MACHINE,
938 "Software\\Wine\\Drives",
941 if(retval != ERROR_SUCCESS)
943 WINE_TRACE(" Unable to open '%s'\n", "Software\\Wine\\Drives");
946 retval = RegSetValueEx(
952 strlen(typeText) + 1);
953 if(retval != ERROR_SUCCESS)
955 WINE_TRACE(" Unable to set value of '%s' to '%s'\n",
956 driveValue, typeText);
959 WINE_TRACE(" Finished setting value of '%s' to '%s'\n",
960 driveValue, typeText);
965 /* Set the drive serial number via a .windows-serial file in */
966 /* the targetpath directory */
967 snprintf(filename, sizeof(filename), "%c:\\.windows-serial", drives[i].letter);
968 WINE_TRACE(" Putting serial number of '%ld' into file '%s'\n",
969 serialNumber, filename);
970 hFile = CreateFile(filename,
975 FILE_ATTRIBUTE_NORMAL,
979 WINE_TRACE(" writing serial number of '%s'\n", drives[i].serial);
982 strlen(drives[i].serial),
993 WINE_TRACE(" CreateFile() error with file '%s'\n", filename);
997 /* if this drive is in use we should free it up */
1000 freeDrive(&drives[i]); /* free up the string memory */
1007 DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1010 drive_entry_t *pDrive;
1014 onDriveInitDialog();
1017 switch (LOWORD(wParam)) {
1018 case IDC_LIST_DRIVES:
1019 /* double click should open the edit window for the chosen drive */
1020 if (HIWORD(wParam) == LBN_DBLCLK)
1021 SendMessageA(hDlg, WM_COMMAND, IDC_BUTTON_EDIT, 0);
1023 if (HIWORD(wParam) == LBN_SELCHANGE) lastSel = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0);
1026 case IDC_BUTTON_ADD:
1027 onAddDriveClicked(hDlg);
1030 case IDC_BUTTON_REMOVE:
1031 if (HIWORD(wParam) != BN_CLICKED) break;
1032 nItem = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0);
1033 pDrive = (drive_entry_t*)SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETITEMDATA, nItem, 0);
1035 refreshDriveDlg(driveDlgHandle);
1038 case IDC_BUTTON_EDIT:
1039 if (HIWORD(wParam) != BN_CLICKED) break;
1040 nItem = SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETCURSEL, 0, 0);
1041 pDrive = (drive_entry_t*)SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETITEMDATA, nItem, 0);
1042 DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) pDrive);
1045 case IDC_BUTTON_AUTODETECT:
1051 case WM_NOTIFY: switch(((LPNMHDR)lParam)->code) {
1052 case PSN_KILLACTIVE:
1053 WINE_TRACE("PSN_KILLACTIVE\n");
1054 SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
1057 applyDriveChanges();
1058 SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
1061 driveDlgHandle = hDlg;
1062 refreshDriveDlg (driveDlgHandle);