Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1691 lines
48 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation, 2000
  3. Module Name :
  4. diskprop.c
  5. Abstract :
  6. Implementation of the Disk Property Page
  7. Revision History :
  8. --*/
  9. #include "propp.h"
  10. #include "diskprop.h"
  11. #include "scsiprop.h"
  12. #include "volprop.h"
  13. //==========================================================================
  14. // Local Constants
  15. //==========================================================================
  16. #define DISKCIPRIVATEDATA_NO_REBOOT_REQUIRED 0x4
  17. //==========================================================================
  18. // Local Function Prototypes
  19. //==========================================================================
  20. const DWORD DiskHelpIDs[]=
  21. {
  22. IDC_DISK_POLICY_WRITE_CACHE, idh_devmgr_disk_write_cache_enabled,
  23. 0, 0
  24. };
  25. typedef struct _DISK_PAGE_DATA {
  26. BOOL IsVolume;
  27. HDEVINFO DeviceInfoSet;
  28. PSP_DEVINFO_DATA DeviceInfoData;
  29. //
  30. // This field represents whether disk
  31. // level write caching may be modified
  32. //
  33. BOOL IsCachingPolicy;
  34. BOOL OrigWriteCacheSetting;
  35. BOOL CurrWriteCacheSetting;
  36. DISK_WRITE_CACHE_STATE WriteCacheState;
  37. DWORD DefaultRemovalPolicy;
  38. DWORD CurrentRemovalPolicy;
  39. STORAGE_HOTPLUG_INFO HotplugInfo;
  40. //
  41. // This field is set when the device stack
  42. // is being torn down which happens during
  43. // a removal policy change
  44. //
  45. BOOL IsBusy;
  46. LPGUID DevClassGuid; // used only for the root page
  47. } DISK_PAGE_DATA, *PDISK_PAGE_DATA;
  48. BOOL
  49. IsUserAdmin(
  50. VOID
  51. )
  52. /*++
  53. Routine Description:
  54. This routine returns TRUE if the caller's process is a
  55. member of the Administrators local group.
  56. Caller is NOT expected to be impersonating anyone and IS
  57. expected to be able to open their own process and process
  58. token.
  59. Arguments:
  60. None.
  61. Return Value:
  62. TRUE - Caller has Administrators local group.
  63. FALSE - Caller does not have Administrators local group.
  64. --*/
  65. {
  66. HANDLE Token;
  67. DWORD BytesRequired;
  68. PTOKEN_GROUPS Groups;
  69. BOOL b;
  70. DWORD i;
  71. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  72. PSID AdministratorsGroup;
  73. //
  74. // Open the process token.
  75. //
  76. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  77. return(FALSE);
  78. }
  79. b = FALSE;
  80. Groups = NULL;
  81. //
  82. // Get group information.
  83. //
  84. if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  85. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  86. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED,BytesRequired))
  87. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
  88. b = AllocateAndInitializeSid(
  89. &NtAuthority,
  90. 2,
  91. SECURITY_BUILTIN_DOMAIN_RID,
  92. DOMAIN_ALIAS_RID_ADMINS,
  93. 0, 0, 0, 0, 0, 0,
  94. &AdministratorsGroup
  95. );
  96. if(b) {
  97. //
  98. // See if the user has the administrator group.
  99. //
  100. b = FALSE;
  101. for(i=0; i<Groups->GroupCount; i++) {
  102. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  103. b = TRUE;
  104. break;
  105. }
  106. }
  107. FreeSid(AdministratorsGroup);
  108. }
  109. }
  110. //
  111. // Clean up and return.
  112. //
  113. if(Groups) {
  114. LocalFree(Groups);
  115. }
  116. CloseHandle(Token);
  117. return(b);
  118. }
  119. INT_PTR
  120. DiskDialogProc(
  121. HWND Dialog,
  122. UINT Message,
  123. WPARAM WParam,
  124. LPARAM LParam
  125. );
  126. BOOL
  127. DiskDialogCallback(
  128. HWND Dialog,
  129. UINT Message,
  130. LPPROPSHEETPAGE Page
  131. );
  132. BOOL
  133. CommonPropPageProvider(
  134. PSP_PROPSHEETPAGE_REQUEST Request,
  135. LPFNADDPROPSHEETPAGE AddPageRoutine,
  136. LPARAM AddPageContext,
  137. LPGUID DevClassGuid
  138. );
  139. BOOL CALLBACK
  140. VolumePropPageProvider(
  141. PSP_PROPSHEETPAGE_REQUEST Request,
  142. LPFNADDPROPSHEETPAGE AddPageRoutine,
  143. LPARAM AddPageContext
  144. )
  145. {
  146. BOOL result;
  147. if(Request->cbSize != sizeof(SP_PROPSHEETPAGE_REQUEST)) {
  148. return FALSE;
  149. }
  150. switch(Request->PageRequested) {
  151. case SPPSR_ENUM_ADV_DEVICE_PROPERTIES: {
  152. result = TRUE;
  153. break;
  154. }
  155. case SPPSR_ENUM_BASIC_DEVICE_PROPERTIES: {
  156. result = FALSE;
  157. break;
  158. }
  159. default: {
  160. result = FALSE;
  161. break;
  162. }
  163. }
  164. //
  165. // Since there's nothing else on the page, don't show the page
  166. // Remove the statement to use this page, e.g. when we want to allow
  167. // the user to select volumes to turn on/off
  168. //
  169. result = FALSE;
  170. if(result) {
  171. result = CommonPropPageProvider(
  172. Request,
  173. AddPageRoutine,
  174. AddPageContext,
  175. (LPGUID) &GUID_DEVCLASS_VOLUME);
  176. }
  177. return result;
  178. }
  179. BOOL
  180. CommonPropPageProvider(
  181. PSP_PROPSHEETPAGE_REQUEST Request,
  182. LPFNADDPROPSHEETPAGE AddPageRoutine,
  183. LPARAM AddPageContext,
  184. LPGUID DevClassGuid
  185. )
  186. {
  187. PDISK_PAGE_DATA data;
  188. PROPSHEETPAGE page;
  189. HPROPSHEETPAGE pageHandle;
  190. BOOL result = TRUE;
  191. HKEY hDeviceKey;
  192. BOOL IsVolume = FALSE;
  193. TCHAR buf[MAX_PATH];
  194. //
  195. // Make sure that we're actually opening a device
  196. //
  197. hDeviceKey = SetupDiOpenDevRegKey(Request->DeviceInfoSet,
  198. Request->DeviceInfoData,
  199. DICS_FLAG_GLOBAL,
  200. 0,
  201. DIREG_DEV,
  202. KEY_ALL_ACCESS);
  203. if (INVALID_HANDLE_VALUE == hDeviceKey) {
  204. IsVolume = TRUE;
  205. }
  206. RegCloseKey(hDeviceKey);
  207. //
  208. // Since there's nothing else on the page, don't show the page
  209. // Remove the statement to use this page, e.g. when we want to allow
  210. // the user to select volumes to turn on/off
  211. //
  212. if (IsVolume)
  213. return FALSE;
  214. //
  215. // At this point we've determined that this is a request for pages we
  216. // provide. Instantiate the pages and call the AddPage routine to put
  217. // them install them.
  218. //
  219. if (!IsUserAdmin()) {
  220. return FALSE;
  221. }
  222. data = LocalAlloc(0, sizeof(DISK_PAGE_DATA));
  223. if(data == NULL) {
  224. return FALSE;
  225. }
  226. data->DeviceInfoSet = Request->DeviceInfoSet;
  227. data->DeviceInfoData = Request->DeviceInfoData;
  228. data->DevClassGuid = DevClassGuid;
  229. data->IsVolume = IsVolume;
  230. memset(&page, 0, sizeof(PROPSHEETPAGE));
  231. page.dwSize = sizeof(PROPSHEETPAGE);
  232. page.dwFlags = PSP_USECALLBACK;
  233. if (IsVolume) {
  234. LoadString(ModuleInstance, IDS_ADVANCED, buf, MAX_PATH);
  235. page.pszTitle = buf;
  236. page.dwFlags |= PSP_USETITLE;
  237. }
  238. page.hInstance = ModuleInstance;
  239. page.pszTemplate = MAKEINTRESOURCE(ID_DISK_PROPPAGE);
  240. page.pfnDlgProc = DiskDialogProc;
  241. page.pfnCallback = DiskDialogCallback;
  242. page.lParam = (LPARAM) data;
  243. pageHandle = CreatePropertySheetPage(&page);
  244. if(pageHandle == FALSE) {
  245. return FALSE;
  246. }
  247. result = AddPageRoutine(pageHandle, AddPageContext);
  248. if(result) {
  249. ScsiPropPageProvider(Request, AddPageRoutine, AddPageContext);
  250. }
  251. return result;
  252. }
  253. VOID
  254. AttemptToSuppressDiskInstallReboot(
  255. IN HDEVINFO DeviceInfoSet,
  256. IN PSP_DEVINFO_DATA DeviceInfoData
  257. )
  258. /*++
  259. Routine Description:
  260. Because disks are listed as "critical devices" (i.e., they're in the
  261. critical device database), they get bootstrapped by PnP during boot. Thus,
  262. by the time we're installing a disk in user-mode, it's most likely already
  263. on-line (unless the disk has some problem). Unfortunately, if the disk is
  264. the boot device, we won't be able to dynamically affect the changes (if
  265. any) to tear the stack down and bring it back up with any new settings,
  266. drivers, etc. This causes problems for OEM Preinstall scenarios where the
  267. target machines have different disks than the source machine used to create
  268. the preinstall image. If we simply perform our default behavior, then
  269. the user's experience would be to unbox their brand new machine, boot for
  270. the first time and go through OOBE, and then be greeted upon login with a
  271. reboot prompt!
  272. To fix this, we've defined a private [DDInstall] section INF flag (specific
  273. to INFs of class "DiskDrive") that indicates we can forego the reboot if
  274. certain criteria are met. Those criteria are:
  275. 1. No files were modified as a result of this device's installation
  276. (determined by checking the devinfo element's
  277. DI_FLAGSEX_RESTART_DEVICE_ONLY flag, which the device installer uses to
  278. track whether such file modifications have occurred).
  279. 2. The INF used to install this device is signed.
  280. 3. The INF driver node has a DiskCiPrivateData = <int> entry in its
  281. [DDInstall] section that has bit 2 (0x4) set. Note that this setting
  282. is intentionally obfuscated because we don't want third parties trying
  283. to use this, as they won't understand the ramifications or
  284. requirements, and will more than likely get this wrong (trading an
  285. annoying but harmless reboot requirement into a much more severe
  286. stability issue).
  287. This routine makes the above checks, and if it is found that the reboot can
  288. be suppressed, it clears the DI_NEEDRESTART and DI_NEEDREBOOT flags from
  289. the devinfo element's device install parameters.
  290. Arguments:
  291. DeviceInfoSet - Supplies the device information set.
  292. DeviceInfoData - Supplies the device information element that has just
  293. been successfully installed (via SetupDiInstallDevice).
  294. Return Value:
  295. None.
  296. --*/
  297. {
  298. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  299. PSP_DRVINFO_DATA DriverInfoData = NULL;
  300. PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData = NULL;
  301. PSP_INF_SIGNER_INFO InfSignerInfo = NULL;
  302. HINF hInf;
  303. TCHAR InfSectionWithExt[255]; // max section name length is 255 chars
  304. INFCONTEXT InfContext;
  305. INT Flags;
  306. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  307. if(!SetupDiGetDeviceInstallParams(DeviceInfoSet,
  308. DeviceInfoData,
  309. &DeviceInstallParams)) {
  310. //
  311. // Couldn't retrieve the device install params--this should never
  312. // happen.
  313. //
  314. goto clean0;
  315. }
  316. if(!(DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  317. //
  318. // The device doesn't require a reboot (must not be the boot device!)
  319. //
  320. goto clean0;
  321. }
  322. if(!(DeviceInstallParams.FlagsEx & DI_FLAGSEX_RESTART_DEVICE_ONLY)) {
  323. //
  324. // Since this flag isn't set, this indicates that the device installer
  325. // modified one or more files as part of this device's installation.
  326. // Thus, it isn't safe for us to suppress the reboot request.
  327. //
  328. goto clean0;
  329. }
  330. //
  331. // OK, we have a device that needs a reboot, and no files were modified
  332. // during its installation. Now check the INF to see if it's signed.
  333. // (Note: the SP_DRVINFO_DATA, SP_DRVINFO_DETAIL_DATA, and
  334. // SP_INF_SIGNER_INFO structures are rather large, so we allocate them
  335. // instead of using lots of stack space.)
  336. //
  337. DriverInfoData = LocalAlloc(0, sizeof(SP_DRVINFO_DATA));
  338. if(DriverInfoData) {
  339. DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
  340. } else {
  341. goto clean0;
  342. }
  343. if(!SetupDiGetSelectedDriver(DeviceInfoSet,
  344. DeviceInfoData,
  345. DriverInfoData)) {
  346. //
  347. // We must be installing the NULL driver (which is unlikely)...
  348. //
  349. goto clean0;
  350. }
  351. DriverInfoDetailData = LocalAlloc(0, sizeof(SP_DRVINFO_DETAIL_DATA));
  352. if(DriverInfoDetailData) {
  353. DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  354. } else {
  355. goto clean0;
  356. }
  357. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  358. DeviceInfoData,
  359. DriverInfoData,
  360. DriverInfoDetailData,
  361. sizeof(SP_DRVINFO_DETAIL_DATA),
  362. NULL)
  363. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  364. //
  365. // Failed to retrieve driver info details--should never happen.
  366. //
  367. goto clean0;
  368. }
  369. InfSignerInfo = LocalAlloc(0, sizeof(SP_INF_SIGNER_INFO));
  370. if(InfSignerInfo) {
  371. InfSignerInfo->cbSize = sizeof(SP_INF_SIGNER_INFO);
  372. } else {
  373. goto clean0;
  374. }
  375. if(!SetupVerifyInfFile(DriverInfoDetailData->InfFileName,
  376. NULL,
  377. InfSignerInfo)) {
  378. //
  379. // INF isn't signed--we wouldn't trust its "no reboot required" flag,
  380. // even if it had one.
  381. //
  382. goto clean0;
  383. }
  384. //
  385. // INF is signed--let's open it up and see if it specifes the "no reboot
  386. // required" flag in it's (decorated) DDInstall section...
  387. //
  388. hInf = SetupOpenInfFile(DriverInfoDetailData->InfFileName,
  389. NULL,
  390. INF_STYLE_WIN4,
  391. NULL
  392. );
  393. if(hInf == INVALID_HANDLE_VALUE) {
  394. //
  395. // Failed to open the INF. This is incredibly odd, since we just got
  396. // through validating the INF's digital signature...
  397. //
  398. goto clean0;
  399. }
  400. if(!SetupDiGetActualSectionToInstall(hInf,
  401. DriverInfoDetailData->SectionName,
  402. InfSectionWithExt,
  403. sizeof(InfSectionWithExt) / sizeof(TCHAR),
  404. NULL,
  405. NULL)
  406. || !SetupFindFirstLine(hInf,
  407. InfSectionWithExt,
  408. TEXT("DiskCiPrivateData"),
  409. &InfContext)
  410. || !SetupGetIntField(&InfContext, 1, &Flags)) {
  411. Flags = 0;
  412. }
  413. SetupCloseInfFile(hInf);
  414. if(Flags & DISKCIPRIVATEDATA_NO_REBOOT_REQUIRED) {
  415. //
  416. // This signed INF is vouching for the fact that no reboot is
  417. // required for full functionality of this disk. Thus, we'll
  418. // clear the DI_NEEDRESTART and DI_NEEDREBOOT flags, so that
  419. // the user won't be prompted to reboot. Note that during the
  420. // default handling routine (SetupDiInstallDevice), a non-fatal
  421. // problem was set on the devnode indicating that a reboot is
  422. // needed. This will not result in a yellow-bang in DevMgr,
  423. // but you would see text in the device status field indicating
  424. // a reboot is needed if you go into the General tab of the
  425. // device's property sheet.
  426. //
  427. CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDRESTART);
  428. CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDREBOOT);
  429. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  430. DeviceInfoData,
  431. &DeviceInstallParams
  432. );
  433. }
  434. clean0:
  435. if(DriverInfoData) {
  436. LocalFree(DriverInfoData);
  437. }
  438. if(DriverInfoDetailData) {
  439. LocalFree(DriverInfoDetailData);
  440. }
  441. if(InfSignerInfo) {
  442. LocalFree(InfSignerInfo);
  443. }
  444. }
  445. DWORD
  446. DiskClassInstaller(
  447. IN DI_FUNCTION InstallFunction,
  448. IN HDEVINFO DeviceInfoSet,
  449. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  450. )
  451. /*++
  452. Routine Description:
  453. This routine is the class installer function for disk drive.
  454. Arguments:
  455. InstallFunction - Supplies the install function.
  456. DeviceInfoSet - Supplies the device info set.
  457. DeviceInfoData - Supplies the device info data.
  458. Return Value:
  459. If this function successfully completed the requested action, the return
  460. value is NO_ERROR.
  461. If the default behavior is to be performed for the requested action, the
  462. return value is ERROR_DI_DO_DEFAULT.
  463. If an error occurred while attempting to perform the requested action, a
  464. Win32 error code is returned.
  465. --*/
  466. {
  467. PROPSHEETPAGE page;
  468. switch (InstallFunction)
  469. {
  470. case DIF_INSTALLDEVICE:
  471. {
  472. //
  473. // Let the default action occur to get the device installed.
  474. //
  475. if(!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  476. //
  477. // Failed to install the device--just return the error reported
  478. //
  479. return GetLastError();
  480. }
  481. //
  482. // Default device install action succeeded, now check for reboot
  483. // requirement and suppress it, if possible.
  484. //
  485. AttemptToSuppressDiskInstallReboot(DeviceInfoSet, DeviceInfoData);
  486. //
  487. // Regardless of whether we successfully suppressed the reboot, we
  488. // still report success, because the install went fine.
  489. //
  490. return NO_ERROR;
  491. }
  492. case DIF_ADDPROPERTYPAGE_ADVANCED:
  493. case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
  494. {
  495. //
  496. // get the current class install parameters for the device
  497. //
  498. SP_ADDPROPERTYPAGE_DATA AddPropertyPageData;
  499. //
  500. // DeviceInfoSet is NULL if setup is requesting property pages for the
  501. // device setup class. We don't want to do anything in this case.
  502. //
  503. if (DeviceInfoData==NULL)
  504. return ERROR_DI_DO_DEFAULT;
  505. ZeroMemory(&AddPropertyPageData, sizeof(SP_ADDPROPERTYPAGE_DATA));
  506. AddPropertyPageData.ClassInstallHeader.cbSize =
  507. sizeof(SP_CLASSINSTALL_HEADER);
  508. if (SetupDiGetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  509. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  510. sizeof(SP_ADDPROPERTYPAGE_DATA), NULL ))
  511. {
  512. PDISK_PAGE_DATA pDiskPageData;
  513. PVOLUME_PAGE_DATA pVolumePageData;
  514. HPROPSHEETPAGE pageHandle;
  515. PROPSHEETPAGE page;
  516. BOOL isScsi;
  517. //
  518. // Ensure that the maximum number of dynamic pages for the device
  519. // has not yet been met
  520. //
  521. if (AddPropertyPageData.NumDynamicPages >=
  522. MAX_INSTALLWIZARD_DYNAPAGES)
  523. return NO_ERROR;
  524. if (InstallFunction==DIF_ADDPROPERTYPAGE_ADVANCED)
  525. {
  526. //
  527. // Add disk property page
  528. //
  529. pDiskPageData = HeapAlloc(GetProcessHeap(), 0,
  530. sizeof(DISK_PAGE_DATA));
  531. if (pDiskPageData)
  532. {
  533. //
  534. // Save DeviceInfoSet and DeviceInfoData
  535. //
  536. pDiskPageData->DeviceInfoSet = DeviceInfoSet;
  537. pDiskPageData->DeviceInfoData = DeviceInfoData;
  538. pDiskPageData->DevClassGuid =
  539. (LPGUID) &GUID_DEVCLASS_DISKDRIVE;
  540. pDiskPageData->IsVolume = FALSE;
  541. memset(&page, 0, sizeof(PROPSHEETPAGE));
  542. //
  543. // Create disk property sheet page
  544. //
  545. page.dwSize = sizeof(PROPSHEETPAGE);
  546. page.dwFlags = PSP_USECALLBACK;
  547. page.hInstance = ModuleInstance;
  548. page.pszTemplate = MAKEINTRESOURCE(ID_DISK_PROPPAGE);
  549. page.pfnDlgProc = DiskDialogProc;
  550. page.pfnCallback = DiskDialogCallback;
  551. page.lParam = (LPARAM) pDiskPageData;
  552. pageHandle = CreatePropertySheetPage(&page);
  553. if(!pageHandle)
  554. {
  555. HeapFree(GetProcessHeap(), 0, pDiskPageData);
  556. return NO_ERROR;
  557. }
  558. //
  559. // Add the new page to the list of dynamic property
  560. // sheets
  561. //
  562. AddPropertyPageData.DynamicPages[
  563. AddPropertyPageData.NumDynamicPages++] = pageHandle;
  564. }
  565. }
  566. //
  567. // Add volume property page
  568. //
  569. if ( AddPropertyPageData.NumDynamicPages >=
  570. MAX_INSTALLWIZARD_DYNAPAGES )
  571. {
  572. SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  573. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  574. sizeof(SP_ADDPROPERTYPAGE_DATA));
  575. return NO_ERROR;
  576. }
  577. if (IsUserAdmin())
  578. pVolumePageData = HeapAlloc(GetProcessHeap(), 0,
  579. sizeof(VOLUME_PAGE_DATA));
  580. else
  581. pVolumePageData = NULL;
  582. if (pVolumePageData)
  583. {
  584. HMODULE LdmModule;
  585. SP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData;
  586. //
  587. // Save DeviceInfoSet and DeviceInfoData
  588. //
  589. pVolumePageData->DeviceInfoSet = DeviceInfoSet;
  590. pVolumePageData->DeviceInfoData = DeviceInfoData;
  591. //
  592. // Create volume property sheet page
  593. //
  594. memset(&page, 0, sizeof(PROPSHEETPAGE));
  595. page.dwSize = sizeof(PROPSHEETPAGE);
  596. page.dwFlags = PSP_USECALLBACK;
  597. page.hInstance = ModuleInstance;
  598. page.pszTemplate = MAKEINTRESOURCE(ID_VOLUME_PROPPAGE);
  599. page.pfnDlgProc = VolumeDialogProc;
  600. page.pfnCallback = VolumeDialogCallback;
  601. page.lParam = (LPARAM) pVolumePageData;
  602. pageHandle = CreatePropertySheetPage(&page);
  603. if(!pageHandle)
  604. {
  605. HeapFree(GetProcessHeap(), 0, pVolumePageData);
  606. return NO_ERROR;
  607. }
  608. //
  609. // Add the new page to the list of dynamic property
  610. // sheets
  611. //
  612. AddPropertyPageData.DynamicPages[
  613. AddPropertyPageData.NumDynamicPages++]=pageHandle;
  614. //
  615. // Check if the property page is pulled up from disk manager.
  616. //
  617. pVolumePageData->bInvokedByDiskmgr = FALSE;
  618. LdmModule = GetModuleHandle(TEXT("dmdskmgr"));
  619. if ( LdmModule )
  620. {
  621. IS_REQUEST_PENDING pfnIsRequestPending;
  622. pfnIsRequestPending = (IS_REQUEST_PENDING)
  623. GetProcAddress(LdmModule, "IsRequestPending");
  624. if (pfnIsRequestPending)
  625. {
  626. if ((*pfnIsRequestPending)())
  627. pVolumePageData->bInvokedByDiskmgr = TRUE;
  628. }
  629. }
  630. }
  631. if (InstallFunction==DIF_ADDPROPERTYPAGE_ADVANCED)
  632. {
  633. //
  634. // Add Scsi property page data
  635. //
  636. if ( AddPropertyPageData.NumDynamicPages >=
  637. MAX_INSTALLWIZARD_DYNAPAGES )
  638. {
  639. SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  640. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  641. sizeof(SP_ADDPROPERTYPAGE_DATA));
  642. return NO_ERROR;
  643. }
  644. isScsi = ScsiCheckDriveType( DeviceInfoSet, DeviceInfoData);
  645. if (isScsi) {
  646. PSCSI_PAGE_DATA pScsiPageData;
  647. pScsiPageData = HeapAlloc(GetProcessHeap(),
  648. 0,
  649. sizeof(SCSI_PAGE_DATA));
  650. if(pScsiPageData == NULL) {
  651. SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  652. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  653. sizeof(SP_ADDPROPERTYPAGE_DATA));
  654. return NO_ERROR;
  655. }
  656. //
  657. // Create scsi property sheet page
  658. //
  659. pScsiPageData->DeviceInfoSet = DeviceInfoSet;
  660. pScsiPageData->DeviceInfoData = DeviceInfoData;
  661. memset(&page, 0, sizeof(PROPSHEETPAGE));
  662. page.dwSize = sizeof(PROPSHEETPAGE);
  663. page.dwFlags = PSP_USECALLBACK;
  664. page.hInstance = ModuleInstance;
  665. page.pszTemplate = MAKEINTRESOURCE(ID_SCSI_PROPPAGE);
  666. page.pfnDlgProc = ScsiDialogProc;
  667. page.pfnCallback = ScsiDialogCallback;
  668. page.lParam = (LPARAM) pScsiPageData;
  669. pageHandle = CreatePropertySheetPage(&page);
  670. if(pageHandle == NULL) {
  671. HeapFree(GetProcessHeap(), 0, pScsiPageData);
  672. SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  673. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  674. sizeof(SP_ADDPROPERTYPAGE_DATA));
  675. return FALSE;
  676. }
  677. AddPropertyPageData.DynamicPages[
  678. AddPropertyPageData.NumDynamicPages++] = pageHandle;
  679. }
  680. }
  681. SetupDiSetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  682. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  683. sizeof(SP_ADDPROPERTYPAGE_DATA));
  684. }
  685. return NO_ERROR;
  686. } // case DIF_ADDPROPERTYPAGE_ADVANCED
  687. }
  688. return ERROR_DI_DO_DEFAULT;
  689. }
  690. HANDLE
  691. GetHandleForDisk(LPTSTR DeviceName)
  692. {
  693. HANDLE h = INVALID_HANDLE_VALUE;
  694. int i = 0;
  695. BOOL success = FALSE;
  696. TCHAR buf[MAX_PATH];
  697. TCHAR fakeDeviceName[MAX_PATH];
  698. h = CreateFile(DeviceName,
  699. GENERIC_WRITE | GENERIC_READ,
  700. FILE_SHARE_WRITE | FILE_SHARE_READ,
  701. NULL,
  702. OPEN_EXISTING,
  703. 0,
  704. NULL);
  705. if (h != INVALID_HANDLE_VALUE)
  706. return h;
  707. while (!success && i < 10) {
  708. wsprintf(buf, _T("DISK_FAKE_DEVICE_%d_"), i++);
  709. success = DefineDosDevice(DDD_RAW_TARGET_PATH,
  710. buf,
  711. DeviceName);
  712. if (success) {
  713. _tcscpy(fakeDeviceName, _T("\\\\.\\"));
  714. _tcscat(fakeDeviceName, buf);
  715. h = CreateFile(fakeDeviceName,
  716. GENERIC_WRITE | GENERIC_READ,
  717. FILE_SHARE_WRITE | FILE_SHARE_READ,
  718. NULL,
  719. OPEN_EXISTING,
  720. 0,
  721. NULL);
  722. DefineDosDevice(DDD_REMOVE_DEFINITION,
  723. buf,
  724. NULL);
  725. }
  726. }
  727. return h;
  728. }
  729. UINT
  730. GetCachingPolicy(PDISK_PAGE_DATA data)
  731. {
  732. HANDLE hDisk;
  733. DISK_CACHE_INFORMATION cacheInfo;
  734. TCHAR buf[MAX_PATH];
  735. DWORD len = MAX_PATH;
  736. CONFIGRET cr;
  737. cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
  738. CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
  739. NULL,
  740. buf,
  741. &len,
  742. 0);
  743. if (cr != CR_SUCCESS) {
  744. return ERROR_GEN_FAILURE;
  745. }
  746. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  747. return ERROR_INVALID_HANDLE;
  748. }
  749. //
  750. // Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
  751. //
  752. if (!DeviceIoControl(hDisk,
  753. IOCTL_DISK_GET_CACHE_INFORMATION,
  754. NULL,
  755. 0,
  756. &cacheInfo,
  757. sizeof(DISK_CACHE_INFORMATION),
  758. &len,
  759. NULL)) {
  760. CloseHandle(hDisk);
  761. return GetLastError();
  762. }
  763. //
  764. // Get write cache state - IOCTL_DISK_GET_WRITE_CACHE_STATE
  765. //
  766. if (!DeviceIoControl(hDisk,
  767. IOCTL_DISK_GET_WRITE_CACHE_STATE,
  768. NULL,
  769. 0,
  770. &data->WriteCacheState,
  771. sizeof(DISK_WRITE_CACHE_STATE),
  772. &len,
  773. NULL)) {
  774. CloseHandle(hDisk);
  775. return GetLastError();
  776. }
  777. data->OrigWriteCacheSetting = cacheInfo.WriteCacheEnabled;
  778. data->CurrWriteCacheSetting = cacheInfo.WriteCacheEnabled;
  779. CloseHandle(hDisk);
  780. return ERROR_SUCCESS;
  781. }
  782. VOID
  783. UpdateCachingPolicy(HWND HWnd, PDISK_PAGE_DATA data)
  784. {
  785. if (!data->IsCachingPolicy)
  786. {
  787. //
  788. // The caching policy cannot be modified
  789. //
  790. return;
  791. }
  792. if (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
  793. {
  794. //
  795. // This policy requires that no caching be done at any
  796. // level. Uncheck and gray out the write cache setting
  797. //
  798. CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, 0);
  799. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), FALSE);
  800. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), FALSE);
  801. data->CurrWriteCacheSetting = FALSE;
  802. }
  803. else
  804. {
  805. //
  806. // This policy allows for caching to be done at any level
  807. //
  808. CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, 1);
  809. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), TRUE);
  810. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), TRUE);
  811. data->CurrWriteCacheSetting = TRUE;
  812. }
  813. }
  814. UINT
  815. SetCachingPolicy(PDISK_PAGE_DATA data)
  816. {
  817. HANDLE hDisk;
  818. DISK_CACHE_INFORMATION cacheInfo;
  819. TCHAR buf[MAX_PATH];
  820. DWORD len = MAX_PATH;
  821. CONFIGRET cr;
  822. cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
  823. CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
  824. NULL,
  825. buf,
  826. &len,
  827. 0);
  828. if (cr != CR_SUCCESS) {
  829. return ERROR_GEN_FAILURE;
  830. }
  831. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  832. return ERROR_INVALID_HANDLE;
  833. }
  834. //
  835. // Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
  836. //
  837. if (!DeviceIoControl(hDisk,
  838. IOCTL_DISK_GET_CACHE_INFORMATION,
  839. NULL,
  840. 0,
  841. &cacheInfo,
  842. sizeof(DISK_CACHE_INFORMATION),
  843. &len,
  844. NULL)) {
  845. CloseHandle(hDisk);
  846. return GetLastError();
  847. }
  848. cacheInfo.WriteCacheEnabled = (BOOLEAN)data->CurrWriteCacheSetting;
  849. //
  850. // Set cache info - IOCTL_DISK_SET_CACHE_INFORMATION
  851. //
  852. if (!DeviceIoControl(hDisk,
  853. IOCTL_DISK_SET_CACHE_INFORMATION,
  854. &cacheInfo,
  855. sizeof(DISK_CACHE_INFORMATION),
  856. NULL,
  857. 0,
  858. &len,
  859. NULL)) {
  860. CloseHandle(hDisk);
  861. return GetLastError();
  862. }
  863. data->OrigWriteCacheSetting = data->CurrWriteCacheSetting;
  864. CloseHandle(hDisk);
  865. return ERROR_SUCCESS;
  866. }
  867. UINT
  868. GetRemovalPolicy(PDISK_PAGE_DATA data)
  869. {
  870. HANDLE hDisk;
  871. TCHAR buf[MAX_PATH];
  872. DWORD len = MAX_PATH;
  873. CONFIGRET cr;
  874. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  875. data->DeviceInfoData,
  876. SPDRP_REMOVAL_POLICY,
  877. 0,
  878. (PBYTE)&data->DefaultRemovalPolicy,
  879. sizeof(DWORD),
  880. NULL))
  881. {
  882. return GetLastError();
  883. }
  884. cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
  885. CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
  886. NULL,
  887. buf,
  888. &len,
  889. 0);
  890. if (cr != CR_SUCCESS) {
  891. return ERROR_GEN_FAILURE;
  892. }
  893. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  894. return ERROR_INVALID_HANDLE;
  895. }
  896. //
  897. // Get hotplug info - IOCTL_STORAGE_GET_HOTPLUG_INFO
  898. //
  899. if (!DeviceIoControl(hDisk,
  900. IOCTL_STORAGE_GET_HOTPLUG_INFO,
  901. NULL,
  902. 0,
  903. &data->HotplugInfo,
  904. sizeof(STORAGE_HOTPLUG_INFO),
  905. &len,
  906. NULL)) {
  907. CloseHandle(hDisk);
  908. return GetLastError();
  909. }
  910. data->CurrentRemovalPolicy = (data->HotplugInfo.DeviceHotplug) ? CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL : CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
  911. CloseHandle(hDisk);
  912. return ERROR_SUCCESS;
  913. }
  914. DWORD WINAPI
  915. UtilpRestartDeviceWr(PDISK_PAGE_DATA data)
  916. {
  917. UtilpRestartDevice(data->DeviceInfoSet, data->DeviceInfoData);
  918. return ERROR_SUCCESS;
  919. }
  920. VOID
  921. UtilpRestartDeviceEx(HWND HWnd, PDISK_PAGE_DATA data)
  922. {
  923. HANDLE hThread = NULL;
  924. MSG msg;
  925. //
  926. // Temporary workaround to prevent the user from
  927. // making any more changes and giving the effect
  928. // that something is happening
  929. //
  930. EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), FALSE);
  931. EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), FALSE);
  932. data->IsBusy = TRUE;
  933. //
  934. // Call this utility on a seperate thread
  935. //
  936. hThread = CreateThread(NULL, 0, UtilpRestartDeviceWr, (LPVOID)data, 0, NULL);
  937. if (!hThread)
  938. {
  939. return;
  940. }
  941. while (1)
  942. {
  943. if (MsgWaitForMultipleObjects(1, &hThread, FALSE, INFINITE, QS_ALLINPUT) != (WAIT_OBJECT_0 + 1))
  944. {
  945. break;
  946. }
  947. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  948. {
  949. if (!PropSheet_IsDialogMessage(HWnd, &msg))
  950. {
  951. TranslateMessage(&msg);
  952. DispatchMessage(&msg);
  953. }
  954. }
  955. }
  956. CloseHandle(hThread);
  957. data->IsBusy = FALSE;
  958. EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), TRUE);
  959. EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), TRUE);
  960. }
  961. UINT
  962. SetRemovalPolicy(HWND HWnd, PDISK_PAGE_DATA data)
  963. {
  964. HANDLE hDisk;
  965. TCHAR buf[MAX_PATH];
  966. DWORD len = MAX_PATH;
  967. CONFIGRET cr;
  968. cr = CM_Get_DevNode_Registry_Property(data->DeviceInfoData->DevInst,
  969. CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
  970. NULL,
  971. buf,
  972. &len,
  973. 0);
  974. if (cr != CR_SUCCESS) {
  975. return ERROR_GEN_FAILURE;
  976. }
  977. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  978. return ERROR_INVALID_HANDLE;
  979. }
  980. data->HotplugInfo.DeviceHotplug = (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) ? TRUE : FALSE;
  981. //
  982. // Set hotplug info - IOCTL_STORAGE_SET_HOTPLUG_INFO
  983. //
  984. if (!DeviceIoControl(hDisk,
  985. IOCTL_STORAGE_SET_HOTPLUG_INFO,
  986. &data->HotplugInfo,
  987. sizeof(STORAGE_HOTPLUG_INFO),
  988. NULL,
  989. 0,
  990. &len,
  991. NULL)) {
  992. CloseHandle(hDisk);
  993. return GetLastError();
  994. }
  995. CloseHandle(hDisk);
  996. UtilpRestartDeviceEx(HWnd, data);
  997. return ERROR_SUCCESS;
  998. }
  999. BOOL
  1000. DiskOnInitDialog(HWND HWnd, HWND HWndFocus, LPARAM LParam)
  1001. {
  1002. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
  1003. LPPROPSHEETPAGE page = (LPPROPSHEETPAGE) LParam;
  1004. diskData = (PDISK_PAGE_DATA) page->lParam;
  1005. DebugPrint((1, "DiskDialogProc: WM_INITDIALOG %#08lx %#08lx\n", HWndFocus, LParam));
  1006. if (diskData->IsVolume) {
  1007. //
  1008. // We should never come in here because the
  1009. // DiskClassInstaller does not put this up
  1010. //
  1011. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_GROUP), SW_HIDE);
  1012. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), SW_HIDE);
  1013. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), SW_HIDE);
  1014. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), SW_HIDE);
  1015. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
  1016. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), SW_HIDE);
  1017. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), SW_HIDE);
  1018. }
  1019. else
  1020. {
  1021. UINT status;
  1022. //
  1023. // Initially assume that the device does not have a surprise removal policy
  1024. //
  1025. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
  1026. diskData->IsBusy = FALSE;
  1027. //
  1028. // Obtain the Caching Policy
  1029. //
  1030. status = GetCachingPolicy(diskData);
  1031. if (status == ERROR_SUCCESS)
  1032. {
  1033. diskData->IsCachingPolicy = TRUE;
  1034. CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, diskData->OrigWriteCacheSetting);
  1035. if (diskData->WriteCacheState != DiskWriteCacheNormal)
  1036. {
  1037. //
  1038. // The write cache option on this device cannot be modified
  1039. // This is either by design or required by the file system
  1040. //
  1041. TCHAR szMesg[MAX_PATH];
  1042. diskData->IsCachingPolicy = FALSE;
  1043. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), FALSE);
  1044. if (diskData->WriteCacheState == DiskWriteCacheForceDisable)
  1045. {
  1046. //
  1047. // Write cache has been disabled to protect data integrity
  1048. //
  1049. if (diskData->OrigWriteCacheSetting == TRUE)
  1050. {
  1051. //
  1052. // Load the warning icon
  1053. //
  1054. HICON hIcon = LoadImage(ModuleInstance,
  1055. MAKEINTRESOURCE(IDI_DISK_POLICY_WARNING),
  1056. IMAGE_ICON,
  1057. GetSystemMetrics(SM_CXSMICON),
  1058. GetSystemMetrics(SM_CYSMICON),
  1059. LR_SHARED);
  1060. SendDlgItemMessage(HWnd, IDC_DISK_POLICY_WRITE_CACHE_ICON, STM_SETICON, (WPARAM)hIcon, 0);
  1061. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_ICON), SW_SHOW);
  1062. //
  1063. // The request to force disable write cache may
  1064. // have failed. Put up the big bad warning sign
  1065. //
  1066. LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG2, szMesg, MAX_PATH);
  1067. }
  1068. else
  1069. {
  1070. //
  1071. // Put up an informational tip
  1072. //
  1073. LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG1, szMesg, MAX_PATH);
  1074. }
  1075. }
  1076. else if (diskData->WriteCacheState == DiskWriteCacheDisableNotSupported)
  1077. {
  1078. //
  1079. // This device does not allow for the write cache to be disabled
  1080. //
  1081. LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG2, szMesg, MAX_PATH);
  1082. }
  1083. SetDlgItemText(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG, szMesg);
  1084. }
  1085. }
  1086. else
  1087. {
  1088. //
  1089. // Either we could not open a handle to the device
  1090. // or this device does not support write caching
  1091. //
  1092. diskData->IsCachingPolicy = FALSE;
  1093. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), SW_HIDE);
  1094. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), SW_HIDE);
  1095. }
  1096. //
  1097. // Obtain the Removal Policy
  1098. //
  1099. status = GetRemovalPolicy(diskData);
  1100. if (status == ERROR_SUCCESS)
  1101. {
  1102. //
  1103. // Check to see if the drive is removable
  1104. //
  1105. if ((diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) ||
  1106. (diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL))
  1107. {
  1108. if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
  1109. {
  1110. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
  1111. UpdateCachingPolicy(HWnd, diskData);
  1112. }
  1113. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_DEFAULT), SW_SHOW);
  1114. }
  1115. else
  1116. {
  1117. //
  1118. // The removal policy on fixed disks cannot be modified
  1119. //
  1120. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
  1121. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
  1122. //
  1123. // Replace the SysLink with static text
  1124. //
  1125. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
  1126. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
  1127. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
  1128. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
  1129. }
  1130. }
  1131. else
  1132. {
  1133. //
  1134. // We could not obtain a removal policy
  1135. //
  1136. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
  1137. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
  1138. //
  1139. // Replace the SysLink with static text
  1140. //
  1141. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
  1142. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
  1143. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
  1144. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
  1145. }
  1146. }
  1147. SetWindowLongPtr(HWnd, DWLP_USER, (LONG_PTR) diskData);
  1148. return TRUE;
  1149. }
  1150. VOID
  1151. DiskOnCommand(HWND HWnd, int id, HWND HWndCtl, UINT codeNotify)
  1152. {
  1153. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
  1154. switch (id)
  1155. {
  1156. case IDC_DISK_POLICY_SURPRISE:
  1157. {
  1158. diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL;
  1159. UpdateCachingPolicy(HWnd, diskData);
  1160. PropSheet_Changed(GetParent(HWnd), HWnd);
  1161. break;
  1162. }
  1163. case IDC_DISK_POLICY_ORDERLY:
  1164. {
  1165. diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
  1166. UpdateCachingPolicy(HWnd, diskData);
  1167. PropSheet_Changed(GetParent(HWnd), HWnd);
  1168. break;
  1169. }
  1170. case IDC_DISK_POLICY_WRITE_CACHE:
  1171. {
  1172. diskData->CurrWriteCacheSetting = !diskData->CurrWriteCacheSetting;
  1173. PropSheet_Changed(GetParent(HWnd), HWnd);
  1174. break;
  1175. }
  1176. case IDC_DISK_POLICY_DEFAULT:
  1177. {
  1178. if (diskData->CurrentRemovalPolicy != diskData->DefaultRemovalPolicy)
  1179. {
  1180. diskData->CurrentRemovalPolicy = diskData->DefaultRemovalPolicy;
  1181. if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL)
  1182. {
  1183. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
  1184. }
  1185. else
  1186. {
  1187. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
  1188. }
  1189. UpdateCachingPolicy(HWnd, diskData);
  1190. }
  1191. PropSheet_Changed(GetParent(HWnd), HWnd);
  1192. break;
  1193. }
  1194. }
  1195. }
  1196. LRESULT
  1197. DiskOnNotify(HWND HWnd, int HWndFocus, LPNMHDR lpNMHdr)
  1198. {
  1199. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
  1200. switch (lpNMHdr->code)
  1201. {
  1202. case PSN_APPLY:
  1203. {
  1204. //
  1205. // Save away the current setting as the original so
  1206. // we don't try to apply again unless it is changed
  1207. //
  1208. if (!diskData->IsVolume)
  1209. {
  1210. UINT status;
  1211. if (diskData->IsCachingPolicy)
  1212. {
  1213. if (diskData->CurrWriteCacheSetting != diskData->OrigWriteCacheSetting)
  1214. {
  1215. status = SetCachingPolicy(diskData);
  1216. }
  1217. }
  1218. if (((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == TRUE)) ||
  1219. ((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == FALSE)))
  1220. {
  1221. status = SetRemovalPolicy(HWnd, diskData);
  1222. }
  1223. }
  1224. break;
  1225. }
  1226. case NM_RETURN:
  1227. case NM_CLICK:
  1228. {
  1229. TCHAR szPath[MAX_PATH];
  1230. LoadString(ModuleInstance, IDS_DISK_POLICY_HOTPLUG, szPath, MAX_PATH);
  1231. ShellExecute(NULL, _T("open"), _T("RUNDLL32.EXE"), szPath, NULL, SW_SHOWNORMAL);
  1232. break;
  1233. }
  1234. }
  1235. return 0;
  1236. }
  1237. VOID
  1238. DiskContextMenu(
  1239. HWND HwndControl,
  1240. WORD Xpos,
  1241. WORD Ypos
  1242. )
  1243. {
  1244. WinHelp(HwndControl,
  1245. _T("devmgr.hlp"),
  1246. HELP_CONTEXTMENU,
  1247. (ULONG_PTR) DiskHelpIDs);
  1248. return;
  1249. }
  1250. VOID
  1251. DiskHelp(
  1252. HWND ParentHwnd,
  1253. LPHELPINFO HelpInfo
  1254. )
  1255. {
  1256. if (HelpInfo->iContextType == HELPINFO_WINDOW) {
  1257. WinHelp((HWND) HelpInfo->hItemHandle,
  1258. _T("devmgr.hlp"),
  1259. HELP_WM_HELP,
  1260. (ULONG_PTR) DiskHelpIDs);
  1261. }
  1262. }
  1263. INT_PTR
  1264. DiskDialogProc(
  1265. HWND hWnd,
  1266. UINT Message,
  1267. WPARAM wParam,
  1268. LPARAM lParam
  1269. )
  1270. {
  1271. switch(Message)
  1272. {
  1273. HANDLE_MSG(hWnd, WM_INITDIALOG, DiskOnInitDialog);
  1274. HANDLE_MSG(hWnd, WM_COMMAND, DiskOnCommand);
  1275. HANDLE_MSG(hWnd, WM_NOTIFY, DiskOnNotify);
  1276. case WM_SETCURSOR:
  1277. {
  1278. //
  1279. // Temporary workaround to prevent the user from
  1280. // making any more changes and giving the effect
  1281. // that something is happening
  1282. //
  1283. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(hWnd, DWLP_USER);
  1284. if (diskData->IsBusy)
  1285. {
  1286. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1287. SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
  1288. return TRUE;
  1289. }
  1290. break;
  1291. }
  1292. case WM_CONTEXTMENU:
  1293. DiskContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  1294. break;
  1295. case WM_HELP:
  1296. DiskHelp(hWnd, (LPHELPINFO)lParam);
  1297. break;
  1298. }
  1299. return FALSE;
  1300. }
  1301. BOOL
  1302. DiskDialogCallback(
  1303. HWND HWnd,
  1304. UINT Message,
  1305. LPPROPSHEETPAGE Page
  1306. )
  1307. {
  1308. return TRUE;
  1309. }
  1310. #if DBG
  1311. #include <stdio.h> // for _vsnprintf
  1312. ULONG PropDebug = 0;
  1313. UCHAR PropBuffer[DEBUG_BUFFER_LENGTH];
  1314. VOID
  1315. PropDebugPrint(
  1316. ULONG DebugPrintLevel,
  1317. PCHAR DebugMessage,
  1318. ...
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. Debug print for properties pages - stolen from classpnp\class.c
  1323. Arguments:
  1324. Debug print level between 0 and 3, with 3 being the most verbose.
  1325. Return Value:
  1326. None
  1327. --*/
  1328. {
  1329. va_list ap;
  1330. va_start(ap, DebugMessage);
  1331. if ((DebugPrintLevel <= (PropDebug & 0x0000ffff)) ||
  1332. ((1 << (DebugPrintLevel + 15)) & PropDebug)) {
  1333. _vsnprintf(PropBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
  1334. DbgPrint(PropBuffer);
  1335. }
  1336. va_end(ap);
  1337. } // end PropDebugPrint()
  1338. #else
  1339. //
  1340. // PropDebugPrint stub
  1341. //
  1342. VOID
  1343. PropDebugPrint(
  1344. ULONG DebugPrintLevel,
  1345. PCHAR DebugMessage,
  1346. ...
  1347. )
  1348. {
  1349. }
  1350. #endif // DBG