| /* | |
| * Drive management UI code | |
| * | |
| * Copyright 2003 Mark Westcott | |
| * Copyright 2003 Mike Hearn | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| */ | |
| #include <assert.h> | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <windef.h> | |
| #include <winbase.h> | |
| #include <winreg.h> | |
| #include <wine/debug.h> | |
| #include <shellapi.h> | |
| #include <objbase.h> | |
| #include <shlguid.h> | |
| #include <shlwapi.h> | |
| #include <shlobj.h> | |
| #include "winecfg.h" | |
| #include "resource.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(winecfg); | |
| static BOOL updatingUI = FALSE; | |
| static char editWindowLetter; /* drive letter of the drive we are currently editing */ | |
| static int lastSel = 0; /* the last drive selected in the property sheet */ | |
| /* returns NULL on failure. caller is responsible for freeing result */ | |
| char *getDriveValue(char letter, const char *valueName) { | |
| HKEY hkDrive = 0; | |
| char *subKeyName; | |
| char *result = NULL; | |
| HRESULT hr; | |
| DWORD bufferSize; | |
| WINE_TRACE("letter=%c, valueName=%s\n", letter, valueName); | |
| subKeyName = malloc(strlen("Drive X")+1); | |
| sprintf(subKeyName, "Drive %c", letter); | |
| hr = RegOpenKeyEx(configKey, subKeyName, 0, KEY_READ, &hkDrive); | |
| if (hr != ERROR_SUCCESS) goto end; | |
| hr = RegQueryValueEx(hkDrive, valueName, NULL, NULL, NULL, &bufferSize); | |
| if (hr != ERROR_SUCCESS) goto end; | |
| result = malloc(bufferSize); | |
| hr = RegQueryValueEx(hkDrive, valueName, NULL, NULL, result, &bufferSize); | |
| if (hr != ERROR_SUCCESS) goto end; | |
| end: | |
| if (hkDrive) RegCloseKey(hkDrive); | |
| free(subKeyName); | |
| return result; | |
| } | |
| /* call with newValue == NULL to remove a value */ | |
| void setDriveValue(char letter, const char *valueName, const char *newValue) { | |
| char *driveSection = malloc(strlen("Drive X")+1); | |
| sprintf(driveSection, "Drive %c", letter); | |
| if (newValue) | |
| addTransaction(driveSection, valueName, ACTION_SET, newValue); | |
| else | |
| addTransaction(driveSection, valueName, ACTION_REMOVE, NULL); | |
| free(driveSection); | |
| } | |
| /* copies a drive configuration branch */ | |
| void copyDrive(char srcLetter, char destLetter) { | |
| char driveSection[sizeof("Drive X") + 1]; | |
| char *path, *label, *type, *serial; | |
| WINE_TRACE("srcLetter=%c, destLetter=%c\n", srcLetter, destLetter); | |
| sprintf(driveSection, "Drive %c", srcLetter); | |
| path = getDriveValue(srcLetter, "Path"); | |
| label = getDriveValue(srcLetter, "Label"); | |
| type = getDriveValue(srcLetter, "Type"); | |
| serial = getDriveValue(srcLetter, "Serial"); | |
| sprintf(driveSection, "Drive %c", destLetter); | |
| if (path) addTransaction(driveSection, "Path", ACTION_SET, path); | |
| if (label) addTransaction(driveSection, "Label", ACTION_SET, label); | |
| if (type) addTransaction(driveSection, "Type", ACTION_SET, type); | |
| if (serial) addTransaction(driveSection, "Serial", ACTION_SET, serial); | |
| if (path) free(path); | |
| if (label) free(label); | |
| if (type) free(type); | |
| if (serial) free(serial); | |
| } | |
| void removeDrive(char letter) { | |
| char driveSection[sizeof("Drive X") + 1]; | |
| sprintf(driveSection, "Drive %c", letter); | |
| addTransaction(driveSection, NULL, ACTION_REMOVE, NULL); | |
| } | |
| int refreshDriveDlg (HWND dialog) | |
| { | |
| int i; | |
| char *subKeyName = malloc(MAX_NAME_LENGTH); | |
| int driveCount = 0; | |
| DWORD sizeOfSubKeyName = MAX_NAME_LENGTH; | |
| int doesDriveCExist = FALSE; | |
| WINE_TRACE("\n"); | |
| updatingUI = TRUE; | |
| /* Clear the listbox */ | |
| SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_RESETCONTENT, 0, 0); | |
| for (i = 0; | |
| RegEnumKeyExA(configKey, i, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, NULL ) != ERROR_NO_MORE_ITEMS; | |
| ++i, sizeOfSubKeyName = MAX_NAME_LENGTH) { | |
| HKEY hkDrive; | |
| char returnBuffer[MAX_NAME_LENGTH]; | |
| DWORD sizeOfReturnBuffer = sizeof(returnBuffer); | |
| LONG r; | |
| WINE_TRACE("%s\n", subKeyName); | |
| if (!strncmp("Drive ", subKeyName, 5)) { | |
| char driveLetter = '\0'; | |
| char *label; | |
| char *title; | |
| char *device; | |
| int titleLen; | |
| const char *itemLabel = "Drive %s (%s)"; | |
| int itemIndex; | |
| if (RegOpenKeyExA (configKey, subKeyName, 0, KEY_READ, &hkDrive) != ERROR_SUCCESS) { | |
| WINE_ERR("unable to open drive registry key"); | |
| RegCloseKey(configKey); | |
| return -1; | |
| } | |
| /* extract the drive letter, force to upper case */ | |
| driveLetter = subKeyName[strlen(subKeyName)-1]; | |
| if (driveLetter) driveLetter = toupper(driveLetter); | |
| if (driveLetter == 'C') doesDriveCExist = TRUE; | |
| ZeroMemory(returnBuffer, sizeof(*returnBuffer)); | |
| sizeOfReturnBuffer = sizeof(returnBuffer); | |
| r = RegQueryValueExA(hkDrive, "Label", NULL, NULL, returnBuffer, &sizeOfReturnBuffer); | |
| if (r == ERROR_SUCCESS) { | |
| label = malloc(sizeOfReturnBuffer); | |
| strncpy(label, returnBuffer, sizeOfReturnBuffer); | |
| } else { | |
| WINE_WARN("label not loaded: %ld\n", r); | |
| label = NULL; | |
| } | |
| device = getDriveValue(driveLetter, "Device"); | |
| /* We now know the label and drive letter, so we can add to the list. The list items will have the letter associated | |
| * with them, which acts as the key. We can then use that letter to get/set the properties of the drive. */ | |
| WINE_TRACE("Adding %c: label=%s to the listbox, device=%s\n", driveLetter, label, device); | |
| /* fixup label */ | |
| if (!label && device) { | |
| label = malloc(strlen("[label read from device ]")+1+strlen(device)); | |
| sprintf(label, "[label read from device %s]", device); | |
| } | |
| if (!label) label = strdup("(no label)"); | |
| titleLen = strlen(itemLabel) - 1 + strlen(label) - 2 + 1; | |
| title = malloc(titleLen); | |
| /* the %s in the item label will be replaced by the drive letter, so -1, then | |
| -2 for the second %s which will be expanded to the label, finally + 1 for terminating #0 */ | |
| snprintf(title, titleLen, "Drive %c: %s", driveLetter, label); | |
| /* the first SendMessage call adds the string and returns the index, the second associates that index with it */ | |
| itemIndex = SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_ADDSTRING ,(WPARAM) -1, (LPARAM) title); | |
| SendMessageA(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_SETITEMDATA, itemIndex, (LPARAM) driveLetter); | |
| free(title); | |
| free(label); | |
| driveCount++; | |
| } | |
| } | |
| WINE_TRACE("loaded %d drives\n", driveCount); | |
| SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LB_SETSEL, TRUE, lastSel); | |
| /* show the warning if there is no Drive C */ | |
| if (!doesDriveCExist) | |
| ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL); | |
| else | |
| ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE); | |
| free(subKeyName); | |
| /* disable or enable controls depending on whether we are editing global vs app specific config */ | |
| if (appSettings == EDITING_GLOBAL) { | |
| WINE_TRACE("enabling controls\n"); | |
| enable(IDC_LIST_DRIVES); | |
| enable(IDC_BUTTON_ADD); | |
| enable(IDC_BUTTON_REMOVE); | |
| enable(IDC_BUTTON_EDIT); | |
| enable(IDC_BUTTON_AUTODETECT); | |
| } else { | |
| WINE_TRACE("disabling controls\n"); | |
| disable(IDC_LIST_DRIVES); | |
| disable(IDC_BUTTON_ADD); | |
| disable(IDC_BUTTON_REMOVE); | |
| disable(IDC_BUTTON_EDIT); | |
| disable(IDC_BUTTON_AUTODETECT); | |
| } | |
| updatingUI = FALSE; | |
| return driveCount; | |
| } | |
| /******************************************************************************/ | |
| /* The Drive Editing Dialog */ | |
| /******************************************************************************/ | |
| #define DRIVE_MASK_BIT(B) 1<<(toupper(B)-'A') | |
| typedef struct { | |
| const char *sCode; | |
| const char *sDesc; | |
| } code_desc_pair; | |
| static code_desc_pair type_pairs[] = { | |
| {"hd", "Local hard disk"}, | |
| {"network", "Network share" }, | |
| {"floppy", "Floppy disk"}, | |
| {"cdrom", "CD-ROM"} | |
| }; | |
| #define DRIVE_TYPE_DEFAULT 1 | |
| void fill_drive_droplist(long mask, char currentLetter, HWND hDlg) | |
| { | |
| int i; | |
| int selection; | |
| int count; | |
| int next_letter; | |
| char sName[4] = "A:"; | |
| for( i=0, count=0, selection=-1, next_letter=-1; i <= 'Z'-'A'; ++i ) { | |
| if( mask & DRIVE_MASK_BIT('A'+i) ) { | |
| int index; | |
| sName[0] = 'A' + i; | |
| index = SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName ); | |
| if( toupper(currentLetter) == 'A' + i ) { | |
| selection = count; | |
| } | |
| if( i >= 2 && next_letter == -1){ /*default drive is first one of C-Z */ | |
| next_letter = count; | |
| } | |
| count++; | |
| } | |
| } | |
| if( selection == -1 ) { | |
| selection = next_letter; | |
| } | |
| SendDlgItemMessage( hDlg, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0 ); | |
| } | |
| #define BOX_MODE_CD_ASSIGN 1 | |
| #define BOX_MODE_CD_AUTODETECT 2 | |
| #define BOX_MODE_NONE 3 | |
| #define BOX_MODE_NORMAL 4 | |
| void enable_labelserial_box(HWND dialog, int mode) | |
| { | |
| WINE_TRACE("mode=%d\n", mode); | |
| switch (mode) { | |
| case BOX_MODE_CD_ASSIGN: | |
| enable(IDC_RADIO_AUTODETECT); | |
| enable(IDC_RADIO_ASSIGN); | |
| disable(IDC_EDIT_DEVICE); | |
| disable(IDC_BUTTON_BROWSE_DEVICE); | |
| enable(IDC_EDIT_SERIAL); | |
| enable(IDC_EDIT_LABEL); | |
| enable(IDC_STATIC_SERIAL); | |
| enable(IDC_STATIC_LABEL); | |
| break; | |
| case BOX_MODE_CD_AUTODETECT: | |
| enable(IDC_RADIO_AUTODETECT); | |
| enable(IDC_RADIO_ASSIGN); | |
| enable(IDC_EDIT_DEVICE); | |
| enable(IDC_BUTTON_BROWSE_DEVICE); | |
| disable(IDC_EDIT_SERIAL); | |
| disable(IDC_EDIT_LABEL); | |
| disable(IDC_STATIC_SERIAL); | |
| disable(IDC_STATIC_LABEL); | |
| break; | |
| case BOX_MODE_NONE: | |
| disable(IDC_RADIO_AUTODETECT); | |
| disable(IDC_RADIO_ASSIGN); | |
| disable(IDC_EDIT_DEVICE); | |
| disable(IDC_BUTTON_BROWSE_DEVICE); | |
| disable(IDC_EDIT_SERIAL); | |
| disable(IDC_EDIT_LABEL); | |
| disable(IDC_STATIC_SERIAL); | |
| disable(IDC_STATIC_LABEL); | |
| break; | |
| case BOX_MODE_NORMAL: | |
| disable(IDC_RADIO_AUTODETECT); | |
| enable(IDC_RADIO_ASSIGN); | |
| disable(IDC_EDIT_DEVICE); | |
| disable(IDC_BUTTON_BROWSE_DEVICE); | |
| enable(IDC_EDIT_SERIAL); | |
| enable(IDC_EDIT_LABEL); | |
| enable(IDC_STATIC_SERIAL); | |
| enable(IDC_STATIC_LABEL); | |
| break; | |
| } | |
| } | |
| /* This function produces a mask for each drive letter that isn't currently used. Each bit of the long result | |
| * represents a letter, with A being the least significant bit, and Z being the most significant. | |
| * | |
| * To calculate this, we loop over each letter, and see if we can get a drive entry for it. If so, we | |
| * set the appropriate bit. At the end, we flip each bit, to give the desired result. | |
| * | |
| * The letter parameter is always marked as being available. This is so the edit dialog can display the | |
| * currently used drive letter alongside the available ones. | |
| */ | |
| long drive_available_mask(char letter) | |
| { | |
| long result = 0; | |
| char curLetter; | |
| char *slop; | |
| WINE_TRACE("\n"); | |
| for (curLetter = 'A'; curLetter < 'Z'; curLetter++) { | |
| slop = getDriveValue(curLetter, "Path"); | |
| if (slop != NULL) { | |
| result |= DRIVE_MASK_BIT(curLetter); | |
| free(slop); | |
| } | |
| } | |
| result = ~result; | |
| if (letter) result |= DRIVE_MASK_BIT(letter); | |
| WINE_TRACE( "finished drive letter loop with %lx\n", result ); | |
| return result; | |
| } | |
| void refreshDriveEditDialog(HWND dialog) { | |
| char *path; | |
| char *type; | |
| char *serial; | |
| char *label; | |
| char *device; | |
| int i, selection; | |
| updatingUI = TRUE; | |
| /* Drive letters */ | |
| fill_drive_droplist( drive_available_mask( editWindowLetter ), editWindowLetter, dialog ); | |
| /* path */ | |
| path = getDriveValue(editWindowLetter, "Path"); | |
| if (path) { | |
| SetWindowText(GetDlgItem(dialog, IDC_EDIT_PATH), path); | |
| } else WINE_WARN("no Path field?\n"); | |
| /* drive type */ | |
| type = getDriveValue(editWindowLetter, "Type"); | |
| if (type) { | |
| for(i = 0, selection = -1; i < sizeof(type_pairs)/sizeof(code_desc_pair); i++) { | |
| SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, | |
| (LPARAM) type_pairs[i].sDesc); | |
| if(strcasecmp(type_pairs[i].sCode, type) == 0){ | |
| selection = i; | |
| } | |
| } | |
| if( selection == -1 ) selection = DRIVE_TYPE_DEFAULT; | |
| SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0); | |
| } else WINE_WARN("no Type field?\n"); | |
| /* removeable media properties */ | |
| serial = getDriveValue(editWindowLetter, "Serial"); | |
| if (serial) { | |
| SendDlgItemMessage(dialog, IDC_EDIT_SERIAL, WM_SETTEXT, 0,(LPARAM)serial); | |
| } else WINE_WARN("no Serial field?\n"); | |
| label = getDriveValue(editWindowLetter, "Label"); | |
| if (label) { | |
| SendDlgItemMessage(dialog, IDC_EDIT_LABEL, WM_SETTEXT, 0,(LPARAM)label); | |
| } else WINE_WARN("no Label field?\n"); | |
| device = getDriveValue(editWindowLetter, "Device"); | |
| if (device) { | |
| SendDlgItemMessage(dialog, IDC_EDIT_DEVICE, WM_SETTEXT, 0,(LPARAM)device); | |
| } else WINE_WARN("no Device field?\n"); | |
| selection = IDC_RADIO_ASSIGN; | |
| if ((type && strcmp("cdrom", type) == 0) || (type && strcmp("floppy", type) == 0)) { | |
| if (device) { | |
| selection = IDC_RADIO_AUTODETECT; | |
| enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT); | |
| } else { | |
| selection = IDC_RADIO_ASSIGN; | |
| enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN); | |
| } | |
| } else { | |
| enable_labelserial_box(dialog, BOX_MODE_NORMAL); | |
| selection = IDC_RADIO_ASSIGN; | |
| } | |
| CheckRadioButton( dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection ); | |
| if (path) SendDlgItemMessage(dialog, IDC_EDIT_PATH, WM_SETTEXT, 0,(LPARAM)path); | |
| if (path) free(path); | |
| if (type) free(type); | |
| if (serial) free(serial); | |
| if (label) free(label); | |
| if (device) free(device); | |
| updatingUI = FALSE; | |
| return; | |
| } | |
| /* storing the drive propsheet HWND here is a bit ugly, but the simplest solution for now */ | |
| static HWND driveDlgHandle; | |
| void onEditChanged(HWND hDlg, WORD controlID) { | |
| WINE_TRACE("controlID=%d\n", controlID); | |
| switch (controlID) { | |
| case IDC_EDIT_LABEL: { | |
| char *label = getDialogItemText(hDlg, controlID); | |
| setDriveValue(editWindowLetter, "Label", label); | |
| refreshDriveDlg(driveDlgHandle); | |
| if (label) free(label); | |
| break; | |
| } | |
| case IDC_EDIT_PATH: { | |
| char *path = getDialogItemText(hDlg, controlID); | |
| if (!path) path = strdup("fake_windows"); /* default to assuming fake_windows in the .wine directory */ | |
| setDriveValue(editWindowLetter, "Path", path); | |
| free(path); | |
| break; | |
| } | |
| case IDC_EDIT_SERIAL: { | |
| char *serial = getDialogItemText(hDlg, controlID); | |
| setDriveValue(editWindowLetter, "Serial", serial); | |
| if (serial) free (serial); | |
| break; | |
| } | |
| case IDC_EDIT_DEVICE: { | |
| char *device = getDialogItemText(hDlg,controlID); | |
| setDriveValue(editWindowLetter, "Device", device); | |
| if (device) free(device); | |
| refreshDriveDlg(driveDlgHandle); | |
| break; | |
| } | |
| } | |
| } | |
| INT_PTR CALLBACK DriveEditDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
| { | |
| int selection; | |
| switch (uMsg) { | |
| case WM_INITDIALOG: { | |
| editWindowLetter = (char) lParam; | |
| refreshDriveEditDialog(hDlg); | |
| } | |
| case WM_COMMAND: | |
| switch (LOWORD(wParam)) { | |
| case IDC_COMBO_TYPE: | |
| if (HIWORD(wParam) != CBN_SELCHANGE) break; | |
| selection = SendDlgItemMessage( hDlg, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0); | |
| if( selection == 2 || selection == 3 ) { /* cdrom or floppy */ | |
| if (IsDlgButtonChecked(hDlg, IDC_RADIO_AUTODETECT)) | |
| enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT); | |
| else | |
| enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN); | |
| } | |
| else { | |
| enable_labelserial_box( hDlg, BOX_MODE_NORMAL ); | |
| } | |
| setDriveValue(editWindowLetter, "Type", type_pairs[selection].sCode); | |
| break; | |
| case IDC_COMBO_LETTER: { | |
| int item = SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETCURSEL, 0, 0); | |
| char newLetter; | |
| SendDlgItemMessage(hDlg, IDC_COMBO_LETTER, CB_GETLBTEXT, item, (LPARAM) &newLetter); | |
| if (HIWORD(wParam) != CBN_SELCHANGE) break; | |
| if (newLetter == editWindowLetter) break; | |
| WINE_TRACE("changing drive letter to %c\n", newLetter); | |
| copyDrive(editWindowLetter, newLetter); | |
| removeDrive(editWindowLetter); | |
| editWindowLetter = newLetter; | |
| refreshDriveDlg(driveDlgHandle); | |
| break; | |
| } | |
| case IDC_BUTTON_BROWSE_PATH: | |
| WRITEME(hDlg); | |
| break; | |
| case IDC_RADIO_AUTODETECT: { | |
| setDriveValue(editWindowLetter, "Label", NULL); | |
| setDriveValue(editWindowLetter, "Serial", NULL); | |
| setDriveValue(editWindowLetter, "Device", getDialogItemText(hDlg, IDC_EDIT_DEVICE)); | |
| enable_labelserial_box(hDlg, BOX_MODE_CD_AUTODETECT); | |
| refreshDriveDlg(driveDlgHandle); | |
| break; | |
| } | |
| case IDC_RADIO_ASSIGN: | |
| setDriveValue(editWindowLetter, "Device", NULL); | |
| setDriveValue(editWindowLetter, "Label", getDialogItemText(hDlg, IDC_EDIT_LABEL)); | |
| setDriveValue(editWindowLetter, "Serial", getDialogItemText(hDlg, IDC_EDIT_SERIAL)); | |
| enable_labelserial_box(hDlg, BOX_MODE_CD_ASSIGN); | |
| refreshDriveDlg(driveDlgHandle); | |
| break; | |
| case ID_BUTTON_OK: | |
| EndDialog(hDlg, wParam); | |
| return TRUE; | |
| } | |
| if (HIWORD(wParam) == EN_CHANGE) onEditChanged(hDlg, LOWORD(wParam)); | |
| break; | |
| } | |
| return FALSE; | |
| } | |
| void onAddDriveClicked(HWND hDlg) { | |
| /* we should allocate a drive letter automatically. We also need some way to let the user choose the mapping point, | |
| for now we will just force them to enter a path automatically, with / being the default. In future we should | |
| be able to temporarily map / then invoke the directory chooser dialog. */ | |
| char newLetter = 'C'; /* we skip A and B, they are historically floppy drives */ | |
| long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */ | |
| char *sectionName; | |
| while (mask & (1 << (newLetter - 'A'))) { | |
| newLetter++; | |
| if (newLetter > 'Z') { | |
| 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); | |
| return; | |
| } | |
| } | |
| WINE_TRACE("allocating drive letter %c\n", newLetter); | |
| sectionName = malloc(strlen("Drive X") + 1); | |
| sprintf(sectionName, "Drive %c", newLetter); | |
| if (newLetter == 'C') { | |
| addTransaction(sectionName, "Path", ACTION_SET, "fake_windows"); | |
| addTransaction(sectionName, "Label", ACTION_SET, "System Drive"); | |
| } else | |
| addTransaction(sectionName, "Path", ACTION_SET, "/"); /* default to root path */ | |
| addTransaction(sectionName, "Type", ACTION_SET, "hd"); | |
| processTransQueue(); /* make sure the drive has been added, even if we are not in instant apply mode */ | |
| free(sectionName); | |
| refreshDriveDlg(driveDlgHandle); | |
| DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) newLetter); | |
| } | |
| INT_PTR CALLBACK | |
| DriveDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
| { | |
| int nItem; | |
| char letter; | |
| switch (uMsg) { | |
| case WM_COMMAND: | |
| switch (LOWORD(wParam)) { | |
| case IDC_LIST_DRIVES: | |
| /* double click should open the edit window for the chosen drive */ | |
| if (HIWORD(wParam) == LBN_DBLCLK) | |
| SendMessageA(hDlg, WM_COMMAND, IDC_BUTTON_EDIT, 0); | |
| if (HIWORD(wParam) == LBN_SELCHANGE) lastSel = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); | |
| break; | |
| case IDC_BUTTON_ADD: | |
| onAddDriveClicked(hDlg); | |
| break; | |
| case IDC_BUTTON_REMOVE: | |
| if (HIWORD(wParam) != BN_CLICKED) break; | |
| nItem = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETCURSEL, 0, 0); | |
| letter = SendDlgItemMessage(hDlg, IDC_LIST_DRIVES, LB_GETITEMDATA, nItem, 0); | |
| removeDrive(letter); | |
| refreshDriveDlg(driveDlgHandle); | |
| break; | |
| case IDC_BUTTON_EDIT: | |
| if (HIWORD(wParam) != BN_CLICKED) break; | |
| nItem = SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETCURSEL, 0, 0); | |
| letter = SendMessage(GetDlgItem(hDlg, IDC_LIST_DRIVES), LB_GETITEMDATA, nItem, 0); | |
| DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) letter); | |
| break; | |
| case IDC_BUTTON_AUTODETECT: | |
| WRITEME(hDlg); | |
| break; | |
| } | |
| break; | |
| case WM_NOTIFY: switch(((LPNMHDR)lParam)->code) { | |
| case PSN_KILLACTIVE: | |
| SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); | |
| break; | |
| case PSN_APPLY: | |
| SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); | |
| break; | |
| case PSN_SETACTIVE: | |
| driveDlgHandle = hDlg; | |
| refreshDriveDlg (driveDlgHandle); | |
| break; | |
| } | |
| break; | |
| } | |
| return FALSE; | |
| } |