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.

3627 lines
99 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. olereg.c
  5. Abstract:
  6. Code to perform OLE registry suppression based on list of
  7. GUIDs in win95upg.inf.
  8. OLE suppression is accomplished by the following algorithm:
  9. 1. Determine all GUIDs that are Win9x-specific, load in
  10. list of manually-suppressed GUIDs. Save this list
  11. to memdb.
  12. 2. Scan registry for GUID settings, then suppress all
  13. linkage to the GUID (the ProgID, Interface, etc).
  14. Use memdb to suppress each registry key/value.
  15. 3. Suppress all shell linkage to suppressed objects
  16. including file associations and desktop links.
  17. 4. Do a sanity check on the unsuppressed objects in
  18. the checked build
  19. Author:
  20. Jim Schmidt (jimschm) 20-Mar-1997
  21. Revision History:
  22. jimschm 23-Sep-1998 Updated for new fileops code
  23. jimschm 28-Jan-1998 Added hack for ActiveSetup key
  24. jimschm 05-May-1997 Added new auto-suppression of non-OLE
  25. shell links
  26. --*/
  27. #include "pch.h"
  28. #include "sysmigp.h"
  29. #include "oleregp.h"
  30. #define S_EXPLORER_SHELLEXECUTEHOOKS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellExecuteHooks")
  31. #define S_EXPLORER_CSSFILTERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CSSFilters")
  32. #define S_EXPLORER_DESKTOP_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace")
  33. #define S_EXPLORER_FILETYPESPROPERTYSHEETHOOK TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileTypesPropertySheetHook")
  34. #define S_EXPLORER_FINDEXTENSIONS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FindExtensions")
  35. #define S_EXPLORER_MYCOMPUTER_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\NameSpace")
  36. #define S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\NetworkNeighborhood\\NameSpace")
  37. #define S_EXPLORER_NEWSHORTCUTHANDLERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\NewShortcutHandlers")
  38. #define S_EXPLORER_REMOTECOMPUTER_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RemoteComputer\\NameSpace")
  39. #define S_EXPLORER_SHELLICONOVERLAYIDENTIFIERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers")
  40. #define S_EXPLORER_VOLUMECACHES TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches")
  41. #define S_ACTIVESETUP TEXT("HKLM\\Software\\Microsoft\\Active Setup\\Installed Components")
  42. #define S_EXTSHELLVIEWS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ExtShellViews")
  43. #define S_SHELLEXTENSIONS_APPROVED TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved")
  44. #define S_SHELLSERVICEOBJECTDELAYLOAD TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad ")
  45. static TCHAR g_DefaultIcon[] = TEXT("DefaultIcon");
  46. #define DBG_OLEREG "OLE Reg"
  47. //
  48. // Strings for AutoSuppress
  49. //
  50. TCHAR g_InprocHandler[] = TEXT("InprocHandler");
  51. TCHAR g_InprocHandler32[] = TEXT("InprocHandler32");
  52. TCHAR g_InprocServer[] = TEXT("InprocServer");
  53. TCHAR g_InprocServer32[] = TEXT("InprocServer32");
  54. TCHAR g_LocalServer[] = TEXT("LocalServer");
  55. TCHAR g_LocalServer32[] = TEXT("LocalServer32");
  56. PCTSTR g_FileRefKeys[] = {
  57. g_InprocHandler,
  58. g_InprocHandler32,
  59. g_InprocServer,
  60. g_InprocServer32,
  61. g_LocalServer,
  62. g_LocalServer32,
  63. NULL
  64. };
  65. static POOLHANDLE g_OlePool;
  66. DWORD
  67. OleReg_GetProgressMax (
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. Estimates the amount of ticks needed to complete OLE registry processing.
  73. Arguments:
  74. none
  75. Return Value:
  76. The number of ticks, equal to the number of ticks added with a delta in
  77. SuppressOleGuids.
  78. --*/
  79. {
  80. if (REPORTONLY()) {
  81. return 0;
  82. }
  83. return TICKS_OLEREG;
  84. }
  85. BOOL
  86. pIgnoreGuid (
  87. IN PCTSTR GuidStr
  88. )
  89. {
  90. INFCONTEXT ic;
  91. MYASSERT (IsGuid (GuidStr, TRUE));
  92. if (IsReportObjectHandled (GuidStr)) {
  93. DEBUGMSG ((DBG_OLEREG, "%s is a handled GUID, will not be suppressed", GuidStr));
  94. return TRUE;
  95. }
  96. if (SetupFindFirstLine (g_Win95UpgInf, S_FORCED_GUIDS, GuidStr, &ic)) {
  97. DEBUGMSG ((DBG_OLEREG, "%s is a forced GUID, will not be suppressed", GuidStr));
  98. return TRUE;
  99. }
  100. return FALSE;
  101. }
  102. BOOL
  103. pSuppressOleGuids (
  104. VOID
  105. )
  106. /*++
  107. Routine Description:
  108. Processes the [Suppressed GUIDs] section of win95upg.inf and auto-suppresses
  109. OLE objects and GUIDs. The inf-based approach allows an OLE object and
  110. all of its linkage to be suppressed. The auto-suppress approach allows
  111. suppression of OLE objects and linkage when the implementation binary
  112. is removed from the system.
  113. Arguments:
  114. none
  115. Return Value:
  116. TRUE if suppression was successful, or FALSE if an error occurred. Call
  117. GetLastError to retrieve the error code.
  118. --*/
  119. {
  120. BOOL Result = FALSE;
  121. DWORD Ticks;
  122. if (REPORTONLY()) {
  123. return TRUE;
  124. }
  125. g_OlePool = PoolMemInitNamedPool ("OLE Reg");
  126. if (!g_OlePool) {
  127. return FALSE;
  128. }
  129. Ticks = GetTickCount();
  130. __try {
  131. ProgressBar_SetComponentById (MSG_OLEREG);
  132. //
  133. // Suppress all GUIDs from [Suppressed GUIDs] section of win95upg.inf:
  134. //
  135. // HKLM\SOFTWARE\Classes\CLSID\<GUID>
  136. // HKLM\SOFTWARE\Classes\Interface\<GUID>
  137. // HKLM\SOFTWARE\Classes\<ProgID>
  138. // HKLM\SOFTWARE\Classes\<VersionIndependentProgID>
  139. //
  140. // Suppress any GUID that has a TreatAs key that points to GUID
  141. //
  142. if (!pProcessGuidSuppressList()) {
  143. __leave;
  144. }
  145. TickProgressBar ();
  146. //
  147. // Scan ProgIDs in HKCR for reference to suppressed GUID
  148. //
  149. if (!pProcessProgIdSuppression()) {
  150. __leave;
  151. }
  152. TickProgressBar ();
  153. //
  154. // Scan HKCR for file extensions that need to be suppressed
  155. //
  156. if (!pProcessFileExtensionSuppression()) {
  157. __leave;
  158. }
  159. TickProgressBar ();
  160. //
  161. // Scan Explorer registry for references to suppressed GUIDs
  162. //
  163. if (!pProcessExplorerSuppression()) {
  164. __leave;
  165. }
  166. TickProgressBar ();
  167. //
  168. // Delete all links requiring incompatible OLE objects
  169. //
  170. if (!pSuppressLinksToSuppressedGuids()) {
  171. __leave;
  172. }
  173. TickProgressBar ();
  174. //
  175. // Preserve all files needed by DefaultIcon
  176. //
  177. if (!pDefaultIconPreservation()) {
  178. __leave;
  179. }
  180. TickProgressBar ();
  181. //
  182. // Preserve all INFs needed by ActiveSetup
  183. //
  184. if (!pActiveSetupProcessing ()) {
  185. __leave;
  186. }
  187. TickProgressBar ();
  188. #ifdef DEBUG
  189. // Checked build sanity check
  190. pProcessOleWarnings();
  191. TickProgressBar ();
  192. #endif
  193. ProgressBar_SetComponent (NULL);
  194. Result = TRUE;
  195. }
  196. __finally {
  197. PoolMemDestroyPool (g_OlePool);
  198. }
  199. Ticks = GetTickCount() - Ticks;
  200. g_ProgressBarTime += Ticks * 2;
  201. return Result;
  202. }
  203. DWORD
  204. SuppressOleGuids (
  205. IN DWORD Request
  206. )
  207. {
  208. switch (Request) {
  209. case REQUEST_QUERYTICKS:
  210. return OleReg_GetProgressMax ();
  211. case REQUEST_RUN:
  212. if (!pSuppressOleGuids ()) {
  213. return GetLastError ();
  214. }
  215. else {
  216. return ERROR_SUCCESS;
  217. }
  218. default:
  219. DEBUGMSG ((DBG_ERROR, "Bad parameter in SuppressOleGuids"));
  220. }
  221. return 0;
  222. }
  223. BOOL
  224. pProcessGuidSuppressList (
  225. VOID
  226. )
  227. /*++
  228. Routine Description:
  229. Processes [Suppressed GUIDs] and auto-suppression. Any OLE object that
  230. is listed in Suppressed GUIDs and exists on the machine is suppressed.
  231. Any OLE object that requires a suppressed object is auto-suppressed.
  232. Any OLE object that has a TreatAs entry to a suppressed object is
  233. suppressed.
  234. This routine performs all GUID suppression and must run first.
  235. ("Auto-suppress" refers to the ability to suppress related OLE objects
  236. that are not listed to be suppressed in win95upg.inf.)
  237. Arguments:
  238. none
  239. Return Value:
  240. TRUE if suppression was successful, or FALSE if an error occurred.
  241. --*/
  242. {
  243. HASHTABLE StrTab;
  244. LONG rc;
  245. REGKEY_ENUM e;
  246. HKEY GuidKey;
  247. PCTSTR Data;
  248. TCHAR Node[MEMDB_MAX];
  249. DWORD Count = 0;
  250. //
  251. // Suppress all GUIDs from [Suppressed GUIDs] section of win95upg.inf:
  252. //
  253. // HKLM\SOFTWARE\Classes\CLSID\<GUID>
  254. // HKLM\SOFTWARE\Classes\Interface\<GUID>
  255. //
  256. StrTab = HtAlloc();
  257. if (!StrTab) {
  258. LOG ((LOG_ERROR, "pProcessGuidSuppressList: Cannot create string table"));
  259. return FALSE;
  260. }
  261. pProcessAutoSuppress (StrTab);
  262. __try {
  263. //
  264. // Fill string table of all GUIDs
  265. //
  266. pFillHashTableWithKeyNames (StrTab, g_Win95UpgInf, S_SUPPRESSED_GUIDS);
  267. //
  268. // Search HKCR\CLSID for each GUID
  269. //
  270. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) {
  271. do {
  272. //
  273. // Determine if item is suppressed:
  274. //
  275. // - it is on the list in [Suppressed GUIDs] of win95upg.inf
  276. // - it is in the GUIDS category of memdb (from TreatAs)
  277. //
  278. //
  279. // First, determine if it is in [Suppressed GUIDs] or from
  280. // auto suppression.
  281. //
  282. rc = (LONG) HtFindString (StrTab, e.SubKeyName);
  283. if (!rc) {
  284. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, e.SubKeyName, NULL, NULL);
  285. if (MemDbGetValue (Node, NULL)) {
  286. rc = 0;
  287. } else {
  288. rc = -1;
  289. }
  290. }
  291. if (rc != -1) {
  292. pSuppressGuidInClsId (e.SubKeyName);
  293. }
  294. //
  295. // If not suppressed, check for TreatAs, and if TreatAs is found,
  296. // put TreatAs GUID in unsuppressed mapping. This is how we handle
  297. // the case where a GUID that is not normally suppressed, but has a
  298. // TreatAs member that points to a suppressed GUID will be suppressed
  299. // as well.
  300. //
  301. else {
  302. GuidKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  303. if (GuidKey) {
  304. Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("TreatAs"));
  305. if (Data) {
  306. //
  307. // Determine if TreatAs GUID is suppressed, and if it
  308. // is, suppress this GUID, otherwise put it on the
  309. // unsuppressed TreatAs list.
  310. //
  311. MemDbBuildKey (
  312. Node,
  313. MEMDB_CATEGORY_GUIDS,
  314. Data,
  315. NULL,
  316. NULL
  317. );
  318. if (MemDbGetValue (Node, NULL)) {
  319. pSuppressGuidInClsId (e.SubKeyName);
  320. } else {
  321. pAddUnsuppressedTreatAsGuid (Data, e.SubKeyName);
  322. }
  323. MemFree (g_hHeap, 0, Data);
  324. }
  325. CloseRegKey (GuidKey);
  326. }
  327. }
  328. Count++;
  329. if (!(Count % 128)) {
  330. TickProgressBar ();
  331. }
  332. } while (EnumNextRegKey (&e));
  333. }
  334. }
  335. __finally {
  336. //
  337. // Clean up string table and memdb
  338. //
  339. HtFree (StrTab);
  340. pRemoveUnsuppressedTreatAsGuids();
  341. }
  342. return TRUE;
  343. }
  344. BOOL
  345. pSuppressLinksToSuppressedGuids (
  346. VOID
  347. )
  348. /*++
  349. Routine Description:
  350. After the GUID suppression list has been made, we scan all the links that
  351. have GUIDs in their command line arguments to find ones that need to be
  352. removed.
  353. Arguments:
  354. none
  355. Return Value:
  356. TRUE if all links were processed, or FALSE if an error occurred.
  357. --*/
  358. {
  359. MEMDB_ENUM e, e2;
  360. TCHAR Node[MEMDB_MAX];
  361. if (MemDbEnumItems (&e, MEMDB_CATEGORY_LINK_GUIDS)) {
  362. do {
  363. //
  364. // Is this GUID suppressed?
  365. //
  366. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.szName);
  367. if (MemDbGetValue (Node, NULL)) {
  368. //
  369. // Yes -- enumerate all sequencers and delete the associated links
  370. //
  371. if (MemDbGetValueEx (&e2, MEMDB_CATEGORY_LINK_GUIDS, e.szName, NULL)) {
  372. do {
  373. if (MemDbBuildKeyFromOffset (e2.dwValue, Node, 1, NULL)) {
  374. //
  375. // Delete all the operations for the file in Node
  376. //
  377. RemoveAllOperationsFromPath (Node);
  378. //
  379. // Now mark file for text mode delete
  380. //
  381. MarkFileForDelete (Node);
  382. DEBUGMSG ((
  383. DBG_OLEREG,
  384. "Link %s points to an incompatible OLE object; deleting.",
  385. Node
  386. ));
  387. }
  388. } while (MemDbEnumNextValue (&e2));
  389. }
  390. }
  391. } while (MemDbEnumNextValue (&e));
  392. //
  393. // No longer needed -- recover space in memdb
  394. //
  395. MemDbDeleteTree (MEMDB_CATEGORY_LINK_GUIDS);
  396. MemDbDeleteTree (MEMDB_CATEGORY_LINK_STRINGS);
  397. }
  398. return TRUE;
  399. }
  400. BOOL
  401. pProcessFileExtensionSuppression (
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Suppresses any file extension that depends on a suppressed OLE object.
  407. The GUID suppression must be complete before this routine is called.
  408. Arguments:
  409. none
  410. Return Value:
  411. TRUE if suppression was successful, or FALSE if an error occurred.
  412. --*/
  413. {
  414. REGKEY_ENUM e;
  415. PCTSTR Data;
  416. TCHAR MemDbKey[MEMDB_MAX];
  417. DWORD value;
  418. BOOL Suppress;
  419. //
  420. // Suppresss any file extension that points to suppressed ProgID
  421. //
  422. if (EnumFirstRegKey (&e, HKEY_CLASSES_ROOT)) {
  423. do {
  424. if (_tcsnextc (e.SubKeyName) != TEXT('.')) {
  425. continue;
  426. }
  427. Suppress = FALSE;
  428. Data = (PCTSTR) GetRegKeyData (e.KeyHandle, e.SubKeyName);
  429. if (Data) {
  430. MemDbBuildKey (MemDbKey, MEMDB_CATEGORY_PROGIDS, NULL, NULL, Data);
  431. if (MemDbGetValue (MemDbKey, &value) &&
  432. (value == PROGID_SUPPRESSED)
  433. ) {
  434. //
  435. // This extension points to a suppressed ProgID key, so
  436. // suppress it.
  437. //
  438. Suppress = TRUE;
  439. } else {
  440. //
  441. // Check for this special case: the extension is for a CLSID,
  442. // not for a ProgId.
  443. //
  444. if (StringIMatchTcharCount (Data, TEXT("CLSID\\"), 6)) {
  445. if (pIsGuidSuppressed (Data + 6)) {
  446. Suppress = TRUE;
  447. }
  448. }
  449. }
  450. MemFree (g_hHeap, 0, Data);
  451. }
  452. if (!Suppress) {
  453. //
  454. // This tests GUIDs AND suppresses the extension if necessary
  455. //
  456. pIsShellExKeySuppressed (
  457. e.KeyHandle,
  458. e.SubKeyName,
  459. TEXT("ShellEx")
  460. );
  461. }
  462. if (Suppress) {
  463. MemDbBuildKey (
  464. MemDbKey,
  465. MEMDB_CATEGORY_HKLM,
  466. TEXT("SOFTWARE\\Classes"),
  467. NULL,
  468. e.SubKeyName
  469. );
  470. Suppress95RegSetting (MemDbKey, NULL);
  471. }
  472. } while (EnumNextRegKey (&e));
  473. }
  474. return TRUE;
  475. }
  476. #define MEMDB_CATEGORY_TMP_SUPPRESS TEXT("TmpSuppress")
  477. BOOL
  478. pIsCLSIDSuppressed (
  479. IN HKEY ParentKey,
  480. IN PCTSTR ParentKeyName,
  481. IN PCTSTR SubKeyName
  482. )
  483. {
  484. HKEY ClsIdKey;
  485. PCTSTR Data;
  486. BOOL result = FALSE;
  487. ClsIdKey = OpenRegKey (ParentKey, SubKeyName);
  488. if (ClsIdKey) {
  489. Data = GetRegKeyData (ClsIdKey, S_EMPTY);
  490. if (Data) {
  491. result = pIsGuidSuppressed (Data);
  492. DEBUGMSG_IF ((result, DBG_OLEREG, "ProgID %s has incompatible CLSID %s", ParentKeyName, Data));
  493. MemFree (g_hHeap, 0, Data);
  494. }
  495. CloseRegKey (ClsIdKey);
  496. }
  497. return result;
  498. }
  499. VOID
  500. pMarkProgIdAsLostDefault (
  501. IN PCTSTR ProgIdName
  502. )
  503. {
  504. if (ProgIdName) {
  505. MemDbSetValueEx (MEMDB_CATEGORY_PROGIDS, ProgIdName, NULL, NULL, PROGID_LOSTDEFAULT, NULL);
  506. }
  507. }
  508. BOOL
  509. pIsShellKeySuppressed (
  510. IN HKEY ParentKey,
  511. IN PCTSTR ParentKeyName,
  512. IN PCTSTR SubKeyName
  513. )
  514. {
  515. REGKEY_ENUM e;
  516. DWORD Processed, Suppressed;
  517. HKEY ShellKey;
  518. TCHAR key [MEMDB_MAX];
  519. PCTSTR Data;
  520. BOOL defaultKey = TRUE;
  521. PCTSTR defaultCommand = NULL;
  522. BOOL IsvCmdLine = FALSE;
  523. ShellKey = OpenRegKey (ParentKey, SubKeyName);
  524. Processed = Suppressed = 0;
  525. if (ShellKey) {
  526. Data = (PCTSTR) GetRegKeyData (ShellKey, S_EMPTY);
  527. if (Data) {
  528. defaultCommand = DuplicatePathString (Data, 0);
  529. defaultKey = FALSE;
  530. MemFree (g_hHeap, 0, Data);
  531. } else {
  532. defaultKey = TRUE;
  533. }
  534. if (EnumFirstRegKey (&e, ShellKey)) {
  535. do {
  536. Processed ++;
  537. if (defaultCommand) {
  538. defaultKey = StringIMatch (e.SubKeyName, defaultCommand);
  539. }
  540. MemDbBuildKey (key, e.SubKeyName, TEXT("command"), NULL, NULL);
  541. Data = (PCTSTR) GetRegKeyData (ShellKey, key);
  542. if (Data) {
  543. if (pIsCmdLineBadEx (Data, &IsvCmdLine)) {
  544. DEBUGMSG ((
  545. DBG_OLEREG,
  546. "ProgID %s has incompatible shell command: shell\\%s\\command[] = %s",
  547. ParentKeyName,
  548. e.SubKeyName,
  549. Data));
  550. MemDbSetValueEx (
  551. MEMDB_CATEGORY_TMP_SUPPRESS,
  552. ParentKeyName,
  553. SubKeyName,
  554. e.SubKeyName,
  555. 0,
  556. NULL);
  557. if (defaultKey) {
  558. pMarkProgIdAsLostDefault (ParentKeyName);
  559. }
  560. Suppressed ++;
  561. }
  562. else if (IsvCmdLine) {
  563. //
  564. // Keep this setting.
  565. //
  566. MemDbBuildKey (key, MEMDB_CATEGORY_HKLM TEXT("\\SOFTWARE\\Classes"), ParentKeyName, SubKeyName, e.SubKeyName);
  567. SuppressNtRegSetting (key, NULL);
  568. }
  569. MemFree (g_hHeap, 0, Data);
  570. }
  571. defaultKey = FALSE;
  572. } while (EnumNextRegKey (&e));
  573. }
  574. if (defaultCommand) {
  575. FreePathString (defaultCommand);
  576. }
  577. CloseRegKey (ShellKey);
  578. }
  579. if (Processed && (Processed == Suppressed)) {
  580. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL);
  581. MemDbDeleteTree (key);
  582. MemDbSetValue (key, 0);
  583. return TRUE;
  584. }
  585. return FALSE;
  586. }
  587. BOOL
  588. pIsProtocolKeySuppressed (
  589. IN HKEY ParentKey,
  590. IN PCTSTR ParentKeyName,
  591. IN PCTSTR SubKeyName
  592. )
  593. {
  594. REGKEY_ENUM e;
  595. DWORD Processed, Suppressed;
  596. HKEY ProtocolKey;
  597. TCHAR key [MEMDB_MAX];
  598. PCTSTR Data;
  599. ProtocolKey = OpenRegKey (ParentKey, SubKeyName);
  600. Processed = Suppressed = 0;
  601. if (ProtocolKey) {
  602. if (EnumFirstRegKey (&e, ProtocolKey)) {
  603. do {
  604. Processed ++;
  605. MemDbBuildKey (key, e.SubKeyName, TEXT("server"), NULL, NULL);
  606. Data = (PCTSTR) GetRegKeyData (ProtocolKey, key);
  607. if (Data) {
  608. if (pIsCmdLineBad (Data)) {
  609. DEBUGMSG ((
  610. DBG_OLEREG,
  611. "ProgID %s has incompatible protocol command: protocol\\%s\\server[] = %s",
  612. ParentKeyName,
  613. e.SubKeyName,
  614. Data));
  615. MemDbSetValueEx (
  616. MEMDB_CATEGORY_TMP_SUPPRESS,
  617. ParentKeyName,
  618. SubKeyName,
  619. e.SubKeyName,
  620. 0,
  621. NULL);
  622. Suppressed ++;
  623. }
  624. MemFree (g_hHeap, 0, Data);
  625. }
  626. } while (EnumNextRegKey (&e));
  627. }
  628. CloseRegKey (ProtocolKey);
  629. }
  630. if (Processed && (Processed == Suppressed)) {
  631. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL);
  632. MemDbDeleteTree (key);
  633. MemDbSetValue (key, 0);
  634. return TRUE;
  635. }
  636. return FALSE;
  637. }
  638. BOOL
  639. pIsExtensionsKeySuppressed (
  640. IN HKEY ParentKey,
  641. IN PCTSTR ParentKeyName,
  642. IN PCTSTR SubKeyName
  643. )
  644. {
  645. REGKEY_ENUM e;
  646. REGVALUE_ENUM ev;
  647. DWORD Processed, Suppressed;
  648. HKEY ExtensionsKey;
  649. TCHAR key [MEMDB_MAX];
  650. PCTSTR Data;
  651. ExtensionsKey = OpenRegKey (ParentKey, SubKeyName);
  652. Processed = Suppressed = 0;
  653. if (ExtensionsKey) {
  654. if (EnumFirstRegKey (&e, ExtensionsKey)) {
  655. do {
  656. Processed ++;
  657. Data = (PCTSTR) GetRegKeyData (ExtensionsKey, e.SubKeyName);
  658. if (Data) {
  659. if (pIsGuidSuppressed (Data)) {
  660. DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible extensions key %s", ParentKeyName, e.SubKeyName));
  661. MemDbSetValueEx (
  662. MEMDB_CATEGORY_TMP_SUPPRESS,
  663. ParentKeyName,
  664. SubKeyName,
  665. e.SubKeyName,
  666. 0,
  667. NULL);
  668. Suppressed ++;
  669. }
  670. MemFree (g_hHeap, 0, Data);
  671. }
  672. } while (EnumNextRegKey (&e));
  673. }
  674. if (EnumFirstRegValue (&ev, ExtensionsKey)) {
  675. do {
  676. Processed ++;
  677. if (ev.Type == REG_SZ) {
  678. Data = (PCTSTR) GetRegValueData (ExtensionsKey, ev.ValueName);
  679. if (Data) {
  680. if (pIsGuidSuppressed (Data)) {
  681. DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible extensions key %s", ParentKeyName, ev.ValueName));
  682. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL);
  683. Data = CreateEncodedRegistryString (key, ev.ValueName);
  684. MemDbSetValue (Data, 0);
  685. FreePathString (Data);
  686. Suppressed ++;
  687. }
  688. MemFree (g_hHeap, 0, Data);
  689. }
  690. }
  691. } while (EnumNextRegValue (&ev));
  692. }
  693. CloseRegKey (ExtensionsKey);
  694. }
  695. if (Processed && (Processed == Suppressed)) {
  696. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL);
  697. MemDbDeleteTree (key);
  698. MemDbSetValue (key, 0);
  699. return TRUE;
  700. }
  701. return FALSE;
  702. }
  703. BOOL
  704. pIsShellExKeySuppressed (
  705. IN HKEY ParentKey,
  706. IN PCTSTR ParentKeyName,
  707. IN PCTSTR SubKeyName
  708. )
  709. {
  710. REGKEY_ENUM e;
  711. DWORD Processed, Suppressed;
  712. HKEY ShellExKey;
  713. HKEY SubKey;
  714. PTSTR key;
  715. BOOL result = FALSE;
  716. PCTSTR Data;
  717. ShellExKey = OpenRegKey (ParentKey, SubKeyName);
  718. Processed = Suppressed = 0;
  719. if (ShellExKey) {
  720. if (EnumFirstRegKey (&e, ShellExKey)) {
  721. do {
  722. Processed ++;
  723. //
  724. // See if the key itself is a suppressed GUID
  725. //
  726. if (pIsGuidSuppressed (e.SubKeyName)) {
  727. DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible shell extension %s", ParentKeyName, e.SubKeyName));
  728. MemDbSetValueEx (
  729. MEMDB_CATEGORY_TMP_SUPPRESS,
  730. ParentKeyName,
  731. SubKeyName,
  732. e.SubKeyName,
  733. 0,
  734. NULL);
  735. Suppressed ++;
  736. continue;
  737. }
  738. //
  739. // See if the default value is a suppressed GUID
  740. //
  741. SubKey = OpenRegKey (ShellExKey, e.SubKeyName);
  742. if (SubKey) {
  743. Data = (PCTSTR) GetRegKeyData (SubKey, S_EMPTY);
  744. if (Data) {
  745. if (pIsGuidSuppressed (Data)) {
  746. DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible shell extension %s", ParentKeyName, Data));
  747. MemDbSetValueEx (
  748. MEMDB_CATEGORY_TMP_SUPPRESS,
  749. ParentKeyName,
  750. SubKeyName,
  751. e.SubKeyName,
  752. 0,
  753. NULL);
  754. Suppressed ++;
  755. MemFree (g_hHeap, 0, Data);
  756. CloseRegKey (SubKey);
  757. continue;
  758. }
  759. MemFree (g_hHeap, 0, Data);
  760. }
  761. CloseRegKey (SubKey);
  762. }
  763. //
  764. // Call recursively on this subkey
  765. //
  766. key = JoinPaths (ParentKeyName, SubKeyName);
  767. if (pIsShellExKeySuppressed (ShellExKey, key, e.SubKeyName)) {
  768. MemDbSetValueEx (
  769. MEMDB_CATEGORY_TMP_SUPPRESS,
  770. ParentKeyName,
  771. SubKeyName,
  772. e.SubKeyName,
  773. 0,
  774. NULL);
  775. Suppressed ++;
  776. }
  777. FreePathString (key);
  778. } while (EnumNextRegKey (&e));
  779. if (Processed && (Processed == Suppressed)) {
  780. key = (PTSTR)AllocPathString (MEMDB_MAX);
  781. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL);
  782. MemDbDeleteTree (key);
  783. MemDbSetValue (key, 0);
  784. FreePathString (key);
  785. result = TRUE;
  786. }
  787. }
  788. CloseRegKey (ShellExKey);
  789. }
  790. return result;
  791. }
  792. BOOL
  793. pProcessProgIdSuppression (
  794. VOID
  795. )
  796. {
  797. REGKEY_ENUM e;
  798. REGKEY_ENUM subKey;
  799. HKEY ProgIdKey;
  800. DWORD Processed, Suppressed;
  801. TCHAR key [MEMDB_MAX];
  802. MEMDB_ENUM memEnum;
  803. BOOL HarmlessKeyFound;
  804. BOOL ActiveSuppression;
  805. DWORD Count = 0;
  806. if (EnumFirstRegKeyStr (&e, TEXT("HKCR"))) {
  807. do {
  808. if (StringIMatch (e.SubKeyName, TEXT("CLSID"))) {
  809. continue;
  810. }
  811. if (StringIMatch (e.SubKeyName, TEXT("Interface"))) {
  812. continue;
  813. }
  814. if (StringIMatch (e.SubKeyName, TEXT("Applications"))) {
  815. continue;
  816. }
  817. if (StringIMatch (e.SubKeyName, TEXT("TypeLib"))) {
  818. continue;
  819. }
  820. if (_tcsnextc (e.SubKeyName) == TEXT('.')) {
  821. continue;
  822. }
  823. ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  824. if (ProgIdKey) {
  825. Processed = 0;
  826. Suppressed = 0;
  827. HarmlessKeyFound = 0;
  828. ActiveSuppression = FALSE;
  829. if (EnumFirstRegKey (&subKey, ProgIdKey)) {
  830. do {
  831. Processed ++;
  832. if (StringIMatch (subKey.SubKeyName, TEXT("CLSID"))) {
  833. if (pIsCLSIDSuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) {
  834. AbortRegKeyEnum (&subKey);
  835. Processed = Suppressed = 1;
  836. HarmlessKeyFound = 0;
  837. ActiveSuppression = TRUE;
  838. break;
  839. }
  840. }
  841. if (StringIMatch (subKey.SubKeyName, TEXT("Shell"))) {
  842. if (pIsShellKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) {
  843. ActiveSuppression = TRUE;
  844. Suppressed ++;
  845. }
  846. }
  847. if (StringIMatch (subKey.SubKeyName, TEXT("Protocol"))) {
  848. if (pIsProtocolKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) {
  849. ActiveSuppression = TRUE;
  850. Suppressed ++;
  851. }
  852. }
  853. if (StringIMatch (subKey.SubKeyName, TEXT("Extensions"))) {
  854. if (pIsExtensionsKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) {
  855. ActiveSuppression = TRUE;
  856. Suppressed ++;
  857. }
  858. }
  859. if (StringIMatch (subKey.SubKeyName, TEXT("ShellEx"))) {
  860. if (pIsShellExKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) {
  861. ActiveSuppression = TRUE;
  862. Suppressed ++;
  863. }
  864. }
  865. if (StringIMatch (subKey.SubKeyName, TEXT("DefaultIcon"))) {
  866. HarmlessKeyFound ++;
  867. }
  868. if (StringIMatch (subKey.SubKeyName, TEXT("Insertable"))) {
  869. HarmlessKeyFound ++;
  870. }
  871. if (StringIMatch (subKey.SubKeyName, TEXT("NotInsertable"))) {
  872. HarmlessKeyFound ++;
  873. }
  874. if (StringIMatch (subKey.SubKeyName, TEXT("ShellFolder"))) {
  875. HarmlessKeyFound ++;
  876. }
  877. } while (EnumNextRegKey (&subKey));
  878. }
  879. if (ActiveSuppression && (Processed == (Suppressed + HarmlessKeyFound))) {
  880. pSuppressProgId (e.SubKeyName);
  881. } else {
  882. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, e.SubKeyName, TEXT("*"), NULL);
  883. if (MemDbEnumFirstValue (&memEnum, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  884. do {
  885. MemDbBuildKey (key, MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), e.SubKeyName, memEnum.szName);
  886. Suppress95RegSetting (key, NULL);
  887. } while (MemDbEnumNextValue (&memEnum));
  888. }
  889. }
  890. MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, e.SubKeyName, NULL, NULL);
  891. MemDbDeleteTree (key);
  892. CloseRegKey (ProgIdKey);
  893. }
  894. Count++;
  895. if (!(Count % 64)) {
  896. TickProgressBar ();
  897. }
  898. } while (EnumNextRegKey (&e));
  899. }
  900. return TRUE;
  901. }
  902. BOOL
  903. pIsGuidSuppressed (
  904. PCTSTR GuidStr
  905. )
  906. /*++
  907. Routine Description:
  908. Determines if a GUID is suppressed or not, and also determines if a
  909. GUID is handled by a migration DLL.
  910. Arguments:
  911. GuidStr - Specifies the GUID to look up, which may or may not contain
  912. the surrounding braces
  913. Return Value:
  914. TRUE if the specified GUID is suppressed, or FALSE if it is not.
  915. The return value is FALSE if the GUID is handled by a migration DLL.
  916. --*/
  917. {
  918. TCHAR Node[MEMDB_MAX];
  919. TCHAR FixedGuid[MAX_GUID];
  920. if (!FixGuid (GuidStr, FixedGuid)) {
  921. return FALSE;
  922. }
  923. if (pIgnoreGuid (FixedGuid)) {
  924. return FALSE;
  925. }
  926. MemDbBuildKey (
  927. Node,
  928. MEMDB_CATEGORY_GUIDS,
  929. NULL,
  930. NULL,
  931. FixedGuid
  932. );
  933. return MemDbGetValue (Node, NULL);
  934. }
  935. BOOL
  936. pScanSubKeysForIncompatibleGuids (
  937. IN PCTSTR ParentKey
  938. )
  939. /*++
  940. Routine Description:
  941. Suppresses the subkeys of the supplied parent key that have text
  942. referencing an incompatible GUID.
  943. Arguments:
  944. ParentKey - Specifies the parent to enumerate keys for
  945. Return Value:
  946. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  947. processing.
  948. --*/
  949. {
  950. REGKEY_ENUM e;
  951. TCHAR Node[MEMDB_MAX];
  952. //
  953. // Enumerate the keys in ParentKey
  954. //
  955. if (EnumFirstRegKeyStr (&e, ParentKey)) {
  956. do {
  957. if (pIsGuidSuppressed (e.SubKeyName)) {
  958. //
  959. // Suppress the enumerated subkey
  960. //
  961. wsprintf (Node, TEXT("%s\\%s"), ParentKey, e.SubKeyName);
  962. Suppress95RegSetting (Node, NULL);
  963. }
  964. } while (EnumNextRegKey (&e));
  965. }
  966. return TRUE;
  967. }
  968. BOOL
  969. pScanValueNamesForIncompatibleGuids (
  970. IN PCTSTR ParentKey
  971. )
  972. /*++
  973. Routine Description:
  974. Suppresses the values of the supplied parent key that have value names
  975. referencing an incompatible GUID.
  976. Arguments:
  977. ParentKey - Specifies the parent to enumerate values of
  978. Return Value:
  979. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  980. processing.
  981. --*/
  982. {
  983. REGVALUE_ENUM e;
  984. HKEY Key;
  985. //
  986. // Enumerate the values in ParentKey
  987. //
  988. Key = OpenRegKeyStr (ParentKey);
  989. if (Key) {
  990. if (EnumFirstRegValue (&e, Key)) {
  991. do {
  992. if (pIsGuidSuppressed (e.ValueName)) {
  993. //
  994. // Suppress the enumerated value
  995. //
  996. Suppress95RegSetting (ParentKey, e.ValueName);
  997. }
  998. } while (EnumNextRegValue (&e));
  999. }
  1000. CloseRegKey (Key);
  1001. }
  1002. return TRUE;
  1003. }
  1004. BOOL
  1005. pScanValueDataForIncompatibleGuids (
  1006. IN PCTSTR ParentKey
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. Suppresses the values of the supplied parent key that have value data
  1011. referencing an incompatible GUID.
  1012. Arguments:
  1013. ParentKey - Specifies the parent to enumerate values of
  1014. Return Value:
  1015. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  1016. processing.
  1017. --*/
  1018. {
  1019. REGVALUE_ENUM e;
  1020. HKEY Key;
  1021. PCTSTR Data;
  1022. //
  1023. // Enumerate the values in ParentKey
  1024. //
  1025. Key = OpenRegKeyStr (ParentKey);
  1026. if (Key) {
  1027. if (EnumFirstRegValue (&e, Key)) {
  1028. do {
  1029. Data = GetRegValueString (Key, e.ValueName);
  1030. if (Data) {
  1031. if (pIsGuidSuppressed (Data)) {
  1032. //
  1033. // Suppress the enumerated value
  1034. //
  1035. Suppress95RegSetting (ParentKey, e.ValueName);
  1036. }
  1037. MemFree (g_hHeap, 0, Data);
  1038. }
  1039. } while (EnumNextRegValue (&e));
  1040. }
  1041. CloseRegKey (Key);
  1042. }
  1043. return TRUE;
  1044. }
  1045. BOOL
  1046. pCheckDefaultValueForIncompatibleGuids (
  1047. IN PCTSTR KeyStr
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Suppresses the specified key if its default value is a suppressed GUID.
  1052. Arguments:
  1053. KeyStr - Specifies key string to process
  1054. Return Value:
  1055. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  1056. processing.
  1057. --*/
  1058. {
  1059. PCTSTR Data;
  1060. HKEY Key;
  1061. //
  1062. // Examine the default value of KeyStr
  1063. //
  1064. Key = OpenRegKeyStr (KeyStr);
  1065. if (Key) {
  1066. Data = GetRegValueString (Key, S_EMPTY);
  1067. CloseRegKey (Key);
  1068. } else {
  1069. Data = NULL;
  1070. }
  1071. if (Data) {
  1072. if (pIsGuidSuppressed (Data)) {
  1073. //
  1074. // Suppress the specified reg key
  1075. //
  1076. Suppress95RegSetting (KeyStr, NULL);
  1077. }
  1078. MemFree (g_hHeap, 0, Data);
  1079. }
  1080. return TRUE;
  1081. }
  1082. BOOL
  1083. pScanDefaultValuesForIncompatibleGuids (
  1084. IN PCTSTR ParentKey
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. Suppresses subkeys that have a default value that is a suppressed GUID.
  1089. Arguments:
  1090. ParentKey - Specifies key string to process
  1091. Return Value:
  1092. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  1093. processing.
  1094. --*/
  1095. {
  1096. REGKEY_ENUM e;
  1097. TCHAR Node[MEMDB_MAX];
  1098. PCTSTR Data;
  1099. HKEY Key;
  1100. //
  1101. // Enumerate the keys in ParentKey
  1102. //
  1103. if (EnumFirstRegKeyStr (&e, ParentKey)) {
  1104. do {
  1105. Key = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1106. if (Key) {
  1107. Data = GetRegValueString (Key, S_EMPTY);
  1108. } else {
  1109. Data = NULL;
  1110. }
  1111. CloseRegKey (Key);
  1112. if (Data) {
  1113. if (pIsGuidSuppressed (Data)) {
  1114. //
  1115. // Suppress the enumerated subkey
  1116. //
  1117. wsprintf (Node, TEXT("%s\\%s"), ParentKey, e.SubKeyName);
  1118. Suppress95RegSetting (Node, NULL);
  1119. }
  1120. MemFree (g_hHeap, 0, Data);
  1121. }
  1122. } while (EnumNextRegKey (&e));
  1123. }
  1124. return TRUE;
  1125. }
  1126. BOOL
  1127. pProcessExplorerSuppression (
  1128. VOID
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. Suppresses the settings in
  1133. HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks
  1134. that reference incompatible GUIDs.
  1135. Arguments:
  1136. none
  1137. Return Value:
  1138. TRUE if everything is OK, or FALSE if an unexpected error occurred during
  1139. processing.
  1140. --*/
  1141. {
  1142. BOOL b = TRUE;
  1143. //
  1144. // Suppress Win9x-specific value data in CSSFilters
  1145. //
  1146. if (b) {
  1147. b = pScanValueDataForIncompatibleGuids (S_EXPLORER_CSSFILTERS);
  1148. }
  1149. //
  1150. // Suppress Win9x-specific keys in Desktop\NameSpace
  1151. //
  1152. if (b) {
  1153. b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_DESKTOP_NAMESPACE);
  1154. }
  1155. //
  1156. // Suppress key of FileTypesPropertySheetHook if default value is Win9x-specific
  1157. //
  1158. if (b) {
  1159. b = pCheckDefaultValueForIncompatibleGuids (S_EXPLORER_FILETYPESPROPERTYSHEETHOOK);
  1160. }
  1161. //
  1162. // Suppress subkeys of FindExtensions if default value is Win9x-specific
  1163. //
  1164. if (b) {
  1165. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_FINDEXTENSIONS);
  1166. }
  1167. //
  1168. // Scan MyComputer\NameSpace for subkeys or subkeys with default values
  1169. // pointing to incompatible GUIDs.
  1170. //
  1171. if (b) {
  1172. b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_MYCOMPUTER_NAMESPACE);
  1173. }
  1174. if (b) {
  1175. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_MYCOMPUTER_NAMESPACE);
  1176. }
  1177. //
  1178. // Scan NetworkNeighborhood\NameSpace for subkeys or subkeys with default values
  1179. // pointing to incompatible GUIDs.
  1180. //
  1181. if (b) {
  1182. b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE);
  1183. }
  1184. if (b) {
  1185. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE);
  1186. }
  1187. //
  1188. // Suppress values that reference incompatible GUIDs
  1189. //
  1190. if (b) {
  1191. b = pScanValueNamesForIncompatibleGuids (S_EXPLORER_NEWSHORTCUTHANDLERS);
  1192. }
  1193. //
  1194. // Scan RemoteComputer\NameSpace for subkeys or subkeys with default values
  1195. // pointing to incompatible GUIDs.
  1196. //
  1197. if (b) {
  1198. b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_REMOTECOMPUTER_NAMESPACE);
  1199. }
  1200. if (b) {
  1201. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_REMOTECOMPUTER_NAMESPACE);
  1202. }
  1203. //
  1204. // Scan ShellExecuteHooks for value names referencing incompatible GUIDs
  1205. //
  1206. if (b) {
  1207. b = pScanValueNamesForIncompatibleGuids (S_EXPLORER_SHELLEXECUTEHOOKS);
  1208. }
  1209. //
  1210. // Scan ShellIconOverlayIdentifiers for subkeys with default values referencing
  1211. // incompatible GUIDs
  1212. //
  1213. if (b) {
  1214. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_SHELLICONOVERLAYIDENTIFIERS);
  1215. }
  1216. //
  1217. // Scan VolumeCaches for subkeys with default values referencing
  1218. // incompatible GUIDs
  1219. //
  1220. if (b) {
  1221. b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_VOLUMECACHES);
  1222. }
  1223. //
  1224. // Scan ExtShellViews for subkeys that reference incompatible GUIDs
  1225. //
  1226. if (b) {
  1227. b = pScanSubKeysForIncompatibleGuids (S_EXTSHELLVIEWS);
  1228. }
  1229. //
  1230. // Scan Shell Extensions\Approved for value names referencing incompatible
  1231. // GUIDs
  1232. //
  1233. if (b) {
  1234. b = pScanValueNamesForIncompatibleGuids (S_SHELLEXTENSIONS_APPROVED);
  1235. }
  1236. //
  1237. // Scan ShellServiceObjectDelayLoad for value data referencing incompatible
  1238. // GUIDs
  1239. //
  1240. if (b) {
  1241. b = pScanValueDataForIncompatibleGuids (S_SHELLSERVICEOBJECTDELAYLOAD);
  1242. }
  1243. return b;
  1244. }
  1245. BOOL
  1246. ExtractIconIntoDatFile (
  1247. IN PCTSTR LongPath,
  1248. IN INT IconIndex,
  1249. IN OUT PICON_EXTRACT_CONTEXT Context,
  1250. OUT PINT NewIconIndex OPTIONAL
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. ExtractIconIntoDatFile preserves a Win9x icon by extracting it from the 9x
  1255. system. If the EXE and icon index pair are known good, then this function
  1256. returns FALSE. Otherwise, this function extracts the icon and saves it into
  1257. a DAT file for processing in GUI mode setup. If icon extraction fails, then
  1258. the default generic icon from shell32.dll is used.
  1259. Arguments:
  1260. LongPath - Specifies the full path to the PE image
  1261. IconIndex - Specifies the icon index to extract. Negative index values
  1262. provide a specific icon resource ID. Positive index values
  1263. indicate which icon, where 0 is the first icon, 1 is the second
  1264. icon, and so on.
  1265. Context - Specifies the extraction context that gives the DAT file and other
  1266. info (used by icon extraction utilities).
  1267. NewIconIndex - Receives the new icon index in
  1268. %windir%\system32\migicons.exe, if the function returns TRUE.
  1269. Zero otherwise.
  1270. Return Value:
  1271. TRUE if the icon was extracted, or if the icon could not be extracted but
  1272. the icon is not known-good. (The default generic icon is used in this case.)
  1273. FALSE if the icon is known-good and does not need to be extracted.
  1274. --*/
  1275. {
  1276. MULTISZ_ENUM MultiSz;
  1277. TCHAR Node[MEMDB_MAX];
  1278. TCHAR IconId[256];
  1279. TCHAR IconIndexStr[32];
  1280. PCTSTR IconList;
  1281. PCTSTR extPtr;
  1282. INT i;
  1283. DWORD Offset;
  1284. static WORD Seq = 0;
  1285. DWORD OrgSeq;
  1286. BOOL result = FALSE;
  1287. BOOL needDefaultIcon = FALSE;
  1288. if (NewIconIndex) {
  1289. *NewIconIndex = 0;
  1290. }
  1291. __try {
  1292. //
  1293. // Is this a compatible icon binary? If so, return FALSE.
  1294. //
  1295. if (IsIconKnownGood (LongPath, IconIndex)) {
  1296. __leave;
  1297. }
  1298. //
  1299. // From this point on, if we fail to extract the icon, use the default.
  1300. //
  1301. needDefaultIcon = TRUE;
  1302. if (!Seq) {
  1303. //
  1304. // Extract the icon from shell32.dll for the default icon. This is
  1305. // the "generic app" icon. We keep the Win9x generic icon instead
  1306. // of the updated NT generic icon, so there is a clear indication
  1307. // that we failed to extract the right thing from Win9x.
  1308. //
  1309. DEBUGMSG ((DBG_OLEREG, "DefaultIconExtraction: Extracting a default icon"));
  1310. Offset = SetFilePointer (Context->IconImageFile, 0, NULL, FILE_CURRENT);
  1311. wsprintf (Node, TEXT("%s\\system\\shell32.dll"), g_WinDir);
  1312. if (!CopyIcon (Context, Node, TEXT("#1"), 0)) {
  1313. DEBUGMSG ((
  1314. DBG_ERROR,
  1315. "DefaultIconExtraction: Can't extract default icon from %s",
  1316. Node
  1317. ));
  1318. } else {
  1319. MemDbBuildKey (
  1320. Node,
  1321. MEMDB_CATEGORY_ICONS,
  1322. TEXT("%s\\system\\shell32.dll"),
  1323. TEXT("0"),
  1324. NULL
  1325. );
  1326. MemDbSetValueAndFlags (Node, Offset, Seq, 0xffff);
  1327. Seq++;
  1328. }
  1329. }
  1330. //
  1331. // Has the icon been extracted already?
  1332. //
  1333. extPtr = GetFileExtensionFromPath (LongPath);
  1334. if ((IconIndex >= 0) && extPtr && (!StringIMatch (extPtr, TEXT("ICO")))) {
  1335. //
  1336. // IconIndex specifies sequential order; get list of
  1337. // resource IDs and find the right one.
  1338. //
  1339. IconList = ExtractIconNamesFromFile (LongPath, &Context->IconList);
  1340. i = IconIndex;
  1341. IconId[0] = 0;
  1342. if (IconList) {
  1343. if (EnumFirstMultiSz (&MultiSz, IconList)) {
  1344. while (i > 0) {
  1345. if (!EnumNextMultiSz (&MultiSz)) {
  1346. break;
  1347. }
  1348. i--;
  1349. }
  1350. if (!i) {
  1351. StringCopy (IconId, MultiSz.CurrentString);
  1352. }
  1353. ELSE_DEBUGMSG ((DBG_OLEREG, "Icon %i not found in %s", i, LongPath));
  1354. }
  1355. }
  1356. ELSE_DEBUGMSG ((DBG_OLEREG, "Icon %i not found in %s", i, LongPath));
  1357. } else {
  1358. //
  1359. // IconIndex specifies resource ID
  1360. //
  1361. wsprintf (IconId, TEXT("#%i"), -IconIndex);
  1362. }
  1363. if (!IconId[0]) {
  1364. //
  1365. // Failed to find icon or failed to read icon index from EXE
  1366. //
  1367. __leave;
  1368. }
  1369. wsprintf (IconIndexStr, TEXT("%i"), IconIndex);
  1370. MemDbBuildKey (Node, MEMDB_CATEGORY_ICONS, LongPath, IconIndexStr, NULL);
  1371. if (!MemDbGetValueAndFlags (Node, NULL, &OrgSeq)) {
  1372. //
  1373. // Extract the icon and save it in a file. During GUI
  1374. // mode, the icon will be saved to a resource-only DLL.
  1375. //
  1376. DEBUGMSG ((
  1377. DBG_OLEREG,
  1378. "Extracting default icon %s in file %s",
  1379. IconId,
  1380. LongPath
  1381. ));
  1382. Offset = SetFilePointer (Context->IconImageFile, 0, NULL, FILE_CURRENT);
  1383. if (!CopyIcon (Context, LongPath, IconId, 0)) {
  1384. DEBUGMSG ((
  1385. DBG_OLEREG,
  1386. "DefaultIconExtraction: CopyIcon failed for %s, %i (%s)!",
  1387. LongPath,
  1388. IconIndex,
  1389. IconId
  1390. ));
  1391. __leave;
  1392. }
  1393. if (NewIconIndex) {
  1394. *NewIconIndex = (INT) (UINT) Seq;
  1395. }
  1396. MemDbBuildKey (
  1397. Node,
  1398. MEMDB_CATEGORY_ICONS,
  1399. LongPath,
  1400. IconIndexStr,
  1401. NULL
  1402. );
  1403. MemDbSetValueAndFlags (Node, Offset, Seq, 0xffff);
  1404. Seq++;
  1405. } else {
  1406. if (NewIconIndex) {
  1407. *NewIconIndex = (INT) (UINT) OrgSeq;
  1408. }
  1409. }
  1410. result = TRUE;
  1411. }
  1412. __finally {
  1413. //
  1414. // Even if we fail, return success if we want the caller to use
  1415. // the default icon (at index 0).
  1416. //
  1417. result |= needDefaultIcon;
  1418. }
  1419. return result;
  1420. }
  1421. VOID
  1422. pExtractDefaultIcon (
  1423. PCTSTR Data,
  1424. PICON_EXTRACT_CONTEXT Context
  1425. )
  1426. {
  1427. TCHAR ArgZero[MAX_CMDLINE];
  1428. TCHAR LongPath[MAX_TCHAR_PATH];
  1429. INT IconIndex;
  1430. PCTSTR p;
  1431. BOOL LongPathFound = FALSE;
  1432. //
  1433. // Determine if the first arg of the command line points to a
  1434. // deleted file or a file to be replaced
  1435. //
  1436. ExtractArgZeroEx (Data, ArgZero, TEXT(","), FALSE);
  1437. p = (PCTSTR) ((PBYTE) Data + ByteCount (ArgZero));
  1438. while (*p == TEXT(' ')) {
  1439. p++;
  1440. }
  1441. if (*p == TEXT(',')) {
  1442. IconIndex = _ttoi (_tcsinc (p));
  1443. } else {
  1444. IconIndex = 0;
  1445. }
  1446. if (!_tcschr (ArgZero, TEXT('\\'))) {
  1447. if (SearchPath (NULL, ArgZero, NULL, MAX_TCHAR_PATH, LongPath, NULL)) {
  1448. LongPathFound = TRUE;
  1449. }
  1450. }
  1451. if (LongPathFound || OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) {
  1452. if (FILESTATUS_UNCHANGED != GetFileStatusOnNt (LongPath)) {
  1453. ExtractIconIntoDatFile (
  1454. LongPath,
  1455. IconIndex,
  1456. Context,
  1457. NULL
  1458. );
  1459. }
  1460. }
  1461. }
  1462. VOID
  1463. pExtractAllDefaultIcons (
  1464. IN HKEY ParentKey
  1465. )
  1466. {
  1467. HKEY DefaultIconKey;
  1468. REGVALUE_ENUM e;
  1469. PCTSTR Data;
  1470. DefaultIconKey = OpenRegKey (ParentKey, TEXT("DefaultIcon"));
  1471. if (DefaultIconKey) {
  1472. //
  1473. // Check all values in DefaultIcon
  1474. //
  1475. if (EnumFirstRegValue (&e, DefaultIconKey)) {
  1476. do {
  1477. Data = (PCTSTR) GetRegValueString (DefaultIconKey, e.ValueName);
  1478. if (Data) {
  1479. pExtractDefaultIcon (Data, &g_IconContext);
  1480. MemFree (g_hHeap, 0, Data);
  1481. }
  1482. } while (EnumNextRegValue (&e));
  1483. }
  1484. CloseRegKey (DefaultIconKey);
  1485. }
  1486. }
  1487. BOOL
  1488. pDefaultIconPreservation (
  1489. VOID
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. This routine scans the DefaultIcon setting of OLE classes and identifies
  1494. any default icon that will be lost by deletion. A copy of the icon is
  1495. stored away in a directory called MigIcons.
  1496. Arguments:
  1497. none
  1498. Return Value:
  1499. TRUE unless an unexpected error occurs.
  1500. --*/
  1501. {
  1502. REGKEY_ENUM e;
  1503. HKEY ProgIdKey;
  1504. TCHAR key[MEMDB_MAX];
  1505. DWORD value;
  1506. //
  1507. // Scan all ProgIDs, looking for default icons that are currently
  1508. // set for deletion. Once found, don't delete the icon, but instead
  1509. // copy the image to %windir%\setup\temp\migicons.
  1510. //
  1511. if (EnumFirstRegKeyStr (&e, TEXT("HKCR"))) {
  1512. do {
  1513. //
  1514. // We extract the icons for all ProgIds that survive on NT.
  1515. //
  1516. MemDbBuildKey (key, MEMDB_CATEGORY_PROGIDS, e.SubKeyName, NULL, NULL);
  1517. if (!MemDbGetValue (key, &value) ||
  1518. (value != PROGID_SUPPRESSED)
  1519. ) {
  1520. ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1521. if (ProgIdKey) {
  1522. pExtractAllDefaultIcons (ProgIdKey);
  1523. CloseRegKey (ProgIdKey);
  1524. }
  1525. }
  1526. } while (EnumNextRegKey (&e));
  1527. }
  1528. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) {
  1529. do {
  1530. //
  1531. // We extract the icons for all GUIDs (even for the suppressed ones).
  1532. // The reason is that if NT installs this GUID we do want to replace
  1533. // the NT default icon with the 9x icon.
  1534. //
  1535. ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1536. if (ProgIdKey) {
  1537. pExtractAllDefaultIcons (ProgIdKey);
  1538. CloseRegKey (ProgIdKey);
  1539. }
  1540. } while (EnumNextRegKey (&e));
  1541. }
  1542. return TRUE;
  1543. }
  1544. BOOL
  1545. pActiveSetupProcessing (
  1546. VOID
  1547. )
  1548. /*++
  1549. Routine Description:
  1550. This routine scans the Active Setup key and suppresses incompatible GUIDs
  1551. and Installed Components subkeys that reference deleted files. If a
  1552. stub path references an INF, we preserve the INF.
  1553. Arguments:
  1554. none
  1555. Return Value:
  1556. TRUE unless an unexpected error occurs.
  1557. --*/
  1558. {
  1559. REGKEY_ENUM e;
  1560. HKEY InstalledComponentKey;
  1561. PCTSTR Data;
  1562. TCHAR ArgZero[MAX_CMDLINE];
  1563. TCHAR LongPath[MAX_TCHAR_PATH];
  1564. TCHAR Node[MEMDB_MAX];
  1565. PCTSTR p;
  1566. PTSTR q;
  1567. PTSTR DupText;
  1568. DWORD status;
  1569. //
  1570. // Scan all Installed Components
  1571. //
  1572. if (EnumFirstRegKeyStr (&e, S_ACTIVESETUP)) {
  1573. do {
  1574. //
  1575. // Determine if the GUID is suppressed, and if it is, suppress
  1576. // the entire Installed Components setting
  1577. //
  1578. if (pIsGuidSuppressed (e.SubKeyName)) {
  1579. wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName);
  1580. Suppress95RegSetting (Node, NULL);
  1581. continue;
  1582. }
  1583. //
  1584. // Get StubPath and determine if it references incompatible files
  1585. //
  1586. InstalledComponentKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1587. if (InstalledComponentKey) {
  1588. __try {
  1589. Data = GetRegValueString (InstalledComponentKey, TEXT("StubPath"));
  1590. if (Data) {
  1591. __try {
  1592. //
  1593. // Determine if the first arg of the command line points to a
  1594. // deleted file
  1595. //
  1596. ExtractArgZeroEx (Data, ArgZero, TEXT(","), FALSE);
  1597. if (OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) {
  1598. status = GetFileStatusOnNt (LongPath);
  1599. if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) {
  1600. //
  1601. // Suppress this key
  1602. //
  1603. wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName);
  1604. Suppress95RegSetting (Node, NULL);
  1605. #pragma prefast(suppress:242, "Perf of breaking try/finally unimportant here")
  1606. continue;
  1607. }
  1608. }
  1609. DupText = NULL;
  1610. //
  1611. // Scan command line for an LaunchINFSectionEx reference
  1612. //
  1613. p = _tcsistr (Data, TEXT("LaunchINF"));
  1614. if (p) {
  1615. p = _tcschr (p, TEXT(' '));
  1616. }
  1617. if (p) {
  1618. while (*p == TEXT(' ')) {
  1619. p = _tcsinc (p);
  1620. }
  1621. //
  1622. // Instead of deleting this file, lets move it
  1623. //
  1624. DupText = DuplicateText (p);
  1625. q = _tcschr (DupText, TEXT(','));
  1626. if (q) {
  1627. *q = 0;
  1628. }
  1629. }
  1630. if (!DupText) {
  1631. p = _tcsistr (Data, TEXT("InstallHInfSection"));
  1632. if (p) {
  1633. p = _tcschr (p, TEXT(' '));
  1634. if (p) {
  1635. p = _tcschr (_tcsinc (p), TEXT(' '));
  1636. // p points to end of section name or NULL
  1637. }
  1638. if (p) {
  1639. p = _tcschr (_tcsinc (p), TEXT(' '));
  1640. // p points to end of number of NULL
  1641. }
  1642. if (p) {
  1643. p = _tcsinc (p);
  1644. DupText = DuplicateText (p);
  1645. }
  1646. }
  1647. }
  1648. if (DupText) {
  1649. if (OurGetLongPathName (DupText, LongPath, MAX_TCHAR_PATH)) {
  1650. status = GetFileStatusOnNt (LongPath);
  1651. if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) {
  1652. //
  1653. // Suppress the setting
  1654. //
  1655. wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName);
  1656. Suppress95RegSetting (Node, NULL);
  1657. }
  1658. }
  1659. FreeText (DupText);
  1660. }
  1661. }
  1662. __finally {
  1663. MemFree (g_hHeap, 0, Data);
  1664. }
  1665. }
  1666. }
  1667. __finally {
  1668. CloseRegKey (InstalledComponentKey);
  1669. }
  1670. }
  1671. } while (EnumNextRegKey (&e));
  1672. }
  1673. return TRUE;
  1674. }
  1675. #ifdef DEBUG
  1676. PCTSTR g_ProgIdFileRefKeys[] = {
  1677. g_DefaultIcon,
  1678. NULL
  1679. };
  1680. TCHAR g_BaseInterface[] = TEXT("BaseInterface");
  1681. TCHAR g_ProxyStubClsId[] = TEXT("ProxyStubClsId");
  1682. TCHAR g_ProxyStubClsId32[] = TEXT("ProxyStubClsId32");
  1683. TCHAR g_TypeLib[] = TEXT("ProxyStubClsId32");
  1684. PCTSTR g_InterfaceRefKeys[] = {
  1685. g_BaseInterface,
  1686. g_ProxyStubClsId,
  1687. g_ProxyStubClsId32,
  1688. g_TypeLib,
  1689. NULL
  1690. };
  1691. BOOL
  1692. pProcessOleWarnings (
  1693. VOID
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. For checked builds, this routine examines the linkage of the entire
  1698. OLE registry and identifies problems such as abandoned links and
  1699. broken inheritance.
  1700. Arguments:
  1701. none
  1702. Return Value:
  1703. TRUE unless an unexpected error occurs.
  1704. --*/
  1705. {
  1706. REGKEY_ENUM e;
  1707. HKEY ClsIdKey;
  1708. HKEY InterfaceKey;
  1709. PCTSTR Data;
  1710. TCHAR Node[MEMDB_MAX];
  1711. BOOL Suppressed;
  1712. INT i;
  1713. //
  1714. // Search HKCR\CLSID for problems
  1715. //
  1716. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) {
  1717. do {
  1718. //
  1719. // Verify key is not garbage
  1720. //
  1721. if (!FixGuid (e.SubKeyName, e.SubKeyName)) {
  1722. continue;
  1723. }
  1724. ClsIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1725. //
  1726. // Determine if this GUID is suppressed
  1727. //
  1728. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName);
  1729. Suppressed = MemDbGetValue (Node, NULL);
  1730. if (ClsIdKey) {
  1731. if (!Suppressed) {
  1732. //
  1733. // Unsuppressed GUID checks
  1734. //
  1735. // AutoConvertTo
  1736. Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("AutoConvertTo"));
  1737. if (Data) {
  1738. //
  1739. // Check if AutoConvertTo is pointing to suppressed GUID
  1740. //
  1741. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data);
  1742. if (MemDbGetValue (Node, NULL)) {
  1743. DEBUGMSG ((DBG_WARNING,
  1744. "GUID %s points to deleted GUID %s",
  1745. e.SubKeyName, Data
  1746. ));
  1747. pAddOleWarning (
  1748. MSG_OBJECT_POINTS_TO_DELETED_GUID,
  1749. ClsIdKey,
  1750. e.SubKeyName
  1751. );
  1752. }
  1753. MemFree (g_hHeap, 0, Data);
  1754. }
  1755. // File references
  1756. for (i = 0 ; g_FileRefKeys[i] ; i++) {
  1757. Data = (PCTSTR) GetRegKeyData (ClsIdKey, g_FileRefKeys[i]);
  1758. if (Data) {
  1759. //
  1760. // Check if the file in Data is in Win9xFileLocation for
  1761. // all users
  1762. //
  1763. pSuppressGuidIfCmdLineBad (
  1764. NULL,
  1765. Data,
  1766. ClsIdKey,
  1767. e.SubKeyName
  1768. );
  1769. MemFree (g_hHeap, 0, Data);
  1770. }
  1771. }
  1772. } else {
  1773. //
  1774. // Suppressed GUID checks
  1775. //
  1776. Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("Interface"));
  1777. if (Data) {
  1778. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data);
  1779. if (MemDbGetValue (Node, NULL)) {
  1780. DEBUGMSG ((DBG_WARNING,
  1781. "Suppressed GUID %s has Interface reference "
  1782. "to unsuppressed %s (potential leak)",
  1783. e.SubKeyName, Data));
  1784. pAddOleWarning (MSG_GUID_LEAK, ClsIdKey, e.SubKeyName);
  1785. }
  1786. MemFree (g_hHeap, 0, Data);
  1787. }
  1788. }
  1789. CloseRegKey (ClsIdKey);
  1790. }
  1791. } while (EnumNextRegKey (&e));
  1792. }
  1793. //
  1794. // Look for problems with an HKCR\Interface entry
  1795. //
  1796. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\Interface"))) {
  1797. do {
  1798. InterfaceKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1799. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName);
  1800. Suppressed = MemDbGetValue (Node, NULL);
  1801. if (InterfaceKey) {
  1802. for (i = 0 ; g_InterfaceRefKeys[i] ; i++) {
  1803. Data = (PCTSTR) GetRegKeyData (
  1804. InterfaceKey,
  1805. g_InterfaceRefKeys[i]
  1806. );
  1807. if (Data) {
  1808. //
  1809. // Check if reference to other GUID is suppressed
  1810. //
  1811. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data);
  1812. if (MemDbGetValue (Node, NULL)) {
  1813. if (!Suppressed) {
  1814. TCHAR CompleteKey[MAX_REGISTRY_KEY];
  1815. //
  1816. // Interface is not suppressed, but it points to a
  1817. // suppressed interface.
  1818. //
  1819. wsprintf (
  1820. CompleteKey,
  1821. TEXT("HKCR\\Interface\\%s"),
  1822. e.SubKeyName
  1823. );
  1824. DEBUGMSG ((
  1825. DBG_WARNING,
  1826. "GUID %s %s subkey points to suppressed GUID %s",
  1827. e.SubKeyName,
  1828. g_InterfaceRefKeys[i],
  1829. Data
  1830. ));
  1831. pAddOleWarning (
  1832. MSG_INTERFACE_BROKEN,
  1833. InterfaceKey,
  1834. CompleteKey
  1835. );
  1836. }
  1837. } else {
  1838. if (Suppressed) {
  1839. TCHAR CompleteKey[MAX_REGISTRY_KEY];
  1840. //
  1841. // Interface is suppressed, but it points to an
  1842. // unsuppressed interface.
  1843. //
  1844. wsprintf (
  1845. CompleteKey,
  1846. TEXT("HKCR\\Interface\\%s"),
  1847. e.SubKeyName
  1848. );
  1849. DEBUGMSG ((
  1850. DBG_WARNING,
  1851. "Suppressed GUID %s %s subkey points to "
  1852. "unsuppressed GUID %s (potential leak)",
  1853. e.SubKeyName,
  1854. g_InterfaceRefKeys[i],
  1855. Data
  1856. ));
  1857. pAddOleWarning (
  1858. MSG_POTENTIAL_INTERFACE_LEAK,
  1859. InterfaceKey,
  1860. CompleteKey
  1861. );
  1862. }
  1863. }
  1864. MemFree (g_hHeap, 0, Data);
  1865. }
  1866. }
  1867. CloseRegKey (InterfaceKey);
  1868. }
  1869. } while (EnumNextRegKey (&e));
  1870. }
  1871. return TRUE;
  1872. }
  1873. #endif
  1874. VOID
  1875. pProcessAutoSuppress (
  1876. IN OUT HASHTABLE StrTab
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. Performs a number of tests to identify OLE objects that are not compatible
  1881. with Windows NT. The tests are based on a list of incompatible files stored
  1882. in memdb. Any OLE object that depends on a file that will not exist on NT
  1883. is automatically suppressed.
  1884. Arguments:
  1885. StrTab - Specifies the string table that holds suppressed GUIDs
  1886. Return Value:
  1887. none
  1888. --*/
  1889. {
  1890. REGKEY_ENUM e, eVer, eNr;
  1891. HKEY ClsIdKey;
  1892. HKEY TypeLibKey;
  1893. HKEY VerKey;
  1894. HKEY NrKey;
  1895. HKEY SubSysKey;
  1896. TCHAR Node[MEMDB_MAX];
  1897. BOOL Suppressed;
  1898. PCTSTR Data;
  1899. BOOL ValidNr;
  1900. BOOL ValidVer;
  1901. BOOL ValidGUID;
  1902. //
  1903. // Search HKCR\CLSID for objects that require a Win95-specific binary
  1904. //
  1905. DEBUGMSG ((DBG_OLEREG, "Looking for CLSID problems..."));
  1906. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) {
  1907. do {
  1908. //
  1909. // Verify key is not garbage
  1910. //
  1911. if (!FixGuid (e.SubKeyName, e.SubKeyName)) {
  1912. DEBUGMSG ((
  1913. DBG_OLEREG,
  1914. "Garbage key ignored: HKCR\\CLSID\\%s",
  1915. e.SubKeyName
  1916. ));
  1917. continue;
  1918. }
  1919. ClsIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1920. //
  1921. // Determine if this GUID is suppressed
  1922. //
  1923. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName);
  1924. Suppressed = MemDbGetValue (Node, NULL);
  1925. if (ClsIdKey) {
  1926. if (!Suppressed) {
  1927. //
  1928. // Unsuppressed GUID checks
  1929. //
  1930. // AutoConvertTo
  1931. Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("AutoConvertTo"));
  1932. if (Data) {
  1933. //
  1934. // Check if AutoConvertTo is pointing to suppressed GUID
  1935. //
  1936. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data);
  1937. if (MemDbGetValue (Node, NULL)) {
  1938. DEBUGMSG ((
  1939. DBG_OLEREG,
  1940. "GUID %s points to deleted GUID %s -> "
  1941. "Auto-suppressed",
  1942. e.SubKeyName,
  1943. Data
  1944. ));
  1945. pAddGuidToTable (StrTab, e.SubKeyName);
  1946. }
  1947. MemFree (g_hHeap, 0, Data);
  1948. }
  1949. // File references
  1950. pSuppressGuidIfBadCmdLine (StrTab, ClsIdKey, e.SubKeyName);
  1951. }
  1952. CloseRegKey (ClsIdKey);
  1953. }
  1954. } while (EnumNextRegKey (&e));
  1955. }
  1956. DEBUGMSG ((DBG_OLEREG, "Looking for TypeLib problems..."));
  1957. if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\TypeLib"))) {
  1958. do {
  1959. //
  1960. // Verify key is not garbage
  1961. //
  1962. if (!FixGuid (e.SubKeyName, e.SubKeyName)) {
  1963. DEBUGMSG ((
  1964. DBG_OLEREG,
  1965. "Garbage key ignored: HKCR\\TypeLib\\%s",
  1966. e.SubKeyName
  1967. ));
  1968. continue;
  1969. }
  1970. TypeLibKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  1971. if (TypeLibKey) {
  1972. MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName);
  1973. Suppressed = MemDbGetValue (Node, NULL);
  1974. if (!Suppressed) {
  1975. ValidGUID = FALSE;
  1976. //
  1977. // Enumerating all versions
  1978. //
  1979. if (EnumFirstRegKey (&eVer, TypeLibKey)) {
  1980. do {
  1981. VerKey = OpenRegKey (eVer.KeyHandle, eVer.SubKeyName);
  1982. if (VerKey) {
  1983. ValidVer = FALSE;
  1984. //
  1985. // Enumerating all subkeys except HELPDIR and FLAGS
  1986. //
  1987. if (EnumFirstRegKey (&eNr, VerKey)) {
  1988. do {
  1989. if (StringIMatch (eNr.SubKeyName, TEXT("FLAGS"))) {
  1990. continue;
  1991. }
  1992. if (StringIMatch (eNr.SubKeyName, TEXT("HELPDIR"))) {
  1993. continue;
  1994. }
  1995. NrKey = OpenRegKey (eNr.KeyHandle, eNr.SubKeyName);
  1996. if (NrKey) {
  1997. ValidNr = FALSE;
  1998. SubSysKey = OpenRegKey (NrKey, TEXT("win16"));
  1999. if (SubSysKey) {
  2000. Data = GetRegValueString (SubSysKey, TEXT(""));
  2001. if (Data) {
  2002. if (pIsCmdLineBad (Data)) {
  2003. wsprintf (
  2004. Node,
  2005. "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s\\%s",
  2006. MEMDB_CATEGORY_HKLM,
  2007. e.SubKeyName,
  2008. eVer.SubKeyName,
  2009. eNr.SubKeyName,
  2010. TEXT("win16")
  2011. );
  2012. Suppress95RegSetting(Node, NULL);
  2013. }
  2014. else {
  2015. ValidNr = TRUE;
  2016. }
  2017. MemFree (g_hHeap, 0, Data);
  2018. }
  2019. CloseRegKey (SubSysKey);
  2020. }
  2021. SubSysKey = OpenRegKey (NrKey, TEXT("win32"));
  2022. if (SubSysKey) {
  2023. Data = GetRegValueString (SubSysKey, TEXT(""));
  2024. if (Data) {
  2025. if (pIsCmdLineBad (Data)) {
  2026. wsprintf (
  2027. Node,
  2028. "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s\\%s",
  2029. MEMDB_CATEGORY_HKLM,
  2030. e.SubKeyName,
  2031. eVer.SubKeyName,
  2032. eNr.SubKeyName,
  2033. TEXT("win32")
  2034. );
  2035. Suppress95RegSetting(Node, NULL);
  2036. }
  2037. else {
  2038. ValidNr = TRUE;
  2039. }
  2040. MemFree (g_hHeap, 0, Data);
  2041. }
  2042. CloseRegKey (SubSysKey);
  2043. }
  2044. CloseRegKey (NrKey);
  2045. if (!ValidNr) {
  2046. wsprintf (
  2047. Node,
  2048. "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s",
  2049. MEMDB_CATEGORY_HKLM,
  2050. e.SubKeyName,
  2051. eVer.SubKeyName,
  2052. eNr.SubKeyName
  2053. );
  2054. Suppress95RegSetting(Node, NULL);
  2055. }
  2056. else {
  2057. ValidVer = TRUE;
  2058. }
  2059. }
  2060. } while (EnumNextRegKey (&eNr));
  2061. }
  2062. CloseRegKey (VerKey);
  2063. if (!ValidVer) {
  2064. wsprintf (
  2065. Node,
  2066. "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s",
  2067. MEMDB_CATEGORY_HKLM,
  2068. e.SubKeyName,
  2069. eVer.SubKeyName
  2070. );
  2071. Suppress95RegSetting(Node, NULL);
  2072. }
  2073. else {
  2074. ValidGUID = TRUE;
  2075. }
  2076. }
  2077. } while (EnumNextRegKey (&eVer));
  2078. }
  2079. if (!ValidGUID) {
  2080. DEBUGMSG ((
  2081. DBG_OLEREG,
  2082. "TypeLib GUID %s is suppressed",
  2083. e.SubKeyName
  2084. ));
  2085. MemDbSetValueEx (MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName, 0, NULL);
  2086. }
  2087. }
  2088. CloseRegKey (TypeLibKey);
  2089. }
  2090. } while (EnumNextRegKey (&e));
  2091. }
  2092. }
  2093. BOOL
  2094. pGetFirstRegKeyThatHasGuid (
  2095. OUT PGUIDKEYSEARCH EnumPtr,
  2096. IN HKEY RootKey
  2097. )
  2098. /*++
  2099. Routine Description:
  2100. pGetFirstRegKeyThatHasGuid starts an enumeration of an OLE object's
  2101. ShellEx subkey. This subkey has zero or more handlers, and each
  2102. handler has zero or more GUIDs. This ShellEx enumerator returns
  2103. the first GUID subkey found under the supplied root.
  2104. Arguments:
  2105. EnumPtr - An uninitialized GUIDKEYSEARCH struct that is used
  2106. to maintain enumeration state and to report the match
  2107. found.
  2108. RootKey - The registry key to begin enumerating at.
  2109. Return Value:
  2110. TRUE if a GUID was found in a handler that is a subkey of RootKey, or
  2111. FALSE if no GUIDs were found.
  2112. --*/
  2113. {
  2114. EnumPtr->State = GUIDKEYSEARCH_FIRST_HANDLER;
  2115. EnumPtr->RootKey = RootKey;
  2116. return pGetNextRegKeyThatHasGuid (EnumPtr);
  2117. }
  2118. BOOL
  2119. pGetNextRegKeyThatHasGuid (
  2120. IN OUT PGUIDKEYSEARCH EnumPtr
  2121. )
  2122. /*++
  2123. Routine Description:
  2124. The "next" enumerator for ShellEx registry key enumeration. This
  2125. enumerator returns the next instance of a GUID in the registry
  2126. (under an OLE object's ShellEx subkey).
  2127. Arguments:
  2128. EnumPtr - The GUIDKEYSEARCH structure used to begin the search.
  2129. If a GUID is found, this structure holds the location
  2130. of the GUID key found.
  2131. Return Value:
  2132. TRUE if a subkey identifying a GUID was found, or FALSE if no
  2133. more instances exist.
  2134. --*/
  2135. {
  2136. BOOL Found = FALSE;
  2137. do {
  2138. switch (EnumPtr->State) {
  2139. case GUIDKEYSEARCH_FIRST_HANDLER:
  2140. //
  2141. // Get the name of the first handler
  2142. //
  2143. if (!EnumFirstRegKey (&EnumPtr->Handlers, EnumPtr->RootKey)) {
  2144. return FALSE;
  2145. }
  2146. EnumPtr->State = GUIDKEYSEARCH_FIRST_GUID;
  2147. break;
  2148. case GUIDKEYSEARCH_NEXT_HANDLER:
  2149. //
  2150. // Get the name of the next handler
  2151. //
  2152. if (!EnumNextRegKey (&EnumPtr->Handlers)) {
  2153. return FALSE;
  2154. }
  2155. EnumPtr->State = GUIDKEYSEARCH_FIRST_GUID;
  2156. break;
  2157. case GUIDKEYSEARCH_FIRST_GUID:
  2158. //
  2159. // Begin GUID key enumeration
  2160. //
  2161. EnumPtr->HandlerKey = OpenRegKey (EnumPtr->Handlers.KeyHandle,
  2162. EnumPtr->Handlers.SubKeyName);
  2163. // Assume no GUIDs
  2164. EnumPtr->State = GUIDKEYSEARCH_NEXT_HANDLER;
  2165. if (EnumPtr->HandlerKey) {
  2166. if (EnumFirstRegKey (&EnumPtr->Guids, EnumPtr->HandlerKey)) {
  2167. //
  2168. // There is at least one key that may be a GUID in this handler
  2169. //
  2170. Found = FixGuid (EnumPtr->Guids.SubKeyName, EnumPtr->Guids.SubKeyName);
  2171. EnumPtr->State = GUIDKEYSEARCH_NEXT_GUID;
  2172. } else {
  2173. CloseRegKey (EnumPtr->HandlerKey);
  2174. }
  2175. }
  2176. break;
  2177. case GUIDKEYSEARCH_NEXT_GUID:
  2178. //
  2179. // Continue GUID key enumeration
  2180. //
  2181. if (!EnumNextRegKey (&EnumPtr->Guids)) {
  2182. CloseRegKey (EnumPtr->HandlerKey);
  2183. EnumPtr->State = GUIDKEYSEARCH_NEXT_HANDLER;
  2184. } else {
  2185. Found = FixGuid (EnumPtr->Guids.SubKeyName, EnumPtr->Guids.SubKeyName);
  2186. }
  2187. break;
  2188. }
  2189. } while (!Found);
  2190. EnumPtr->KeyName = EnumPtr->Guids.SubKeyName;
  2191. return TRUE;
  2192. }
  2193. DWORD
  2194. pCountGuids (
  2195. IN PGUIDKEYSEARCH EnumPtr
  2196. )
  2197. /*++
  2198. Routine Description:
  2199. Given a valid EnumPtr, this function will count the total number
  2200. of GUIDs in the current handler.
  2201. Arguments:
  2202. EnumPtr - Must be a valid GUIDKEYSEARCH structure, prepared by
  2203. pGetFirstRegKeyThatHasGuid or pGetNextRegKeyThatHasGuid.
  2204. Return Value:
  2205. The count of valid GUIDs for the current handler.
  2206. --*/
  2207. {
  2208. REGKEY_ENUM e;
  2209. DWORD Count = 0;
  2210. //
  2211. // Count the number of GUIDs in the current handler
  2212. //
  2213. if (EnumPtr->State == GUIDKEYSEARCH_NEXT_GUID) {
  2214. if (EnumFirstRegKey (&e, EnumPtr->HandlerKey)) {
  2215. do {
  2216. Count++;
  2217. } while (EnumNextRegKey (&e));
  2218. }
  2219. }
  2220. return Count;
  2221. }
  2222. BOOL
  2223. pFillHashTableWithKeyNames (
  2224. OUT HASHTABLE Table,
  2225. IN HINF InfFile,
  2226. IN PCTSTR Section
  2227. )
  2228. /*++
  2229. Routine Description:
  2230. A general-purpose INF-to-string table copy routine. Takes the keys
  2231. in a given section and adds them to the supplied string table.
  2232. Arguments:
  2233. Table - A pointer to an initialize string table
  2234. InfFile - The handle to an open INF file
  2235. Section - Section within the INF file containing strings
  2236. Return Value:
  2237. TRUE if no errors were encountered.
  2238. --*/
  2239. {
  2240. INFCONTEXT ic;
  2241. TCHAR Key[MAX_ENCODED_RULE];
  2242. if (SetupFindFirstLine (InfFile, Section, NULL, &ic)) {
  2243. do {
  2244. if (SetupGetStringField (&ic, 0, Key, MAX_ENCODED_RULE, NULL)) {
  2245. HtAddString (Table, Key);
  2246. }
  2247. ELSE_DEBUGMSG ((
  2248. DBG_WARNING,
  2249. "No key for line in section %s (line %u)",
  2250. Section,
  2251. ic.Line
  2252. ));
  2253. } while (SetupFindNextLine (&ic, &ic));
  2254. }
  2255. ELSE_DEBUGMSG ((DBG_WARNING, "Section %s is empty", Section));
  2256. return TRUE;
  2257. }
  2258. BOOL
  2259. pSuppressProgId (
  2260. PCTSTR ProgIdName
  2261. )
  2262. /*++
  2263. Routine Description:
  2264. Suppresses a ProgID registry key.
  2265. Arguments:
  2266. ProgIdName - The name of the OLE ProgID to suppress
  2267. Return Value:
  2268. TRUE if ProgIdName is a valid ProgID on the system.
  2269. --*/
  2270. {
  2271. TCHAR RegKey[MAX_REGISTRY_KEY];
  2272. HKEY ProgIdKey;
  2273. TCHAR MemDbKey[MEMDB_MAX];
  2274. if (*ProgIdName) {
  2275. wsprintf (RegKey, TEXT("HKCR\\%s"), ProgIdName);
  2276. ProgIdKey = OpenRegKeyStr (RegKey);
  2277. if (ProgIdKey) {
  2278. CloseRegKey (ProgIdKey);
  2279. DEBUGMSG ((DBG_OLEREG, "Suppressing ProgId: %s", ProgIdName));
  2280. MemDbSetValueEx (MEMDB_CATEGORY_PROGIDS, NULL, NULL, ProgIdName, PROGID_SUPPRESSED, NULL);
  2281. MemDbBuildKey(MemDbKey,MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), NULL, ProgIdName);
  2282. Suppress95RegSetting(MemDbKey,NULL);
  2283. return TRUE;
  2284. }
  2285. }
  2286. return FALSE;
  2287. }
  2288. VOID
  2289. pSuppressGuidInClsId (
  2290. IN PCTSTR Guid
  2291. )
  2292. /*++
  2293. Routine Description:
  2294. Does all the work necessary to suppress a GUID and its associated
  2295. ProgID (if it has one).
  2296. Arguments:
  2297. Guid - The string identifing a GUID that is in HKCR\CLSID
  2298. Return Value:
  2299. none
  2300. --*/
  2301. {
  2302. TCHAR Node[MEMDB_MAX];
  2303. MEMDB_ENUM e;
  2304. HKEY GuidKey;
  2305. PCTSTR Data;
  2306. MYASSERT (IsGuid (Guid, TRUE));
  2307. if (pIgnoreGuid (Guid)) {
  2308. return;
  2309. }
  2310. //
  2311. // - Remove it from UGUIDS memdb category
  2312. // - Add it to GUIDS memdb category
  2313. // - Suppress HKLM\SOFTWARE\Classes\CLSID\<GUID>
  2314. // - Suppress HKLM\SOFTWARE\Classes\Interface\<GUID>
  2315. //
  2316. // Suppress all TreatAs GUIDs
  2317. if (MemDbGetValueEx (&e, MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL)) {
  2318. do {
  2319. pSuppressGuidInClsId (e.szName);
  2320. } while (MemDbEnumNextValue (&e));
  2321. }
  2322. // Remove TreatAs GUIDs
  2323. MemDbBuildKey (Node, MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL, NULL);
  2324. MemDbDeleteTree (Node);
  2325. // Add to suppressed GUID category and to registry suppression
  2326. MemDbSetValueEx (MEMDB_CATEGORY_GUIDS, NULL, NULL, Guid, 0, NULL);
  2327. // Get ProgID of GUID
  2328. wsprintf (Node, TEXT("HKCR\\CLSID\\%s"), Guid);
  2329. GuidKey = OpenRegKeyStr (Node);
  2330. if (GuidKey) {
  2331. BOOL ProgIdFound = FALSE;
  2332. // Suppress ProgIDs
  2333. Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("ProgID"));
  2334. if (Data) {
  2335. ProgIdFound |= pSuppressProgId (Data);
  2336. MemFree (g_hHeap, 0, Data);
  2337. }
  2338. // Version-independent ProgIDs
  2339. Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("VersionIndependentProgID"));
  2340. if (Data) {
  2341. ProgIdFound |= pSuppressProgId (Data);
  2342. MemFree (g_hHeap, 0, Data);
  2343. }
  2344. // Possibly the default name
  2345. Data = (PCTSTR) GetRegValueData (GuidKey, TEXT(""));
  2346. if (Data) {
  2347. ProgIdFound |= pSuppressProgId (Data);
  2348. MemFree (g_hHeap, 0, Data);
  2349. }
  2350. DEBUGMSG_IF ((
  2351. !ProgIdFound,
  2352. DBG_OLEREG,
  2353. "The suppressed registry key %s has no associated ProgID",
  2354. Node
  2355. ));
  2356. CloseRegKey (GuidKey);
  2357. }
  2358. }
  2359. VOID
  2360. pAddUnsuppressedTreatAsGuid (
  2361. PCTSTR Guid,
  2362. PCTSTR TreatAsGuid
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. Keeps track of unsuppressed TreatAs GUIDs that need further processing.
  2367. Arguments:
  2368. Guid - A string identifying the GUID that should be treated as
  2369. another GUID
  2370. TreatAsGuid - The replacement GUID
  2371. Return Value:
  2372. none
  2373. --*/
  2374. {
  2375. MemDbSetValueEx (MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL, TreatAsGuid, 0, NULL);
  2376. }
  2377. VOID
  2378. pRemoveUnsuppressedTreatAsGuids (
  2379. VOID
  2380. )
  2381. /*++
  2382. Routine Description:
  2383. Cleanup function for unsuppressed GUIDs.
  2384. Arguments:
  2385. none
  2386. Return Value:
  2387. none
  2388. --*/
  2389. {
  2390. TCHAR Node[MEMDB_MAX];
  2391. MemDbBuildKey (Node, MEMDB_CATEGORY_UNSUP_GUIDS, NULL, NULL, NULL);
  2392. MemDbDeleteTree (Node);
  2393. }
  2394. VOID
  2395. pAddOleWarning (
  2396. IN WORD MsgId,
  2397. IN HKEY Object, OPTIONAL
  2398. IN PCTSTR KeyName
  2399. )
  2400. /*++
  2401. Routine Description:
  2402. Adds a warning to the incompatibility report. It loads the human-readable
  2403. name from the specified OLE registry key. The message is formatted with
  2404. the human-readable object name as the first parameter and the registry
  2405. location as the second parameter.
  2406. Arguments:
  2407. MsgID - Supplies the ID of the message to display
  2408. Object - Specifies the handle of a registry key whos default value
  2409. is a human-readable object name.
  2410. KeyName - The registry key location
  2411. Return Value:
  2412. none
  2413. --*/
  2414. {
  2415. PCTSTR Data;
  2416. if (Object) {
  2417. Data = (PCTSTR) GetRegValueData (Object, S_EMPTY);
  2418. } else {
  2419. Data = NULL;
  2420. }
  2421. LOG ((LOG_WARNING, (PCSTR)MsgId, Data ? Data : S_EMPTY, KeyName, g_Win95Name));
  2422. if (Data) {
  2423. MemFree (g_hHeap, 0, Data);
  2424. }
  2425. }
  2426. VOID
  2427. pSuppressGuidIfBadCmdLine (
  2428. IN HASHTABLE StrTab,
  2429. IN HKEY ClsIdKey,
  2430. IN PCTSTR GuidStr
  2431. )
  2432. /*++
  2433. Routine Description:
  2434. Suppresses the specified GUID if its CLSID settings reference a Win9x-
  2435. specific binary. The suppression is written to a string table which
  2436. is later transfered to memdb. The transfer operation suppresses all
  2437. linkage to the GUID.
  2438. Arguments:
  2439. StrTab - The table that holds a list of suppressed GUIDs
  2440. ClsIdKey - The registry handle of a subkey of HKCR\CLSID
  2441. GuidStr - The GUID to suppress if an invalid command line is found
  2442. Return Value:
  2443. none
  2444. --*/
  2445. {
  2446. PCTSTR Data;
  2447. INT i;
  2448. BOOL b;
  2449. MYASSERT (IsGuid (GuidStr, TRUE));
  2450. if (pIgnoreGuid (GuidStr)) {
  2451. return;
  2452. }
  2453. for (i = 0 ; g_FileRefKeys[i] ; i++) {
  2454. Data = (PCTSTR) GetRegKeyData (ClsIdKey, g_FileRefKeys[i]);
  2455. if (Data) {
  2456. //
  2457. // Check if the file in Data is in Win9xFileLocation for any user
  2458. //
  2459. b = pSuppressGuidIfCmdLineBad (
  2460. StrTab,
  2461. Data,
  2462. ClsIdKey,
  2463. GuidStr
  2464. );
  2465. MemFree (g_hHeap, 0, Data);
  2466. if (b) {
  2467. return;
  2468. }
  2469. }
  2470. }
  2471. }
  2472. VOID
  2473. pSuppressProgIdWithBadCmdLine (
  2474. IN HKEY ProgId,
  2475. IN PCTSTR ProgIdStr
  2476. )
  2477. /*++
  2478. Routine Description:
  2479. Suppresses the specified ProgId if it references a Win9x-specific binary.
  2480. The suppression is written directly to memdb.
  2481. This function is called after all Suppressed GUIDs have been processed,
  2482. and is used to suppress OLE objects that are not caught by an invalid
  2483. HKCR\CLSID entry.
  2484. Arguments:
  2485. ProgId - The registry handle of a subkey of the root of HKCR
  2486. ProgIdStr - The name of the ProgID key to suppress if a bad cmd line is
  2487. found.
  2488. Return Value:
  2489. none
  2490. --*/
  2491. {
  2492. PCTSTR Data;
  2493. INT i;
  2494. for (i = 0 ; g_FileRefKeys[i]; i++) {
  2495. Data = (PCTSTR) GetRegKeyData (ProgId, g_FileRefKeys[i]);
  2496. if (Data) {
  2497. //
  2498. // Check if the file in Data is in Win9xFileLocation for any user
  2499. //
  2500. if (pIsCmdLineBad (Data)) {
  2501. DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible command line %s", ProgId, Data));
  2502. pSuppressProgId (ProgIdStr);
  2503. break;
  2504. }
  2505. MemFree (g_hHeap, 0, Data);
  2506. }
  2507. }
  2508. }
  2509. VOID
  2510. pAddGuidToTable (
  2511. IN HASHTABLE Table,
  2512. IN PCTSTR GuidStr
  2513. )
  2514. /*++
  2515. Routine Description:
  2516. Adds a GUID to a string table. For checked builds, it does a quick
  2517. test to see how many GUIDs get suppressed more than once.
  2518. Arguments:
  2519. Table - Specifies table that receives the GUID entry
  2520. GuidStr - Specifies the string of the GUID
  2521. Return Value:
  2522. none
  2523. --*/
  2524. {
  2525. #ifdef DEBUG
  2526. //
  2527. // Just for yuks, let's see if we're wasting time by suppressing
  2528. // an already suppressed GUID...
  2529. //
  2530. DWORD rc;
  2531. if (HtFindString (Table, GuidStr)) {
  2532. DEBUGMSG ((DBG_OLEREG, "FYI - GUID %s is already suppressed", GuidStr));
  2533. }
  2534. MYASSERT (IsGuid (GuidStr, TRUE));
  2535. #endif
  2536. HtAddString (Table, GuidStr);
  2537. }
  2538. BOOL
  2539. pSuppressGuidIfCmdLineBad (
  2540. IN OUT HASHTABLE StrTab, OPTIONAL
  2541. IN PCTSTR CmdLine,
  2542. IN HKEY DescriptionKey,
  2543. IN PCTSTR GuidStr OPTIONAL
  2544. )
  2545. /*++
  2546. Routine Description:
  2547. Suppresses an OLE object if the specified command line contains a Win9x-
  2548. specific binary. Only the first argument of the command line is examined;
  2549. an other arguments that cannot be upgraded are ignored.
  2550. Arguments:
  2551. StrTab - Specifies the table that holds the list of suppressed GUIDs.
  2552. If NULL, a warning will be displayed, and GuidKey must not be
  2553. NULL.
  2554. CmdLine - Specifies the command line to examine
  2555. DescriptionKey - Specifies a key whos default value is the description of the
  2556. object.
  2557. GuidStr - Specifies the GUID string. This parameter is optional only
  2558. if StrTab is NULL.
  2559. Return Value:
  2560. TRUE if CmdLine is incompatible, FALSE otherwise.
  2561. --*/
  2562. {
  2563. BOOL b = FALSE;
  2564. if (GuidStr) {
  2565. MYASSERT (IsGuid (GuidStr, TRUE));
  2566. if (pIgnoreGuid (GuidStr)) {
  2567. return TRUE;
  2568. }
  2569. }
  2570. if (pIsCmdLineBad (CmdLine)) {
  2571. //
  2572. // OLE object points to deleted file
  2573. //
  2574. b = TRUE;
  2575. if (!StrTab) {
  2576. // Warning!!
  2577. DEBUGMSG ((DBG_WARNING,
  2578. "Reg key %s points to deleted file %s",
  2579. GuidStr, CmdLine));
  2580. pAddOleWarning (
  2581. MSG_OBJECT_POINTS_TO_DELETED_FILE,
  2582. DescriptionKey,
  2583. GuidStr
  2584. );
  2585. } else {
  2586. MYASSERT (GuidStr);
  2587. DEBUGMSG ((
  2588. DBG_OLEREG,
  2589. "Auto-suppressed %s because it requires a Win9x-specific file: %s",
  2590. GuidStr,
  2591. CmdLine
  2592. ));
  2593. pAddGuidToTable (StrTab, GuidStr);
  2594. }
  2595. }
  2596. return b;
  2597. }
  2598. BOOL
  2599. pSearchSubkeyDataForBadFiles (
  2600. IN OUT HASHTABLE SuppressTable,
  2601. IN HKEY KeyHandle,
  2602. IN PCTSTR LastKey,
  2603. IN PCTSTR GuidStr,
  2604. IN HKEY DescriptionKey
  2605. )
  2606. /*++
  2607. Routine Description:
  2608. Scans a number of OLE settings for bad command lines, including the
  2609. object's command and the default icon binary. If a reference to a
  2610. Win9x-specific binary is detected, the GUID is suppressed.
  2611. This function recurses through all subkeys of the OLE object.
  2612. Arguments:
  2613. SuppressTable - Specifies the table that holds the suppressed GUID list
  2614. KeyHandle - An open registry key of an OLE object to be examined
  2615. recursively.
  2616. LastKey - Specifies the name of the OLE object's subkey being
  2617. processed. Special processing is done for some subkeys.
  2618. GuidStr - The GUID of the OLE object.
  2619. DescriptionKey - A handle to the key who's default value identifies the
  2620. OLE object's key.
  2621. Return Value:
  2622. TRUE if an incompatible cmd line was found, FALSE otherwise.
  2623. --*/
  2624. {
  2625. REGKEY_ENUM ek;
  2626. REGVALUE_ENUM ev;
  2627. HKEY SubKeyHandle;
  2628. PCTSTR Data;
  2629. BOOL b;
  2630. MYASSERT (IsGuid (GuidStr, FALSE));
  2631. if (StringIMatch (LastKey, TEXT("Command")) ||
  2632. StringIMatch (LastKey, g_DefaultIcon)
  2633. ) {
  2634. if (EnumFirstRegValue (&ev, KeyHandle)) {
  2635. do {
  2636. Data = (PCTSTR) GetRegValueData (KeyHandle, ev.ValueName);
  2637. if (Data) {
  2638. // If this thing has a path name somewhere, process it
  2639. b = pSuppressGuidIfCmdLineBad (
  2640. SuppressTable,
  2641. Data,
  2642. DescriptionKey,
  2643. GuidStr
  2644. );
  2645. MemFree (g_hHeap, 0, Data);
  2646. if (b) {
  2647. return TRUE;
  2648. }
  2649. }
  2650. } while (EnumNextRegValue (&ev));
  2651. }
  2652. }
  2653. if (EnumFirstRegKey (&ek, KeyHandle)) {
  2654. do {
  2655. SubKeyHandle = OpenRegKey (ek.KeyHandle, ek.SubKeyName);
  2656. if (SubKeyHandle) {
  2657. b = pSearchSubkeyDataForBadFiles (
  2658. SuppressTable,
  2659. SubKeyHandle,
  2660. ek.SubKeyName,
  2661. GuidStr,
  2662. DescriptionKey
  2663. );
  2664. CloseRegKey (SubKeyHandle);
  2665. if (b) {
  2666. AbortRegKeyEnum (&ek);
  2667. return TRUE;
  2668. }
  2669. }
  2670. } while (EnumNextRegKey (&ek));
  2671. }
  2672. return FALSE;
  2673. }
  2674. BOOL
  2675. pIsCmdLineBadEx (
  2676. IN PCTSTR CmdLine,
  2677. OUT PBOOL UsableIsvCmdLine OPTIONAL
  2678. )
  2679. /*++
  2680. Routine Description:
  2681. Determines if the specified command line's first argument is listed in
  2682. memdb's Win9xFileLocation category. If it is listed, and the file is
  2683. marked for permanent removal, TRUE is returned. If it is not listed,
  2684. or if it is listed but has an NT equivalent, FALSE is returned.
  2685. Arguments:
  2686. CmdLine - Specifies the command line to examine
  2687. UsableIsvCmdLine - Optional variable that receives wether the
  2688. command line contains a compatible third
  2689. party cmd line.
  2690. Return Value:
  2691. TRUE if command line requires Win9x-specific binaries, FALSE if
  2692. the command line uses a valid binary or is not a command line.
  2693. --*/
  2694. {
  2695. BOOL FileMarked = FALSE;
  2696. TCHAR ArgZero[MAX_CMDLINE];
  2697. TCHAR LongPath[MAX_TCHAR_PATH];
  2698. DWORD status;
  2699. if (UsableIsvCmdLine) {
  2700. *UsableIsvCmdLine = FALSE;
  2701. }
  2702. //
  2703. // Determine if the first arg of the command line points to a
  2704. // deleted (or moved) file
  2705. //
  2706. ExtractArgZeroEx (CmdLine, ArgZero, TEXT(","), FALSE);
  2707. if (OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) {
  2708. status = GetFileStatusOnNt (LongPath);
  2709. if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) {
  2710. return TRUE;
  2711. }
  2712. else if (UsableIsvCmdLine) {
  2713. status = GetOperationsOnPath (LongPath);
  2714. if ((status & OPERATION_OS_FILE) != OPERATION_OS_FILE) {
  2715. *UsableIsvCmdLine = TRUE;
  2716. }
  2717. }
  2718. }
  2719. ELSE_DEBUGMSG ((
  2720. DBG_OLEREG,
  2721. "pIsCmdLineBad: Cannot get full path name; assuming %s is not a command line",
  2722. ArgZero
  2723. ));
  2724. return FALSE;
  2725. }
  2726. BOOL
  2727. pIsCmdLineBad (
  2728. IN PCTSTR CmdLine
  2729. )
  2730. {
  2731. return pIsCmdLineBadEx (CmdLine, NULL);
  2732. }