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 int driveIndex = getDrive(letter);
75 if(drives[driveIndex].in_use)
78 WINE_TRACE("letter == '%c', unixpath == '%s', label == '%s', serial == '%s', type == %d\n",
79 letter, targetpath, label, serial, type);
81 drives[driveIndex].letter = toupper(letter);
82 drives[driveIndex].unixpath = strdup(targetpath);
83 drives[driveIndex].label = strdup(label);
84 drives[driveIndex].serial = strdup(serial);
85 drives[driveIndex].type = type;
86 drives[driveIndex].in_use = TRUE;
91 /* frees up the memory associated with a drive and returns the */
92 /* pNext of the given drive entry */
93 void freeDrive(drive_entry_t *pDrive)
95 free(pDrive->unixpath);
99 pDrive->in_use = FALSE;
102 void setDriveLabel(drive_entry_t *pDrive, char *label)
104 WINE_TRACE("pDrive->letter '%c', label = '%s'\n", pDrive->letter, label);
106 pDrive->label = strdup(label);
109 void setDriveSerial(drive_entry_t *pDrive, char *serial)
111 WINE_TRACE("pDrive->letter '%c', serial = '%s'\n", pDrive->letter, serial);
112 free(pDrive->serial);
113 pDrive->serial = strdup(serial);
116 void setDrivePath(drive_entry_t *pDrive, char *path)
118 WINE_TRACE("pDrive->letter '%c', path = '%s'\n", pDrive->letter, path);
119 free(pDrive->unixpath);
120 pDrive->unixpath = strdup(path);
123 BOOL copyDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
127 WINE_TRACE("pDst already in use\n");
131 if(!pSrc->unixpath) WINE_TRACE("!pSrc->unixpath\n");
132 if(!pSrc->label) WINE_TRACE("!pSrc->label\n");
133 if(!pSrc->serial) WINE_TRACE("!pSrc->serial\n");
135 pDst->unixpath = strdup(pSrc->unixpath);
136 pDst->label = strdup(pSrc->label);
137 pDst->serial = strdup(pSrc->serial);
138 pDst->type = pSrc->type;
144 BOOL moveDrive(drive_entry_t *pSrc, drive_entry_t *pDst)
146 WINE_TRACE("pSrc->letter == %c, pDst->letter == %c\n", pSrc->letter, pDst->letter);
148 if(!copyDrive(pSrc, pDst))
150 WINE_TRACE("copyDrive failed\n");
158 int refreshDriveDlg (HWND dialog)
161 int doesDriveCExist = FALSE;
168 /* Clear the listbox */
169 SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_RESETCONTENT, 0, 0);
171 for(i = 0; i < 26; i++)
177 /* skip over any unused drives */
178 if(!drives[i].in_use)
181 if(drives[i].letter == 'C')
182 doesDriveCExist = TRUE;
184 titleLen = snprintf(title, 0, "Drive %c:\\ %s", 'A' + i,
186 titleLen++; /* add a byte for the trailing null */
188 title = malloc(titleLen);
190 /* the %s in the item label will be replaced by the drive letter, so -1, then
191 -2 for the second %s which will be expanded to the label, finally + 1 for terminating #0 */
192 snprintf(title, titleLen, "Drive %c:\\ %s", 'A' + i,
195 WINE_TRACE("title is '%s'\n", title);
197 /* the first SendMessage call adds the string and returns the index, the second associates that index with it */
198 itemIndex = SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_ADDSTRING ,(WPARAM) -1, (LPARAM) title);
199 SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_SETITEMDATA, itemIndex, (LPARAM) &drives[i]);
205 WINE_TRACE("loaded %d drives\n", driveCount);
206 SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETSEL, TRUE, lastSel);
208 /* show the warning if there is no Drive C */
209 if (!doesDriveCExist)
210 ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
212 ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
214 /* disable or enable controls depending on whether we are editing global vs app specific config */
215 if (appSettings == EDITING_GLOBAL) {
216 WINE_TRACE("enabling controls\n");
217 enable(IDC_LIST_DRIVES);
218 enable(IDC_BUTTON_ADD);
219 enable(IDC_BUTTON_REMOVE);
220 enable(IDC_BUTTON_EDIT);
221 enable(IDC_BUTTON_AUTODETECT);
224 WINE_TRACE("disabling controls\n");
225 disable(IDC_LIST_DRIVES);
226 disable(IDC_BUTTON_ADD);
227 disable(IDC_BUTTON_REMOVE);
228 disable(IDC_BUTTON_EDIT);
229 disable(IDC_BUTTON_AUTODETECT);
237 /******************************************************************************/
238 /* The Drive Editing Dialog */
239 /******************************************************************************/
240 #define DRIVE_MASK_BIT(B) 1<<(toupper(B)-'A')
247 static code_desc_pair type_pairs[] = {
248 {DRIVE_FIXED, "Local hard disk"},
249 {DRIVE_REMOTE, "Network share" },
250 {DRIVE_REMOVABLE, "Floppy disk"},
251 {DRIVE_CDROM, "CD-ROM"}
253 #define DRIVE_TYPE_DEFAULT 1
256 void fill_drive_droplist(long mask, char currentLetter, HWND hDlg)
262 char sName[4] = "A:";
264 for( i=0, count=0, selection=-1, next_letter=-1; i <= 'Z'-'A'; ++i ) {
265 if( mask & DRIVE_MASK_BIT('A'+i) ) {
269 index = SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName );
271 if( toupper(currentLetter) == 'A' + i ) {
275 if( i >= 2 && next_letter == -1){ /*default drive is first one of C-Z */
283 if( selection == -1 ) {
284 selection = next_letter;
287 SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0 );
290 #define BOX_MODE_CD_ASSIGN 1
291 #define BOX_MODE_CD_AUTODETECT 2
292 #define BOX_MODE_NONE 3
293 #define BOX_MODE_NORMAL 4
294 void enable_labelserial_box(HWND dialog, int mode)
296 WINE_TRACE("mode=%d\n", mode);
298 case BOX_MODE_CD_ASSIGN:
299 /* enable(IDC_RADIO_AUTODETECT); */
300 enable(IDC_RADIO_ASSIGN);
301 disable(IDC_EDIT_DEVICE);
302 disable(IDC_BUTTON_BROWSE_DEVICE);
303 enable(IDC_EDIT_SERIAL);
304 enable(IDC_EDIT_LABEL);
305 enable(IDC_STATIC_SERIAL);
306 enable(IDC_STATIC_LABEL);
309 case BOX_MODE_CD_AUTODETECT:
310 /* enable(IDC_RADIO_AUTODETECT); */
311 enable(IDC_RADIO_ASSIGN);
312 enable(IDC_EDIT_DEVICE);
313 enable(IDC_BUTTON_BROWSE_DEVICE);
314 disable(IDC_EDIT_SERIAL);
315 disable(IDC_EDIT_LABEL);
316 disable(IDC_STATIC_SERIAL);
317 disable(IDC_STATIC_LABEL);
321 disable(IDC_RADIO_AUTODETECT);
322 disable(IDC_RADIO_ASSIGN);
323 disable(IDC_EDIT_DEVICE);
324 disable(IDC_BUTTON_BROWSE_DEVICE);
325 disable(IDC_EDIT_SERIAL);
326 disable(IDC_EDIT_LABEL);
327 disable(IDC_STATIC_SERIAL);
328 disable(IDC_STATIC_LABEL);
331 case BOX_MODE_NORMAL:
332 disable(IDC_RADIO_AUTODETECT);
333 enable(IDC_RADIO_ASSIGN);
334 disable(IDC_EDIT_DEVICE);
335 disable(IDC_BUTTON_BROWSE_DEVICE);
336 enable(IDC_EDIT_SERIAL);
337 enable(IDC_EDIT_LABEL);
338 enable(IDC_STATIC_SERIAL);
339 enable(IDC_STATIC_LABEL);
344 /* This function produces a mask for each drive letter that isn't currently used. Each bit of the long result
345 * represents a letter, with A being the least significant bit, and Z being the most significant.
347 * To calculate this, we loop over each letter, and see if we can get a drive entry for it. If so, we
348 * set the appropriate bit. At the end, we flip each bit, to give the desired result.
350 * The letter parameter is always marked as being available. This is so the edit dialog can display the
351 * currently used drive letter alongside the available ones.
353 long drive_available_mask(char letter)
361 for(i = 0; i < 26; i++)
363 if(!drives[i].in_use) continue;
364 result |= (1 << (toupper(drives[i].letter) - 'A'));
368 if (letter) result |= DRIVE_MASK_BIT(letter);
370 WINE_TRACE( "finished drive letter loop with %lx\n", result );
374 void advancedDriveEditDialog(HWND hDlg, BOOL showAdvanced)
376 #define ADVANCED_DELTA 120
379 static BOOL got_initial_ok_position = FALSE;
381 static RECT windowpos; /* we only use the height of this rectangle */
382 static BOOL got_initial_window_position = FALSE;
384 static RECT current_window;
390 if(!got_initial_ok_position)
393 GetWindowRect(GetDlgItem(hDlg, ID_BUTTON_OK), &okpos);
396 ScreenToClient(hDlg, &pt);
397 okpos.right+= (pt.x - okpos.left);
398 okpos.bottom+= (pt.y - okpos.top);
401 got_initial_ok_position = TRUE;
404 if(!got_initial_window_position)
406 GetWindowRect(hDlg, &windowpos);
407 got_initial_window_position = TRUE;
414 text = "Hide Advanced";
418 offset = ADVANCED_DELTA;
419 text = "Show Advanced";
422 ShowWindow(GetDlgItem(hDlg, IDC_STATIC_TYPE), state);
423 ShowWindow(GetDlgItem(hDlg, IDC_COMBO_TYPE), state);
424 ShowWindow(GetDlgItem(hDlg, IDC_BOX_LABELSERIAL), state);
425 ShowWindow(GetDlgItem(hDlg, IDC_RADIO_AUTODETECT), state);
426 ShowWindow(GetDlgItem(hDlg, IDC_RADIO_ASSIGN), state);
427 ShowWindow(GetDlgItem(hDlg, IDC_EDIT_LABEL), state);
428 ShowWindow(GetDlgItem(hDlg, IDC_EDIT_DEVICE), state);
429 ShowWindow(GetDlgItem(hDlg, IDC_STATIC_LABEL), state);
430 ShowWindow(GetDlgItem(hDlg, IDC_BUTTON_BROWSE_DEVICE), state);
431 SetWindowPos(GetDlgItem(hDlg, ID_BUTTON_OK),
433 okpos.left, okpos.top - offset, okpos.right - okpos.left,
434 okpos.bottom - okpos.top,
437 /* resize the parent window */
438 GetWindowRect(hDlg, ¤t_window);
443 windowpos.right - windowpos.left,
444 windowpos.bottom - windowpos.top - offset,
447 /* update the button text based on the state */
448 SetWindowText(GetDlgItem(hDlg, IDC_BUTTON_SHOW_HIDE_ADVANCED),
453 void refreshDriveEditDialog(HWND dialog) {
459 int i, selection = -1;
466 fill_drive_droplist( drive_available_mask( editDriveEntry->letter ), editDriveEntry->letter, dialog );
469 path = editDriveEntry->unixpath;
471 WINE_TRACE("set path control text to '%s'\n", path);
472 SetWindowText(GetDlgItem(dialog, IDC_EDIT_PATH), path);
473 } else WINE_WARN("no Path field?\n");
476 type = editDriveEntry->type;
478 for(i = 0; i < sizeof(type_pairs)/sizeof(code_desc_pair); i++) {
479 SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0,
480 (LPARAM) type_pairs[i].sDesc);
481 if(type_pairs[i].sCode == type){
486 if( selection == -1 ) selection = DRIVE_TYPE_DEFAULT;
487 SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
488 } else WINE_WARN("no Type field?\n");
491 /* removeable media properties */
492 label = editDriveEntry->label;
494 SendDlgItemMessage(dialog, IDC_EDIT_LABEL, WM_SETTEXT, 0,(LPARAM)label);
495 } else WINE_WARN("no Label field?\n");
497 /* set serial edit text */
498 serial = editDriveEntry->serial;
500 SendDlgItemMessage(dialog, IDC_EDIT_SERIAL, WM_SETTEXT, 0,(LPARAM)serial);
501 } else WINE_WARN("no Serial field?\n");
503 /* TODO: get the device here to put into the edit box */
504 device = "Not implemented yet";
506 SendDlgItemMessage(dialog, IDC_EDIT_DEVICE, WM_SETTEXT, 0,(LPARAM)device);
507 } else WINE_WARN("no Device field?\n");
509 selection = IDC_RADIO_ASSIGN;
510 if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE)) {
513 selection = IDC_RADIO_AUTODETECT;
514 enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT);
517 selection = IDC_RADIO_ASSIGN;
518 enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
523 enable_labelserial_box(dialog, BOX_MODE_NORMAL);
524 selection = IDC_RADIO_ASSIGN;
527 CheckRadioButton( dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection );
534 /* storing the drive propsheet HWND here is a bit ugly, but the simplest solution for now */
535 static HWND driveDlgHandle;
537 void onEditChanged(HWND hDlg, WORD controlID) {
538 WINE_TRACE("controlID=%d\n", controlID);
540 case IDC_EDIT_LABEL: {
541 char *label = getDialogItemText(hDlg, controlID);
542 if(!label) label = strdup("");
543 setDriveLabel(editDriveEntry, label);
544 refreshDriveDlg(driveDlgHandle);
545 if (label) free(label);
548 case IDC_EDIT_PATH: {
549 char *path = getDialogItemText(hDlg, controlID);
550 if (!path) path = strdup("fake_windows"); /* default to assuming fake_windows in the .wine directory */
551 WINE_TRACE("got path from control of '%s'\n", path);
552 setDrivePath(editDriveEntry, path);
556 case IDC_EDIT_SERIAL: {
557 char *serial = getDialogItemText(hDlg, controlID);
558 if(!serial) serial = strdup("");
559 setDriveSerial(editDriveEntry, serial);
560 if (serial) free (serial);
563 case IDC_EDIT_DEVICE: {
564 char *device = getDialogItemText(hDlg,controlID);
565 /* TODO: handle device if/when it makes sense to do so.... */
566 if (device) free(device);
567 refreshDriveDlg(driveDlgHandle);
573 /* edit a drive entry */
574 INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
577 static BOOL advanced = FALSE;
581 EndDialog(hDlg, wParam);
584 case WM_INITDIALOG: {
585 enable_labelserial_box(hDlg, BOX_MODE_NORMAL);
586 advancedDriveEditDialog(hDlg, advanced);
587 editDriveEntry = (drive_entry_t*)lParam;
588 refreshDriveEditDialog(hDlg);
592 switch (LOWORD(wParam)) {
594 if (HIWORD(wParam) != CBN_SELCHANGE) break;
595 selection = SendDlgItemMessage( hDlg, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
596 if( selection == 2 || selection == 3 ) { /* cdrom or floppy */
597 if (IsDlgButtonChecked(hDlg, IDC_RADIO_AUTODETECT))
598 enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT);
600 enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN);
603 enable_labelserial_box( hDlg, BOX_MODE_NORMAL );
605 editDriveEntry->type = type_pairs[selection].sCode;
608 case IDC_COMBO_LETTER: {
609 int item = SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETCURSEL, 0, 0);
611 SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETLBTEXT, item, (LPARAM) newLetter);
613 if (HIWORD(wParam) != CBN_SELCHANGE) break;
614 if (newLetter[0] == editDriveEntry->letter) break;
616 WINE_TRACE("changing drive letter to %c\n", newLetter[0]);
617 moveDrive(editDriveEntry, &drives[getDrive(newLetter[0])]);
618 editDriveEntry = &drives[getDrive(newLetter[0])];
619 refreshDriveDlg(driveDlgHandle);
623 case IDC_BUTTON_BROWSE_PATH:
627 case IDC_RADIO_AUTODETECT: {
629 WINE_FIXME("Implement autodetection\n");
630 enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT);
631 refreshDriveDlg(driveDlgHandle);
635 case IDC_RADIO_ASSIGN:
638 edit = getDialogItemText(hDlg, IDC_EDIT_LABEL);
639 if(!edit) edit = strdup("");
640 setDriveLabel(editDriveEntry, edit);
643 serial = getDialogItemText(hDlg, IDC_EDIT_SERIAL);
644 if(!serial) serial = strdup("");
645 setDriveSerial(editDriveEntry, serial);
648 /* TODO: we don't have a device at this point */
649 /* setDriveValue(editWindowLetter, "Device", NULL); */
650 enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN);
651 refreshDriveDlg(driveDlgHandle);
655 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
656 advanced = (advanced == TRUE) ? FALSE : TRUE; /* toggle state */
657 advancedDriveEditDialog(hDlg, advanced);
661 EndDialog(hDlg, wParam);
665 if (HIWORD(wParam) == EN_CHANGE) onEditChanged(hDlg, LOWORD(wParam));
671 void onAddDriveClicked(HWND hDlg) {
672 /* we should allocate a drive letter automatically. We also need some way to let the user choose the mapping point,
673 for now we will just force them to enter a path automatically, with / being the default. In future we should
674 be able to temporarily map / then invoke the directory chooser dialog. */
676 char newLetter = 'C'; /* we skip A and B, they are historically floppy drives */
677 long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
679 while (mask & (1 << (newLetter - 'A'))) {
681 if (newLetter > 'Z') {
682 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);
686 WINE_TRACE("allocating drive letter %c\n", newLetter);
688 if(newLetter == 'C') {
689 addDrive(newLetter, "fake_windows", "System Drive", "", DRIVE_FIXED);
691 addDrive(newLetter, "/", "", "", DRIVE_FIXED);
694 refreshDriveDlg(driveDlgHandle);
696 DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) &(drives[getDrive(newLetter)]));
699 void onDriveInitDialog(void)
701 char *pDevices, *pDev;
708 /* setup the drives array */
709 pDev = pDevices = malloc(512);
710 ret = GetLogicalDriveStrings(512, pDevices);
712 /* make all devices unused */
713 for(i = 0; i < 26; i++)
715 drives[i].letter = 'A' + i;
716 drives[i].in_use = FALSE;
723 CHAR volumeNameBuffer[512];
725 CHAR serialNumberString[256];
726 DWORD maxComponentLength;
727 DWORD fileSystemFlags;
728 CHAR fileSystemName[128];
732 char targetpath[256];
734 *pDevices = toupper(*pDevices);
736 WINE_TRACE("pDevices == '%s'\n", pDevices);
738 volumeNameBuffer[0] = 0;
740 retval = GetVolumeInformation(pDevices,
742 sizeof(volumeNameBuffer),
747 sizeof(fileSystemName));
750 WINE_TRACE("GetVolumeInformation() for '%s' failed, setting serialNumber to 0\n", pDevices);
755 WINE_TRACE("serialNumber: '0x%lX'\n", serialNumber);
757 /* build rootpath for GetDriveType() */
758 strncpy(rootpath, pDevices, sizeof(rootpath));
759 pathlen = strlen(rootpath);
760 /* ensure that we have a backslash on the root path */
761 if((rootpath[pathlen - 1] != '\\') &&
762 (pathlen < sizeof(rootpath)))
764 rootpath[pathlen] = '\\';
765 rootpath[pathlen + 1] = 0;
768 strncpy(simplepath, pDevices, 2); /* QueryDosDevice() requires no trailing backslash */
770 QueryDosDevice(simplepath, targetpath, sizeof(targetpath));
772 snprintf(serialNumberString, sizeof(serialNumberString), "%lX", serialNumber);
773 WINE_TRACE("serialNumberString: '%s'\n", serialNumberString);
774 addDrive(*pDevices, targetpath, volumeNameBuffer, serialNumberString, GetDriveType(rootpath));
776 ret-=strlen(pDevices);
777 pDevices+=strlen(pDevices);
779 /* skip over any nulls */
780 while((*pDevices == 0) && (ret))
789 WINE_TRACE("found %d drives\n", i);
795 void applyDriveChanges(void)
799 CHAR targetpath[256];
801 CHAR volumeNameBuffer[512];
803 DWORD maxComponentLength;
804 DWORD fileSystemFlags;
805 CHAR fileSystemName[128];
811 /* add each drive and remove as we go */
812 for(i = 0; i < 26; i++)
814 defineDevice = FALSE;
816 snprintf(devicename, sizeof(devicename), "%c:", 'A' + i);
819 if(QueryDosDevice(devicename, targetpath, sizeof(targetpath)))
824 /* if we found a drive and have a drive then compare things */
825 if(foundDrive && drives[i].in_use)
827 char newSerialNumberText[256];
829 volumeNameBuffer[0] = 0;
831 WINE_TRACE("drives[i].letter: '%c'\n", drives[i].letter);
833 snprintf(devicename, sizeof(devicename), "%c:\\", 'A' + i);
834 retval = GetVolumeInformation(devicename,
836 sizeof(volumeNameBuffer),
841 sizeof(fileSystemName));
844 WINE_TRACE(" GetVolumeInformation() for '%s' failed\n", devicename);
845 WINE_TRACE(" Skipping this drive\n");
847 continue; /* skip this drive */
850 snprintf(newSerialNumberText, sizeof(newSerialNumberText), "%lX", serialNumber);
852 WINE_TRACE(" current path: '%s', new path: '%s'\n",
853 targetpath, drives[i].unixpath);
854 WINE_TRACE(" current label: '%s', new label: '%s'\n",
855 volumeNameBuffer, drives[i].label);
856 WINE_TRACE(" current serial: '%s', new serial: '%s'\n",
857 newSerialNumberText, drives[i].serial);
859 /* compare to what we have */
860 /* do we have the same targetpath? */
861 if(strcmp(drives[i].unixpath, targetpath) ||
862 strcmp(drives[i].label, volumeNameBuffer) ||
863 strcmp(drives[i].serial, newSerialNumberText))
866 WINE_TRACE(" making changes to drive '%s'\n", devicename);
869 WINE_TRACE(" no changes to drive '%s'\n", devicename);
871 } else if(foundDrive && !drives[i].in_use)
873 /* remove this drive */
874 if(!DefineDosDevice(DDD_REMOVE_DEFINITION, devicename, drives[i].unixpath))
876 WINE_ERR("unable to remove devicename of '%s', targetpath of '%s'\n",
877 devicename, drives[i].unixpath);
881 WINE_TRACE("removed devicename of '%s', targetpath of '%s'\n",
882 devicename, drives[i].unixpath);
884 } else if(drives[i].in_use) /* foundDrive must be false from the above check */
889 /* adding and modifying are the same steps */
897 char driveValue[256];
899 /* define this drive */
900 /* DefineDosDevice() requires that NO trailing slash be present */
901 snprintf(devicename, sizeof(devicename), "%c:", 'A' + i);
902 if(!DefineDosDevice(DDD_RAW_TARGET_PATH, devicename, drives[i].unixpath))
904 WINE_ERR(" unable to define devicename of '%s', targetpath of '%s'\n",
905 devicename, drives[i].unixpath);
909 WINE_TRACE(" added devicename of '%s', targetpath of '%s'\n",
910 devicename, drives[i].unixpath);
912 /* SetVolumeLabel() requires a trailing slash */
913 snprintf(devicename, sizeof(devicename), "%c:\\", 'A' + i);
914 if(!SetVolumeLabel(devicename, drives[i].label))
916 WINE_ERR("unable to set volume label for devicename of '%s', label of '%s'\n",
917 devicename, drives[i].label);
921 WINE_TRACE(" set volume label for devicename of '%s', label of '%s'\n",
922 devicename, drives[i].label);
926 /* Set the drive type in the registry */
927 if(drives[i].type == DRIVE_FIXED)
929 else if(drives[i].type == DRIVE_REMOTE)
930 typeText = "network";
931 else if(drives[i].type == DRIVE_REMOVABLE)
933 else /* must be DRIVE_CDROM */
937 snprintf(driveValue, sizeof(driveValue), "%c:", toupper(drives[i].letter));
939 retval = RegOpenKey(HKEY_LOCAL_MACHINE,
940 "Software\\Wine\\Drives",
943 if(retval != ERROR_SUCCESS)
945 WINE_TRACE(" Unable to open '%s'\n", "Software\\Wine\\Drives");
948 retval = RegSetValueEx(
954 strlen(typeText) + 1);
955 if(retval != ERROR_SUCCESS)
957 WINE_TRACE(" Unable to set value of '%s' to '%s'\n",
958 driveValue, typeText);
961 WINE_TRACE(" Finished setting value of '%s' to '%s'\n",
962 driveValue, typeText);
967 /* Set the drive serial number via a .windows-serial file in */
968 /* the targetpath directory */
969 snprintf(filename, sizeof(filename), "%c:\\.windows-serial", drives[i].letter);
970 WINE_TRACE(" Putting serial number of '%ld' into file '%s'\n",
971 serialNumber, filename);
972 hFile = CreateFile(filename,
977 FILE_ATTRIBUTE_NORMAL,
981 WINE_TRACE(" writing serial number of '%s'\n", drives[i].serial);
984 strlen(drives[i].serial),
995 WINE_TRACE(" CreateFile() error with file '%s'\n", filename);
999 /* if this drive is in use we should free it up */
1000 if(drives[i].in_use)
1002 freeDrive(&drives[i]); /* free up the string memory */
1009 DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1012 drive_entry_t *pDrive;
1016 onDriveInitDialog();
1019 switch (LOWORD(wParam)) {
1020 case IDC_LIST_DRIVES:
1021 /* double click should open the edit window for the chosen drive */
1022 if (HIWORD(wParam) == LBN_DBLCLK)
1023 SendMessageA(hDlg, WM_COMMAND, IDC_BUTTON_EDIT, 0);
1025 if (HIWORD(wParam) == LBN_SELCHANGE) lastSel = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0);
1028 case IDC_BUTTON_ADD:
1029 onAddDriveClicked(hDlg);
1032 case IDC_BUTTON_REMOVE:
1033 if (HIWORD(wParam) != BN_CLICKED) break;
1034 nItem = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0);
1035 pDrive = (drive_entry_t*)SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETITEMDATA, nItem, 0);
1037 refreshDriveDlg(driveDlgHandle);
1040 case IDC_BUTTON_EDIT:
1041 if (HIWORD(wParam) != BN_CLICKED) break;
1042 nItem = SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETCURSEL, 0, 0);
1043 pDrive = (drive_entry_t*)SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETITEMDATA, nItem, 0);
1044 DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) pDrive);
1047 case IDC_BUTTON_AUTODETECT:
1053 case WM_NOTIFY: switch(((LPNMHDR)lParam)->code) {
1054 case PSN_KILLACTIVE:
1055 WINE_TRACE("PSN_KILLACTIVE\n");
1056 SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
1059 applyDriveChanges();
1060 SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
1063 driveDlgHandle = hDlg;
1064 refreshDriveDlg (driveDlgHandle);