windows-nt/Source/XPSP1/NT/drivers/storage/proppage/diskprop.c
2020-09-26 16:20:57 +08:00

1692 lines
48 KiB
C

/*++
Copyright (c) Microsoft Corporation, 2000
Module Name :
diskprop.c
Abstract :
Implementation of the Disk Property Page
Revision History :
--*/
#include "propp.h"
#include "diskprop.h"
#include "scsiprop.h"
#include "volprop.h"
//==========================================================================
// Local Constants
//==========================================================================
#define DISKCIPRIVATEDATA_NO_REBOOT_REQUIRED 0x4
//==========================================================================
// Local Function Prototypes
//==========================================================================
const DWORD DiskHelpIDs[]=
{
IDC_DISK_POLICY_WRITE_CACHE, idh_devmgr_disk_write_cache_enabled,
0, 0
};
typedef struct _DISK_PAGE_DATA {
BOOL IsVolume;
HDEVINFO DeviceInfoSet;
PSP_DEVINFO_DATA DeviceInfoData;
//
// This field represents whether disk
// level write caching may be modified
//
BOOL IsCachingPolicy;
BOOL OrigWriteCacheSetting;
BOOL CurrWriteCacheSetting;
DISK_WRITE_CACHE_STATE WriteCacheState;
DWORD DefaultRemovalPolicy;
DWORD CurrentRemovalPolicy;
STORAGE_HOTPLUG_INFO HotplugInfo;
//
// This field is set when the device stack
// is being torn down which happens during
// a removal policy change
//
BOOL IsBusy;
LPGUID DevClassGuid; // used only for the root page
} DISK_PAGE_DATA, *PDISK_PAGE_DATA;
BOOL
IsUserAdmin(
VOID
)
/*++
Routine Description:
This routine returns TRUE if the caller's process is a
member of the Administrators local group.
Caller is NOT expected to be impersonating anyone and IS
expected to be able to open their own process and process
token.
Arguments:
None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
--*/
{
HANDLE Token;
DWORD BytesRequired;
PTOKEN_GROUPS Groups;
BOOL b;
DWORD i;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
//
// Open the process token.
//
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
return(FALSE);
}
b = FALSE;
Groups = NULL;
//
// Get group information.
//
if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
&& (Groups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED,BytesRequired))
&& GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
b = AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup
);
if(b) {
//
// See if the user has the administrator group.
//
b = FALSE;
for(i=0; i<Groups->GroupCount; i++) {
if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
b = TRUE;
break;
}
}
FreeSid(AdministratorsGroup);
}
}
//
// Clean up and return.
//
if(Groups) {
LocalFree(Groups);
}
CloseHandle(Token);
return(b);
}
INT_PTR
DiskDialogProc(
HWND Dialog,
UINT Message,
WPARAM WParam,
LPARAM LParam
);
BOOL
DiskDialogCallback(
HWND Dialog,
UINT Message,
LPPROPSHEETPAGE Page
);
BOOL
CommonPropPageProvider(
PSP_PROPSHEETPAGE_REQUEST Request,
LPFNADDPROPSHEETPAGE AddPageRoutine,
LPARAM AddPageContext,
LPGUID DevClassGuid
);
BOOL CALLBACK
VolumePropPageProvider(
PSP_PROPSHEETPAGE_REQUEST Request,
LPFNADDPROPSHEETPAGE AddPageRoutine,
LPARAM AddPageContext
)
{
BOOL result;
if(Request->cbSize != sizeof(SP_PROPSHEETPAGE_REQUEST)) {
return FALSE;
}
switch(Request->PageRequested) {
case SPPSR_ENUM_ADV_DEVICE_PROPERTIES: {
result = TRUE;
break;
}
case SPPSR_ENUM_BASIC_DEVICE_PROPERTIES: {
result = FALSE;
break;
}
default: {
result = FALSE;
break;
}
}
//
// Since there's nothing else on the page, don't show the page
// Remove the statement to use this page, e.g. when we want to allow
// the user to select volumes to turn on/off
//
result = FALSE;
if(result) {
result = CommonPropPageProvider(
Request,
AddPageRoutine,
AddPageContext,
(LPGUID) &GUID_DEVCLASS_VOLUME);
}
return result;
}
BOOL
CommonPropPageProvider(
PSP_PROPSHEETPAGE_REQUEST Request,
LPFNADDPROPSHEETPAGE AddPageRoutine,
LPARAM AddPageContext,
LPGUID DevClassGuid
)
{
PDISK_PAGE_DATA data;
PROPSHEETPAGE page;
HPROPSHEETPAGE pageHandle;
BOOL result = TRUE;
HKEY hDeviceKey;
BOOL IsVolume = FALSE;
TCHAR buf[MAX_PATH];
//
// Make sure that we're actually opening a device
//
hDeviceKey = SetupDiOpenDevRegKey(Request->DeviceInfoSet,
Request->DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_ALL_ACCESS);
if (INVALID_HANDLE_VALUE == hDeviceKey) {
IsVolume = TRUE;
}
RegCloseKey(hDeviceKey);
//
// Since there's nothing else on the page, don't show the page
// Remove the statement to use this page, e.g. when we want to allow
// the user to select volumes to turn on/off
//
if (IsVolume)
return FALSE;
//
// At this point we've determined that this is a request for pages we
// provide. Instantiate the pages and call the AddPage routine to put
// them install them.
//
if (!IsUserAdmin()) {
return FALSE;
}
data = LocalAlloc(0, sizeof(DISK_PAGE_DATA));
if(data == NULL) {
return FALSE;
}
data->DeviceInfoSet = Request->DeviceInfoSet;
data->DeviceInfoData = Request->DeviceInfoData;
data->DevClassGuid = DevClassGuid;
data->IsVolume = IsVolume;
memset(&page, 0, sizeof(PROPSHEETPAGE));
page.dwSize = sizeof(PROPSHEETPAGE);
page.dwFlags = PSP_USECALLBACK;
if (IsVolume) {
LoadString(ModuleInstance, IDS_ADVANCED, buf, MAX_PATH);
page.pszTitle = buf;
page.dwFlags |= PSP_USETITLE;
}
page.hInstance = ModuleInstance;
page.pszTemplate = MAKEINTRESOURCE(ID_DISK_PROPPAGE);
page.pfnDlgProc = DiskDialogProc;
page.pfnCallback = DiskDialogCallback;
page.lParam = (LPARAM) data;
pageHandle = CreatePropertySheetPage(&page);
if(pageHandle == FALSE) {
return FALSE;
}
result = AddPageRoutine(pageHandle, AddPageContext);
if(result) {
ScsiPropPageProvider(Request, AddPageRoutine, AddPageContext);
}
return result;
}
VOID
AttemptToSuppressDiskInstallReboot(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
Because disks are listed as "critical devices" (i.e., they're in the
critical device database), they get bootstrapped by PnP during boot. Thus,
by the time we're installing a disk in user-mode, it's most likely already
on-line (unless the disk has some problem). Unfortunately, if the disk is
the boot device, we won't be able to dynamically affect the changes (if
any) to tear the stack down and bring it back up with any new settings,
drivers, etc. This causes problems for OEM Preinstall scenarios where the
target machines have different disks than the source machine used to create
the preinstall image. If we simply perform our default behavior, then
the user's experience would be to unbox their brand new machine, boot for
the first time and go through OOBE, and then be greeted upon login with a
reboot prompt!
To fix this, we've defined a private [DDInstall] section INF flag (specific
to INFs of class "DiskDrive") that indicates we can forego the reboot if
certain criteria are met. Those criteria are:
1. No files were modified as a result of this device's installation
(determined by checking the devinfo element's
DI_FLAGSEX_RESTART_DEVICE_ONLY flag, which the device installer uses to
track whether such file modifications have occurred).
2. The INF used to install this device is signed.
3. The INF driver node has a DiskCiPrivateData = <int> entry in its
[DDInstall] section that has bit 2 (0x4) set. Note that this setting
is intentionally obfuscated because we don't want third parties trying
to use this, as they won't understand the ramifications or
requirements, and will more than likely get this wrong (trading an
annoying but harmless reboot requirement into a much more severe
stability issue).
This routine makes the above checks, and if it is found that the reboot can
be suppressed, it clears the DI_NEEDRESTART and DI_NEEDREBOOT flags from
the devinfo element's device install parameters.
Arguments:
DeviceInfoSet - Supplies the device information set.
DeviceInfoData - Supplies the device information element that has just
been successfully installed (via SetupDiInstallDevice).
Return Value:
None.
--*/
{
SP_DEVINSTALL_PARAMS DeviceInstallParams;
PSP_DRVINFO_DATA DriverInfoData = NULL;
PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData = NULL;
PSP_INF_SIGNER_INFO InfSignerInfo = NULL;
HINF hInf;
TCHAR InfSectionWithExt[255]; // max section name length is 255 chars
INFCONTEXT InfContext;
INT Flags;
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if(!SetupDiGetDeviceInstallParams(DeviceInfoSet,
DeviceInfoData,
&DeviceInstallParams)) {
//
// Couldn't retrieve the device install params--this should never
// happen.
//
goto clean0;
}
if(!(DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
//
// The device doesn't require a reboot (must not be the boot device!)
//
goto clean0;
}
if(!(DeviceInstallParams.FlagsEx & DI_FLAGSEX_RESTART_DEVICE_ONLY)) {
//
// Since this flag isn't set, this indicates that the device installer
// modified one or more files as part of this device's installation.
// Thus, it isn't safe for us to suppress the reboot request.
//
goto clean0;
}
//
// OK, we have a device that needs a reboot, and no files were modified
// during its installation. Now check the INF to see if it's signed.
// (Note: the SP_DRVINFO_DATA, SP_DRVINFO_DETAIL_DATA, and
// SP_INF_SIGNER_INFO structures are rather large, so we allocate them
// instead of using lots of stack space.)
//
DriverInfoData = LocalAlloc(0, sizeof(SP_DRVINFO_DATA));
if(DriverInfoData) {
DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
} else {
goto clean0;
}
if(!SetupDiGetSelectedDriver(DeviceInfoSet,
DeviceInfoData,
DriverInfoData)) {
//
// We must be installing the NULL driver (which is unlikely)...
//
goto clean0;
}
DriverInfoDetailData = LocalAlloc(0, sizeof(SP_DRVINFO_DETAIL_DATA));
if(DriverInfoDetailData) {
DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
} else {
goto clean0;
}
if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
DeviceInfoData,
DriverInfoData,
DriverInfoDetailData,
sizeof(SP_DRVINFO_DETAIL_DATA),
NULL)
&& (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
//
// Failed to retrieve driver info details--should never happen.
//
goto clean0;
}
InfSignerInfo = LocalAlloc(0, sizeof(SP_INF_SIGNER_INFO));
if(InfSignerInfo) {
InfSignerInfo->cbSize = sizeof(SP_INF_SIGNER_INFO);
} else {
goto clean0;
}
if(!SetupVerifyInfFile(DriverInfoDetailData->InfFileName,
NULL,
InfSignerInfo)) {
//
// INF isn't signed--we wouldn't trust its "no reboot required" flag,
// even if it had one.
//
goto clean0;
}
//
// INF is signed--let's open it up and see if it specifes the "no reboot
// required" flag in it's (decorated) DDInstall section...
//
hInf = SetupOpenInfFile(DriverInfoDetailData->InfFileName,
NULL,
INF_STYLE_WIN4,
NULL
);
if(hInf == INVALID_HANDLE_VALUE) {
//
// Failed to open the INF. This is incredibly odd, since we just got
// through validating the INF's digital signature...
//
goto clean0;
}
if(!SetupDiGetActualSectionToInstall(hInf,
DriverInfoDetailData->SectionName,
InfSectionWithExt,
sizeof(InfSectionWithExt) / sizeof(TCHAR),
NULL,
NULL)
|| !SetupFindFirstLine(hInf,
InfSectionWithExt,
TEXT("DiskCiPrivateData"),
&InfContext)
|| !SetupGetIntField(&InfContext, 1, &Flags)) {
Flags = 0;
}
SetupCloseInfFile(hInf);
if(Flags & DISKCIPRIVATEDATA_NO_REBOOT_REQUIRED) {
//
// This signed INF is vouching for the fact that no reboot is
// required for full functionality of this disk. Thus, we'll
// clear the DI_NEEDRESTART and DI_NEEDREBOOT flags, so that
// the user won't be prompted to reboot. Note that during the
// default handling routine (SetupDiInstallDevice), a non-fatal
// problem was set on the devnode indicating that a reboot is
// needed. This will not result in a yellow-bang in DevMgr,
// but you would see text in the device status field indicating
// a reboot is needed if you go into the General tab of the
// device's property sheet.
//
CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDRESTART);
CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDREBOOT);
SetupDiSetDeviceInstallParams(DeviceInfoSet,
DeviceInfoData,
&DeviceInstallParams
);
}
clean0:
if(DriverInfoData) {
LocalFree(DriverInfoData);
}
if(DriverInfoDetailData) {
LocalFree(DriverInfoDetailData);
}
if(InfSignerInfo) {
LocalFree(InfSignerInfo);
}
}
DWORD
DiskClassInstaller(
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
/*++
Routine Description:
This routine is the class installer function for disk drive.
Arguments:
InstallFunction - Supplies the install function.
DeviceInfoSet - Supplies the device info set.
DeviceInfoData - Supplies the device info data.
Return Value:
If this function successfully completed the requested action, the return
value is NO_ERROR.
If the default behavior is to be performed for the requested action, the
return value is ERROR_DI_DO_DEFAULT.
If an error occurred while attempting to perform the requested action, a
Win32 error code is returned.
--*/
{
PROPSHEETPAGE page;
switch (InstallFunction)
{
case DIF_INSTALLDEVICE:
{
//
// Let the default action occur to get the device installed.
//
if(!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
//
// Failed to install the device--just return the error reported
//
return GetLastError();
}
//
// Default device install action succeeded, now check for reboot
// requirement and suppress it, if possible.
//
AttemptToSuppressDiskInstallReboot(DeviceInfoSet, DeviceInfoData);
//
// Regardless of whether we successfully suppressed the reboot, we
// still report success, because the install went fine.
//
return NO_ERROR;
}
case DIF_ADDPROPERTYPAGE_ADVANCED:
case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
{
//
// get the current class install parameters for the device
//
SP_ADDPROPERTYPAGE_DATA AddPropertyPageData;
//
// DeviceInfoSet is NULL if setup is requesting property pages for the
// device setup class. We don't want to do anything in this case.
//
if (DeviceInfoData==NULL)
return ERROR_DI_DO_DEFAULT;
ZeroMemory(&AddPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA));
AddPropertyPageData.ClassInstallHeader.cbSize =
sizeof(SP_CLASSINSTALL_HEADER);
if (SetupDiGetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA), NULL ))
{
PDISK_PAGE_DATA pDiskPageData;
PVOLUME_PAGE_DATA pVolumePageData;
HPROPSHEETPAGE pageHandle;
PROPSHEETPAGE page;
BOOL isScsi;
//
// Ensure that the maximum number of dynamic pages for the device
// has not yet been met
//
if (AddPropertyPageData.NumDynamicPages >=
MAX_INSTALLWIZARD_DYNAPAGES)
return NO_ERROR;
if (InstallFunction==DIF_ADDPROPERTYPAGE_ADVANCED)
{
//
// Add disk property page
//
pDiskPageData = HeapAlloc(GetProcessHeap(), 0,
sizeof(DISK_PAGE_DATA));
if (pDiskPageData)
{
//
// Save DeviceInfoSet and DeviceInfoData
//
pDiskPageData->DeviceInfoSet = DeviceInfoSet;
pDiskPageData->DeviceInfoData = DeviceInfoData;
pDiskPageData->DevClassGuid =
(LPGUID) &GUID_DEVCLASS_DISKDRIVE;
pDiskPageData->IsVolume = FALSE;
memset(&page, 0, sizeof(PROPSHEETPAGE));
//
// Create disk property sheet page
//
page.dwSize = sizeof(PROPSHEETPAGE);
page.dwFlags = PSP_USECALLBACK;
page.hInstance = ModuleInstance;
page.pszTemplate = MAKEINTRESOURCE(ID_DISK_PROPPAGE);
page.pfnDlgProc = DiskDialogProc;
page.pfnCallback = DiskDialogCallback;
page.lParam = (LPARAM) pDiskPageData;
pageHandle = CreatePropertySheetPage(&page);
if(!pageHandle)
{
HeapFree(GetProcessHeap(), 0, pDiskPageData);
return NO_ERROR;
}
//
// Add the new page to the list of dynamic property
// sheets
//
AddPropertyPageData.DynamicPages[
AddPropertyPageData.NumDynamicPages++] = pageHandle;
}
}
//
// Add volume property page
//
if ( AddPropertyPageData.NumDynamicPages >=
MAX_INSTALLWIZARD_DYNAPAGES )
{
SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
return NO_ERROR;
}
if (IsUserAdmin())
pVolumePageData = HeapAlloc(GetProcessHeap(), 0,
sizeof(VOLUME_PAGE_DATA));
else
pVolumePageData = NULL;
if (pVolumePageData)
{
HMODULE LdmModule;
SP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData;
//
// Save DeviceInfoSet and DeviceInfoData
//
pVolumePageData->DeviceInfoSet = DeviceInfoSet;
pVolumePageData->DeviceInfoData = DeviceInfoData;
//
// Create volume property sheet page
//
memset(&page, 0, sizeof(PROPSHEETPAGE));
page.dwSize = sizeof(PROPSHEETPAGE);
page.dwFlags = PSP_USECALLBACK;
page.hInstance = ModuleInstance;
page.pszTemplate = MAKEINTRESOURCE(ID_VOLUME_PROPPAGE);
page.pfnDlgProc = VolumeDialogProc;
page.pfnCallback = VolumeDialogCallback;
page.lParam = (LPARAM) pVolumePageData;
pageHandle = CreatePropertySheetPage(&page);
if(!pageHandle)
{
HeapFree(GetProcessHeap(), 0, pVolumePageData);
return NO_ERROR;
}
//
// Add the new page to the list of dynamic property
// sheets
//
AddPropertyPageData.DynamicPages[
AddPropertyPageData.NumDynamicPages++]=pageHandle;
//
// Check if the property page is pulled up from disk manager.
//
pVolumePageData->bInvokedByDiskmgr = FALSE;
LdmModule = GetModuleHandle(TEXT("dmdskmgr"));
if ( LdmModule )
{
IS_REQUEST_PENDING pfnIsRequestPending;
pfnIsRequestPending = (IS_REQUEST_PENDING)
GetProcAddress(LdmModule, "IsRequestPending");
if (pfnIsRequestPending)
{
if ((*pfnIsRequestPending)())
pVolumePageData->bInvokedByDiskmgr = TRUE;
}
}
}
if (InstallFunction==DIF_ADDPROPERTYPAGE_ADVANCED)
{
//
// Add Scsi property page data
//
if ( AddPropertyPageData.NumDynamicPages >=
MAX_INSTALLWIZARD_DYNAPAGES )
{
SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
return NO_ERROR;
}
isScsi = ScsiCheckDriveType( DeviceInfoSet, DeviceInfoData);
if (isScsi) {
PSCSI_PAGE_DATA pScsiPageData;
pScsiPageData = HeapAlloc(GetProcessHeap(),
0,
sizeof(SCSI_PAGE_DATA));
if(pScsiPageData == NULL) {
SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
return NO_ERROR;
}
//
// Create scsi property sheet page
//
pScsiPageData->DeviceInfoSet = DeviceInfoSet;
pScsiPageData->DeviceInfoData = DeviceInfoData;
memset(&page, 0, sizeof(PROPSHEETPAGE));
page.dwSize = sizeof(PROPSHEETPAGE);
page.dwFlags = PSP_USECALLBACK;
page.hInstance = ModuleInstance;
page.pszTemplate = MAKEINTRESOURCE(ID_SCSI_PROPPAGE);
page.pfnDlgProc = ScsiDialogProc;
page.pfnCallback = ScsiDialogCallback;
page.lParam = (LPARAM) pScsiPageData;
pageHandle = CreatePropertySheetPage(&page);
if(pageHandle == NULL) {
HeapFree(GetProcessHeap(), 0, pScsiPageData);
SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
return FALSE;
}
AddPropertyPageData.DynamicPages[
AddPropertyPageData.NumDynamicPages++] = pageHandle;
}
}
SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
}
return NO_ERROR;
} // case DIF_ADDPROPERTYPAGE_ADVANCED
}
return ERROR_DI_DO_DEFAULT;
}
HANDLE
GetHandleForDisk(LPTSTR DeviceName)
{
HANDLE h = INVALID_HANDLE_VALUE;
int i = 0;
BOOL success = FALSE;
TCHAR buf[MAX_PATH];
TCHAR fakeDeviceName[MAX_PATH];
h = CreateFile(DeviceName,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (h != INVALID_HANDLE_VALUE)
return h;
while (!success && i < 10) {
wsprintf(buf, _T("DISK_FAKE_DEVICE_%d_"), i++);
success = DefineDosDevice(DDD_RAW_TARGET_PATH,
buf,
DeviceName);
if (success) {
_tcscpy(fakeDeviceName, _T("\\\\.\\"));
_tcscat(fakeDeviceName, buf);
h = CreateFile(fakeDeviceName,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
DefineDosDevice(DDD_REMOVE_DEFINITION,
buf,
NULL);
}
}
return h;
}
UINT
GetCachingPolicy(PDISK_PAGE_DATA data)
{
HANDLE hDisk;
DISK_CACHE_INFORMATION cacheInfo;
TCHAR buf[MAX_PATH];
DWORD len = MAX_PATH;
CONFIGRET cr;
cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
NULL,
buf,
&len,
0);
if (cr != CR_SUCCESS) {
return ERROR_GEN_FAILURE;
}
if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
return ERROR_INVALID_HANDLE;
}
//
// Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
//
if (!DeviceIoControl(hDisk,
IOCTL_DISK_GET_CACHE_INFORMATION,
NULL,
0,
&cacheInfo,
sizeof(DISK_CACHE_INFORMATION),
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
//
// Get write cache state - IOCTL_DISK_GET_WRITE_CACHE_STATE
//
if (!DeviceIoControl(hDisk,
IOCTL_DISK_GET_WRITE_CACHE_STATE,
NULL,
0,
&data->WriteCacheState,
sizeof(DISK_WRITE_CACHE_STATE),
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
data->OrigWriteCacheSetting = cacheInfo.WriteCacheEnabled;
data->CurrWriteCacheSetting = cacheInfo.WriteCacheEnabled;
CloseHandle(hDisk);
return ERROR_SUCCESS;
}
VOID
UpdateCachingPolicy(HWND HWnd, PDISK_PAGE_DATA data)
{
if (!data->IsCachingPolicy)
{
//
// The caching policy cannot be modified
//
return;
}
if (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
{
//
// This policy requires that no caching be done at any
// level. Uncheck and gray out the write cache setting
//
CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, 0);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), FALSE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), FALSE);
data->CurrWriteCacheSetting = FALSE;
}
else
{
//
// This policy allows for caching to be done at any level
//
CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, 1);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), TRUE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), TRUE);
data->CurrWriteCacheSetting = TRUE;
}
}
UINT
SetCachingPolicy(PDISK_PAGE_DATA data)
{
HANDLE hDisk;
DISK_CACHE_INFORMATION cacheInfo;
TCHAR buf[MAX_PATH];
DWORD len = MAX_PATH;
CONFIGRET cr;
cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
NULL,
buf,
&len,
0);
if (cr != CR_SUCCESS) {
return ERROR_GEN_FAILURE;
}
if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
return ERROR_INVALID_HANDLE;
}
//
// Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
//
if (!DeviceIoControl(hDisk,
IOCTL_DISK_GET_CACHE_INFORMATION,
NULL,
0,
&cacheInfo,
sizeof(DISK_CACHE_INFORMATION),
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
cacheInfo.WriteCacheEnabled = (BOOLEAN)data->CurrWriteCacheSetting;
//
// Set cache info - IOCTL_DISK_SET_CACHE_INFORMATION
//
if (!DeviceIoControl(hDisk,
IOCTL_DISK_SET_CACHE_INFORMATION,
&cacheInfo,
sizeof(DISK_CACHE_INFORMATION),
NULL,
0,
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
data->OrigWriteCacheSetting = data->CurrWriteCacheSetting;
CloseHandle(hDisk);
return ERROR_SUCCESS;
}
UINT
GetRemovalPolicy(PDISK_PAGE_DATA data)
{
HANDLE hDisk;
TCHAR buf[MAX_PATH];
DWORD len = MAX_PATH;
CONFIGRET cr;
if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
data->DeviceInfoData,
SPDRP_REMOVAL_POLICY,
0,
(PBYTE)&data->DefaultRemovalPolicy,
sizeof(DWORD),
NULL))
{
return GetLastError();
}
cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
NULL,
buf,
&len,
0);
if (cr != CR_SUCCESS) {
return ERROR_GEN_FAILURE;
}
if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
return ERROR_INVALID_HANDLE;
}
//
// Get hotplug info - IOCTL_STORAGE_GET_HOTPLUG_INFO
//
if (!DeviceIoControl(hDisk,
IOCTL_STORAGE_GET_HOTPLUG_INFO,
NULL,
0,
&data->HotplugInfo,
sizeof(STORAGE_HOTPLUG_INFO),
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
data->CurrentRemovalPolicy = (data->HotplugInfo.DeviceHotplug) ? CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL : CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
CloseHandle(hDisk);
return ERROR_SUCCESS;
}
DWORD WINAPI
UtilpRestartDeviceWr(PDISK_PAGE_DATA data)
{
UtilpRestartDevice(data->DeviceInfoSet, data->DeviceInfoData);
return ERROR_SUCCESS;
}
VOID
UtilpRestartDeviceEx(HWND HWnd, PDISK_PAGE_DATA data)
{
HANDLE hThread = NULL;
MSG msg;
//
// Temporary workaround to prevent the user from
// making any more changes and giving the effect
// that something is happening
//
EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), FALSE);
EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), FALSE);
data->IsBusy = TRUE;
//
// Call this utility on a seperate thread
//
hThread = CreateThread(NULL, 0, UtilpRestartDeviceWr, (LPVOID)data, 0, NULL);
if (!hThread)
{
return;
}
while (1)
{
if (MsgWaitForMultipleObjects(1, &hThread, FALSE, INFINITE, QS_ALLINPUT) != (WAIT_OBJECT_0 + 1))
{
break;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!PropSheet_IsDialogMessage(HWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
CloseHandle(hThread);
data->IsBusy = FALSE;
EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), TRUE);
EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), TRUE);
}
UINT
SetRemovalPolicy(HWND HWnd, PDISK_PAGE_DATA data)
{
HANDLE hDisk;
TCHAR buf[MAX_PATH];
DWORD len = MAX_PATH;
CONFIGRET cr;
cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
NULL,
buf,
&len,
0);
if (cr != CR_SUCCESS) {
return ERROR_GEN_FAILURE;
}
if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
return ERROR_INVALID_HANDLE;
}
data->HotplugInfo.DeviceHotplug = (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) ? TRUE : FALSE;
//
// Set hotplug info - IOCTL_STORAGE_SET_HOTPLUG_INFO
//
if (!DeviceIoControl(hDisk,
IOCTL_STORAGE_SET_HOTPLUG_INFO,
&data->HotplugInfo,
sizeof(STORAGE_HOTPLUG_INFO),
NULL,
0,
&len,
NULL)) {
CloseHandle(hDisk);
return GetLastError();
}
CloseHandle(hDisk);
UtilpRestartDeviceEx(HWnd, data);
return ERROR_SUCCESS;
}
BOOL
DiskOnInitDialog(HWND HWnd, HWND HWndFocus, LPARAM LParam)
{
PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
LPPROPSHEETPAGE page = (LPPROPSHEETPAGE) LParam;
diskData = (PDISK_PAGE_DATA) page->lParam;
DebugPrint((1, "DiskDialogProc: WM_INITDIALOG %#08lx %#08lx\n", HWndFocus, LParam));
if (diskData->IsVolume) {
//
// We should never come in here because the
// DiskClassInstaller does not put this up
//
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_GROUP), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), SW_HIDE);
}
else
{
UINT status;
//
// Initially assume that the device does not have a surprise removal policy
//
CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
diskData->IsBusy = FALSE;
//
// Obtain the Caching Policy
//
status = GetCachingPolicy(diskData);
if (status == ERROR_SUCCESS)
{
diskData->IsCachingPolicy = TRUE;
CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, diskData->OrigWriteCacheSetting);
if (diskData->WriteCacheState != DiskWriteCacheNormal)
{
//
// The write cache option on this device cannot be modified
// This is either by design or required by the file system
//
TCHAR szMesg[MAX_PATH];
diskData->IsCachingPolicy = FALSE;
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), FALSE);
if (diskData->WriteCacheState == DiskWriteCacheForceDisable)
{
//
// Write cache has been disabled to protect data integrity
//
if (diskData->OrigWriteCacheSetting == TRUE)
{
//
// Load the warning icon
//
HICON hIcon = LoadImage(ModuleInstance,
MAKEINTRESOURCE(IDI_DISK_POLICY_WARNING),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_SHARED);
SendDlgItemMessage(HWnd, IDC_DISK_POLICY_WRITE_CACHE_ICON, STM_SETICON, (WPARAM)hIcon, 0);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_ICON), SW_SHOW);
//
// The request to force disable write cache may
// have failed. Put up the big bad warning sign
//
LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG2, szMesg, MAX_PATH);
}
else
{
//
// Put up an informational tip
//
LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG1, szMesg, MAX_PATH);
}
}
else if (diskData->WriteCacheState == DiskWriteCacheDisableNotSupported)
{
//
// This device does not allow for the write cache to be disabled
//
LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG2, szMesg, MAX_PATH);
}
SetDlgItemText(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG, szMesg);
}
}
else
{
//
// Either we could not open a handle to the device
// or this device does not support write caching
//
diskData->IsCachingPolicy = FALSE;
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), SW_HIDE);
}
//
// Obtain the Removal Policy
//
status = GetRemovalPolicy(diskData);
if (status == ERROR_SUCCESS)
{
//
// Check to see if the drive is removable
//
if ((diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) ||
(diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL))
{
if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
{
CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
UpdateCachingPolicy(HWnd, diskData);
}
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_DEFAULT), SW_SHOW);
}
else
{
//
// The removal policy on fixed disks cannot be modified
//
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
//
// Replace the SysLink with static text
//
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
}
}
else
{
//
// We could not obtain a removal policy
//
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
//
// Replace the SysLink with static text
//
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
}
}
SetWindowLongPtr(HWnd, DWLP_USER, (LONG_PTR) diskData);
return TRUE;
}
VOID
DiskOnCommand(HWND HWnd, int id, HWND HWndCtl, UINT codeNotify)
{
PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
switch (id)
{
case IDC_DISK_POLICY_SURPRISE:
{
diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL;
UpdateCachingPolicy(HWnd, diskData);
PropSheet_Changed(GetParent(HWnd), HWnd);
break;
}
case IDC_DISK_POLICY_ORDERLY:
{
diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
UpdateCachingPolicy(HWnd, diskData);
PropSheet_Changed(GetParent(HWnd), HWnd);
break;
}
case IDC_DISK_POLICY_WRITE_CACHE:
{
diskData->CurrWriteCacheSetting = !diskData->CurrWriteCacheSetting;
PropSheet_Changed(GetParent(HWnd), HWnd);
break;
}
case IDC_DISK_POLICY_DEFAULT:
{
if (diskData->CurrentRemovalPolicy != diskData->DefaultRemovalPolicy)
{
diskData->CurrentRemovalPolicy = diskData->DefaultRemovalPolicy;
if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL)
{
CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
}
else
{
CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
}
UpdateCachingPolicy(HWnd, diskData);
}
PropSheet_Changed(GetParent(HWnd), HWnd);
break;
}
}
}
LRESULT
DiskOnNotify(HWND HWnd, int HWndFocus, LPNMHDR lpNMHdr)
{
PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
switch (lpNMHdr->code)
{
case PSN_APPLY:
{
//
// Save away the current setting as the original so
// we don't try to apply again unless it is changed
//
if (!diskData->IsVolume)
{
UINT status;
if (diskData->IsCachingPolicy)
{
if (diskData->CurrWriteCacheSetting != diskData->OrigWriteCacheSetting)
{
status = SetCachingPolicy(diskData);
}
}
if (((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == TRUE)) ||
((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == FALSE)))
{
status = SetRemovalPolicy(HWnd, diskData);
}
}
break;
}
case NM_RETURN:
case NM_CLICK:
{
TCHAR szPath[MAX_PATH];
LoadString(ModuleInstance, IDS_DISK_POLICY_HOTPLUG, szPath, MAX_PATH);
ShellExecute(NULL, _T("open"), _T("RUNDLL32.EXE"), szPath, NULL, SW_SHOWNORMAL);
break;
}
}
return 0;
}
VOID
DiskContextMenu(
HWND HwndControl,
WORD Xpos,
WORD Ypos
)
{
WinHelp(HwndControl,
_T("devmgr.hlp"),
HELP_CONTEXTMENU,
(ULONG_PTR) DiskHelpIDs);
return;
}
VOID
DiskHelp(
HWND ParentHwnd,
LPHELPINFO HelpInfo
)
{
if (HelpInfo->iContextType == HELPINFO_WINDOW) {
WinHelp((HWND) HelpInfo->hItemHandle,
_T("devmgr.hlp"),
HELP_WM_HELP,
(ULONG_PTR) DiskHelpIDs);
}
}
INT_PTR
DiskDialogProc(
HWND hWnd,
UINT Message,
WPARAM wParam,
LPARAM lParam
)
{
switch(Message)
{
HANDLE_MSG(hWnd, WM_INITDIALOG, DiskOnInitDialog);
HANDLE_MSG(hWnd, WM_COMMAND, DiskOnCommand);
HANDLE_MSG(hWnd, WM_NOTIFY, DiskOnNotify);
case WM_SETCURSOR:
{
//
// Temporary workaround to prevent the user from
// making any more changes and giving the effect
// that something is happening
//
PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(hWnd, DWLP_USER);
if (diskData->IsBusy)
{
SetCursor(LoadCursor(NULL, IDC_WAIT));
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
break;
}
case WM_CONTEXTMENU:
DiskContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
break;
case WM_HELP:
DiskHelp(hWnd, (LPHELPINFO)lParam);
break;
}
return FALSE;
}
BOOL
DiskDialogCallback(
HWND HWnd,
UINT Message,
LPPROPSHEETPAGE Page
)
{
return TRUE;
}
#if DBG
#include <stdio.h> // for _vsnprintf
ULONG PropDebug = 0;
UCHAR PropBuffer[DEBUG_BUFFER_LENGTH];
VOID
PropDebugPrint(
ULONG DebugPrintLevel,
PCHAR DebugMessage,
...
)
/*++
Routine Description:
Debug print for properties pages - stolen from classpnp\class.c
Arguments:
Debug print level between 0 and 3, with 3 being the most verbose.
Return Value:
None
--*/
{
va_list ap;
va_start(ap, DebugMessage);
if ((DebugPrintLevel <= (PropDebug & 0x0000ffff)) ||
((1 << (DebugPrintLevel + 15)) & PropDebug)) {
_vsnprintf(PropBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
DbgPrint(PropBuffer);
}
va_end(ap);
} // end PropDebugPrint()
#else
//
// PropDebugPrint stub
//
VOID
PropDebugPrint(
ULONG DebugPrintLevel,
PCHAR DebugMessage,
...
)
{
}
#endif // DBG