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.

1276 lines
35 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. RedBook.c
  5. Abstract:
  6. This command line utility adds and removes redbook
  7. for a given drive.
  8. Author:
  9. Henry Gabryjelski (henrygab)
  10. Environment:
  11. user mode only
  12. Notes:
  13. Revision History:
  14. 07-30-98 : Created
  15. --*/
  16. #include "propp.h"
  17. #include "storprop.h"
  18. //
  19. // redefine these to do what i want them to.
  20. // allows the appearance of structured c++ with
  21. // the performance of c.
  22. //
  23. #ifdef TRY
  24. #undef TRY
  25. #endif
  26. #ifdef LEAVE
  27. #undef LEAVE
  28. #endif
  29. #ifdef FINALLY
  30. #undef FINALLY
  31. #endif
  32. #define TRY
  33. #define LEAVE goto __label;
  34. #define FINALLY __label:
  35. //
  36. // just to give out unique errors
  37. //
  38. #define ERROR_REDBOOK_FILTER 0x80ff00f0L
  39. #define ERROR_REDBOOK_PASS_THROUGH 0x80ff00f1L
  40. #if DBG
  41. #ifdef UNICODE
  42. #define DbgPrintAllMultiSz DbgPrintAllMultiSzW
  43. #else
  44. #define DbgPrintAllMultiSz DbgPrintAllMultiSzA
  45. #endif // UNICODE
  46. VOID DbgPrintAllMultiSzW(WCHAR *String)
  47. {
  48. ULONG i = 0;
  49. while(*String != UNICODE_NULL) {
  50. DebugPrint((1, "StorProp => MultiSz %3d: %ws\n", i++, String));
  51. while (*String != UNICODE_NULL) {
  52. String++;
  53. }
  54. String++; // go past the first NULL
  55. }
  56. }
  57. VOID DbgPrintAllMultiSzA(CHAR *String)
  58. {
  59. ULONG i = 0;
  60. while(*String != ANSI_NULL) {
  61. DebugPrint((1, "StorProp => MultiSz %3d: %ws\n", i++, String));
  62. while (*String != ANSI_NULL) {
  63. String++;
  64. }
  65. String++; // go past the first NULL
  66. }
  67. }
  68. #else // !DBG
  69. #define DbgPrintAllMultiSz
  70. #define DbgPrintAllMultiSz
  71. #endif // DBG
  72. ////////////////////////////////////////////////////////////////////////////////
  73. // Local prototypes, not exported anywhere
  74. BOOL
  75. IsUserAdmin();
  76. LONG
  77. RedbookpUpperFilterRegDelete(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData);
  78. LONG
  79. RedbookpUpperFilterRegInstall(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData);
  80. BOOLEAN
  81. UtilpIsSingleSzOfMultiSzInMultiSz(
  82. IN LPTSTR FindOneOfThese,
  83. IN LPTSTR WithinThese
  84. );
  85. DWORD
  86. UtilpMultiSzSearchAndDeleteCaseInsensitive(
  87. LPTSTR FindThis,
  88. LPTSTR FindWithin,
  89. DWORD *NewStringLength
  90. );
  91. ////////////////////////////////////////////////////////////////////////////////
  92. ////////////////////////////////////////////////////////////////////////////////
  93. //
  94. // the actual callbacks should do very little, codewise
  95. //
  96. ////////////////////////////////////////////////////////////////////////////////
  97. DWORD
  98. CdromCddaInfo(
  99. IN HDEVINFO HDevInfo,
  100. IN PSP_DEVINFO_DATA DevInfoData,
  101. OUT PREDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO CddaInfo,
  102. IN OUT PULONG BufferSize
  103. )
  104. /*++
  105. Routine Description:
  106. Returns whether the drive is a 'known good' drive.
  107. Returns whether the drive supports CDDA at all.
  108. Returns whether the drive supports accurate CDDA for only some read sizes.
  109. ...
  110. Arguments:
  111. CDDAInfo must point to a pre-allocated buffer for this info
  112. BufferSize will give size of this buffer, to allow for more fields
  113. to be added later in a safe manner.
  114. Return Value:
  115. will return ERROR_SUCCESS/STATUS_SUCCESS (both zero)
  116. Notes:
  117. If cannot open these registry keys, will default to FALSE,
  118. since the caller will most likely not have the ability to enable
  119. redbook anyways.
  120. --*/
  121. {
  122. HKEY enumHandle = INVALID_HANDLE_VALUE;
  123. HKEY subkeyHandle = INVALID_HANDLE_VALUE;
  124. REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO info;
  125. ULONG i;
  126. DWORD dataType;
  127. DWORD dataSize;
  128. LONG error;
  129. error = ERROR_SUCCESS;
  130. if ((*BufferSize == 0) || (CddaInfo == NULL)) {
  131. *BufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
  132. return ERROR_INSUFFICIENT_BUFFER;
  133. }
  134. RtlZeroMemory(CddaInfo, *BufferSize);
  135. RtlZeroMemory(&info, sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO));
  136. info.Version = REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO_VERSION;
  137. TRY {
  138. enumHandle = SetupDiOpenDevRegKey(HDevInfo,
  139. DevInfoData,
  140. DICS_FLAG_GLOBAL,
  141. 0,
  142. DIREG_DEV,
  143. KEY_READ);
  144. if (enumHandle == INVALID_HANDLE_VALUE) {
  145. DebugPrint((1, "StorProp.CddaInfo => unable to open dev key\n"));
  146. error = ERROR_OUT_OF_PAPER;
  147. LEAVE;
  148. }
  149. error = RegOpenKey(enumHandle, TEXT("DigitalAudio"), &subkeyHandle);
  150. if (error != ERROR_SUCCESS) {
  151. DebugPrint((1, "StorProp.CddaInfo => unable to open subkey\n"));
  152. LEAVE;
  153. }
  154. for (i=0; i<3; i++) {
  155. PBYTE buffer;
  156. TCHAR * keyName;
  157. if (i == 0) {
  158. keyName = TEXT("CDDAAccurate");
  159. buffer = (PBYTE)(&info.Accurate);
  160. } else if (i == 1) {
  161. keyName = TEXT("CDDASupported");
  162. buffer = (PBYTE)(&info.Supported);
  163. } else if (i == 2) {
  164. keyName = TEXT("ReadSizesSupported");
  165. buffer = (PBYTE)(&info.AccurateMask0);
  166. #if DBG
  167. } else {
  168. DebugPrint((0, "StorProp.CddaInfo => Looping w/o handling\n"));
  169. DebugBreak();
  170. #endif
  171. }
  172. dataSize = sizeof(DWORD);
  173. error = RegQueryValueEx(subkeyHandle,
  174. keyName,
  175. NULL,
  176. &dataType,
  177. buffer,
  178. &dataSize);
  179. if (error != ERROR_SUCCESS) {
  180. DebugPrint((1, "StorProp.CddaInfo => unable to query %ws %x\n",
  181. keyName, error));
  182. LEAVE;
  183. }
  184. if (dataType != REG_DWORD) {
  185. DebugPrint((1, "StorProp.CddaInfo => %ws wrong data type (%x)\n",
  186. keyName, dataType));
  187. error = ERROR_INVALID_DATA;
  188. LEAVE;
  189. }
  190. DebugPrint((1, "StorProp.CddaInfo => %ws == %x\n",
  191. keyName, *buffer));
  192. }
  193. } FINALLY {
  194. if (subkeyHandle != INVALID_HANDLE_VALUE) {
  195. RegCloseKey(subkeyHandle);
  196. }
  197. if (enumHandle != INVALID_HANDLE_VALUE) {
  198. RegCloseKey(enumHandle);
  199. }
  200. if (error == ERROR_SUCCESS) {
  201. //
  202. // everything succeeded -- copy only the amount they requested
  203. // and don't care about it being aligned on any particular buffer size.
  204. // this is the only other place the user buffer should be modified
  205. //
  206. if (*BufferSize > sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) {
  207. *BufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
  208. }
  209. DebugPrint((2, "StorProp.CddaInfo => everything worked\n"));
  210. RtlCopyMemory(CddaInfo, &info, *BufferSize);
  211. } else {
  212. DebugPrint((2, "StorProp.CddaInfo => something failed\n"));
  213. *BufferSize = 0;
  214. }
  215. }
  216. return error;
  217. }
  218. BOOL
  219. CdromKnownGoodDigitalPlayback(
  220. IN HDEVINFO HDevInfo,
  221. IN PSP_DEVINFO_DATA DevInfoData
  222. )
  223. /*++
  224. Routine Description:
  225. Returns whether this drive is a 'known good' drive.
  226. Arguments:
  227. Return Value:
  228. Notes:
  229. default to FALSE, since if fails, caller probably does not
  230. have ability to enable redbook anyways.
  231. this routine is outdated -- callers should call CdromCddaInfo()
  232. directly for more exact information.
  233. --*/
  234. {
  235. REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO CddaInfo;
  236. ULONG bufferSize;
  237. DWORD error;
  238. bufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
  239. #if DBG
  240. DbgPrint("\n\nOutdated call to CdromKnownGoodDigitalPlayback(), "
  241. "should be calling CdromCddaInfo()\n\n");
  242. #endif // DBG
  243. error = CdromCddaInfo(HDevInfo, DevInfoData, &CddaInfo, &bufferSize);
  244. if (error != ERROR_SUCCESS) {
  245. return FALSE;
  246. }
  247. if (bufferSize <= sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) {
  248. return FALSE;
  249. }
  250. if (CddaInfo.Accurate) {
  251. return TRUE;
  252. }
  253. if (CddaInfo.Supported && CddaInfo.AccurateMask0) {
  254. return TRUE;
  255. }
  256. return FALSE;
  257. }
  258. LONG
  259. CdromEnableDigitalPlayback(
  260. IN HDEVINFO HDevInfo,
  261. IN PSP_DEVINFO_DATA DevInfoData,
  262. IN BOOLEAN ForceUnknown
  263. )
  264. /*++
  265. Routine Description:
  266. Enables redbook
  267. 1) add redbook to filter list (if not there)
  268. 2) if not on stack (via test of guid) re-start stack
  269. 3) if still not on stack, error
  270. 4) set wmi guid item enabled
  271. Arguments:
  272. DevInfo - the device to enable it on
  273. DevInfoData -
  274. ForceUnknown - will set a popup if not a known good drive and this is false
  275. Return Value:
  276. ERROR_XXX value
  277. --*/
  278. {
  279. LONG status;
  280. SP_DEVINSTALL_PARAMS devInstallParameters;
  281. REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO digitalInfo;
  282. ULONG digitalInfoSize;
  283. BOOLEAN enableIt;
  284. //
  285. // restrict to administrator ???
  286. //
  287. if (!IsUserAdmin()) {
  288. DebugPrint((1, "StorProp.Enable => you need to be administrator to "
  289. "enable redbook\n"));
  290. return ERROR_ACCESS_DENIED;
  291. }
  292. digitalInfoSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
  293. RtlZeroMemory(&digitalInfo, digitalInfoSize);
  294. status = CdromCddaInfo(HDevInfo, DevInfoData,
  295. &digitalInfo, &digitalInfoSize);
  296. if (status != ERROR_SUCCESS) {
  297. DebugPrint((1, "StorProp.Enable => not success getting info %x\n",
  298. status));
  299. //
  300. // fake some info
  301. //
  302. digitalInfo.Version = REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO_VERSION;
  303. digitalInfo.Accurate = 0;
  304. digitalInfo.Supported = 1;
  305. digitalInfo.AccurateMask0 = -1;
  306. digitalInfoSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
  307. }
  308. if (digitalInfoSize < sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) {
  309. DebugPrint((3, "StorProp.Enable => returned %x bytes? (not %x)\n",
  310. digitalInfoSize,
  311. sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)
  312. ));
  313. return ERROR_ACCESS_DENIED;
  314. }
  315. if (!digitalInfo.Supported) {
  316. DebugPrint((1, "StorProp.Enable => This drive will never "
  317. "support redbook\n"));
  318. // return ERROR_INVALID_FUNCTION; // log an error here?
  319. }
  320. //
  321. // if it's not accurate AND we don't have the compensating info AND
  322. // they didn't force it to install, then popup a dialog.
  323. //
  324. if (!(digitalInfo.Accurate) &&
  325. !(digitalInfo.AccurateMask0) &&
  326. !(ForceUnknown)
  327. ) {
  328. BOOLEAN okToProceed = FALSE;
  329. TCHAR buffer[MAX_PATH+1];
  330. TCHAR bufferTitle[MAX_PATH+1];
  331. buffer[0] = '\0';
  332. bufferTitle[0] = '\0';
  333. buffer[MAX_PATH] = '\0';
  334. bufferTitle[MAX_PATH] = '\0';
  335. //
  336. // not forced, and not known good. pop up a box asking permission
  337. //
  338. LoadString(ModuleInstance,
  339. REDBOOK_UNKNOWN_DRIVE_CONFIRM,
  340. buffer,
  341. MAX_PATH);
  342. LoadString(ModuleInstance,
  343. REDBOOK_UNKNOWN_DRIVE_CONFIRM_TITLE,
  344. bufferTitle,
  345. MAX_PATH);
  346. if (MessageBox(GetDesktopWindow(),
  347. buffer,
  348. bufferTitle,
  349. MB_YESNO | // ok and cancel buttons
  350. MB_ICONQUESTION | // question icon
  351. MB_DEFBUTTON2 | // cancel is default
  352. MB_SYSTEMMODAL // must respond to this box
  353. ) == IDYES) {
  354. okToProceed = TRUE;
  355. }
  356. if (!okToProceed) {
  357. DebugPrint((3, "StorProp.Enable => User did not force installation "
  358. "on unknown drive\n"));
  359. return ERROR_REDBOOK_FILTER;
  360. }
  361. }
  362. //
  363. // ensure it is in the filter list
  364. //
  365. RedbookpUpperFilterRegInstall(HDevInfo, DevInfoData);
  366. //
  367. // restart the device to load redbook
  368. //
  369. if (!UtilpRestartDevice(HDevInfo, DevInfoData)) {
  370. DebugPrint((1, "StorProp.Enable => Restart failed\n"));
  371. } else {
  372. DebugPrint((1, "StorProp.Enable => Restart succeeded\n"));
  373. }
  374. return ERROR_SUCCESS;
  375. }
  376. LONG
  377. CdromDisableDigitalPlayback(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData)
  378. {
  379. DWORD status = ERROR_SUCCESS;
  380. //
  381. // This API is restrict to admins only
  382. //
  383. if (!IsUserAdmin())
  384. {
  385. DebugPrint((1, "StorProp.Disable => User is not administrator\n"));
  386. return ERROR_ACCESS_DENIED;
  387. }
  388. //
  389. // Delete redbook from the upper filters list regardless
  390. //
  391. status = RedbookpUpperFilterRegDelete(HDevInfo, DevInfoData);
  392. if (status == ERROR_SUCCESS)
  393. {
  394. //
  395. // Restart the device to remove redbook from the stack
  396. //
  397. UtilpRestartDevice(HDevInfo, DevInfoData);
  398. }
  399. return status;
  400. }
  401. LONG
  402. CdromIsDigitalPlaybackEnabled(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData, OUT PBOOLEAN Enabled)
  403. {
  404. DWORD status = ERROR_SUCCESS;
  405. DWORD dwSize = 0;
  406. *Enabled = FALSE;
  407. status = SetupDiGetDeviceRegistryProperty(HDevInfo,
  408. DevInfoData,
  409. SPDRP_UPPERFILTERS,
  410. NULL,
  411. NULL,
  412. 0,
  413. &dwSize) ? ERROR_SUCCESS : GetLastError();
  414. if (status == ERROR_INSUFFICIENT_BUFFER)
  415. {
  416. TCHAR* szBuffer = LocalAlloc(LPTR, dwSize);
  417. if (szBuffer)
  418. {
  419. if (SetupDiGetDeviceRegistryProperty(HDevInfo,
  420. DevInfoData,
  421. SPDRP_UPPERFILTERS,
  422. NULL,
  423. (PBYTE)szBuffer,
  424. dwSize,
  425. NULL))
  426. {
  427. if (UtilpIsSingleSzOfMultiSzInMultiSz(_T("redbook\0"), szBuffer))
  428. {
  429. //
  430. // Digital playback is indeed enabled
  431. //
  432. *Enabled = TRUE;
  433. }
  434. status = ERROR_SUCCESS;
  435. }
  436. else
  437. {
  438. status = GetLastError();
  439. }
  440. LocalFree(szBuffer);
  441. }
  442. else
  443. {
  444. status = ERROR_NOT_ENOUGH_MEMORY;
  445. }
  446. }
  447. else if (status == ERROR_INVALID_DATA)
  448. {
  449. //
  450. // There probably isn't any upper filter installed
  451. //
  452. status = ERROR_SUCCESS;
  453. }
  454. return status;
  455. }
  456. ////////////////////////////////////////////////////////////////////////////////
  457. //
  458. // The support routines do all the work....
  459. //
  460. ////////////////////////////////////////////////////////////////////////////////
  461. HANDLE
  462. UtilpGetDeviceHandle(
  463. HDEVINFO DevInfo,
  464. PSP_DEVINFO_DATA DevInfoData,
  465. LPGUID ClassGuid,
  466. DWORD DesiredAccess
  467. )
  468. /*++
  469. Routine Description:
  470. gets a handle for a device
  471. Arguments:
  472. the name of the device to open
  473. Return Value:
  474. handle to the device opened, which must be later closed by the caller.
  475. Notes:
  476. this function is also in the class installer (syssetup.dll)
  477. so please propogate fixes there as well
  478. --*/
  479. {
  480. BOOL status;
  481. ULONG i;
  482. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  483. SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
  484. HDEVINFO devInfoWithInterface = NULL;
  485. PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
  486. PTSTR deviceInstanceId = NULL;
  487. ULONG deviceInterfaceDetailDataSize;
  488. ULONG deviceInstanceIdSize;
  489. TRY {
  490. //
  491. // get the ID for this device
  492. //
  493. for (i=deviceInstanceIdSize=0; i<2; i++) {
  494. if (deviceInstanceIdSize != 0) {
  495. //
  496. // deviceInstanceIdSize is returned in CHARACTERS
  497. // by SetupDiGetDeviceInstanceId(), so must allocate
  498. // returned size * sizeof(TCHAR)
  499. //
  500. deviceInstanceId =
  501. LocalAlloc(LPTR, deviceInstanceIdSize * sizeof(TCHAR));
  502. if (deviceInstanceId == NULL) {
  503. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to "
  504. "allocate for deviceInstanceId\n"));
  505. LEAVE;
  506. }
  507. }
  508. status = SetupDiGetDeviceInstanceId(DevInfo,
  509. DevInfoData,
  510. deviceInstanceId,
  511. deviceInstanceIdSize,
  512. &deviceInstanceIdSize
  513. );
  514. }
  515. if (!status) {
  516. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get "
  517. "Device IDs\n"));
  518. LEAVE;
  519. }
  520. //
  521. // Get all the cdroms in the system
  522. //
  523. devInfoWithInterface = SetupDiGetClassDevs(ClassGuid,
  524. deviceInstanceId,
  525. NULL,
  526. DIGCF_DEVICEINTERFACE
  527. );
  528. if (devInfoWithInterface == NULL) {
  529. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get "
  530. "list of CdRom's in system\n"));
  531. LEAVE;
  532. }
  533. memset(&deviceInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
  534. deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  535. status = SetupDiEnumDeviceInterfaces(devInfoWithInterface,
  536. NULL,
  537. ClassGuid,
  538. 0,
  539. &deviceInterfaceData
  540. );
  541. if (!status) {
  542. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get "
  543. "SP_DEVICE_INTERFACE_DATA\n"));
  544. LEAVE;
  545. }
  546. for (i=deviceInterfaceDetailDataSize=0; i<2; i++) {
  547. if (deviceInterfaceDetailDataSize != 0) {
  548. //
  549. // deviceInterfaceDetailDataSize is returned in BYTES
  550. // by SetupDiGetDeviceInstanceId(), so must allocate
  551. // returned size only
  552. //
  553. deviceInterfaceDetailData =
  554. LocalAlloc (LPTR, deviceInterfaceDetailDataSize);
  555. if (deviceInterfaceDetailData == NULL) {
  556. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to "
  557. "allocate for deviceInterfaceDetailData\n"));
  558. LEAVE;
  559. }
  560. deviceInterfaceDetailData->cbSize =
  561. sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  562. }
  563. status = SetupDiGetDeviceInterfaceDetail(devInfoWithInterface,
  564. &deviceInterfaceData,
  565. deviceInterfaceDetailData,
  566. deviceInterfaceDetailDataSize,
  567. &deviceInterfaceDetailDataSize,
  568. NULL);
  569. }
  570. if (!status) {
  571. DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get "
  572. "DeviceInterfaceDetail\n"));
  573. LEAVE;
  574. }
  575. if (deviceInterfaceDetailDataSize <=
  576. FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath)) {
  577. DebugPrint((1, "StorProp.GetDeviceHandle => No device path\n"));
  578. status = ERROR_PATH_NOT_FOUND;
  579. LEAVE;
  580. }
  581. //
  582. // no need to memcpy it, just use the path returned to us.
  583. //
  584. fileHandle = CreateFile(deviceInterfaceDetailData->DevicePath,
  585. DesiredAccess,
  586. FILE_SHARE_READ | FILE_SHARE_WRITE,
  587. NULL,
  588. OPEN_EXISTING,
  589. 0,
  590. NULL);
  591. if (fileHandle == INVALID_HANDLE_VALUE) {
  592. DebugPrint((1, "StorProp.GetDeviceHandle => Final CreateFile() "
  593. "failed\n"));
  594. LEAVE;
  595. }
  596. DebugPrint((3, "StorProp.GetDeviceHandle => handle %x opened\n",
  597. fileHandle));
  598. } FINALLY {
  599. if (devInfoWithInterface != NULL) {
  600. SetupDiDestroyDeviceInfoList(devInfoWithInterface);
  601. }
  602. if (deviceInterfaceDetailData != NULL) {
  603. LocalFree (deviceInterfaceDetailData);
  604. }
  605. }
  606. return fileHandle;
  607. }
  608. BOOLEAN
  609. UtilpRestartDevice(
  610. IN HDEVINFO HDevInfo,
  611. IN PSP_DEVINFO_DATA DevInfoData
  612. )
  613. /*++
  614. Routine Description:
  615. Arguments:
  616. Return Value:
  617. --*/
  618. {
  619. SP_PROPCHANGE_PARAMS parameters;
  620. SP_DEVINSTALL_PARAMS installParameters;
  621. BOOLEAN succeeded = FALSE;
  622. RtlZeroMemory(&parameters, sizeof(SP_PROPCHANGE_PARAMS));
  623. RtlZeroMemory(&installParameters, sizeof(SP_DEVINSTALL_PARAMS));
  624. //
  625. // Initialize the SP_CLASSINSTALL_HEADER struct at the beginning of the
  626. // SP_PROPCHANGE_PARAMS struct. this allows SetupDiSetClassInstallParams
  627. // to work.
  628. //
  629. parameters.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  630. parameters.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  631. //
  632. // Initialize SP_PROPCHANGE_PARAMS such that the device will be STOPPED
  633. //
  634. parameters.Scope = DICS_FLAG_CONFIGSPECIFIC;
  635. parameters.HwProfile = 0; // current profile
  636. //
  637. // prepare for the call to SetupDiCallClassInstaller (to stop the device)
  638. //
  639. parameters.StateChange = DICS_STOP;
  640. if (!SetupDiSetClassInstallParams(HDevInfo,
  641. DevInfoData,
  642. (PSP_CLASSINSTALL_HEADER)&parameters,
  643. sizeof(SP_PROPCHANGE_PARAMS))) {
  644. DebugPrint((1, "UtilpRestartDevice => Couldn't stop the device (%x)\n",
  645. GetLastError()));
  646. goto FinishRestart;
  647. }
  648. //
  649. // actually stop the device
  650. //
  651. if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
  652. HDevInfo,
  653. DevInfoData)) {
  654. DebugPrint((1, "UtilpRestartDevice => call to class installer "
  655. "(STOP) failed (%x)\n", GetLastError()));
  656. goto FinishRestart;
  657. }
  658. //
  659. // prepare for the call to SetupDiCallClassInstaller (to start the device)
  660. //
  661. parameters.StateChange = DICS_START;
  662. if (!SetupDiSetClassInstallParams(HDevInfo,
  663. DevInfoData,
  664. (PSP_CLASSINSTALL_HEADER)&parameters,
  665. sizeof(SP_PROPCHANGE_PARAMS))) {
  666. DebugPrint((1, "UtilpRestartDevice => Couldn't stop the device (%x)\n",
  667. GetLastError()));
  668. goto FinishRestart;
  669. }
  670. //
  671. // actually start the device
  672. //
  673. if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
  674. HDevInfo,
  675. DevInfoData)) {
  676. DebugPrint((1, "UtilpRestartDevice => call to class installer "
  677. "(STOP) failed (%x)\n", GetLastError()));
  678. goto FinishRestart;
  679. }
  680. succeeded = TRUE;
  681. FinishRestart:
  682. //
  683. // this call will succeed, but we should still check the status
  684. //
  685. if (!SetupDiGetDeviceInstallParams(HDevInfo,
  686. DevInfoData,
  687. &installParameters)) {
  688. DebugPrint((1, "UtilpRestartDevice => Couldn't get the device install "
  689. "paramters (%x)\n", GetLastError()));
  690. return FALSE;
  691. }
  692. if (TEST_FLAG(installParameters.Flags, DI_NEEDREBOOT)) {
  693. DebugPrint((1, "UtilpRestartDevice => Device needs a reboot.\n"));
  694. return FALSE;
  695. }
  696. if (TEST_FLAG(installParameters.Flags, DI_NEEDRESTART)) {
  697. DebugPrint((1, "UtilpRestartDevice => Device needs a restart(!).\n"));
  698. return FALSE;
  699. }
  700. if (succeeded) {
  701. DebugPrint((1, "UtilpRestartDevice => Device successfully stopped and "
  702. "restarted.\n"));
  703. return TRUE;
  704. }
  705. SET_FLAG(installParameters.Flags, DI_NEEDRESTART);
  706. DebugPrint((1, "UtilpRestartDevice => Device needs to be restarted.\n"));
  707. SetupDiSetDeviceInstallParams(HDevInfo, DevInfoData, &installParameters);
  708. return FALSE;
  709. }
  710. LONG
  711. RedbookpUpperFilterRegDelete(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData)
  712. {
  713. DWORD status = ERROR_SUCCESS;
  714. DWORD dwSize = 0;
  715. status = SetupDiGetDeviceRegistryProperty(HDevInfo,
  716. DevInfoData,
  717. SPDRP_UPPERFILTERS,
  718. NULL,
  719. NULL,
  720. 0,
  721. &dwSize) ? ERROR_SUCCESS : GetLastError();
  722. if (status == ERROR_INSUFFICIENT_BUFFER)
  723. {
  724. TCHAR* szBuffer = LocalAlloc(LPTR, dwSize);
  725. if (szBuffer)
  726. {
  727. if (SetupDiGetDeviceRegistryProperty(HDevInfo,
  728. DevInfoData,
  729. SPDRP_UPPERFILTERS,
  730. NULL,
  731. (PBYTE)szBuffer,
  732. dwSize,
  733. NULL))
  734. {
  735. if (UtilpMultiSzSearchAndDeleteCaseInsensitive(_T("redbook"), szBuffer, &dwSize))
  736. {
  737. status = SetupDiSetDeviceRegistryProperty(HDevInfo,
  738. DevInfoData,
  739. SPDRP_UPPERFILTERS,
  740. (dwSize == 0) ? NULL : (PBYTE)szBuffer,
  741. dwSize) ? ERROR_SUCCESS : GetLastError();
  742. }
  743. else
  744. {
  745. //
  746. // Redbook isn't loaded for this device
  747. //
  748. status = ERROR_SUCCESS;
  749. }
  750. }
  751. else
  752. {
  753. status = GetLastError();
  754. }
  755. LocalFree(szBuffer);
  756. }
  757. else
  758. {
  759. status = ERROR_NOT_ENOUGH_MEMORY;
  760. }
  761. }
  762. else if (status == ERROR_INVALID_DATA)
  763. {
  764. //
  765. // There probably isn't any upper filter installed
  766. //
  767. status = ERROR_SUCCESS;
  768. }
  769. return status;
  770. }
  771. LONG
  772. RedbookpUpperFilterRegInstall(IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData)
  773. {
  774. DWORD status = ERROR_SUCCESS;
  775. DWORD dwSize = 0;
  776. status = SetupDiGetDeviceRegistryProperty(HDevInfo,
  777. DevInfoData,
  778. SPDRP_UPPERFILTERS,
  779. NULL,
  780. NULL,
  781. 0,
  782. &dwSize) ? ERROR_SUCCESS : GetLastError();
  783. if (status == ERROR_INSUFFICIENT_BUFFER)
  784. {
  785. TCHAR* szBuffer = LocalAlloc(LPTR, dwSize);
  786. if (szBuffer)
  787. {
  788. if (SetupDiGetDeviceRegistryProperty(HDevInfo,
  789. DevInfoData,
  790. SPDRP_UPPERFILTERS,
  791. NULL,
  792. (PBYTE)szBuffer,
  793. dwSize,
  794. NULL))
  795. {
  796. if (!UtilpIsSingleSzOfMultiSzInMultiSz(_T("redbook\0"), szBuffer))
  797. {
  798. //
  799. // Add Redbook to the beginning of the list
  800. //
  801. DWORD dwNewSize = dwSize + sizeof(_T("redbook"));
  802. TCHAR* szNewBuffer = LocalAlloc(LPTR, dwNewSize);
  803. if (szNewBuffer)
  804. {
  805. _tcscpy(szNewBuffer, _T("redbook"));
  806. RtlCopyMemory(szNewBuffer + _tcslen(_T("redbook")) + 1, szBuffer, dwSize);
  807. status = SetupDiSetDeviceRegistryProperty(HDevInfo,
  808. DevInfoData,
  809. SPDRP_UPPERFILTERS,
  810. (PBYTE)szNewBuffer,
  811. dwNewSize) ? ERROR_SUCCESS : GetLastError();
  812. LocalFree(szNewBuffer);
  813. }
  814. else
  815. {
  816. status = ERROR_NOT_ENOUGH_MEMORY;
  817. }
  818. }
  819. else
  820. {
  821. //
  822. // Redbook is already loaded for this device
  823. //
  824. status = ERROR_SUCCESS;
  825. }
  826. }
  827. else
  828. {
  829. status = GetLastError();
  830. }
  831. LocalFree(szBuffer);
  832. }
  833. else
  834. {
  835. status = ERROR_NOT_ENOUGH_MEMORY;
  836. }
  837. }
  838. else if (status == ERROR_INVALID_DATA)
  839. {
  840. //
  841. // There probably isn't any upper filter installed
  842. //
  843. TCHAR szBuffer[] = _T("redbook\0");
  844. dwSize = sizeof(szBuffer);
  845. status = SetupDiSetDeviceRegistryProperty(HDevInfo,
  846. DevInfoData,
  847. SPDRP_UPPERFILTERS,
  848. (PBYTE)szBuffer,
  849. dwSize) ? ERROR_SUCCESS : GetLastError();
  850. }
  851. return status;
  852. }
  853. BOOLEAN
  854. UtilpIsSingleSzOfMultiSzInMultiSz(
  855. IN LPTSTR FindOneOfThese,
  856. IN LPTSTR WithinThese
  857. )
  858. /*++
  859. Routine Description:
  860. Deletes all instances of a string from within a multi-sz.
  861. automagically operates on either unicode or ansi or ??
  862. Arguments:
  863. FindOneOfThese - multisz to search with
  864. WithinThese - multisz to search in
  865. Return Value:
  866. 1/20 of one cent, or the number of strings deleted, rounded down.
  867. Notes:
  868. expect small inputs, so n*m is acceptable run time.
  869. --*/
  870. {
  871. LPTSTR searchFor;
  872. LPTSTR within;
  873. //
  874. // loop through all strings in FindOneOfThese
  875. //
  876. searchFor = FindOneOfThese;
  877. while ( _tcscmp(searchFor, TEXT("\0")) ) {
  878. //
  879. // loop through all strings in WithinThese
  880. //
  881. within = WithinThese;
  882. while ( _tcscmp(within, TEXT("\0"))) {
  883. //
  884. // if the are equal, return TRUE
  885. //
  886. if ( !_tcscmp(searchFor, within) ) {
  887. return TRUE;
  888. }
  889. within += _tcslen(within) + 1;
  890. } // end of WithinThese loop
  891. searchFor += _tcslen(searchFor) + 1;
  892. } // end of FindOneOfThese loop
  893. return FALSE;
  894. }
  895. DWORD
  896. UtilpMultiSzSearchAndDeleteCaseInsensitive(
  897. LPTSTR FindThis,
  898. LPTSTR FindWithin,
  899. DWORD *NewStringLength
  900. )
  901. /*++
  902. Routine Description:
  903. Deletes all instances of a string from within a multi-sz.
  904. automagically operates on either unicode or ansi or ??
  905. Arguments:
  906. NewStringLength is in BYTES, not number of chars
  907. Return Value:
  908. 1/20 of one cent, or the number of strings deleted, rounded down.
  909. --*/
  910. {
  911. LPTSTR search;
  912. DWORD charOffset;
  913. DWORD instancesDeleted;
  914. if ((*NewStringLength) % sizeof(TCHAR)) {
  915. assert(!"String must be in bytes, does not divide by sizeof(TCHAR)\n");
  916. return 0;
  917. }
  918. if ((*NewStringLength) < sizeof(TCHAR)*2) {
  919. assert(!"String must be multi-sz, which requires at least two chars\n");
  920. return 0;
  921. }
  922. charOffset = 0;
  923. instancesDeleted = 0;
  924. search = FindWithin;
  925. //
  926. // loop while there string length is not zero
  927. // couldn't find a TNULL, or i'd just compare.
  928. //
  929. while (_tcsicmp(search, TEXT("\0")) != 0) {
  930. //
  931. // if this string matches...
  932. //
  933. if (_tcsicmp(search, FindThis) == 0) {
  934. //
  935. // the new length is smaller
  936. // remove the string (and terminating null)
  937. //
  938. instancesDeleted++;
  939. *NewStringLength -= (_tcslen(search) + 1) * sizeof(TCHAR);
  940. RtlMoveMemory(search,
  941. search + _tcslen(search) + 1,
  942. *NewStringLength - (charOffset * sizeof(TCHAR))
  943. );
  944. } else {
  945. //
  946. // move current search pointer
  947. // increment current offset (in CHARS)
  948. //
  949. charOffset += _tcslen(search) + 1;
  950. search += _tcslen(search) + 1;
  951. }
  952. //
  953. // it's that simple
  954. //
  955. }
  956. //
  957. // if deleted all strings, set to double-null
  958. //
  959. if (*NewStringLength == sizeof(TCHAR)) {
  960. FindWithin = TEXT("\0");
  961. *NewStringLength = 0;
  962. }
  963. return instancesDeleted;
  964. }