/*++ Copyright (c) 1997 Microsoft Corporation Module Name: olereg.c Abstract: Code to perform OLE registry suppression based on list of GUIDs in win95upg.inf. OLE suppression is accomplished by the following algorithm: 1. Determine all GUIDs that are Win9x-specific, load in list of manually-suppressed GUIDs. Save this list to memdb. 2. Scan registry for GUID settings, then suppress all linkage to the GUID (the ProgID, Interface, etc). Use memdb to suppress each registry key/value. 3. Suppress all shell linkage to suppressed objects including file associations and desktop links. 4. Do a sanity check on the unsuppressed objects in the checked build Author: Jim Schmidt (jimschm) 20-Mar-1997 Revision History: jimschm 23-Sep-1998 Updated for new fileops code jimschm 28-Jan-1998 Added hack for ActiveSetup key jimschm 05-May-1997 Added new auto-suppression of non-OLE shell links --*/ #include "pch.h" #include "sysmigp.h" #include "progbar.h" #include "oleregp.h" #include "regops.h" #define S_EXPLORER_SHELLEXECUTEHOOKS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellExecuteHooks") #define S_EXPLORER_CSSFILTERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CSSFilters") #define S_EXPLORER_DESKTOP_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace") #define S_EXPLORER_FILETYPESPROPERTYSHEETHOOK TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileTypesPropertySheetHook") #define S_EXPLORER_FINDEXTENSIONS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FindExtensions") #define S_EXPLORER_MYCOMPUTER_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\NameSpace") #define S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\NetworkNeighborhood\\NameSpace") #define S_EXPLORER_NEWSHORTCUTHANDLERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\NewShortcutHandlers") #define S_EXPLORER_REMOTECOMPUTER_NAMESPACE TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RemoteComputer\\NameSpace") #define S_EXPLORER_SHELLICONOVERLAYIDENTIFIERS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers") #define S_EXPLORER_VOLUMECACHES TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches") #define S_ACTIVESETUP TEXT("HKLM\\Software\\Microsoft\\Active Setup\\Installed Components") #define S_EXTSHELLVIEWS TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ExtShellViews") #define S_SHELLEXTENSIONS_APPROVED TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved") #define S_SHELLSERVICEOBJECTDELAYLOAD TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad ") static TCHAR g_DefaultIcon[] = TEXT("DefaultIcon"); #define DBG_OLEREG "OLE Reg" // // Strings for AutoSuppress // TCHAR g_InprocHandler[] = TEXT("InprocHandler"); TCHAR g_InprocHandler32[] = TEXT("InprocHandler32"); TCHAR g_InprocServer[] = TEXT("InprocServer"); TCHAR g_InprocServer32[] = TEXT("InprocServer32"); TCHAR g_LocalServer[] = TEXT("LocalServer"); TCHAR g_LocalServer32[] = TEXT("LocalServer32"); PCTSTR g_FileRefKeys[] = { g_InprocHandler, g_InprocHandler32, g_InprocServer, g_InprocServer32, g_LocalServer, g_LocalServer32, NULL }; static POOLHANDLE g_OlePool; DWORD OleReg_GetProgressMax ( VOID ) /*++ Routine Description: Estimates the amount of ticks needed to complete OLE registry processing. Arguments: none Return Value: The number of ticks, equal to the number of ticks added with a delta in SuppressOleGuids. --*/ { if (REPORTONLY()) { return 0; } return TICKS_OLEREG; } BOOL pIgnoreGuid ( IN PCTSTR GuidStr ) { INFCONTEXT ic; MYASSERT (IsGuid (GuidStr, TRUE)); if (IsReportObjectHandled (GuidStr)) { DEBUGMSG ((DBG_OLEREG, "%s is a handled GUID, will not be suppressed", GuidStr)); return TRUE; } if (SetupFindFirstLine (g_Win95UpgInf, S_FORCED_GUIDS, GuidStr, &ic)) { DEBUGMSG ((DBG_OLEREG, "%s is a forced GUID, will not be suppressed", GuidStr)); return TRUE; } return FALSE; } BOOL pSuppressOleGuids ( VOID ) /*++ Routine Description: Processes the [Suppressed GUIDs] section of win95upg.inf and auto-suppresses OLE objects and GUIDs. The inf-based approach allows an OLE object and all of its linkage to be suppressed. The auto-suppress approach allows suppression of OLE objects and linkage when the implementation binary is removed from the system. Arguments: none Return Value: TRUE if suppression was successful, or FALSE if an error occurred. Call GetLastError to retrieve the error code. --*/ { BOOL Result = FALSE; DWORD Ticks; if (REPORTONLY()) { return TRUE; } g_OlePool = PoolMemInitNamedPool ("OLE Reg"); if (!g_OlePool) { return FALSE; } Ticks = GetTickCount(); __try { ProgressBar_SetComponentById (MSG_OLEREG); // // Suppress all GUIDs from [Suppressed GUIDs] section of win95upg.inf: // // HKLM\SOFTWARE\Classes\CLSID\ // HKLM\SOFTWARE\Classes\Interface\ // HKLM\SOFTWARE\Classes\ // HKLM\SOFTWARE\Classes\ // // Suppress any GUID that has a TreatAs key that points to GUID // if (!pProcessGuidSuppressList()) { __leave; } TickProgressBar (); // // Scan ProgIDs in HKCR for reference to suppressed GUID // if (!pProcessProgIdSuppression()) { __leave; } TickProgressBar (); // // Scan HKCR for file extensions that need to be suppressed // if (!pProcessFileExtensionSuppression()) { __leave; } TickProgressBar (); // // Scan Explorer registry for references to suppressed GUIDs // if (!pProcessExplorerSuppression()) { __leave; } TickProgressBar (); // // Delete all links requiring incompatible OLE objects // if (!pSuppressLinksToSuppressedGuids()) { __leave; } TickProgressBar (); // // Preserve all files needed by DefaultIcon // if (!pDefaultIconPreservation()) { __leave; } TickProgressBar (); // // Preserve all INFs needed by ActiveSetup // if (!pActiveSetupProcessing ()) { __leave; } TickProgressBar (); #ifdef DEBUG // Checked build sanity check pProcessOleWarnings(); TickProgressBar (); #endif ProgressBar_SetComponent (NULL); Result = TRUE; } __finally { PoolMemDestroyPool (g_OlePool); } Ticks = GetTickCount() - Ticks; g_ProgressBarTime += Ticks * 2; return Result; } DWORD SuppressOleGuids ( IN DWORD Request ) { switch (Request) { case REQUEST_QUERYTICKS: return OleReg_GetProgressMax (); case REQUEST_RUN: if (!pSuppressOleGuids ()) { return GetLastError (); } else { return ERROR_SUCCESS; } default: DEBUGMSG ((DBG_ERROR, "Bad parameter in SuppressOleGuids")); } return 0; } BOOL pProcessGuidSuppressList ( VOID ) /*++ Routine Description: Processes [Suppressed GUIDs] and auto-suppression. Any OLE object that is listed in Suppressed GUIDs and exists on the machine is suppressed. Any OLE object that requires a suppressed object is auto-suppressed. Any OLE object that has a TreatAs entry to a suppressed object is suppressed. This routine performs all GUID suppression and must run first. ("Auto-suppress" refers to the ability to suppress related OLE objects that are not listed to be suppressed in win95upg.inf.) Arguments: none Return Value: TRUE if suppression was successful, or FALSE if an error occurred. --*/ { HASHTABLE StrTab; LONG rc; REGKEY_ENUM e; HKEY GuidKey; PCTSTR Data; TCHAR Node[MEMDB_MAX]; DWORD Count = 0; // // Suppress all GUIDs from [Suppressed GUIDs] section of win95upg.inf: // // HKLM\SOFTWARE\Classes\CLSID\ // HKLM\SOFTWARE\Classes\Interface\ // StrTab = HtAlloc(); if (!StrTab) { LOG ((LOG_ERROR, "pProcessGuidSuppressList: Cannot create string table")); return FALSE; } pProcessAutoSuppress (StrTab); __try { // // Fill string table of all GUIDs // pFillHashTableWithKeyNames (StrTab, g_Win95UpgInf, S_SUPPRESSED_GUIDS); // // Search HKCR\CLSID for each GUID // if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) { do { // // Determine if item is suppressed: // // - it is on the list in [Suppressed GUIDs] of win95upg.inf // - it is in the GUIDS category of memdb (from TreatAs) // // // First, determine if it is in [Suppressed GUIDs] or from // auto suppression. // rc = (LONG) HtFindString (StrTab, e.SubKeyName); if (!rc) { MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, e.SubKeyName, NULL, NULL); if (MemDbGetValue (Node, NULL)) { rc = 0; } else { rc = -1; } } if (rc != -1) { pSuppressGuidInClsId (e.SubKeyName); } // // If not suppressed, check for TreatAs, and if TreatAs is found, // put TreatAs GUID in unsuppressed mapping. This is how we handle // the case where a GUID that is not normally suppressed, but has a // TreatAs member that points to a suppressed GUID will be suppressed // as well. // else { GuidKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (GuidKey) { Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("TreatAs")); if (Data) { // // Determine if TreatAs GUID is suppressed, and if it // is, suppress this GUID, otherwise put it on the // unsuppressed TreatAs list. // MemDbBuildKey ( Node, MEMDB_CATEGORY_GUIDS, Data, NULL, NULL ); if (MemDbGetValue (Node, NULL)) { pSuppressGuidInClsId (e.SubKeyName); } else { pAddUnsuppressedTreatAsGuid (Data, e.SubKeyName); } MemFree (g_hHeap, 0, Data); } CloseRegKey (GuidKey); } } Count++; if (!(Count % 128)) { TickProgressBar (); } } while (EnumNextRegKey (&e)); } } __finally { // // Clean up string table and memdb // HtFree (StrTab); pRemoveUnsuppressedTreatAsGuids(); } return TRUE; } BOOL pSuppressLinksToSuppressedGuids ( VOID ) /*++ Routine Description: After the GUID suppression list has been made, we scan all the links that have GUIDs in their command line arguments to find ones that need to be removed. Arguments: none Return Value: TRUE if all links were processed, or FALSE if an error occurred. --*/ { MEMDB_ENUM e, e2; TCHAR Node[MEMDB_MAX]; if (MemDbEnumItems (&e, MEMDB_CATEGORY_LINK_GUIDS)) { do { // // Is this GUID suppressed? // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.szName); if (MemDbGetValue (Node, NULL)) { // // Yes -- enumerate all sequencers and delete the associated links // if (MemDbGetValueEx (&e2, MEMDB_CATEGORY_LINK_GUIDS, e.szName, NULL)) { do { if (MemDbBuildKeyFromOffset (e2.dwValue, Node, 1, NULL)) { // // Delete all the operations for the file in Node // RemoveAllOperationsFromPath (Node); // // Now mark file for text mode delete // MarkFileForDelete (Node); DEBUGMSG (( DBG_OLEREG, "Link %s points to an incompatible OLE object; deleting.", Node )); } } while (MemDbEnumNextValue (&e2)); } } } while (MemDbEnumNextValue (&e)); // // No longer needed -- recover space in memdb // MemDbDeleteTree (MEMDB_CATEGORY_LINK_GUIDS); MemDbDeleteTree (MEMDB_CATEGORY_LINK_STRINGS); } return TRUE; } BOOL pProcessFileExtensionSuppression ( VOID ) /*++ Routine Description: Suppresses any file extension that depends on a suppressed OLE object. The GUID suppression must be complete before this routine is called. Arguments: none Return Value: TRUE if suppression was successful, or FALSE if an error occurred. --*/ { REGKEY_ENUM e; PCTSTR Data; TCHAR MemDbKey[MEMDB_MAX]; DWORD value; BOOL Suppress; // // Suppresss any file extension that points to suppressed ProgID // if (EnumFirstRegKey (&e, HKEY_CLASSES_ROOT)) { do { if (_tcsnextc (e.SubKeyName) != TEXT('.')) { continue; } Suppress = FALSE; Data = (PCTSTR) GetRegKeyData (e.KeyHandle, e.SubKeyName); if (Data) { MemDbBuildKey (MemDbKey, MEMDB_CATEGORY_PROGIDS, NULL, NULL, Data); if (MemDbGetValue (MemDbKey, &value) && (value == PROGID_SUPPRESSED) ) { // // This extension points to a suppressed ProgID key, so // suppress it. // Suppress = TRUE; } else { // // Check for this special case: the extension is for a CLSID, // not for a ProgId. // if (StringIMatchCharCount (Data, TEXT("CLSID\\"), 6)) { if (pIsGuidSuppressed (Data + 6)) { Suppress = TRUE; } } } MemFree (g_hHeap, 0, Data); } if (!Suppress) { // // This tests GUIDs AND suppresses the extension if necessary // pIsShellExKeySuppressed ( e.KeyHandle, e.SubKeyName, TEXT("ShellEx") ); } if (Suppress) { MemDbBuildKey ( MemDbKey, MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), NULL, e.SubKeyName ); Suppress95RegSetting (MemDbKey, NULL); } } while (EnumNextRegKey (&e)); } return TRUE; } #define MEMDB_CATEGORY_TMP_SUPPRESS TEXT("TmpSuppress") BOOL pIsCLSIDSuppressed ( IN HKEY ParentKey, IN PCTSTR ParentKeyName, IN PCTSTR SubKeyName ) { HKEY ClsIdKey; PCTSTR Data; BOOL result = FALSE; ClsIdKey = OpenRegKey (ParentKey, SubKeyName); if (ClsIdKey) { Data = GetRegKeyData (ClsIdKey, S_EMPTY); if (Data) { result = pIsGuidSuppressed (Data); DEBUGMSG_IF ((result, DBG_OLEREG, "ProgID %s has incompatible CLSID %s", ParentKeyName, Data)); MemFree (g_hHeap, 0, Data); } CloseRegKey (ClsIdKey); } return result; } VOID pMarkProgIdAsLostDefault ( IN PCTSTR ProgIdName ) { if (ProgIdName) { MemDbSetValueEx (MEMDB_CATEGORY_PROGIDS, ProgIdName, NULL, NULL, PROGID_LOSTDEFAULT, NULL); } } BOOL pIsShellKeySuppressed ( IN HKEY ParentKey, IN PCTSTR ParentKeyName, IN PCTSTR SubKeyName ) { REGKEY_ENUM e; DWORD Processed, Suppressed; HKEY ShellKey; TCHAR key [MEMDB_MAX]; PCTSTR Data; BOOL defaultKey = TRUE; PCTSTR defaultCommand = NULL; BOOL IsvCmdLine = FALSE; ShellKey = OpenRegKey (ParentKey, SubKeyName); Processed = Suppressed = 0; if (ShellKey) { Data = (PCTSTR) GetRegKeyData (ShellKey, S_EMPTY); if (Data) { defaultCommand = DuplicatePathString (Data, 0); defaultKey = FALSE; MemFree (g_hHeap, 0, Data); } else { defaultKey = TRUE; } if (EnumFirstRegKey (&e, ShellKey)) { do { Processed ++; if (defaultCommand) { defaultKey = StringIMatch (e.SubKeyName, defaultCommand); } MemDbBuildKey (key, e.SubKeyName, TEXT("command"), NULL, NULL); Data = (PCTSTR) GetRegKeyData (ShellKey, key); if (Data) { if (pIsCmdLineBadEx (Data, &IsvCmdLine)) { DEBUGMSG (( DBG_OLEREG, "ProgID %s has incompatible shell command: shell\\%s\\command[] = %s", ParentKeyName, e.SubKeyName, Data)); MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); if (defaultKey) { pMarkProgIdAsLostDefault (ParentKeyName); } Suppressed ++; } else if (IsvCmdLine) { // // Keep this setting. // MemDbBuildKey (key, MEMDB_CATEGORY_HKLM TEXT("\\SOFTWARE\\Classes"), ParentKeyName, SubKeyName, e.SubKeyName); SuppressNtRegSetting (key, NULL); } MemFree (g_hHeap, 0, Data); } defaultKey = FALSE; } while (EnumNextRegKey (&e)); } if (defaultCommand) { FreePathString (defaultCommand); } CloseRegKey (ShellKey); } if (Processed && (Processed == Suppressed)) { MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL); MemDbDeleteTree (key); MemDbSetValue (key, 0); return TRUE; } return FALSE; } BOOL pIsProtocolKeySuppressed ( IN HKEY ParentKey, IN PCTSTR ParentKeyName, IN PCTSTR SubKeyName ) { REGKEY_ENUM e; DWORD Processed, Suppressed; HKEY ProtocolKey; TCHAR key [MEMDB_MAX]; PCTSTR Data; ProtocolKey = OpenRegKey (ParentKey, SubKeyName); Processed = Suppressed = 0; if (ProtocolKey) { if (EnumFirstRegKey (&e, ProtocolKey)) { do { Processed ++; MemDbBuildKey (key, e.SubKeyName, TEXT("server"), NULL, NULL); Data = (PCTSTR) GetRegKeyData (ProtocolKey, key); if (Data) { if (pIsCmdLineBad (Data)) { DEBUGMSG (( DBG_OLEREG, "ProgID %s has incompatible protocol command: protocol\\%s\\server[] = %s", ParentKeyName, e.SubKeyName, Data)); MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); Suppressed ++; } MemFree (g_hHeap, 0, Data); } } while (EnumNextRegKey (&e)); } CloseRegKey (ProtocolKey); } if (Processed && (Processed == Suppressed)) { MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL); MemDbDeleteTree (key); MemDbSetValue (key, 0); return TRUE; } return FALSE; } BOOL pIsExtensionsKeySuppressed ( IN HKEY ParentKey, IN PCTSTR ParentKeyName, IN PCTSTR SubKeyName ) { REGKEY_ENUM e; REGVALUE_ENUM ev; DWORD Processed, Suppressed; HKEY ExtensionsKey; TCHAR key [MEMDB_MAX]; PCTSTR Data; ExtensionsKey = OpenRegKey (ParentKey, SubKeyName); Processed = Suppressed = 0; if (ExtensionsKey) { if (EnumFirstRegKey (&e, ExtensionsKey)) { do { Processed ++; Data = (PCTSTR) GetRegKeyData (ExtensionsKey, e.SubKeyName); if (Data) { if (pIsGuidSuppressed (Data)) { DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible extensions key %s", ParentKeyName, e.SubKeyName)); MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); Suppressed ++; } MemFree (g_hHeap, 0, Data); } } while (EnumNextRegKey (&e)); } if (EnumFirstRegValue (&ev, ExtensionsKey)) { do { Processed ++; if (ev.Type == REG_SZ) { Data = (PCTSTR) GetRegValueData (ExtensionsKey, ev.ValueName); if (Data) { if (pIsGuidSuppressed (Data)) { DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible extensions key %s", ParentKeyName, ev.ValueName)); MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL); Data = CreateEncodedRegistryString (key, ev.ValueName); MemDbSetValue (Data, 0); FreePathString (Data); Suppressed ++; } MemFree (g_hHeap, 0, Data); } } } while (EnumNextRegValue (&ev)); } CloseRegKey (ExtensionsKey); } if (Processed && (Processed == Suppressed)) { MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL); MemDbDeleteTree (key); MemDbSetValue (key, 0); return TRUE; } return FALSE; } BOOL pIsShellExKeySuppressed ( IN HKEY ParentKey, IN PCTSTR ParentKeyName, IN PCTSTR SubKeyName ) { REGKEY_ENUM e; DWORD Processed, Suppressed; HKEY ShellExKey; HKEY SubKey; PTSTR key; BOOL result = FALSE; PCTSTR Data; ShellExKey = OpenRegKey (ParentKey, SubKeyName); Processed = Suppressed = 0; if (ShellExKey) { if (EnumFirstRegKey (&e, ShellExKey)) { do { Processed ++; // // See if the key itself is a suppressed GUID // if (pIsGuidSuppressed (e.SubKeyName)) { DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible shell extension %s", ParentKeyName, e.SubKeyName)); MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); Suppressed ++; continue; } // // See if the default value is a suppressed GUID // SubKey = OpenRegKey (ShellExKey, e.SubKeyName); if (SubKey) { Data = (PCTSTR) GetRegKeyData (SubKey, S_EMPTY); if (Data) { if (pIsGuidSuppressed (Data)) { DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible shell extension %s", ParentKeyName, Data)); MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); Suppressed ++; MemFree (g_hHeap, 0, Data); CloseRegKey (SubKey); continue; } MemFree (g_hHeap, 0, Data); } CloseRegKey (SubKey); } // // Call recursively on this subkey // key = JoinPaths (ParentKeyName, SubKeyName); if (pIsShellExKeySuppressed (ShellExKey, key, e.SubKeyName)) { MemDbSetValueEx ( MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, e.SubKeyName, 0, NULL); Suppressed ++; } FreePathString (key); } while (EnumNextRegKey (&e)); if (Processed && (Processed == Suppressed)) { key = (PTSTR)AllocPathString (MEMDB_MAX); MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, ParentKeyName, SubKeyName, NULL); MemDbDeleteTree (key); MemDbSetValue (key, 0); FreePathString (key); result = TRUE; } } CloseRegKey (ShellExKey); } return result; } BOOL pProcessProgIdSuppression ( VOID ) { REGKEY_ENUM e; REGKEY_ENUM subKey; HKEY ProgIdKey; DWORD Processed, Suppressed; TCHAR key [MEMDB_MAX]; MEMDB_ENUM memEnum; BOOL HarmlessKeyFound; BOOL ActiveSuppression; DWORD Count = 0; if (EnumFirstRegKeyStr (&e, TEXT("HKCR"))) { do { if (StringIMatch (e.SubKeyName, TEXT("CLSID"))) { continue; } if (StringIMatch (e.SubKeyName, TEXT("Interface"))) { continue; } if (StringIMatch (e.SubKeyName, TEXT("Applications"))) { continue; } if (StringIMatch (e.SubKeyName, TEXT("TypeLib"))) { continue; } if (_tcsnextc (e.SubKeyName) == TEXT('.')) { continue; } ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (ProgIdKey) { Processed = 0; Suppressed = 0; HarmlessKeyFound = 0; ActiveSuppression = FALSE; if (EnumFirstRegKey (&subKey, ProgIdKey)) { do { Processed ++; if (StringIMatch (subKey.SubKeyName, TEXT("CLSID"))) { if (pIsCLSIDSuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) { AbortRegKeyEnum (&subKey); Processed = Suppressed = 1; HarmlessKeyFound = 0; ActiveSuppression = TRUE; break; } } if (StringIMatch (subKey.SubKeyName, TEXT("Shell"))) { if (pIsShellKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) { ActiveSuppression = TRUE; Suppressed ++; } } if (StringIMatch (subKey.SubKeyName, TEXT("Protocol"))) { if (pIsProtocolKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) { ActiveSuppression = TRUE; Suppressed ++; } } if (StringIMatch (subKey.SubKeyName, TEXT("Extensions"))) { if (pIsExtensionsKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) { ActiveSuppression = TRUE; Suppressed ++; } } if (StringIMatch (subKey.SubKeyName, TEXT("ShellEx"))) { if (pIsShellExKeySuppressed (ProgIdKey, e.SubKeyName, subKey.SubKeyName)) { ActiveSuppression = TRUE; Suppressed ++; } } if (StringIMatch (subKey.SubKeyName, TEXT("DefaultIcon"))) { HarmlessKeyFound ++; } if (StringIMatch (subKey.SubKeyName, TEXT("Insertable"))) { HarmlessKeyFound ++; } if (StringIMatch (subKey.SubKeyName, TEXT("NotInsertable"))) { HarmlessKeyFound ++; } if (StringIMatch (subKey.SubKeyName, TEXT("ShellFolder"))) { HarmlessKeyFound ++; } } while (EnumNextRegKey (&subKey)); } if (ActiveSuppression && (Processed == (Suppressed + HarmlessKeyFound))) { pSuppressProgId (e.SubKeyName); } else { MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, e.SubKeyName, TEXT("*"), NULL); if (MemDbEnumFirstValue (&memEnum, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) { do { MemDbBuildKey (key, MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), e.SubKeyName, memEnum.szName); Suppress95RegSetting (key, NULL); } while (MemDbEnumNextValue (&memEnum)); } } MemDbBuildKey (key, MEMDB_CATEGORY_TMP_SUPPRESS, e.SubKeyName, NULL, NULL); MemDbDeleteTree (key); CloseRegKey (ProgIdKey); } Count++; if (!(Count % 64)) { TickProgressBar (); } } while (EnumNextRegKey (&e)); } return TRUE; } BOOL pIsGuidSuppressed ( PCTSTR GuidStr ) /*++ Routine Description: Determines if a GUID is suppressed or not, and also determines if a GUID is handled by a migration DLL. Arguments: GuidStr - Specifies the GUID to look up, which may or may not contain the surrounding braces Return Value: TRUE if the specified GUID is suppressed, or FALSE if it is not. The return value is FALSE if the GUID is handled by a migration DLL. --*/ { TCHAR Node[MEMDB_MAX]; TCHAR FixedGuid[MAX_GUID]; if (!FixGuid (GuidStr, FixedGuid)) { return FALSE; } if (pIgnoreGuid (FixedGuid)) { return FALSE; } MemDbBuildKey ( Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, FixedGuid ); return MemDbGetValue (Node, NULL); } BOOL pScanSubKeysForIncompatibleGuids ( IN PCTSTR ParentKey ) /*++ Routine Description: Suppresses the subkeys of the supplied parent key that have text referencing an incompatible GUID. Arguments: ParentKey - Specifies the parent to enumerate keys for Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { REGKEY_ENUM e; TCHAR Node[MEMDB_MAX]; // // Enumerate the keys in ParentKey // if (EnumFirstRegKeyStr (&e, ParentKey)) { do { if (pIsGuidSuppressed (e.SubKeyName)) { // // Suppress the enumerated subkey // wsprintf (Node, TEXT("%s\\%s"), ParentKey, e.SubKeyName); Suppress95RegSetting (Node, NULL); } } while (EnumNextRegKey (&e)); } return TRUE; } BOOL pScanValueNamesForIncompatibleGuids ( IN PCTSTR ParentKey ) /*++ Routine Description: Suppresses the values of the supplied parent key that have value names referencing an incompatible GUID. Arguments: ParentKey - Specifies the parent to enumerate values of Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { REGVALUE_ENUM e; HKEY Key; // // Enumerate the values in ParentKey // Key = OpenRegKeyStr (ParentKey); if (Key) { if (EnumFirstRegValue (&e, Key)) { do { if (pIsGuidSuppressed (e.ValueName)) { // // Suppress the enumerated value // Suppress95RegSetting (ParentKey, e.ValueName); } } while (EnumNextRegValue (&e)); } CloseRegKey (Key); } return TRUE; } BOOL pScanValueDataForIncompatibleGuids ( IN PCTSTR ParentKey ) /*++ Routine Description: Suppresses the values of the supplied parent key that have value data referencing an incompatible GUID. Arguments: ParentKey - Specifies the parent to enumerate values of Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { REGVALUE_ENUM e; HKEY Key; PCTSTR Data; // // Enumerate the values in ParentKey // Key = OpenRegKeyStr (ParentKey); if (Key) { if (EnumFirstRegValue (&e, Key)) { do { Data = GetRegValueString (Key, e.ValueName); if (Data) { if (pIsGuidSuppressed (Data)) { // // Suppress the enumerated value // Suppress95RegSetting (ParentKey, e.ValueName); } MemFree (g_hHeap, 0, Data); } } while (EnumNextRegValue (&e)); } CloseRegKey (Key); } return TRUE; } BOOL pCheckDefaultValueForIncompatibleGuids ( IN PCTSTR KeyStr ) /*++ Routine Description: Suppresses the specified key if its default value is a suppressed GUID. Arguments: KeyStr - Specifies key string to process Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { PCTSTR Data; HKEY Key; // // Examine the default value of KeyStr // Key = OpenRegKeyStr (KeyStr); if (Key) { Data = GetRegValueString (Key, S_EMPTY); CloseRegKey (Key); } else { Data = NULL; } if (Data) { if (pIsGuidSuppressed (Data)) { // // Suppress the specified reg key // Suppress95RegSetting (KeyStr, NULL); } MemFree (g_hHeap, 0, Data); } return TRUE; } BOOL pScanDefaultValuesForIncompatibleGuids ( IN PCTSTR ParentKey ) /*++ Routine Description: Suppresses subkeys that have a default value that is a suppressed GUID. Arguments: ParentKey - Specifies key string to process Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { REGKEY_ENUM e; TCHAR Node[MEMDB_MAX]; PCTSTR Data; HKEY Key; // // Enumerate the keys in ParentKey // if (EnumFirstRegKeyStr (&e, ParentKey)) { do { Key = OpenRegKey (e.KeyHandle, e.SubKeyName); if (Key) { Data = GetRegValueString (Key, S_EMPTY); } else { Data = NULL; } CloseRegKey (Key); if (Data) { if (pIsGuidSuppressed (Data)) { // // Suppress the enumerated subkey // wsprintf (Node, TEXT("%s\\%s"), ParentKey, e.SubKeyName); Suppress95RegSetting (Node, NULL); } MemFree (g_hHeap, 0, Data); } } while (EnumNextRegKey (&e)); } return TRUE; } BOOL pProcessExplorerSuppression ( VOID ) /*++ Routine Description: Suppresses the settings in HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks that reference incompatible GUIDs. Arguments: none Return Value: TRUE if everything is OK, or FALSE if an unexpected error occurred during processing. --*/ { BOOL b = TRUE; // // Suppress Win9x-specific value data in CSSFilters // if (b) { b = pScanValueDataForIncompatibleGuids (S_EXPLORER_CSSFILTERS); } // // Suppress Win9x-specific keys in Desktop\NameSpace // if (b) { b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_DESKTOP_NAMESPACE); } // // Suppress key of FileTypesPropertySheetHook if default value is Win9x-specific // if (b) { b = pCheckDefaultValueForIncompatibleGuids (S_EXPLORER_FILETYPESPROPERTYSHEETHOOK); } // // Suppress subkeys of FindExtensions if default value is Win9x-specific // if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_FINDEXTENSIONS); } // // Scan MyComputer\NameSpace for subkeys or subkeys with default values // pointing to incompatible GUIDs. // if (b) { b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_MYCOMPUTER_NAMESPACE); } if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_MYCOMPUTER_NAMESPACE); } // // Scan NetworkNeighborhood\NameSpace for subkeys or subkeys with default values // pointing to incompatible GUIDs. // if (b) { b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE); } if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_NETWORKNEIGHBORHOOD_NAMESPACE); } // // Suppress values that reference incompatible GUIDs // if (b) { b = pScanValueNamesForIncompatibleGuids (S_EXPLORER_NEWSHORTCUTHANDLERS); } // // Scan RemoteComputer\NameSpace for subkeys or subkeys with default values // pointing to incompatible GUIDs. // if (b) { b = pScanSubKeysForIncompatibleGuids (S_EXPLORER_REMOTECOMPUTER_NAMESPACE); } if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_REMOTECOMPUTER_NAMESPACE); } // // Scan ShellExecuteHooks for value names referencing incompatible GUIDs // if (b) { b = pScanValueNamesForIncompatibleGuids (S_EXPLORER_SHELLEXECUTEHOOKS); } // // Scan ShellIconOverlayIdentifiers for subkeys with default values referencing // incompatible GUIDs // if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_SHELLICONOVERLAYIDENTIFIERS); } // // Scan VolumeCaches for subkeys with default values referencing // incompatible GUIDs // if (b) { b = pScanDefaultValuesForIncompatibleGuids (S_EXPLORER_VOLUMECACHES); } // // Scan ExtShellViews for subkeys that reference incompatible GUIDs // if (b) { b = pScanSubKeysForIncompatibleGuids (S_EXTSHELLVIEWS); } // // Scan Shell Extensions\Approved for value names referencing incompatible // GUIDs // if (b) { b = pScanValueNamesForIncompatibleGuids (S_SHELLEXTENSIONS_APPROVED); } // // Scan ShellServiceObjectDelayLoad for value data referencing incompatible // GUIDs // if (b) { b = pScanValueDataForIncompatibleGuids (S_SHELLSERVICEOBJECTDELAYLOAD); } return b; } BOOL ExtractIconIntoDatFile ( IN PCTSTR LongPath, IN INT IconIndex, IN OUT PICON_EXTRACT_CONTEXT Context, OUT PINT NewIconIndex OPTIONAL ) /*++ Routine Description: ExtractIconIntoDatFile preserves a Win9x icon by extracting it from the 9x system. If the EXE and icon index pair are known good, then this function returns FALSE. Otherwise, this function extracts the icon and saves it into a DAT file for processing in GUI mode setup. If icon extraction fails, then the default generic icon from shell32.dll is used. Arguments: LongPath - Specifies the full path to the PE image IconIndex - Specifies the icon index to extract. Negative index values provide a specific icon resource ID. Positive index values indicate which icon, where 0 is the first icon, 1 is the second icon, and so on. Context - Specifies the extraction context that gives the DAT file and other info (used by icon extraction utilities). NewIconIndex - Receives the new icon index in %windir%\system32\migicons.exe, if the function returns TRUE. Zero otherwise. Return Value: TRUE if the icon was extracted, or if the icon could not be extracted but the icon is not known-good. (The default generic icon is used in this case.) FALSE if the icon is known-good and does not need to be extracted. --*/ { MULTISZ_ENUM MultiSz; TCHAR Node[MEMDB_MAX]; TCHAR IconId[256]; TCHAR IconIndexStr[32]; PCTSTR IconList; PCTSTR extPtr; INT i; DWORD Offset; static WORD Seq = 0; DWORD OrgSeq; BOOL result = FALSE; BOOL needDefaultIcon = FALSE; if (NewIconIndex) { *NewIconIndex = 0; } __try { // // Is this a compatible icon binary? If so, return FALSE. // if (IsIconKnownGood (LongPath, IconIndex)) { __leave; } // // From this point on, if we fail to extract the icon, use the default. // needDefaultIcon = TRUE; if (!Seq) { // // Extract the icon from shell32.dll for the default icon. This is // the "generic app" icon. We keep the Win9x generic icon instead // of the updated NT generic icon, so there is a clear indication // that we failed to extract the right thing from Win9x. // DEBUGMSG ((DBG_OLEREG, "DefaultIconExtraction: Extracting a default icon")); Offset = SetFilePointer (Context->IconImageFile, 0, NULL, FILE_CURRENT); wsprintf (Node, TEXT("%s\\system\\shell32.dll"), g_WinDir); if (!CopyIcon (Context, Node, TEXT("#1"), 0)) { DEBUGMSG (( DBG_ERROR, "DefaultIconExtraction: Can't extract default icon from %s", Node )); } else { MemDbBuildKey ( Node, MEMDB_CATEGORY_ICONS, TEXT("%s\\system\\shell32.dll"), TEXT("0"), NULL ); MemDbSetValueAndFlags (Node, Offset, Seq, 0xffff); Seq++; } } // // Has the icon been extracted already? // extPtr = GetFileExtensionFromPath (LongPath); if ((IconIndex >= 0) && extPtr && (!StringIMatch (extPtr, TEXT("ICO")))) { // // IconIndex specifies sequential order; get list of // resource IDs and find the right one. // IconList = ExtractIconNamesFromFile (LongPath, &Context->IconList); i = IconIndex; IconId[0] = 0; if (IconList) { if (EnumFirstMultiSz (&MultiSz, IconList)) { while (i > 0) { if (!EnumNextMultiSz (&MultiSz)) { break; } i--; } if (!i) { StringCopy (IconId, MultiSz.CurrentString); } ELSE_DEBUGMSG ((DBG_OLEREG, "Icon %i not found in %s", i, LongPath)); } } ELSE_DEBUGMSG ((DBG_OLEREG, "Icon %i not found in %s", i, LongPath)); } else { // // IconIndex specifies resource ID // wsprintf (IconId, TEXT("#%i"), -IconIndex); } if (!IconId[0]) { // // Failed to find icon or failed to read icon index from EXE // __leave; } wsprintf (IconIndexStr, TEXT("%i"), IconIndex); MemDbBuildKey (Node, MEMDB_CATEGORY_ICONS, LongPath, IconIndexStr, NULL); if (!MemDbGetValueAndFlags (Node, NULL, &OrgSeq)) { // // Extract the icon and save it in a file. During GUI // mode, the icon will be saved to a resource-only DLL. // DEBUGMSG (( DBG_OLEREG, "Extracting default icon %s in file %s", IconId, LongPath )); Offset = SetFilePointer (Context->IconImageFile, 0, NULL, FILE_CURRENT); if (!CopyIcon (Context, LongPath, IconId, 0)) { DEBUGMSG (( DBG_OLEREG, "DefaultIconExtraction: CopyIcon failed for %s, %i (%s)!", LongPath, IconIndex, IconId )); __leave; } if (NewIconIndex) { *NewIconIndex = (INT) (UINT) Seq; } MemDbBuildKey ( Node, MEMDB_CATEGORY_ICONS, LongPath, IconIndexStr, NULL ); MemDbSetValueAndFlags (Node, Offset, Seq, 0xffff); Seq++; } else { if (NewIconIndex) { *NewIconIndex = (INT) (UINT) OrgSeq; } } result = TRUE; } __finally { // // Even if we fail, return success if we want the caller to use // the default icon (at index 0). // result |= needDefaultIcon; } return result; } VOID pExtractDefaultIcon ( PCTSTR Data, PICON_EXTRACT_CONTEXT Context ) { TCHAR ArgZero[MAX_CMDLINE]; TCHAR LongPath[MAX_TCHAR_PATH]; INT IconIndex; PCTSTR p; BOOL LongPathFound = FALSE; // // Determine if the first arg of the command line points to a // deleted file or a file to be replaced // ExtractArgZeroEx (Data, ArgZero, TEXT(","), FALSE); p = (PCTSTR) ((PBYTE) Data + ByteCount (ArgZero)); while (*p == TEXT(' ')) { p++; } if (*p == TEXT(',')) { IconIndex = _ttoi (_tcsinc (p)); } else { IconIndex = 0; } if (!_tcschr (ArgZero, TEXT('\\'))) { if (SearchPath (NULL, ArgZero, NULL, MAX_TCHAR_PATH, LongPath, NULL)) { LongPathFound = TRUE; } } if (LongPathFound || OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) { if (FILESTATUS_UNCHANGED != GetFileStatusOnNt (LongPath)) { ExtractIconIntoDatFile ( LongPath, IconIndex, Context, NULL ); } } } VOID pExtractAllDefaultIcons ( IN HKEY ParentKey ) { HKEY DefaultIconKey; REGVALUE_ENUM e; PCTSTR Data; DefaultIconKey = OpenRegKey (ParentKey, TEXT("DefaultIcon")); if (DefaultIconKey) { // // Check all values in DefaultIcon // if (EnumFirstRegValue (&e, DefaultIconKey)) { do { Data = (PCTSTR) GetRegValueString (DefaultIconKey, e.ValueName); if (Data) { pExtractDefaultIcon (Data, &g_IconContext); MemFree (g_hHeap, 0, Data); } } while (EnumNextRegValue (&e)); } CloseRegKey (DefaultIconKey); } } BOOL pDefaultIconPreservation ( VOID ) /*++ Routine Description: This routine scans the DefaultIcon setting of OLE classes and identifies any default icon that will be lost by deletion. A copy of the icon is stored away in a directory called MigIcons. Arguments: none Return Value: TRUE unless an unexpected error occurs. --*/ { REGKEY_ENUM e; HKEY ProgIdKey; TCHAR key[MEMDB_MAX]; DWORD value; // // Scan all ProgIDs, looking for default icons that are currently // set for deletion. Once found, don't delete the icon, but instead // copy the image to %windir%\setup\temp\migicons. // if (EnumFirstRegKeyStr (&e, TEXT("HKCR"))) { do { // // We extract the icons for all ProgIds that survive on NT. // MemDbBuildKey (key, MEMDB_CATEGORY_PROGIDS, e.SubKeyName, NULL, NULL); if (!MemDbGetValue (key, &value) || (value != PROGID_SUPPRESSED) ) { ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (ProgIdKey) { pExtractAllDefaultIcons (ProgIdKey); CloseRegKey (ProgIdKey); } } } while (EnumNextRegKey (&e)); } if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) { do { // // We extract the icons for all GUIDs (even for the suppressed ones). // The reason is that if NT installs this GUID we do want to replace // the NT default icon with the 9x icon. // ProgIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (ProgIdKey) { pExtractAllDefaultIcons (ProgIdKey); CloseRegKey (ProgIdKey); } } while (EnumNextRegKey (&e)); } return TRUE; } BOOL pActiveSetupProcessing ( VOID ) /*++ Routine Description: This routine scans the Active Setup key and suppresses incompatible GUIDs and Installed Components subkeys that reference deleted files. If a stub path references an INF, we preserve the INF. Arguments: none Return Value: TRUE unless an unexpected error occurs. --*/ { REGKEY_ENUM e; HKEY InstalledComponentKey; PCTSTR Data; TCHAR ArgZero[MAX_CMDLINE]; TCHAR LongPath[MAX_TCHAR_PATH]; TCHAR Node[MEMDB_MAX]; PCTSTR p; PTSTR q; PTSTR DupText; DWORD status; // // Scan all Installed Components // if (EnumFirstRegKeyStr (&e, S_ACTIVESETUP)) { do { // // Determine if the GUID is suppressed, and if it is, suppress // the entire Installed Components setting // if (pIsGuidSuppressed (e.SubKeyName)) { wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName); Suppress95RegSetting (Node, NULL); continue; } // // Get StubPath and determine if it references incompatible files // InstalledComponentKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (InstalledComponentKey) { __try { Data = GetRegValueString (InstalledComponentKey, TEXT("StubPath")); if (Data) { __try { // // Determine if the first arg of the command line points to a // deleted file // ExtractArgZeroEx (Data, ArgZero, TEXT(","), FALSE); if (OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) { status = GetFileStatusOnNt (LongPath); if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) { // // Suppress this key // wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName); Suppress95RegSetting (Node, NULL); continue; } } DupText = NULL; // // Scan command line for an LaunchINFSectionEx reference // p = _tcsistr (Data, TEXT("LaunchINF")); if (p) { p = _tcschr (p, TEXT(' ')); } if (p) { while (*p == TEXT(' ')) { p = _tcsinc (p); } // // Instead of deleting this file, lets move it // DupText = DuplicateText (p); q = _tcschr (DupText, TEXT(',')); if (q) { *q = 0; } } if (!DupText) { p = _tcsistr (Data, TEXT("InstallHInfSection")); if (p) { p = _tcschr (p, TEXT(' ')); if (p) { p = _tcschr (_tcsinc (p), TEXT(' ')); // p points to end of section name or NULL } if (p) { p = _tcschr (_tcsinc (p), TEXT(' ')); // p points to end of number of NULL } if (p) { p = _tcsinc (p); DupText = DuplicateText (p); } } } if (DupText) { if (OurGetLongPathName (DupText, LongPath, MAX_TCHAR_PATH)) { status = GetFileStatusOnNt (LongPath); if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) { // // Suppress the setting // wsprintf (Node, TEXT("%s\\%s"), S_ACTIVESETUP, e.SubKeyName); Suppress95RegSetting (Node, NULL); } } FreeText (DupText); } } __finally { MemFree (g_hHeap, 0, Data); } } } __finally { CloseRegKey (InstalledComponentKey); } } } while (EnumNextRegKey (&e)); } return TRUE; } #ifdef DEBUG PCTSTR g_ProgIdFileRefKeys[] = { g_DefaultIcon, NULL }; TCHAR g_BaseInterface[] = TEXT("BaseInterface"); TCHAR g_ProxyStubClsId[] = TEXT("ProxyStubClsId"); TCHAR g_ProxyStubClsId32[] = TEXT("ProxyStubClsId32"); TCHAR g_TypeLib[] = TEXT("ProxyStubClsId32"); PCTSTR g_InterfaceRefKeys[] = { g_BaseInterface, g_ProxyStubClsId, g_ProxyStubClsId32, g_TypeLib, NULL }; BOOL pProcessOleWarnings ( VOID ) /*++ Routine Description: For checked builds, this routine examines the linkage of the entire OLE registry and identifies problems such as abandoned links and broken inheritance. Arguments: none Return Value: TRUE unless an unexpected error occurs. --*/ { REGKEY_ENUM e; HKEY ClsIdKey; HKEY InterfaceKey; PCTSTR Data; TCHAR Node[MEMDB_MAX]; BOOL Suppressed; INT i; // // Search HKCR\CLSID for problems // if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) { do { // // Verify key is not garbage // if (!FixGuid (e.SubKeyName, e.SubKeyName)) { continue; } ClsIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName); // // Determine if this GUID is suppressed // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName); Suppressed = MemDbGetValue (Node, NULL); if (ClsIdKey) { if (!Suppressed) { // // Unsuppressed GUID checks // // AutoConvertTo Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("AutoConvertTo")); if (Data) { // // Check if AutoConvertTo is pointing to suppressed GUID // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data); if (MemDbGetValue (Node, NULL)) { DEBUGMSG ((DBG_WARNING, "GUID %s points to deleted GUID %s", e.SubKeyName, Data )); pAddOleWarning ( MSG_OBJECT_POINTS_TO_DELETED_GUID, ClsIdKey, e.SubKeyName ); } MemFree (g_hHeap, 0, Data); } // File references for (i = 0 ; g_FileRefKeys[i] ; i++) { Data = (PCTSTR) GetRegKeyData (ClsIdKey, g_FileRefKeys[i]); if (Data) { // // Check if the file in Data is in Win9xFileLocation for // all users // pSuppressGuidIfCmdLineBad ( NULL, Data, ClsIdKey, e.SubKeyName ); MemFree (g_hHeap, 0, Data); } } } else { // // Suppressed GUID checks // Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("Interface")); if (Data) { MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data); if (MemDbGetValue (Node, NULL)) { DEBUGMSG ((DBG_WARNING, "Suppressed GUID %s has Interface reference " "to unsuppressed %s (potential leak)", e.SubKeyName, Data)); pAddOleWarning (MSG_GUID_LEAK, ClsIdKey, e.SubKeyName); } MemFree (g_hHeap, 0, Data); } } CloseRegKey (ClsIdKey); } } while (EnumNextRegKey (&e)); } // // Look for problems with an HKCR\Interface entry // if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\Interface"))) { do { InterfaceKey = OpenRegKey (e.KeyHandle, e.SubKeyName); MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName); Suppressed = MemDbGetValue (Node, NULL); if (InterfaceKey) { for (i = 0 ; g_InterfaceRefKeys[i] ; i++) { Data = (PCTSTR) GetRegKeyData ( InterfaceKey, g_InterfaceRefKeys[i] ); if (Data) { // // Check if reference to other GUID is suppressed // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data); if (MemDbGetValue (Node, NULL)) { if (!Suppressed) { TCHAR CompleteKey[MAX_REGISTRY_KEY]; // // Interface is not suppressed, but it points to a // suppressed interface. // wsprintf ( CompleteKey, TEXT("HKCR\\Interface\\%s"), e.SubKeyName ); DEBUGMSG (( DBG_WARNING, "GUID %s %s subkey points to suppressed GUID %s", e.SubKeyName, g_InterfaceRefKeys[i], Data )); pAddOleWarning ( MSG_INTERFACE_BROKEN, InterfaceKey, CompleteKey ); } } else { if (Suppressed) { TCHAR CompleteKey[MAX_REGISTRY_KEY]; // // Interface is suppressed, but it points to an // unsuppressed interface. // wsprintf ( CompleteKey, TEXT("HKCR\\Interface\\%s"), e.SubKeyName ); DEBUGMSG (( DBG_WARNING, "Suppressed GUID %s %s subkey points to " "unsuppressed GUID %s (potential leak)", e.SubKeyName, g_InterfaceRefKeys[i], Data )); pAddOleWarning ( MSG_POTENTIAL_INTERFACE_LEAK, InterfaceKey, CompleteKey ); } } MemFree (g_hHeap, 0, Data); } } CloseRegKey (InterfaceKey); } } while (EnumNextRegKey (&e)); } return TRUE; } #endif VOID pProcessAutoSuppress ( IN OUT HASHTABLE StrTab ) /*++ Routine Description: Performs a number of tests to identify OLE objects that are not compatible with Windows NT. The tests are based on a list of incompatible files stored in memdb. Any OLE object that depends on a file that will not exist on NT is automatically suppressed. Arguments: StrTab - Specifies the string table that holds suppressed GUIDs Return Value: none --*/ { REGKEY_ENUM e, eVer, eNr; HKEY ClsIdKey; HKEY TypeLibKey; HKEY VerKey; HKEY NrKey; HKEY SubSysKey; TCHAR Node[MEMDB_MAX]; BOOL Suppressed; PCTSTR Data; BOOL ValidNr; BOOL ValidVer; BOOL ValidGUID; // // Search HKCR\CLSID for objects that require a Win95-specific binary // DEBUGMSG ((DBG_OLEREG, "Looking for CLSID problems...")); if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\CLSID"))) { do { // // Verify key is not garbage // if (!FixGuid (e.SubKeyName, e.SubKeyName)) { DEBUGMSG (( DBG_OLEREG, "Garbage key ignored: HKCR\\CLSID\\%s", e.SubKeyName )); continue; } ClsIdKey = OpenRegKey (e.KeyHandle, e.SubKeyName); // // Determine if this GUID is suppressed // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName); Suppressed = MemDbGetValue (Node, NULL); if (ClsIdKey) { if (!Suppressed) { // // Unsuppressed GUID checks // // AutoConvertTo Data = (PCTSTR) GetRegKeyData (ClsIdKey, TEXT("AutoConvertTo")); if (Data) { // // Check if AutoConvertTo is pointing to suppressed GUID // MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, Data); if (MemDbGetValue (Node, NULL)) { DEBUGMSG (( DBG_OLEREG, "GUID %s points to deleted GUID %s -> " "Auto-suppressed", e.SubKeyName, Data )); pAddGuidToTable (StrTab, e.SubKeyName); } MemFree (g_hHeap, 0, Data); } // File references pSuppressGuidIfBadCmdLine (StrTab, ClsIdKey, e.SubKeyName); } CloseRegKey (ClsIdKey); } } while (EnumNextRegKey (&e)); } DEBUGMSG ((DBG_OLEREG, "Looking for TypeLib problems...")); if (EnumFirstRegKeyStr (&e, TEXT("HKCR\\TypeLib"))) { do { // // Verify key is not garbage // if (!FixGuid (e.SubKeyName, e.SubKeyName)) { DEBUGMSG (( DBG_OLEREG, "Garbage key ignored: HKCR\\TypeLib\\%s", e.SubKeyName )); continue; } TypeLibKey = OpenRegKey (e.KeyHandle, e.SubKeyName); if (TypeLibKey) { MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName); Suppressed = MemDbGetValue (Node, NULL); if (!Suppressed) { ValidGUID = FALSE; // // Enumerating all versions // if (EnumFirstRegKey (&eVer, TypeLibKey)) { do { VerKey = OpenRegKey (eVer.KeyHandle, eVer.SubKeyName); if (VerKey) { ValidVer = FALSE; // // Enumerating all subkeys except HELPDIR and FLAGS // if (EnumFirstRegKey (&eNr, VerKey)) { do { if (StringIMatch (eNr.SubKeyName, TEXT("FLAGS"))) { continue; } if (StringIMatch (eNr.SubKeyName, TEXT("HELPDIR"))) { continue; } NrKey = OpenRegKey (eNr.KeyHandle, eNr.SubKeyName); if (NrKey) { ValidNr = FALSE; SubSysKey = OpenRegKey (NrKey, TEXT("win16")); if (SubSysKey) { Data = GetRegValueString (SubSysKey, TEXT("")); if (Data) { if (pIsCmdLineBad (Data)) { wsprintf ( Node, "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s\\%s", MEMDB_CATEGORY_HKLM, e.SubKeyName, eVer.SubKeyName, eNr.SubKeyName, TEXT("win16") ); Suppress95RegSetting(Node, NULL); } else { ValidNr = TRUE; } MemFree (g_hHeap, 0, Data); } CloseRegKey (SubSysKey); } SubSysKey = OpenRegKey (NrKey, TEXT("win32")); if (SubSysKey) { Data = GetRegValueString (SubSysKey, TEXT("")); if (Data) { if (pIsCmdLineBad (Data)) { wsprintf ( Node, "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s\\%s", MEMDB_CATEGORY_HKLM, e.SubKeyName, eVer.SubKeyName, eNr.SubKeyName, TEXT("win32") ); Suppress95RegSetting(Node, NULL); } else { ValidNr = TRUE; } MemFree (g_hHeap, 0, Data); } CloseRegKey (SubSysKey); } CloseRegKey (NrKey); if (!ValidNr) { wsprintf ( Node, "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s\\%s", MEMDB_CATEGORY_HKLM, e.SubKeyName, eVer.SubKeyName, eNr.SubKeyName ); Suppress95RegSetting(Node, NULL); } else { ValidVer = TRUE; } } } while (EnumNextRegKey (&eNr)); } CloseRegKey (VerKey); if (!ValidVer) { wsprintf ( Node, "%s\\SOFTWARE\\Classes\\TypeLib\\%s\\%s", MEMDB_CATEGORY_HKLM, e.SubKeyName, eVer.SubKeyName ); Suppress95RegSetting(Node, NULL); } else { ValidGUID = TRUE; } } } while (EnumNextRegKey (&eVer)); } if (!ValidGUID) { DEBUGMSG (( DBG_OLEREG, "TypeLib GUID %s is suppressed", e.SubKeyName )); MemDbSetValueEx (MEMDB_CATEGORY_GUIDS, NULL, NULL, e.SubKeyName, 0, NULL); } } CloseRegKey (TypeLibKey); } } while (EnumNextRegKey (&e)); } } BOOL pGetFirstRegKeyThatHasGuid ( OUT PGUIDKEYSEARCH EnumPtr, IN HKEY RootKey ) /*++ Routine Description: pGetFirstRegKeyThatHasGuid starts an enumeration of an OLE object's ShellEx subkey. This subkey has zero or more handlers, and each handler has zero or more GUIDs. This ShellEx enumerator returns the first GUID subkey found under the supplied root. Arguments: EnumPtr - An uninitialized GUIDKEYSEARCH struct that is used to maintain enumeration state and to report the match found. RootKey - The registry key to begin enumerating at. Return Value: TRUE if a GUID was found in a handler that is a subkey of RootKey, or FALSE if no GUIDs were found. --*/ { EnumPtr->State = GUIDKEYSEARCH_FIRST_HANDLER; EnumPtr->RootKey = RootKey; return pGetNextRegKeyThatHasGuid (EnumPtr); } BOOL pGetNextRegKeyThatHasGuid ( IN OUT PGUIDKEYSEARCH EnumPtr ) /*++ Routine Description: The "next" enumerator for ShellEx registry key enumeration. This enumerator returns the next instance of a GUID in the registry (under an OLE object's ShellEx subkey). Arguments: EnumPtr - The GUIDKEYSEARCH structure used to begin the search. If a GUID is found, this structure holds the location of the GUID key found. Return Value: TRUE if a subkey identifying a GUID was found, or FALSE if no more instances exist. --*/ { BOOL Found = FALSE; do { switch (EnumPtr->State) { case GUIDKEYSEARCH_FIRST_HANDLER: // // Get the name of the first handler // if (!EnumFirstRegKey (&EnumPtr->Handlers, EnumPtr->RootKey)) { return FALSE; } EnumPtr->State = GUIDKEYSEARCH_FIRST_GUID; break; case GUIDKEYSEARCH_NEXT_HANDLER: // // Get the name of the next handler // if (!EnumNextRegKey (&EnumPtr->Handlers)) { return FALSE; } EnumPtr->State = GUIDKEYSEARCH_FIRST_GUID; break; case GUIDKEYSEARCH_FIRST_GUID: // // Begin GUID key enumeration // EnumPtr->HandlerKey = OpenRegKey (EnumPtr->Handlers.KeyHandle, EnumPtr->Handlers.SubKeyName); // Assume no GUIDs EnumPtr->State = GUIDKEYSEARCH_NEXT_HANDLER; if (EnumPtr->HandlerKey) { if (EnumFirstRegKey (&EnumPtr->Guids, EnumPtr->HandlerKey)) { // // There is at least one key that may be a GUID in this handler // Found = FixGuid (EnumPtr->Guids.SubKeyName, EnumPtr->Guids.SubKeyName); EnumPtr->State = GUIDKEYSEARCH_NEXT_GUID; } else { CloseRegKey (EnumPtr->HandlerKey); } } break; case GUIDKEYSEARCH_NEXT_GUID: // // Continue GUID key enumeration // if (!EnumNextRegKey (&EnumPtr->Guids)) { CloseRegKey (EnumPtr->HandlerKey); EnumPtr->State = GUIDKEYSEARCH_NEXT_HANDLER; } else { Found = FixGuid (EnumPtr->Guids.SubKeyName, EnumPtr->Guids.SubKeyName); } break; } } while (!Found); EnumPtr->KeyName = EnumPtr->Guids.SubKeyName; return TRUE; } DWORD pCountGuids ( IN PGUIDKEYSEARCH EnumPtr ) /*++ Routine Description: Given a valid EnumPtr, this function will count the total number of GUIDs in the current handler. Arguments: EnumPtr - Must be a valid GUIDKEYSEARCH structure, prepared by pGetFirstRegKeyThatHasGuid or pGetNextRegKeyThatHasGuid. Return Value: The count of valid GUIDs for the current handler. --*/ { REGKEY_ENUM e; DWORD Count = 0; // // Count the number of GUIDs in the current handler // if (EnumPtr->State == GUIDKEYSEARCH_NEXT_GUID) { if (EnumFirstRegKey (&e, EnumPtr->HandlerKey)) { do { Count++; } while (EnumNextRegKey (&e)); } } return Count; } BOOL pFillHashTableWithKeyNames ( OUT HASHTABLE Table, IN HINF InfFile, IN PCTSTR Section ) /*++ Routine Description: A general-purpose INF-to-string table copy routine. Takes the keys in a given section and adds them to the supplied string table. Arguments: Table - A pointer to an initialize string table InfFile - The handle to an open INF file Section - Section within the INF file containing strings Return Value: TRUE if no errors were encountered. --*/ { INFCONTEXT ic; TCHAR Key[MAX_ENCODED_RULE]; if (SetupFindFirstLine (InfFile, Section, NULL, &ic)) { do { if (SetupGetStringField (&ic, 0, Key, MAX_ENCODED_RULE, NULL)) { HtAddString (Table, Key); } ELSE_DEBUGMSG (( DBG_WARNING, "No key for line in section %s (line %u)", Section, ic.Line )); } while (SetupFindNextLine (&ic, &ic)); } ELSE_DEBUGMSG ((DBG_WARNING, "Section %s is empty", Section)); return TRUE; } BOOL pSuppressProgId ( PCTSTR ProgIdName ) /*++ Routine Description: Suppresses a ProgID registry key. Arguments: ProgIdName - The name of the OLE ProgID to suppress Return Value: TRUE if ProgIdName is a valid ProgID on the system. --*/ { TCHAR RegKey[MAX_REGISTRY_KEY]; HKEY ProgIdKey; TCHAR MemDbKey[MEMDB_MAX]; if (*ProgIdName) { wsprintf (RegKey, TEXT("HKCR\\%s"), ProgIdName); ProgIdKey = OpenRegKeyStr (RegKey); if (ProgIdKey) { CloseRegKey (ProgIdKey); DEBUGMSG ((DBG_OLEREG, "Suppressing ProgId: %s", ProgIdName)); MemDbSetValueEx (MEMDB_CATEGORY_PROGIDS, NULL, NULL, ProgIdName, PROGID_SUPPRESSED, NULL); MemDbBuildKey(MemDbKey,MEMDB_CATEGORY_HKLM, TEXT("SOFTWARE\\Classes"), NULL, ProgIdName); Suppress95RegSetting(MemDbKey,NULL); return TRUE; } } return FALSE; } VOID pSuppressGuidInClsId ( IN PCTSTR Guid ) /*++ Routine Description: Does all the work necessary to suppress a GUID and its associated ProgID (if it has one). Arguments: Guid - The string identifing a GUID that is in HKCR\CLSID Return Value: none --*/ { TCHAR Node[MEMDB_MAX]; MEMDB_ENUM e; HKEY GuidKey; PCTSTR Data; MYASSERT (IsGuid (Guid, TRUE)); if (pIgnoreGuid (Guid)) { return; } // // - Remove it from UGUIDS memdb category // - Add it to GUIDS memdb category // - Suppress HKLM\SOFTWARE\Classes\CLSID\ // - Suppress HKLM\SOFTWARE\Classes\Interface\ // // Suppress all TreatAs GUIDs if (MemDbGetValueEx (&e, MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL)) { do { pSuppressGuidInClsId (e.szName); } while (MemDbEnumNextValue (&e)); } // Remove TreatAs GUIDs MemDbBuildKey (Node, MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL, NULL); MemDbDeleteTree (Node); // Add to suppressed GUID category and to registry suppression MemDbSetValueEx (MEMDB_CATEGORY_GUIDS, NULL, NULL, Guid, 0, NULL); // Get ProgID of GUID wsprintf (Node, TEXT("HKCR\\CLSID\\%s"), Guid); GuidKey = OpenRegKeyStr (Node); if (GuidKey) { BOOL ProgIdFound = FALSE; // Suppress ProgIDs Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("ProgID")); if (Data) { ProgIdFound |= pSuppressProgId (Data); MemFree (g_hHeap, 0, Data); } // Version-independent ProgIDs Data = (PCTSTR) GetRegKeyData (GuidKey, TEXT("VersionIndependentProgID")); if (Data) { ProgIdFound |= pSuppressProgId (Data); MemFree (g_hHeap, 0, Data); } // Possibly the default name Data = (PCTSTR) GetRegValueData (GuidKey, TEXT("")); if (Data) { ProgIdFound |= pSuppressProgId (Data); MemFree (g_hHeap, 0, Data); } DEBUGMSG_IF (( !ProgIdFound, DBG_OLEREG, "The suppressed registry key %s has no associated ProgID", Node )); CloseRegKey (GuidKey); } } VOID pAddUnsuppressedTreatAsGuid ( PCTSTR Guid, PCTSTR TreatAsGuid ) /*++ Routine Description: Keeps track of unsuppressed TreatAs GUIDs that need further processing. Arguments: Guid - A string identifying the GUID that should be treated as another GUID TreatAsGuid - The replacement GUID Return Value: none --*/ { MemDbSetValueEx (MEMDB_CATEGORY_UNSUP_GUIDS, Guid, NULL, TreatAsGuid, 0, NULL); } VOID pRemoveUnsuppressedTreatAsGuids ( VOID ) /*++ Routine Description: Cleanup function for unsuppressed GUIDs. Arguments: none Return Value: none --*/ { TCHAR Node[MEMDB_MAX]; MemDbBuildKey (Node, MEMDB_CATEGORY_UNSUP_GUIDS, NULL, NULL, NULL); MemDbDeleteTree (Node); } VOID pAddOleWarning ( IN WORD MsgId, IN HKEY Object, OPTIONAL IN PCTSTR KeyName ) /*++ Routine Description: Adds a warning to the incompatibility report. It loads the human-readable name from the specified OLE registry key. The message is formatted with the human-readable object name as the first parameter and the registry location as the second parameter. Arguments: MsgID - Supplies the ID of the message to display Object - Specifies the handle of a registry key whos default value is a human-readable object name. KeyName - The registry key location Return Value: none --*/ { PCTSTR Data; if (Object) { Data = (PCTSTR) GetRegValueData (Object, S_EMPTY); } else { Data = NULL; } LOG ((LOG_WARNING, (PCSTR)MsgId, Data ? Data : S_EMPTY, KeyName, g_Win95Name)); if (Data) { MemFree (g_hHeap, 0, Data); } } VOID pSuppressGuidIfBadCmdLine ( IN HASHTABLE StrTab, IN HKEY ClsIdKey, IN PCTSTR GuidStr ) /*++ Routine Description: Suppresses the specified GUID if its CLSID settings reference a Win9x- specific binary. The suppression is written to a string table which is later transfered to memdb. The transfer operation suppresses all linkage to the GUID. Arguments: StrTab - The table that holds a list of suppressed GUIDs ClsIdKey - The registry handle of a subkey of HKCR\CLSID GuidStr - The GUID to suppress if an invalid command line is found Return Value: none --*/ { PCTSTR Data; INT i; BOOL b; MYASSERT (IsGuid (GuidStr, TRUE)); if (pIgnoreGuid (GuidStr)) { return; } for (i = 0 ; g_FileRefKeys[i] ; i++) { Data = (PCTSTR) GetRegKeyData (ClsIdKey, g_FileRefKeys[i]); if (Data) { // // Check if the file in Data is in Win9xFileLocation for any user // b = pSuppressGuidIfCmdLineBad ( StrTab, Data, ClsIdKey, GuidStr ); MemFree (g_hHeap, 0, Data); if (b) { return; } } } } VOID pSuppressProgIdWithBadCmdLine ( IN HKEY ProgId, IN PCTSTR ProgIdStr ) /*++ Routine Description: Suppresses the specified ProgId if it references a Win9x-specific binary. The suppression is written directly to memdb. This function is called after all Suppressed GUIDs have been processed, and is used to suppress OLE objects that are not caught by an invalid HKCR\CLSID entry. Arguments: ProgId - The registry handle of a subkey of the root of HKCR ProgIdStr - The name of the ProgID key to suppress if a bad cmd line is found. Return Value: none --*/ { PCTSTR Data; INT i; for (i = 0 ; g_FileRefKeys[i]; i++) { Data = (PCTSTR) GetRegKeyData (ProgId, g_FileRefKeys[i]); if (Data) { // // Check if the file in Data is in Win9xFileLocation for any user // if (pIsCmdLineBad (Data)) { DEBUGMSG ((DBG_OLEREG, "ProgID %s has incompatible command line %s", ProgId, Data)); pSuppressProgId (ProgIdStr); break; } MemFree (g_hHeap, 0, Data); } } } VOID pAddGuidToTable ( IN HASHTABLE Table, IN PCTSTR GuidStr ) /*++ Routine Description: Adds a GUID to a string table. For checked builds, it does a quick test to see how many GUIDs get suppressed more than once. Arguments: Table - Specifies table that receives the GUID entry GuidStr - Specifies the string of the GUID Return Value: none --*/ { #ifdef DEBUG // // Just for yuks, let's see if we're wasting time by suppressing // an already suppressed GUID... // DWORD rc; if (HtFindString (Table, GuidStr)) { DEBUGMSG ((DBG_OLEREG, "FYI - GUID %s is already suppressed", GuidStr)); } MYASSERT (IsGuid (GuidStr, TRUE)); #endif HtAddString (Table, GuidStr); } BOOL pSuppressGuidIfCmdLineBad ( IN OUT HASHTABLE StrTab, OPTIONAL IN PCTSTR CmdLine, IN HKEY DescriptionKey, IN PCTSTR GuidStr OPTIONAL ) /*++ Routine Description: Suppresses an OLE object if the specified command line contains a Win9x- specific binary. Only the first argument of the command line is examined; an other arguments that cannot be upgraded are ignored. Arguments: StrTab - Specifies the table that holds the list of suppressed GUIDs. If NULL, a warning will be displayed, and GuidKey must not be NULL. CmdLine - Specifies the command line to examine DescriptionKey - Specifies a key whos default value is the description of the object. GuidStr - Specifies the GUID string. This parameter is optional only if StrTab is NULL. Return Value: TRUE if CmdLine is incompatible, FALSE otherwise. --*/ { BOOL b = FALSE; if (GuidStr) { MYASSERT (IsGuid (GuidStr, TRUE)); if (pIgnoreGuid (GuidStr)) { return TRUE; } } if (pIsCmdLineBad (CmdLine)) { // // OLE object points to deleted file // b = TRUE; if (!StrTab) { // Warning!! DEBUGMSG ((DBG_WARNING, "Reg key %s points to deleted file %s", GuidStr, CmdLine)); pAddOleWarning ( MSG_OBJECT_POINTS_TO_DELETED_FILE, DescriptionKey, GuidStr ); } else { MYASSERT (GuidStr); DEBUGMSG (( DBG_OLEREG, "Auto-suppressed %s because it requires a Win9x-specific file: %s", GuidStr, CmdLine )); pAddGuidToTable (StrTab, GuidStr); } } return b; } BOOL pSearchSubkeyDataForBadFiles ( IN OUT HASHTABLE SuppressTable, IN HKEY KeyHandle, IN PCTSTR LastKey, IN PCTSTR GuidStr, IN HKEY DescriptionKey ) /*++ Routine Description: Scans a number of OLE settings for bad command lines, including the object's command and the default icon binary. If a reference to a Win9x-specific binary is detected, the GUID is suppressed. This function recurses through all subkeys of the OLE object. Arguments: SuppressTable - Specifies the table that holds the suppressed GUID list KeyHandle - An open registry key of an OLE object to be examined recursively. LastKey - Specifies the name of the OLE object's subkey being processed. Special processing is done for some subkeys. GuidStr - The GUID of the OLE object. DescriptionKey - A handle to the key who's default value identifies the OLE object's key. Return Value: TRUE if an incompatible cmd line was found, FALSE otherwise. --*/ { REGKEY_ENUM ek; REGVALUE_ENUM ev; HKEY SubKeyHandle; PCTSTR Data; BOOL b; MYASSERT (IsGuid (GuidStr, FALSE)); if (StringIMatch (LastKey, TEXT("Command")) || StringIMatch (LastKey, g_DefaultIcon) ) { if (EnumFirstRegValue (&ev, KeyHandle)) { do { Data = (PCTSTR) GetRegValueData (KeyHandle, ev.ValueName); if (Data) { // If this thing has a path name somewhere, process it b = pSuppressGuidIfCmdLineBad ( SuppressTable, Data, DescriptionKey, GuidStr ); MemFree (g_hHeap, 0, Data); if (b) { return TRUE; } } } while (EnumNextRegValue (&ev)); } } if (EnumFirstRegKey (&ek, KeyHandle)) { do { SubKeyHandle = OpenRegKey (ek.KeyHandle, ek.SubKeyName); if (SubKeyHandle) { b = pSearchSubkeyDataForBadFiles ( SuppressTable, SubKeyHandle, ek.SubKeyName, GuidStr, DescriptionKey ); CloseRegKey (SubKeyHandle); if (b) { AbortRegKeyEnum (&ek); return TRUE; } } } while (EnumNextRegKey (&ek)); } return FALSE; } BOOL pIsCmdLineBadEx ( IN PCTSTR CmdLine, OUT PBOOL UsableIsvCmdLine OPTIONAL ) /*++ Routine Description: Determines if the specified command line's first argument is listed in memdb's Win9xFileLocation category. If it is listed, and the file is marked for permanent removal, TRUE is returned. If it is not listed, or if it is listed but has an NT equivalent, FALSE is returned. Arguments: CmdLine - Specifies the command line to examine UsableIsvCmdLine - Optional variable that receives wether the command line contains a compatible third party cmd line. Return Value: TRUE if command line requires Win9x-specific binaries, FALSE if the command line uses a valid binary or is not a command line. --*/ { BOOL FileMarked = FALSE; TCHAR ArgZero[MAX_CMDLINE]; TCHAR LongPath[MAX_TCHAR_PATH]; DWORD status; if (UsableIsvCmdLine) { *UsableIsvCmdLine = FALSE; } // // Determine if the first arg of the command line points to a // deleted (or moved) file // ExtractArgZeroEx (CmdLine, ArgZero, TEXT(","), FALSE); if (OurGetLongPathName (ArgZero, LongPath, MAX_TCHAR_PATH)) { status = GetFileStatusOnNt (LongPath); if ((status & FILESTATUS_DELETED) == FILESTATUS_DELETED) { return TRUE; } else if (UsableIsvCmdLine) { status = GetOperationsOnPath (LongPath); if ((status & OPERATION_OS_FILE) != OPERATION_OS_FILE) { *UsableIsvCmdLine = TRUE; } } } ELSE_DEBUGMSG (( DBG_OLEREG, "pIsCmdLineBad: Cannot get full path name; assuming %s is not a command line", ArgZero )); return FALSE; } BOOL pIsCmdLineBad ( IN PCTSTR CmdLine ) { return pIsCmdLineBadEx (CmdLine, NULL); }