Leaked source code of windows server 2003
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.

1296 lines
40 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name :
  4. diskprop.c
  5. Abstract :
  6. Implementation of the Disk Class Installer and its Policies Tab
  7. Revision History :
  8. --*/
  9. #include "propp.h"
  10. #include "diskprop.h"
  11. #include "volprop.h"
  12. BOOL
  13. IsUserAdmin(VOID)
  14. /*++
  15. Routine Description:
  16. This routine returns TRUE if the caller's process is a
  17. member of the Administrators local group.
  18. Caller is NOT expected to be impersonating anyone and IS
  19. expected to be able to open their own process and process
  20. token.
  21. Arguments:
  22. None.
  23. Return Value:
  24. TRUE - Caller has Administrators local group.
  25. FALSE - Caller does not have Administrators local group.
  26. --*/
  27. {
  28. HANDLE Token;
  29. DWORD BytesRequired;
  30. PTOKEN_GROUPS Groups;
  31. BOOL b;
  32. DWORD i;
  33. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  34. PSID AdministratorsGroup;
  35. //
  36. // Open the process token.
  37. //
  38. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  39. return(FALSE);
  40. }
  41. b = FALSE;
  42. Groups = NULL;
  43. //
  44. // Get group information.
  45. //
  46. if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  47. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  48. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED,BytesRequired))
  49. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
  50. b = AllocateAndInitializeSid(
  51. &NtAuthority,
  52. 2,
  53. SECURITY_BUILTIN_DOMAIN_RID,
  54. DOMAIN_ALIAS_RID_ADMINS,
  55. 0, 0, 0, 0, 0, 0,
  56. &AdministratorsGroup
  57. );
  58. if(b) {
  59. //
  60. // See if the user has the administrator group.
  61. //
  62. b = FALSE;
  63. for(i=0; i<Groups->GroupCount; i++) {
  64. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  65. b = TRUE;
  66. break;
  67. }
  68. }
  69. FreeSid(AdministratorsGroup);
  70. }
  71. }
  72. //
  73. // Clean up and return.
  74. //
  75. if(Groups) {
  76. LocalFree(Groups);
  77. }
  78. CloseHandle(Token);
  79. return(b);
  80. }
  81. BOOL CALLBACK
  82. VolumePropPageProvider(PSP_PROPSHEETPAGE_REQUEST Request, LPFNADDPROPSHEETPAGE AddPageRoutine, LPARAM AddPageContext)
  83. {
  84. //
  85. // Since there is nothing to be displayed simply fail this call
  86. //
  87. return FALSE;
  88. }
  89. VOID
  90. AttemptToSuppressDiskInstallReboot(IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData)
  91. /*++
  92. Routine Description:
  93. Because disks are listed as "critical devices" (i.e., they're in the
  94. critical device database), they get bootstrapped by PnP during boot. Thus,
  95. by the time we're installing a disk in user-mode, it's most likely already
  96. on-line (unless the disk has some problem). Unfortunately, if the disk is
  97. the boot device, we won't be able to dynamically affect the changes (if
  98. any) to tear the stack down and bring it back up with any new settings,
  99. drivers, etc. This causes problems for OEM Preinstall scenarios where the
  100. target machines have different disks than the source machine used to create
  101. the preinstall image. If we simply perform our default behavior, then
  102. the user's experience would be to unbox their brand new machine, boot for
  103. the first time and go through OOBE, and then be greeted upon login with a
  104. reboot prompt!
  105. To fix this, we've defined a private [DDInstall] section INF flag (specific
  106. to INFs of class "DiskDrive") that indicates we can forego the reboot if
  107. certain criteria are met. Those criteria are:
  108. 1. No files were modified as a result of this device's installation
  109. (determined by checking the devinfo element's
  110. DI_FLAGSEX_RESTART_DEVICE_ONLY flag, which the device installer uses to
  111. track whether such file modifications have occurred).
  112. 2. The INF used to install this device is signed.
  113. 3. The INF driver node has a DiskCiPrivateData = <int> entry in its
  114. [DDInstall] section that has bit 2 (0x4) set. Note that this setting
  115. is intentionally obfuscated because we don't want third parties trying
  116. to use this, as they won't understand the ramifications or
  117. requirements, and will more than likely get this wrong (trading an
  118. annoying but harmless reboot requirement into a much more severe
  119. stability issue).
  120. This routine makes the above checks, and if it is found that the reboot can
  121. be suppressed, it clears the DI_NEEDRESTART and DI_NEEDREBOOT flags from
  122. the devinfo element's device install parameters.
  123. Arguments:
  124. DeviceInfoSet - Supplies the device information set.
  125. DeviceInfoData - Supplies the device information element that has just
  126. been successfully installed (via SetupDiInstallDevice).
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  132. PSP_DRVINFO_DATA DriverInfoData = NULL;
  133. PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData = NULL;
  134. PSP_INF_SIGNER_INFO InfSignerInfo = NULL;
  135. HINF hInf;
  136. TCHAR InfSectionWithExt[255]; // max section name length is 255 chars
  137. INFCONTEXT InfContext;
  138. INT Flags;
  139. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  140. if(!SetupDiGetDeviceInstallParams(DeviceInfoSet,
  141. DeviceInfoData,
  142. &DeviceInstallParams)) {
  143. //
  144. // Couldn't retrieve the device install params--this should never
  145. // happen.
  146. //
  147. goto clean0;
  148. }
  149. if(!(DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  150. //
  151. // The device doesn't require a reboot (must not be the boot device!)
  152. //
  153. goto clean0;
  154. }
  155. if(!(DeviceInstallParams.FlagsEx & DI_FLAGSEX_RESTART_DEVICE_ONLY)) {
  156. //
  157. // Since this flag isn't set, this indicates that the device installer
  158. // modified one or more files as part of this device's installation.
  159. // Thus, it isn't safe for us to suppress the reboot request.
  160. //
  161. goto clean0;
  162. }
  163. //
  164. // OK, we have a device that needs a reboot, and no files were modified
  165. // during its installation. Now check the INF to see if it's signed.
  166. // (Note: the SP_DRVINFO_DATA, SP_DRVINFO_DETAIL_DATA, and
  167. // SP_INF_SIGNER_INFO structures are rather large, so we allocate them
  168. // instead of using lots of stack space.)
  169. //
  170. DriverInfoData = LocalAlloc(0, sizeof(SP_DRVINFO_DATA));
  171. if(DriverInfoData) {
  172. DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
  173. } else {
  174. goto clean0;
  175. }
  176. if(!SetupDiGetSelectedDriver(DeviceInfoSet,
  177. DeviceInfoData,
  178. DriverInfoData)) {
  179. //
  180. // We must be installing the NULL driver (which is unlikely)...
  181. //
  182. goto clean0;
  183. }
  184. DriverInfoDetailData = LocalAlloc(0, sizeof(SP_DRVINFO_DETAIL_DATA));
  185. if(DriverInfoDetailData) {
  186. DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  187. } else {
  188. goto clean0;
  189. }
  190. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  191. DeviceInfoData,
  192. DriverInfoData,
  193. DriverInfoDetailData,
  194. sizeof(SP_DRVINFO_DETAIL_DATA),
  195. NULL)
  196. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  197. //
  198. // Failed to retrieve driver info details--should never happen.
  199. //
  200. goto clean0;
  201. }
  202. InfSignerInfo = LocalAlloc(0, sizeof(SP_INF_SIGNER_INFO));
  203. if(InfSignerInfo) {
  204. InfSignerInfo->cbSize = sizeof(SP_INF_SIGNER_INFO);
  205. } else {
  206. goto clean0;
  207. }
  208. if(!SetupVerifyInfFile(DriverInfoDetailData->InfFileName,
  209. NULL,
  210. InfSignerInfo)) {
  211. //
  212. // INF isn't signed--we wouldn't trust its "no reboot required" flag,
  213. // even if it had one.
  214. //
  215. goto clean0;
  216. }
  217. //
  218. // INF is signed--let's open it up and see if it specifes the "no reboot
  219. // required" flag in it's (decorated) DDInstall section...
  220. //
  221. hInf = SetupOpenInfFile(DriverInfoDetailData->InfFileName,
  222. NULL,
  223. INF_STYLE_WIN4,
  224. NULL
  225. );
  226. if(hInf == INVALID_HANDLE_VALUE) {
  227. //
  228. // Failed to open the INF. This is incredibly odd, since we just got
  229. // through validating the INF's digital signature...
  230. //
  231. goto clean0;
  232. }
  233. if(!SetupDiGetActualSectionToInstall(hInf,
  234. DriverInfoDetailData->SectionName,
  235. InfSectionWithExt,
  236. sizeof(InfSectionWithExt) / sizeof(TCHAR),
  237. NULL,
  238. NULL)
  239. || !SetupFindFirstLine(hInf,
  240. InfSectionWithExt,
  241. TEXT("DiskCiPrivateData"),
  242. &InfContext)
  243. || !SetupGetIntField(&InfContext, 1, &Flags)) {
  244. Flags = 0;
  245. }
  246. SetupCloseInfFile(hInf);
  247. if(Flags & DISKCIPRIVATEDATA_NO_REBOOT_REQUIRED) {
  248. //
  249. // This signed INF is vouching for the fact that no reboot is
  250. // required for full functionality of this disk. Thus, we'll
  251. // clear the DI_NEEDRESTART and DI_NEEDREBOOT flags, so that
  252. // the user won't be prompted to reboot. Note that during the
  253. // default handling routine (SetupDiInstallDevice), a non-fatal
  254. // problem was set on the devnode indicating that a reboot is
  255. // needed. This will not result in a yellow-bang in DevMgr,
  256. // but you would see text in the device status field indicating
  257. // a reboot is needed if you go into the General tab of the
  258. // device's property sheet.
  259. //
  260. CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDRESTART);
  261. CLEAR_FLAG(DeviceInstallParams.Flags, DI_NEEDREBOOT);
  262. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  263. DeviceInfoData,
  264. &DeviceInstallParams
  265. );
  266. }
  267. clean0:
  268. if(DriverInfoData) {
  269. LocalFree(DriverInfoData);
  270. }
  271. if(DriverInfoDetailData) {
  272. LocalFree(DriverInfoDetailData);
  273. }
  274. if(InfSignerInfo) {
  275. LocalFree(InfSignerInfo);
  276. }
  277. }
  278. DWORD
  279. DiskClassInstaller(IN DI_FUNCTION InstallFunction, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
  280. /*++
  281. Routine Description:
  282. This routine is the class installer function for disk drive.
  283. Arguments:
  284. InstallFunction - Supplies the install function.
  285. DeviceInfoSet - Supplies the device info set.
  286. DeviceInfoData - Supplies the device info data.
  287. Return Value:
  288. If this function successfully completed the requested action, the return
  289. value is NO_ERROR.
  290. If the default behavior is to be performed for the requested action, the
  291. return value is ERROR_DI_DO_DEFAULT.
  292. If an error occurred while attempting to perform the requested action, a
  293. Win32 error code is returned.
  294. --*/
  295. {
  296. switch (InstallFunction)
  297. {
  298. case DIF_INSTALLDEVICE:
  299. {
  300. //
  301. // Let the default action occur to get the device installed.
  302. //
  303. if (!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData))
  304. {
  305. //
  306. // Failed to install the device--just return the error reported
  307. //
  308. return GetLastError();
  309. }
  310. //
  311. // Default device install action succeeded, now check for reboot
  312. // requirement and suppress it, if possible.
  313. //
  314. AttemptToSuppressDiskInstallReboot(DeviceInfoSet, DeviceInfoData);
  315. //
  316. // Regardless of whether we successfully suppressed the reboot, we
  317. // still report success, because the install went fine.
  318. //
  319. return NO_ERROR;
  320. }
  321. case DIF_ADDPROPERTYPAGE_ADVANCED:
  322. case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
  323. {
  324. SP_ADDPROPERTYPAGE_DATA AddPropertyPageData = { 0 };
  325. //
  326. // These property sheets are not for the entire class
  327. //
  328. if (DeviceInfoData == NULL)
  329. {
  330. break;
  331. }
  332. AddPropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  333. if (SetupDiGetClassInstallParams(DeviceInfoSet,
  334. DeviceInfoData,
  335. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  336. sizeof(SP_ADDPROPERTYPAGE_DATA),
  337. NULL))
  338. {
  339. //
  340. // Ensure that the maximum number of dynamic pages has not yet been met
  341. //
  342. if (AddPropertyPageData.NumDynamicPages >= MAX_INSTALLWIZARD_DYNAPAGES)
  343. {
  344. return NO_ERROR;
  345. }
  346. if (InstallFunction == DIF_ADDPROPERTYPAGE_ADVANCED)
  347. {
  348. //
  349. // Create the Disk Policies Tab
  350. //
  351. PDISK_PAGE_DATA pData = HeapAlloc(GetProcessHeap(), 0, sizeof(DISK_PAGE_DATA));
  352. if (pData)
  353. {
  354. HPROPSHEETPAGE hPage = NULL;
  355. PROPSHEETPAGE page = { 0 };
  356. pData->DeviceInfoSet = DeviceInfoSet;
  357. pData->DeviceInfoData = DeviceInfoData;
  358. page.dwSize = sizeof(PROPSHEETPAGE);
  359. page.dwFlags = PSP_USECALLBACK;
  360. page.hInstance = ModuleInstance;
  361. page.pszTemplate = MAKEINTRESOURCE(ID_DISK_PROPPAGE);
  362. page.pfnDlgProc = DiskDialogProc;
  363. page.pfnCallback = DiskDialogCallback;
  364. page.lParam = (LPARAM) pData;
  365. hPage = CreatePropertySheetPage(&page);
  366. if (hPage)
  367. {
  368. AddPropertyPageData.DynamicPages[AddPropertyPageData.NumDynamicPages++] = hPage;
  369. }
  370. else
  371. {
  372. HeapFree(GetProcessHeap(), 0, pData);
  373. }
  374. }
  375. }
  376. //
  377. // The Volumes Tab is limited to Administrators
  378. //
  379. if (IsUserAdmin() && AddPropertyPageData.NumDynamicPages < MAX_INSTALLWIZARD_DYNAPAGES)
  380. {
  381. //
  382. // Create the Volumes Tab
  383. //
  384. PVOLUME_PAGE_DATA pData = HeapAlloc(GetProcessHeap(), 0, sizeof(VOLUME_PAGE_DATA));
  385. if (pData)
  386. {
  387. HPROPSHEETPAGE hPage = NULL;
  388. PROPSHEETPAGE page = { 0 };
  389. pData->DeviceInfoSet = DeviceInfoSet;
  390. pData->DeviceInfoData = DeviceInfoData;
  391. page.dwSize = sizeof(PROPSHEETPAGE);
  392. page.dwFlags = PSP_USECALLBACK;
  393. page.hInstance = ModuleInstance;
  394. page.pszTemplate = MAKEINTRESOURCE(ID_VOLUME_PROPPAGE);
  395. page.pfnDlgProc = VolumeDialogProc;
  396. page.pfnCallback = VolumeDialogCallback;
  397. page.lParam = (LPARAM) pData;
  398. hPage = CreatePropertySheetPage(&page);
  399. if (hPage)
  400. {
  401. //
  402. // Look to see if we were launched by Disk Management
  403. //
  404. HMODULE LdmModule = NULL;
  405. pData->bInvokedByDiskmgr = FALSE;
  406. LdmModule = GetModuleHandle(TEXT("dmdskmgr"));
  407. if (LdmModule)
  408. {
  409. IS_REQUEST_PENDING pfnIsRequestPending = (IS_REQUEST_PENDING) GetProcAddress(LdmModule, "IsRequestPending");
  410. if (pfnIsRequestPending)
  411. {
  412. if ((*pfnIsRequestPending)())
  413. {
  414. pData->bInvokedByDiskmgr = TRUE;
  415. }
  416. }
  417. }
  418. AddPropertyPageData.DynamicPages[AddPropertyPageData.NumDynamicPages++] = hPage;
  419. }
  420. else
  421. {
  422. HeapFree(GetProcessHeap(), 0, pData);
  423. }
  424. }
  425. }
  426. SetupDiSetClassInstallParams(DeviceInfoSet,
  427. DeviceInfoData,
  428. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  429. sizeof(SP_ADDPROPERTYPAGE_DATA));
  430. }
  431. return NO_ERROR;
  432. }
  433. }
  434. return ERROR_DI_DO_DEFAULT;
  435. }
  436. HANDLE
  437. GetHandleForDisk(LPTSTR DeviceName)
  438. {
  439. HANDLE h = INVALID_HANDLE_VALUE;
  440. int i = 0;
  441. BOOL success = FALSE;
  442. TCHAR buf[MAX_PATH] = { 0 };
  443. TCHAR fakeDeviceName[MAX_PATH] = { 0 };
  444. h = CreateFile(DeviceName,
  445. GENERIC_WRITE | GENERIC_READ,
  446. FILE_SHARE_WRITE | FILE_SHARE_READ,
  447. NULL,
  448. OPEN_EXISTING,
  449. 0,
  450. NULL);
  451. if (h != INVALID_HANDLE_VALUE)
  452. return h;
  453. while (!success && i < 10) {
  454. _sntprintf(buf, sizeof(buf) / sizeof(buf[0]) - 1, _T("DISK_FAKE_DEVICE_%d_"), i++);
  455. success = DefineDosDevice(DDD_RAW_TARGET_PATH,
  456. buf,
  457. DeviceName);
  458. if (success) {
  459. _sntprintf(fakeDeviceName, sizeof(fakeDeviceName) / sizeof(fakeDeviceName[0]) - 1, _T("\\\\.\\%s"), buf);
  460. h = CreateFile(fakeDeviceName,
  461. GENERIC_WRITE | GENERIC_READ,
  462. FILE_SHARE_WRITE | FILE_SHARE_READ,
  463. NULL,
  464. OPEN_EXISTING,
  465. 0,
  466. NULL);
  467. DefineDosDevice(DDD_REMOVE_DEFINITION,
  468. buf,
  469. NULL);
  470. }
  471. }
  472. return h;
  473. }
  474. UINT
  475. GetCachingPolicy(PDISK_PAGE_DATA data)
  476. {
  477. HANDLE hDisk;
  478. DISK_CACHE_INFORMATION cacheInfo;
  479. TCHAR buf[MAX_PATH] = { 0 };
  480. DWORD len;
  481. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  482. data->DeviceInfoData,
  483. SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
  484. NULL,
  485. (PBYTE)buf,
  486. sizeof(buf) - sizeof(TCHAR),
  487. NULL))
  488. {
  489. return GetLastError();
  490. }
  491. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  492. return ERROR_INVALID_HANDLE;
  493. }
  494. //
  495. // Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
  496. //
  497. if (!DeviceIoControl(hDisk,
  498. IOCTL_DISK_GET_CACHE_INFORMATION,
  499. NULL,
  500. 0,
  501. &cacheInfo,
  502. sizeof(DISK_CACHE_INFORMATION),
  503. &len,
  504. NULL)) {
  505. CloseHandle(hDisk);
  506. return GetLastError();
  507. }
  508. data->OrigWriteCacheSetting = cacheInfo.WriteCacheEnabled;
  509. data->CurrWriteCacheSetting = cacheInfo.WriteCacheEnabled;
  510. //
  511. // Get the cache setting - IOCTL_DISK_GET_CACHE_SETTING
  512. //
  513. if (!DeviceIoControl(hDisk,
  514. IOCTL_DISK_GET_CACHE_SETTING,
  515. NULL,
  516. 0,
  517. &data->CacheSetting,
  518. sizeof(DISK_CACHE_SETTING),
  519. &len,
  520. NULL)) {
  521. CloseHandle(hDisk);
  522. return GetLastError();
  523. }
  524. data->CurrentIsPowerProtected = data->CacheSetting.IsPowerProtected;
  525. CloseHandle(hDisk);
  526. return ERROR_SUCCESS;
  527. }
  528. VOID
  529. UpdateCachingPolicy(HWND HWnd, PDISK_PAGE_DATA data)
  530. {
  531. if (data->IsCachingPolicy)
  532. {
  533. if (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
  534. {
  535. //
  536. // This policy requires that no caching be done at any
  537. // level. Uncheck and gray out the write cache setting
  538. //
  539. CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, 0);
  540. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), FALSE);
  541. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), FALSE);
  542. data->CurrWriteCacheSetting = FALSE;
  543. }
  544. else
  545. {
  546. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), TRUE);
  547. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), TRUE);
  548. }
  549. if (data->CurrWriteCacheSetting == FALSE)
  550. {
  551. //
  552. // The power-protected mode option does not apply if
  553. // caching is off. Uncheck and gray out this setting
  554. //
  555. CheckDlgButton(HWnd, IDC_DISK_POLICY_PP_CACHE, 0);
  556. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE), FALSE);
  557. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE_MESG), FALSE);
  558. data->CurrentIsPowerProtected = FALSE;
  559. }
  560. else
  561. {
  562. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE), TRUE);
  563. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE_MESG), TRUE);
  564. }
  565. }
  566. else
  567. {
  568. //
  569. // The caching policy cannot be modified
  570. //
  571. }
  572. }
  573. UINT
  574. SetCachingPolicy(PDISK_PAGE_DATA data)
  575. {
  576. HANDLE hDisk;
  577. DISK_CACHE_INFORMATION cacheInfo;
  578. TCHAR buf[MAX_PATH] = { 0 };
  579. DWORD len;
  580. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  581. data->DeviceInfoData,
  582. SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
  583. NULL,
  584. (PBYTE)buf,
  585. sizeof(buf) - sizeof(TCHAR),
  586. NULL))
  587. {
  588. return GetLastError();
  589. }
  590. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  591. return ERROR_INVALID_HANDLE;
  592. }
  593. data->CacheSetting.IsPowerProtected = (BOOLEAN)data->CurrentIsPowerProtected;
  594. //
  595. // Set the cache setting - IOCTL_DISK_SET_CACHE_SETTING
  596. //
  597. if (!DeviceIoControl(hDisk,
  598. IOCTL_DISK_SET_CACHE_SETTING,
  599. &data->CacheSetting,
  600. sizeof(DISK_CACHE_SETTING),
  601. NULL,
  602. 0,
  603. &len,
  604. NULL)) {
  605. CloseHandle(hDisk);
  606. return GetLastError();
  607. }
  608. //
  609. // Get cache info - IOCTL_DISK_GET_CACHE_INFORMATION
  610. //
  611. if (!DeviceIoControl(hDisk,
  612. IOCTL_DISK_GET_CACHE_INFORMATION,
  613. NULL,
  614. 0,
  615. &cacheInfo,
  616. sizeof(DISK_CACHE_INFORMATION),
  617. &len,
  618. NULL)) {
  619. CloseHandle(hDisk);
  620. return GetLastError();
  621. }
  622. cacheInfo.WriteCacheEnabled = (BOOLEAN)data->CurrWriteCacheSetting;
  623. //
  624. // Set cache info - IOCTL_DISK_SET_CACHE_INFORMATION
  625. //
  626. if (!DeviceIoControl(hDisk,
  627. IOCTL_DISK_SET_CACHE_INFORMATION,
  628. &cacheInfo,
  629. sizeof(DISK_CACHE_INFORMATION),
  630. NULL,
  631. 0,
  632. &len,
  633. NULL)) {
  634. CloseHandle(hDisk);
  635. return GetLastError();
  636. }
  637. data->OrigWriteCacheSetting = data->CurrWriteCacheSetting;
  638. CloseHandle(hDisk);
  639. return ERROR_SUCCESS;
  640. }
  641. UINT
  642. GetRemovalPolicy(PDISK_PAGE_DATA data)
  643. {
  644. HANDLE hDisk;
  645. TCHAR buf[MAX_PATH] = { 0 };
  646. DWORD len;
  647. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  648. data->DeviceInfoData,
  649. SPDRP_REMOVAL_POLICY,
  650. NULL,
  651. (PBYTE)&data->DefaultRemovalPolicy,
  652. sizeof(DWORD),
  653. NULL))
  654. {
  655. return GetLastError();
  656. }
  657. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  658. data->DeviceInfoData,
  659. SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
  660. NULL,
  661. (PBYTE)buf,
  662. sizeof(buf) - sizeof(TCHAR),
  663. NULL))
  664. {
  665. return GetLastError();
  666. }
  667. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  668. return ERROR_INVALID_HANDLE;
  669. }
  670. //
  671. // Get hotplug info - IOCTL_STORAGE_GET_HOTPLUG_INFO
  672. //
  673. if (!DeviceIoControl(hDisk,
  674. IOCTL_STORAGE_GET_HOTPLUG_INFO,
  675. NULL,
  676. 0,
  677. &data->HotplugInfo,
  678. sizeof(STORAGE_HOTPLUG_INFO),
  679. &len,
  680. NULL)) {
  681. CloseHandle(hDisk);
  682. return GetLastError();
  683. }
  684. data->CurrentRemovalPolicy = (data->HotplugInfo.DeviceHotplug) ? CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL : CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
  685. CloseHandle(hDisk);
  686. return ERROR_SUCCESS;
  687. }
  688. DWORD WINAPI
  689. UtilpRestartDeviceWr(PDISK_PAGE_DATA data)
  690. {
  691. UtilpRestartDevice(data->DeviceInfoSet, data->DeviceInfoData);
  692. return ERROR_SUCCESS;
  693. }
  694. VOID
  695. UtilpRestartDeviceEx(HWND HWnd, PDISK_PAGE_DATA data)
  696. {
  697. HANDLE hThread = NULL;
  698. MSG msg;
  699. //
  700. // Temporary workaround to prevent the user from
  701. // making any more changes and giving the effect
  702. // that something is happening
  703. //
  704. EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), FALSE);
  705. EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), FALSE);
  706. data->IsBusy = TRUE;
  707. //
  708. // Call this utility on a seperate thread
  709. //
  710. hThread = CreateThread(NULL, 0, UtilpRestartDeviceWr, (LPVOID)data, 0, NULL);
  711. if (hThread)
  712. {
  713. while (1)
  714. {
  715. if (MsgWaitForMultipleObjects(1, &hThread, FALSE, INFINITE, QS_ALLINPUT) != (WAIT_OBJECT_0 + 1))
  716. {
  717. break;
  718. }
  719. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  720. {
  721. if (!PropSheet_IsDialogMessage(HWnd, &msg))
  722. {
  723. TranslateMessage(&msg);
  724. DispatchMessage(&msg);
  725. }
  726. }
  727. }
  728. CloseHandle(hThread);
  729. }
  730. data->IsBusy = FALSE;
  731. EnableWindow(GetDlgItem(GetParent(HWnd), IDOK), TRUE);
  732. EnableWindow(GetDlgItem(GetParent(HWnd), IDCANCEL), TRUE);
  733. }
  734. UINT
  735. SetRemovalPolicy(HWND HWnd, PDISK_PAGE_DATA data)
  736. {
  737. HANDLE hDisk;
  738. TCHAR buf[MAX_PATH] = { 0 };
  739. DWORD len;
  740. if (!SetupDiGetDeviceRegistryProperty(data->DeviceInfoSet,
  741. data->DeviceInfoData,
  742. SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
  743. NULL,
  744. (PBYTE)buf,
  745. sizeof(buf) - sizeof(TCHAR),
  746. NULL))
  747. {
  748. return GetLastError();
  749. }
  750. if (INVALID_HANDLE_VALUE == (hDisk = GetHandleForDisk(buf))) {
  751. return ERROR_INVALID_HANDLE;
  752. }
  753. data->HotplugInfo.DeviceHotplug = (data->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) ? TRUE : FALSE;
  754. //
  755. // Set hotplug info - IOCTL_STORAGE_SET_HOTPLUG_INFO
  756. //
  757. if (!DeviceIoControl(hDisk,
  758. IOCTL_STORAGE_SET_HOTPLUG_INFO,
  759. &data->HotplugInfo,
  760. sizeof(STORAGE_HOTPLUG_INFO),
  761. NULL,
  762. 0,
  763. &len,
  764. NULL)) {
  765. CloseHandle(hDisk);
  766. return GetLastError();
  767. }
  768. CloseHandle(hDisk);
  769. UtilpRestartDeviceEx(HWnd, data);
  770. return ERROR_SUCCESS;
  771. }
  772. BOOL
  773. DiskOnInitDialog(HWND HWnd, HWND HWndFocus, LPARAM LParam)
  774. {
  775. LPPROPSHEETPAGE page = (LPPROPSHEETPAGE) LParam;
  776. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) page->lParam;
  777. UINT status;
  778. //
  779. // Initially assume that the device does not have a surprise removal policy
  780. //
  781. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
  782. diskData->IsBusy = FALSE;
  783. //
  784. // Obtain the Caching Policy
  785. //
  786. status = GetCachingPolicy(diskData);
  787. if (status == ERROR_SUCCESS)
  788. {
  789. diskData->IsCachingPolicy = TRUE;
  790. CheckDlgButton(HWnd, IDC_DISK_POLICY_WRITE_CACHE, diskData->OrigWriteCacheSetting);
  791. //
  792. // Determine the most appropriate message to display under this setting
  793. //
  794. if (diskData->CacheSetting.State != DiskCacheNormal)
  795. {
  796. TCHAR szMesg[MAX_PATH] = { 0 };
  797. //
  798. // The write caching option on this device should either be
  799. // disabled (to protect data integrity) or cannot be modified
  800. //
  801. if (diskData->CacheSetting.State == DiskCacheWriteThroughNotSupported)
  802. {
  803. LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG1, szMesg, MAX_PATH);
  804. }
  805. else if (diskData->CacheSetting.State == DiskCacheModifyUnsuccessful)
  806. {
  807. LoadString(ModuleInstance, IDS_DISK_POLICY_WRITE_CACHE_MSG2, szMesg, MAX_PATH);
  808. }
  809. SetDlgItemText(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG, szMesg);
  810. }
  811. //
  812. // The power-protected mode option does not apply if
  813. // caching is off. Uncheck and gray out this setting
  814. //
  815. if (diskData->OrigWriteCacheSetting == FALSE)
  816. {
  817. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE), FALSE);
  818. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE_MESG), FALSE);
  819. diskData->CurrentIsPowerProtected = FALSE;
  820. }
  821. CheckDlgButton(HWnd, IDC_DISK_POLICY_PP_CACHE, diskData->CurrentIsPowerProtected);
  822. }
  823. else
  824. {
  825. //
  826. // Either we could not open a handle to the device
  827. // or this device does not support write caching
  828. //
  829. diskData->IsCachingPolicy = FALSE;
  830. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE), SW_HIDE);
  831. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_WRITE_CACHE_MESG), SW_HIDE);
  832. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE), SW_HIDE);
  833. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_PP_CACHE_MESG), SW_HIDE);
  834. }
  835. //
  836. // Obtain the Removal Policy
  837. //
  838. status = GetRemovalPolicy(diskData);
  839. if (status == ERROR_SUCCESS)
  840. {
  841. //
  842. // Check to see if the drive is removable
  843. //
  844. if ((diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) ||
  845. (diskData->DefaultRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL))
  846. {
  847. if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL)
  848. {
  849. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
  850. UpdateCachingPolicy(HWnd, diskData);
  851. }
  852. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_DEFAULT), SW_SHOW);
  853. }
  854. else
  855. {
  856. //
  857. // The removal policy on fixed disks cannot be modified
  858. //
  859. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
  860. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
  861. //
  862. // Replace the SysLink with static text
  863. //
  864. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
  865. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
  866. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
  867. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
  868. }
  869. }
  870. else
  871. {
  872. //
  873. // We could not obtain a removal policy
  874. //
  875. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE), FALSE);
  876. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_SURPRISE_MESG), FALSE);
  877. //
  878. // Replace the SysLink with static text
  879. //
  880. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MESG), SW_HIDE);
  881. ShowWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), SW_SHOW);
  882. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY), FALSE);
  883. EnableWindow(GetDlgItem(HWnd, IDC_DISK_POLICY_ORDERLY_MSGD), FALSE);
  884. }
  885. SetWindowLongPtr(HWnd, DWLP_USER, (LONG_PTR) diskData);
  886. return TRUE;
  887. }
  888. VOID
  889. DiskOnCommand(HWND HWnd, INT id, HWND HWndCtl, UINT codeNotify)
  890. {
  891. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
  892. switch (id)
  893. {
  894. case IDC_DISK_POLICY_SURPRISE:
  895. {
  896. diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL;
  897. UpdateCachingPolicy(HWnd, diskData);
  898. PropSheet_Changed(GetParent(HWnd), HWnd);
  899. break;
  900. }
  901. case IDC_DISK_POLICY_ORDERLY:
  902. {
  903. diskData->CurrentRemovalPolicy = CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL;
  904. UpdateCachingPolicy(HWnd, diskData);
  905. PropSheet_Changed(GetParent(HWnd), HWnd);
  906. break;
  907. }
  908. case IDC_DISK_POLICY_WRITE_CACHE:
  909. {
  910. diskData->CurrWriteCacheSetting = !diskData->CurrWriteCacheSetting;
  911. UpdateCachingPolicy(HWnd, diskData);
  912. PropSheet_Changed(GetParent(HWnd), HWnd);
  913. break;
  914. }
  915. case IDC_DISK_POLICY_PP_CACHE:
  916. {
  917. diskData->CurrentIsPowerProtected = !diskData->CurrentIsPowerProtected;
  918. PropSheet_Changed(GetParent(HWnd), HWnd);
  919. break;
  920. }
  921. case IDC_DISK_POLICY_DEFAULT:
  922. {
  923. if (diskData->CurrentRemovalPolicy != diskData->DefaultRemovalPolicy)
  924. {
  925. diskData->CurrentRemovalPolicy = diskData->DefaultRemovalPolicy;
  926. if (diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL)
  927. {
  928. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_ORDERLY);
  929. }
  930. else
  931. {
  932. CheckRadioButton(HWnd, IDC_DISK_POLICY_SURPRISE, IDC_DISK_POLICY_ORDERLY, IDC_DISK_POLICY_SURPRISE);
  933. }
  934. UpdateCachingPolicy(HWnd, diskData);
  935. PropSheet_Changed(GetParent(HWnd), HWnd);
  936. }
  937. break;
  938. }
  939. }
  940. }
  941. LRESULT
  942. DiskOnNotify(HWND HWnd, INT HWndFocus, LPNMHDR lpNMHdr)
  943. {
  944. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(HWnd, DWLP_USER);
  945. switch (lpNMHdr->code)
  946. {
  947. case PSN_APPLY:
  948. {
  949. if (diskData->IsCachingPolicy)
  950. {
  951. if ((diskData->CurrWriteCacheSetting != diskData->OrigWriteCacheSetting) ||
  952. (diskData->CacheSetting.IsPowerProtected != diskData->CurrentIsPowerProtected))
  953. {
  954. SetCachingPolicy(diskData);
  955. }
  956. }
  957. if (((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == TRUE)) ||
  958. ((diskData->CurrentRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL) && (diskData->HotplugInfo.DeviceHotplug == FALSE)))
  959. {
  960. SetRemovalPolicy(HWnd, diskData);
  961. }
  962. break;
  963. }
  964. case NM_RETURN:
  965. case NM_CLICK:
  966. {
  967. TCHAR szPath[MAX_PATH] = { 0 };
  968. LoadString(ModuleInstance, IDS_DISK_POLICY_HOTPLUG, szPath, MAX_PATH);
  969. ShellExecute(NULL, _T("open"), _T("RUNDLL32.EXE"), szPath, NULL, SW_SHOWNORMAL);
  970. break;
  971. }
  972. }
  973. return 0;
  974. }
  975. VOID
  976. DiskContextMenu(HWND HwndControl, WORD Xpos, WORD Ypos)
  977. {
  978. WinHelp(HwndControl, _T("devmgr.hlp"), HELP_CONTEXTMENU, (ULONG_PTR) DiskHelpIDs);
  979. }
  980. VOID
  981. DiskHelp(HWND ParentHwnd, LPHELPINFO HelpInfo)
  982. {
  983. if (HelpInfo->iContextType == HELPINFO_WINDOW)
  984. {
  985. WinHelp((HWND) HelpInfo->hItemHandle, _T("devmgr.hlp"), HELP_WM_HELP, (ULONG_PTR) DiskHelpIDs);
  986. }
  987. }
  988. INT_PTR
  989. DiskDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
  990. {
  991. switch(Message)
  992. {
  993. HANDLE_MSG(hWnd, WM_INITDIALOG, DiskOnInitDialog);
  994. HANDLE_MSG(hWnd, WM_COMMAND, DiskOnCommand);
  995. HANDLE_MSG(hWnd, WM_NOTIFY, DiskOnNotify);
  996. case WM_SETCURSOR:
  997. {
  998. //
  999. // Temporary workaround to prevent the user from
  1000. // making any more changes and giving the effect
  1001. // that something is happening
  1002. //
  1003. PDISK_PAGE_DATA diskData = (PDISK_PAGE_DATA) GetWindowLongPtr(hWnd, DWLP_USER);
  1004. if (diskData->IsBusy)
  1005. {
  1006. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1007. SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
  1008. return TRUE;
  1009. }
  1010. break;
  1011. }
  1012. case WM_CONTEXTMENU:
  1013. DiskContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  1014. break;
  1015. case WM_HELP:
  1016. DiskHelp(hWnd, (LPHELPINFO)lParam);
  1017. break;
  1018. }
  1019. return FALSE;
  1020. }
  1021. BOOL
  1022. DiskDialogCallback(HWND HWnd, UINT Message, LPPROPSHEETPAGE Page)
  1023. {
  1024. switch (Message)
  1025. {
  1026. case PSPCB_CREATE:
  1027. {
  1028. break;
  1029. }
  1030. case PSPCB_RELEASE:
  1031. {
  1032. PDISK_PAGE_DATA pData = (PDISK_PAGE_DATA) Page->lParam;
  1033. HeapFree(GetProcessHeap(), 0, pData);
  1034. break;
  1035. }
  1036. }
  1037. return TRUE;
  1038. }