|
|
/*++
Copyright (c) 1993-1994 Microsoft Corporation
Module Name:
cdrom.c
Abstract:
This module contains the set of routines that display and control the drive letters for CdRom devices.
Author:
Bob Rinne (bobri) 12/9/93
Environment:
User process.
Notes:
Revision History:
--*/
#include "fdisk.h"
#include "shellapi.h"
#include <string.h>
#include <stdio.h>
#include <wchar.h>
#include <malloc.h>
PCDROM_DESCRIPTOR CdRomChainBase = NULL; PCDROM_DESCRIPTOR CdRomChainLast = NULL; PCDROM_DESCRIPTOR CdRomChanged = NULL;
static BOOLEAN CdRomFirstCall = TRUE; static TCHAR SourcePathLetter = (TCHAR) '\0'; static TCHAR SourcePathKeyName[80]; static TCHAR SourcePathValueName[30];
VOID CdRomAddDevice( IN PWSTR NtName, IN WCHAR DriveLetter )
/*++
Routine Description:
Build a cdrom description structure for this and fill it in.
Arguments:
NtName - The unicode name for the device. DriveLetter - The DosDevice name.
Return Value:
None
--*/
{ PCDROM_DESCRIPTOR cdrom; PWCHAR cp; LONG error; HKEY keyHandle; DWORD valueType; ULONG size; TCHAR *string;
if (CdRomFirstCall) { CdRomFirstCall = FALSE;
// Get the registry path and value name.
LoadString(hModule, IDS_SOURCE_PATH, SourcePathKeyName, sizeof(SourcePathKeyName)/sizeof(TCHAR)); LoadString(hModule, IDS_SOURCE_PATH_NAME, SourcePathValueName, sizeof(SourcePathValueName)/sizeof(TCHAR));
error = RegOpenKey(HKEY_LOCAL_MACHINE, SourcePathKeyName, &keyHandle); if (error == NO_ERROR) { error = RegQueryValueEx(keyHandle, SourcePathValueName, NULL, &valueType, (PUCHAR)NULL, &size);
if (error == NO_ERROR) { string = (PUCHAR) LocalAlloc(LMEM_FIXED, size); if (string) { error = RegQueryValueEx(keyHandle, SourcePathValueName, NULL, &valueType, string, &size); if (error == NO_ERROR) { SourcePathLetter = *string; } } LocalFree(string); } RegCloseKey(keyHandle); } }
cdrom = (PCDROM_DESCRIPTOR) malloc(sizeof(CDROM_DESCRIPTOR)); if (cdrom) { cdrom->DeviceName = (PWSTR) malloc((wcslen(NtName)+1)*sizeof(WCHAR)); if (cdrom->DeviceName) { wcscpy(cdrom->DeviceName, NtName); cp = cdrom->DeviceName; while (*cp) { if (iswdigit(*cp)) { break; } cp++; }
if (*cp) { cdrom->DeviceNumber = wcstoul(cp, (WCHAR) 0, 10); } cdrom->DriveLetter = DriveLetter; cdrom->Next = NULL; cdrom->NewDriveLetter = (WCHAR) 0; if (CdRomChainBase) { CdRomChainLast->Next = cdrom; } else { AllowCdRom = TRUE; CdRomChainBase = cdrom; } CdRomChainLast = cdrom; } else { free(cdrom); } } }
BOOL CALLBACK CdRomDlgProc( IN HWND hDlg, IN UINT wMsg, IN WPARAM wParam, IN LPARAM lParam )
/*++
Routine Description:
Handle the dialog for CD-ROMS
Arguments:
Standard Windows dialog procedure
Return Value:
TRUE if something was deleted. FALSE otherwise.
--*/
{ HWND hwndCombo; DWORD selection; DWORD index; CHAR driveLetter; TCHAR string[40]; PCDROM_DESCRIPTOR cdrom; static PCDROM_DESCRIPTOR currentCdrom; static CHAR currentSelectionLetter;
switch (wMsg) { case WM_INITDIALOG:
// Store all device strings into the selection area.
hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES); cdrom = currentCdrom = CdRomChainBase; currentSelectionLetter = (CHAR) cdrom->DriveLetter; while (cdrom) { sprintf(string, "CdRom%d", cdrom->DeviceNumber); SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string); cdrom = cdrom->Next; } SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
// Update the drive letter selections.
selection = index = 0; hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX); string[1] = TEXT(':'); string[2] = 0; for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) { if ((DriveLetterIsAvailable((CHAR)driveLetter)) || (driveLetter == currentSelectionLetter)) { *string = driveLetter; SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string); if (driveLetter == currentSelectionLetter) { selection = index; } index++; } }
// set the current selection to the appropriate index
SendMessage(hwndCombo, CB_SETCURSEL, selection, 0); return TRUE;
case WM_COMMAND: switch (wParam) {
case FD_IDHELP: DialogHelp(HC_DM_DLG_CDROM); break;
case IDCANCEL:
EndDialog(hDlg, FALSE); break;
case IDOK:
// User has selected the drive letter and wants the mount to occur.
hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX); selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0); SendMessage(hwndCombo, CB_GETLBTEXT, selection, (LONG)string); currentCdrom->NewDriveLetter = (WCHAR) string[0]; CdRomChanged = currentCdrom; EndDialog(hDlg, TRUE); break;
default:
if (HIWORD(wParam) == LBN_SELCHANGE) { TCHAR *cp;
if (LOWORD(wParam) != IDC_CDROM_NAMES) { break; }
// The state of something in the dialog changed.
hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES); selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0); SendMessage(hwndCombo, CB_GETLBTEXT, selection, (LONG)string);
// The format of the string returned is "cdrom#". Parse the
// value of # in order to find the selection.
cp = string; while (*cp) { cp++; } cp--; while ((*cp >= (TCHAR) '0') && (*cp <= (TCHAR) '9')) { cp--; } cp++;
selection = 0; while (*cp) { selection = (selection * 10) + (*cp - (TCHAR) '0'); cp++; }
// Find the matching device name.
for (cdrom = CdRomChainBase; cdrom; cdrom = cdrom->Next) {
if (selection == cdrom->DeviceNumber) {
// found the match
currentSelectionLetter = (CHAR) cdrom->DriveLetter; currentCdrom = cdrom; break; } }
// The only thing that is important is to track the cdrom
// device name selected and update the drive letter list.
selection = index = 0; hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX); SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); string[1] = TEXT(':'); string[2] = 0; for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) { if ((DriveLetterIsAvailable((CHAR)driveLetter)) || (driveLetter == currentSelectionLetter)) { *string = driveLetter; SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string); if (driveLetter == currentSelectionLetter) { selection = index; } index++; } }
// set the current selection to the appropriate index
SendMessage(hwndCombo, CB_SETCURSEL, selection, 0); } break; } }
return FALSE; }
VOID CdRom( IN HWND Dialog, IN PVOID Param )
/*++
Routine Description:
Start the CdRom dialogs.
Arguments:
None
Return Value:
None
--*/
{ BOOLEAN result = 0; DWORD action, ec; TCHAR name[40]; TCHAR letter[10]; PWSTR linkTarget; OBJECT_ATTRIBUTES oa; WCHAR dosName[20]; HANDLE handle; NTSTATUS status; IO_STATUS_BLOCK statusBlock; ANSI_STRING ansiName; UNICODE_STRING unicodeName; UINT errorMode;
result = DialogBoxParam(hModule, MAKEINTRESOURCE(IDD_CDROM), Dialog, CdRomDlgProc, (ULONG) NULL); if (result) {
action = ConfirmationDialog(MSG_DRIVE_RENAME_WARNING, MB_ICONQUESTION | MB_YESNOCANCEL);
if (!action) { return; }
// Attempt to open and lock the cdrom.
sprintf(name, "\\Device\\CdRom%d", CdRomChanged->DeviceNumber);
RtlInitAnsiString(&ansiName, name); status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
if (!NT_SUCCESS(status)) { ErrorDialog(MSG_CDROM_LETTER_ERROR); return; }
memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES)); oa.Length = sizeof(OBJECT_ATTRIBUTES); oa.ObjectName = &unicodeName; oa.Attributes = OBJ_CASE_INSENSITIVE;
errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); status = NtOpenFile(&handle, SYNCHRONIZE | FILE_READ_DATA, &oa, &statusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); RtlFreeUnicodeString(&unicodeName); SetErrorMode(errorMode);
if (!NT_SUCCESS(status)) { ErrorDialog(MSG_CANNOT_LOCK_CDROM); return; }
// Lock the drive to insure that no other access is occurring
// to the volume. This is done via the "Low" routine for
// convenience
status = LowLockDrive(handle);
if (!NT_SUCCESS(status)) { LowCloseDisk(handle); ErrorDialog(MSG_CANNOT_LOCK_CDROM); return; }
// Before attempting to move the name, see if the letter
// is currently in use - could be a new network connection
// or a partition that is scheduled for deletion.
wsprintfW(dosName, L"\\DosDevices\\%wc:", (WCHAR) CdRomChanged->NewDriveLetter); ec = GetDriveLetterLinkTarget(dosName, &linkTarget); if (ec == NO_ERROR) {
// Something is using this letter.
LowCloseDisk(handle); ErrorDialog(MSG_CANNOT_MOVE_CDROM); return; }
// remove existing definition - if this fails don't continue.
sprintf(letter, "%c:", (UCHAR) CdRomChanged->DriveLetter); if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) letter, (LPCTSTR) NULL)) { LowCloseDisk(handle); ErrorDialog(MSG_CDROM_LETTER_ERROR); return; } status = DiskRegistryAssignCdRomLetter(CdRomChanged->DeviceName, CdRomChanged->NewDriveLetter); MarkDriveLetterFree((UCHAR)CdRomChanged->DriveLetter);
// See if this was the device used to install NT
if (SourcePathLetter) { if (SourcePathLetter == CdRomChanged->DriveLetter) { LONG error; HKEY keyHandle; DWORD valueType; ULONG size; TCHAR *string;
// Update the source path
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SourcePathKeyName, 0, KEY_ALL_ACCESS, &keyHandle); if (error == NO_ERROR) { error = RegQueryValueEx(keyHandle, SourcePathValueName, NULL, &valueType, (PUCHAR)NULL, &size);
if (error == NO_ERROR) { string = (PUCHAR) LocalAlloc(LMEM_FIXED, size); if (string) { error = RegQueryValueEx(keyHandle, SourcePathValueName, NULL, &valueType, string, &size); if (error == NO_ERROR) { *string = SourcePathLetter = (UCHAR) CdRomChanged->NewDriveLetter; RegSetValueEx(keyHandle, SourcePathValueName, 0, REG_SZ, string, size); } } LocalFree(string); } RegCloseKey(keyHandle); } } }
// set up new device letter - name is already set up
sprintf(letter, "%c:", (UCHAR) CdRomChanged->NewDriveLetter); if (DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) letter, (LPCTSTR) name)) { CdRomChanged->DriveLetter = CdRomChanged->NewDriveLetter; MarkDriveLetterUsed((UCHAR)CdRomChanged->DriveLetter); } else { RegistryChanged = TRUE; } LowCloseDisk(handle); } }
|