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.

778 lines
23 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. fereg.c
  5. Abstract:
  6. Japanese/korean-specific registry settings.
  7. Author:
  8. Ted Miller (tedm) 04-July-1995
  9. Revision History:
  10. Adapted from hideyukn's code in textmode\kernel\spconfig.c.
  11. --*/
  12. #include <precomp.h>
  13. #pragma hdrstop
  14. NTSTATUS
  15. SpDeleteValueKey(
  16. IN HANDLE hKeyRoot,
  17. IN PWSTR KeyName,
  18. IN PWSTR ValueName
  19. );
  20. NTSTATUS
  21. FESetKeyboardParams(
  22. IN PVOID SifHandle,
  23. IN HANDLE ControlSetKeyHandle,
  24. IN PHARDWARE_COMPONENT *HwComponents,
  25. IN PWSTR LayerDriver
  26. )
  27. /*++
  28. Routine Description:
  29. Set parameters in the registry relating to the keyboard type
  30. selected by the user.
  31. Arguments:
  32. SifHandle - supplies handle to open/loaded setup info file (txtsetup.sif).
  33. ControlSetKeyHandle - supplies handle to open registry key for current
  34. control set (ie, HKEY_LOCAL_MACHINE\CurrentControlSet).
  35. HwComponents - supplies the address of the master hardware components
  36. array.
  37. Return Value:
  38. NT Status code indicating result of operation.
  39. --*/
  40. {
  41. WCHAR KeyEntryName[100] = L"Services\\";
  42. NTSTATUS Status;
  43. PWSTR KeyboardPortDriver;
  44. PWSTR KeyboardId;
  45. PWSTR KeyboardDll;
  46. PWSTR KeyboardPnPId;
  47. PWSTR KeyboardTypeStr;
  48. PWSTR KeyboardSubtypeStr;
  49. ULONG KeyboardType;
  50. ULONG KeyboardSubtype;
  51. ULONG val;
  52. PHARDWARE_COMPONENT hw;
  53. hw = HwComponents[HwComponentKeyboard];
  54. //
  55. // if third party's driver is selected, we don't write LayerDriver data
  56. // into registry.
  57. //
  58. if(hw->ThirdPartyOptionSelected) {
  59. //
  60. // [This modification is requested by Japanese hardware provider]
  61. //
  62. // if user replace keyboard port driver with thirdpartys one,
  63. // we should disable build-in keyboard port driver (i8042prt.sys)
  64. // because if i8042prt is initialized faster than OEM driver and
  65. // i8042prt can recoganize the port device, the oem driver will fail
  66. // to initialization due to conflict of hardware resorce.
  67. //
  68. // ** BUG BUG **
  69. //
  70. // how about mouse? mouse might use i8042prt, we should not disbale
  71. // it when user only replace keyboard port. this might causes critical
  72. // error. But I believe, the mouse device also handled by OEM port
  73. // driver.
  74. //
  75. // Disable the built-in port driver.
  76. //
  77. if(IS_FILETYPE_PRESENT(hw->FileTypeBits,HwFilePort)) {
  78. val = SERVICE_DISABLED;
  79. Status = SpOpenSetValueAndClose(
  80. ControlSetKeyHandle,
  81. L"Services\\i8042prt",
  82. L"Start",
  83. REG_DWORD,
  84. &val,
  85. sizeof(ULONG)
  86. );
  87. } else {
  88. Status = STATUS_SUCCESS;
  89. }
  90. } else {
  91. //
  92. // Get keyboard port driver name and layer driver name from txtsetup.sif
  93. //
  94. KeyboardId = HwComponents[HwComponentKeyboard]->IdString;
  95. KeyboardPortDriver = SpGetSectionKeyIndex(SifHandle,szKeyboard,KeyboardId,2);
  96. KeyboardDll = SpGetSectionKeyIndex(SifHandle,szKeyboard,KeyboardId,3);
  97. KeyboardTypeStr = SpGetSectionKeyIndex(SifHandle,szKeyboard,KeyboardId,4);
  98. KeyboardSubtypeStr = SpGetSectionKeyIndex(SifHandle,szKeyboard,KeyboardId,5);
  99. KeyboardPnPId = SpGetSectionKeyIndex(SifHandle,szKeyboard,KeyboardId,6);
  100. if(KeyboardPortDriver && KeyboardDll) {
  101. //
  102. // Build registry path such as L"Services\\KeyboardPortDriver\\Parameters"
  103. // and write into registry.
  104. //
  105. wcscat(KeyEntryName,KeyboardPortDriver);
  106. wcscat(KeyEntryName,L"\\Parameters");
  107. //
  108. // Save Keyboard layout driver name.
  109. //
  110. Status = SpOpenSetValueAndClose(
  111. ControlSetKeyHandle,
  112. KeyEntryName,
  113. LayerDriver,
  114. REG_SZ,
  115. KeyboardDll,
  116. (wcslen(KeyboardDll)+1)*sizeof(WCHAR)
  117. );
  118. if(NT_SUCCESS(Status)) {
  119. if (KeyboardPnPId) {
  120. //
  121. // Save Keyboard PnP Id.
  122. //
  123. Status = SpOpenSetValueAndClose(
  124. ControlSetKeyHandle,
  125. KeyEntryName,
  126. L"OverrideKeyboardIdentifier",
  127. REG_SZ,
  128. KeyboardPnPId,
  129. (wcslen(KeyboardPnPId)+1)*sizeof(WCHAR)
  130. );
  131. }
  132. if(KeyboardTypeStr && KeyboardSubtypeStr) {
  133. UNICODE_STRING UnicodeString;
  134. //
  135. // Convert the string to DWORD value.
  136. //
  137. RtlInitUnicodeString(&UnicodeString,KeyboardTypeStr);
  138. RtlUnicodeStringToInteger(&UnicodeString,10,&KeyboardType);
  139. RtlInitUnicodeString(&UnicodeString,KeyboardSubtypeStr);
  140. RtlUnicodeStringToInteger(&UnicodeString,10,&KeyboardSubtype);
  141. Status = SpOpenSetValueAndClose(
  142. ControlSetKeyHandle,
  143. KeyEntryName,
  144. L"OverrideKeyboardType",
  145. REG_DWORD,
  146. &KeyboardType,
  147. sizeof(ULONG)
  148. );
  149. if(NT_SUCCESS(Status)) {
  150. Status = SpOpenSetValueAndClose(
  151. ControlSetKeyHandle,
  152. KeyEntryName,
  153. L"OverrideKeyboardSubtype",
  154. REG_DWORD,
  155. &KeyboardSubtype,
  156. sizeof(ULONG)
  157. );
  158. }
  159. }
  160. }
  161. } else {
  162. Status = STATUS_SUCCESS;
  163. }
  164. }
  165. return(Status);
  166. }
  167. NTSTATUS
  168. FEUpgradeKeyboardParams(
  169. IN PVOID SifHandle,
  170. IN HANDLE ControlSetKeyHandle,
  171. IN PHARDWARE_COMPONENT *HwComponents,
  172. IN PWSTR LayerDriver
  173. )
  174. {
  175. BYTE DataBuffer[256];
  176. ULONG LayerDriverLength;
  177. PWSTR LayerDriverCandidate;
  178. PWSTR LayerDriverName = NULL;
  179. PWSTR KeyboardTypeStr = NULL;
  180. PWSTR KeyboardSubtypeStr = NULL;
  181. PWSTR KeyboardPnPId = NULL;
  182. ULONG KeyboardType;
  183. ULONG KeyboardSubtype;
  184. NTSTATUS Status;
  185. ULONG LineIndex;
  186. UNICODE_STRING UnicodeString;
  187. //
  188. // This code is hardly depended on 'i8042prt.sys'.
  189. // if the active driver for keyboard is not 'i8042prt.sys',
  190. // we don't need to do this, but we write down this to registry for just in case.
  191. //
  192. //
  193. // Get current keyboard layout driver name.
  194. //
  195. //
  196. // from NT5, the keyword LayerDriver has been changed to
  197. //
  198. // "LayerDriver JPN" | "LayerDriver KOR"
  199. //
  200. // Since NT5 sets KeyboardType & KeyboardSubtype correctly
  201. //
  202. // When new LayerDriver key is opened successfully,
  203. //
  204. // it means system is >= NT5 and we don't need to do more.
  205. //
  206. Status = SpGetValueKey(ControlSetKeyHandle,
  207. L"Services\\i8042prt\\Parameters",
  208. LayerDriver,
  209. sizeof(DataBuffer),
  210. DataBuffer,
  211. &LayerDriverLength);
  212. if (NT_SUCCESS(Status)) {
  213. return (STATUS_SUCCESS);
  214. }
  215. Status = SpGetValueKey(ControlSetKeyHandle,
  216. L"Services\\i8042prt\\Parameters",
  217. L"LayerDriver",
  218. sizeof(DataBuffer),
  219. DataBuffer,
  220. &LayerDriverLength);
  221. if (NT_SUCCESS(Status)) {
  222. //
  223. // Get pointer to registry data.
  224. //
  225. LayerDriverName = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)DataBuffer)->Data);
  226. //
  227. // Search driver name from txtsetup.sif.
  228. //
  229. for (LineIndex = 0; ; LineIndex++) {
  230. //
  231. // Get candidate layout driver name for this line.
  232. //
  233. LayerDriverCandidate = SpGetSectionLineIndex(SifHandle,szKeyboard,LineIndex,3);
  234. if (LayerDriverCandidate == NULL) {
  235. //
  236. // We may reach at end of the list.
  237. //
  238. break;
  239. }
  240. //
  241. // Compare this candidate with active layout driver.
  242. //
  243. if (_wcsicmp(LayerDriverName,LayerDriverCandidate) == 0) {
  244. //
  245. // This is what we want, Get KeyboardType and SubType from Sif.
  246. //
  247. KeyboardTypeStr = SpGetSectionLineIndex(SifHandle,szKeyboard,LineIndex,4);
  248. KeyboardSubtypeStr = SpGetSectionLineIndex(SifHandle,szKeyboard,LineIndex,5);
  249. KeyboardPnPId = SpGetSectionLineIndex(SifHandle,szKeyboard,LineIndex,6);
  250. break;
  251. }
  252. }
  253. Status = SpOpenSetValueAndClose(
  254. ControlSetKeyHandle,
  255. L"Services\\i8042prt\\Parameters",
  256. LayerDriver,
  257. REG_SZ,
  258. LayerDriverName,
  259. (wcslen(LayerDriverName)+1)*sizeof(WCHAR)
  260. );
  261. if (NT_SUCCESS(Status)) {
  262. Status = SpDeleteValueKey(
  263. ControlSetKeyHandle,
  264. L"Services\\i8042prt\\Parameters",
  265. L"LayerDriver"
  266. );
  267. }
  268. }
  269. if (KeyboardPnPId) {
  270. //
  271. // Save Keyboard PnP Id.
  272. //
  273. Status = SpOpenSetValueAndClose(
  274. ControlSetKeyHandle,
  275. L"Services\\i8042prt\\Parameters",
  276. L"OverrideKeyboardIdentifier",
  277. REG_SZ,
  278. KeyboardPnPId,
  279. (wcslen(KeyboardPnPId)+1)*sizeof(WCHAR)
  280. );
  281. }
  282. if ((KeyboardTypeStr == NULL) || (KeyboardSubtypeStr == NULL)) {
  283. //
  284. // We could not find the driver from list, just use default..
  285. //
  286. KeyboardTypeStr = SpGetSectionKeyIndex(SifHandle,szKeyboard,L"STANDARD",4);
  287. KeyboardSubtypeStr = SpGetSectionKeyIndex(SifHandle,szKeyboard,L"STANDARD",5);
  288. if ((KeyboardTypeStr == NULL) || (KeyboardSubtypeStr == NULL)) {
  289. //
  290. // if it still has problem. set hardcodeed default (PC/AT Enhanced)...
  291. //
  292. KeyboardTypeStr = L"4\0";
  293. KeyboardSubtypeStr = L"0\0";
  294. }
  295. }
  296. //
  297. // Convert the string to DWORD value.
  298. //
  299. RtlInitUnicodeString(&UnicodeString,KeyboardTypeStr);
  300. RtlUnicodeStringToInteger(&UnicodeString,10,&KeyboardType);
  301. RtlInitUnicodeString(&UnicodeString,KeyboardSubtypeStr);
  302. RtlUnicodeStringToInteger(&UnicodeString,10,&KeyboardSubtype);
  303. //
  304. // Updates registry.
  305. //
  306. Status = SpOpenSetValueAndClose(
  307. ControlSetKeyHandle,
  308. L"Services\\i8042prt\\Parameters",
  309. L"OverrideKeyboardType",
  310. REG_DWORD,
  311. &KeyboardType,
  312. sizeof(ULONG)
  313. );
  314. if(NT_SUCCESS(Status)) {
  315. Status = SpOpenSetValueAndClose(
  316. ControlSetKeyHandle,
  317. L"Services\\i8042prt\\Parameters",
  318. L"OverrideKeyboardSubtype",
  319. REG_DWORD,
  320. &KeyboardSubtype,
  321. sizeof(ULONG)
  322. );
  323. }
  324. KdPrint(("KEYBOARD UPGRADE INFORMATION\n"));
  325. KdPrint((" Current Keyboard layout = %ws\n",LayerDriverName));
  326. KdPrint((" Upgrade keyboard Type = %d\n",KeyboardType));
  327. KdPrint((" Upgrade keyboard Subtype = %d\n",KeyboardSubtype));
  328. KdPrint((" Upgrade keyboard identifier = %ws\n",KeyboardPnPId));
  329. return(Status);
  330. }
  331. #define KEYBOARD_LAYOUTS_PATH L"Control\\Keyboard Layouts"
  332. #define IME_FILE_NAME L"IME file"
  333. #define LAYOUT_TEXT_NAME L"Layout Text"
  334. NTSTATUS
  335. FEUpgradeKeyboardLayout(
  336. IN HANDLE ControlSetKeyHandle,
  337. IN PWSTR OldDefaultIMEName,
  338. IN PWSTR NewDefaultIMEName,
  339. IN PWSTR NewDefaultIMEText
  340. )
  341. {
  342. OBJECT_ATTRIBUTES KeyRootObjA;
  343. OBJECT_ATTRIBUTES KeyNodeObjA;
  344. HANDLE KeyRoot;
  345. HANDLE KeyNode;
  346. NTSTATUS Status;
  347. DWORD ResultLength;
  348. UNICODE_STRING KeyboardRoot;
  349. UNICODE_STRING KeyboardNode;
  350. UNICODE_STRING IMEFile;
  351. UNICODE_STRING LayoutText;
  352. PBYTE DataBuffer[256];
  353. WCHAR NodeKeyPath[64];
  354. WCHAR SubKeyName[16];
  355. ULONG EnumerateIndex = 0;
  356. //
  357. // Initalize "IME file" and "Layout Text".
  358. //
  359. RtlInitUnicodeString(&IMEFile,IME_FILE_NAME);
  360. RtlInitUnicodeString(&LayoutText,LAYOUT_TEXT_NAME);
  361. //
  362. // Build Registry path for "keyboard Layouts".
  363. //
  364. RtlInitUnicodeString(&KeyboardRoot,KEYBOARD_LAYOUTS_PATH);
  365. //
  366. // Open "Keyboard Layouts" key.
  367. //
  368. InitializeObjectAttributes(&KeyRootObjA,
  369. &KeyboardRoot,
  370. OBJ_CASE_INSENSITIVE,
  371. ControlSetKeyHandle, NULL);
  372. Status = ZwOpenKey(&KeyRoot,KEY_ALL_ACCESS,&KeyRootObjA);
  373. if (!NT_SUCCESS(Status)) {
  374. KdPrint(("SPDDLANG:Fail to open (%x) (%ws)\n",Status,KeyboardRoot.Buffer));
  375. //
  376. // If we fail here, it might be upgrade from NT 3.1 or 3.5...
  377. // Then just return as SUCCESS.
  378. //
  379. return (STATUS_SUCCESS);
  380. }
  381. //
  382. // Enumerate installed keyboard layouts..
  383. //
  384. while (TRUE) {
  385. Status = ZwEnumerateKey(KeyRoot,
  386. EnumerateIndex,
  387. KeyBasicInformation,
  388. (PKEY_BASIC_INFORMATION)DataBuffer,
  389. sizeof(DataBuffer),
  390. &ResultLength);
  391. if (!NT_SUCCESS(Status)) {
  392. //
  393. // we might reach end of data...
  394. //
  395. break;
  396. }
  397. //
  398. // Initialize subkey buffer.
  399. //
  400. RtlZeroMemory(SubKeyName,sizeof(SubKeyName));
  401. //
  402. // Get subkey name..
  403. //
  404. RtlCopyMemory(SubKeyName,
  405. ((PKEY_BASIC_INFORMATION)DataBuffer)->Name,
  406. ((PKEY_BASIC_INFORMATION)DataBuffer)->NameLength);
  407. //
  408. // We know the key is everytime '8' characters...
  409. //
  410. if (((PKEY_BASIC_INFORMATION)DataBuffer)->NameLength != 0x10) {
  411. SubKeyName[8] = L'\0';
  412. }
  413. //
  414. // Build path for sub keys
  415. //
  416. wcscpy(NodeKeyPath,KEYBOARD_LAYOUTS_PATH);
  417. KeyboardNode.Buffer = NodeKeyPath;
  418. KeyboardNode.Length = wcslen(NodeKeyPath) * sizeof(WCHAR);
  419. KeyboardNode.MaximumLength = sizeof(NodeKeyPath);
  420. RtlAppendUnicodeToString(&KeyboardNode,L"\\");
  421. RtlAppendUnicodeToString(&KeyboardNode,SubKeyName);
  422. KdPrint(("SPDDLANG:SubKey = %ws\n",KeyboardNode.Buffer));
  423. //
  424. // Open its subkey...
  425. //
  426. InitializeObjectAttributes(&KeyNodeObjA,
  427. &KeyboardNode,
  428. OBJ_CASE_INSENSITIVE,
  429. ControlSetKeyHandle, NULL);
  430. Status = ZwOpenKey(&KeyNode,KEY_ALL_ACCESS,&KeyNodeObjA);
  431. if (!NT_SUCCESS(Status)) {
  432. KdPrint(("SPDDLANG:Fail to open (%x) (%ws)\n",Status,KeyboardNode.Buffer));
  433. //
  434. // We should not encounter error, because the key should be exist...
  435. // Anyway, continue to enumerate...
  436. //
  437. EnumerateIndex++;
  438. continue;
  439. }
  440. //
  441. // Find "IME file" value key.
  442. //
  443. Status = ZwQueryValueKey(KeyNode,
  444. &IMEFile,
  445. KeyValuePartialInformation,
  446. (PKEY_VALUE_PARTIAL_INFORMATION)DataBuffer,
  447. sizeof(DataBuffer),
  448. &ResultLength);
  449. if (NT_SUCCESS(Status)) {
  450. PWSTR IMEFileName = (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)DataBuffer)->Data);
  451. //
  452. // Upcases the file name..
  453. //
  454. _wcsupr(IMEFileName);
  455. if (wcsstr(IMEFileName,L".EXE")) {
  456. KdPrint(("SPDDLANG:Delete IME file = %ws\n",IMEFileName));
  457. //
  458. // This is Old "EXE" type IME file, let it deleted.
  459. //
  460. ZwDeleteKey(KeyNode);
  461. //
  462. // Adjust enumeration number...
  463. //
  464. EnumerateIndex--;
  465. } else {
  466. KdPrint(("SPDDLANG:Keep IME file = %ws\n",IMEFileName));
  467. //
  468. // This might be New "DLL" type IME file. let it be as is..
  469. //
  470. if (OldDefaultIMEName && NewDefaultIMEName) {
  471. //
  472. // if this entry is for 3.x default IME. let it upgrade to new one.
  473. //
  474. if (wcsstr(IMEFileName,OldDefaultIMEName)) {
  475. KdPrint(("SPDDLANG:Upgrade IME file = %ws to %ws\n",
  476. IMEFileName,NewDefaultIMEName));
  477. //
  478. // Upgrade IME.
  479. //
  480. Status = ZwSetValueKey(KeyNode,
  481. &IMEFile,
  482. 0,
  483. REG_SZ,
  484. (PVOID) NewDefaultIMEName,
  485. (wcslen(NewDefaultIMEName)+1)*sizeof(WCHAR));
  486. //
  487. // Upgrade "Layout Text" also ?
  488. //
  489. if (NewDefaultIMEText) {
  490. Status = ZwSetValueKey(KeyNode,
  491. &LayoutText,
  492. 0,
  493. REG_SZ,
  494. (PVOID) NewDefaultIMEText,
  495. (wcslen(NewDefaultIMEText)+1)*sizeof(WCHAR));
  496. }
  497. }
  498. }
  499. }
  500. } else {
  501. KdPrint(("SPDDLANG:no IME file\n"));
  502. //
  503. // This layout seems like does not have any IME, just leave it there.
  504. //
  505. Status = STATUS_SUCCESS;
  506. }
  507. ZwClose(KeyNode);
  508. //
  509. // Enumerate next..
  510. //
  511. EnumerateIndex++;
  512. }
  513. ZwClose(KeyRoot);
  514. KdPrint(("SPDDLANG:Retcode = %x\n",Status));
  515. if (Status == STATUS_NO_MORE_ENTRIES) {
  516. //
  517. // We enumerate all of sub keys...
  518. //
  519. Status = STATUS_SUCCESS;
  520. }
  521. return (Status);
  522. }
  523. #define DOSDEV_REG_PATH L"Control\\Session Manager\\DOS Devices"
  524. NTSTATUS
  525. FEUpgradeRemoveMO(
  526. IN HANDLE ControlSetKeyHandle)
  527. {
  528. OBJECT_ATTRIBUTES KeyRootObjA;
  529. HANDLE KeyRoot;
  530. NTSTATUS Status;
  531. DWORD ResultLength;
  532. UNICODE_STRING DosDevice;
  533. UNICODE_STRING UnicodeValueName;
  534. BYTE DataBuffer[512];
  535. WCHAR NodeKeyPath[64];
  536. WCHAR ValueName[256];
  537. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  538. PKEY_VALUE_PARTIAL_INFORMATION DataInfo;
  539. ULONG EnumerateIndex = 0;
  540. //
  541. // Build Registry path for "Control\\Session Manager\\DOS Devices".
  542. //
  543. RtlInitUnicodeString(&DosDevice,DOSDEV_REG_PATH);
  544. //
  545. // Open "DOS Devices" key.
  546. //
  547. InitializeObjectAttributes(&KeyRootObjA,
  548. &DosDevice,
  549. OBJ_CASE_INSENSITIVE,
  550. ControlSetKeyHandle, NULL);
  551. Status = ZwOpenKey(&KeyRoot,KEY_ALL_ACCESS,&KeyRootObjA);
  552. if (!NT_SUCCESS(Status)) {
  553. KdPrint(("SPDDLANG:Fail to open (%x) (%ws)\n",Status,DosDevice.Buffer));
  554. //
  555. // If we fail here, it might be upgrade from NT 3.1 or 3.5...
  556. // Then just return as SUCCESS.
  557. //
  558. return (STATUS_SUCCESS);
  559. }
  560. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) DataBuffer;
  561. //
  562. // Enumerate all installed devices..
  563. //
  564. while (TRUE) {
  565. Status = ZwEnumerateValueKey(KeyRoot,
  566. EnumerateIndex,
  567. KeyValueFullInformation,
  568. DataBuffer,
  569. sizeof(DataBuffer),
  570. &ResultLength);
  571. if (!NT_SUCCESS(Status)) {
  572. //
  573. // we might reach end of data...
  574. //
  575. break;
  576. }
  577. //
  578. // Get subkey name..
  579. //
  580. RtlCopyMemory((PBYTE)ValueName,
  581. ValueInfo->Name,
  582. ValueInfo->NameLength);
  583. ValueName[ValueInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  584. RtlInitUnicodeString(&UnicodeValueName,ValueName);
  585. Status = ZwQueryValueKey(KeyRoot,
  586. &UnicodeValueName,
  587. KeyValuePartialInformation,
  588. DataBuffer,
  589. sizeof(DataBuffer),
  590. &ResultLength);
  591. DataInfo = (PKEY_VALUE_PARTIAL_INFORMATION) DataBuffer;
  592. if (NT_SUCCESS(Status)) {
  593. PWSTR PathData = (PWSTR)(DataInfo->Data);
  594. //
  595. // Upcases the file name..
  596. //
  597. _wcsupr(PathData);
  598. if (wcsstr(PathData,L"\\OPTICALDISK")) {
  599. KdPrint(("SPDDLANG:Delete MO %ws = %ws\n",ValueName,PathData));
  600. Status = SpDeleteValueKey(
  601. ControlSetKeyHandle,
  602. DOSDEV_REG_PATH,
  603. ValueName
  604. );
  605. }
  606. }
  607. //
  608. // Enumerate next..
  609. //
  610. EnumerateIndex++;
  611. }
  612. ZwClose(KeyRoot);
  613. KdPrint(("SPDDLANG:Retcode = %x\n",Status));
  614. if (Status == STATUS_NO_MORE_ENTRIES) {
  615. //
  616. // We enumerate all of sub keys...
  617. //
  618. Status = STATUS_SUCCESS;
  619. }
  620. return (Status);
  621. }