RegistryUtils.cpp
1 #include "RegistryUtils.h" 2 #include <common/utils/winapi_error.h> 3 #include <map> 4 5 using namespace std; 6 7 extern std::vector<std::wstring> processes; 8 9 namespace 10 { 11 vector<pair<HKEY, wstring>> registryKeys = { 12 { HKEY_CLASSES_ROOT, L"CLSID\\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}" }, 13 { HKEY_CLASSES_ROOT, L"powertoys" }, 14 { HKEY_CLASSES_ROOT, L"CLSID\\{ddee2b8a-6807-48a6-bb20-2338174ff779}" }, 15 { HKEY_CLASSES_ROOT, L"CLSID\\{36B27788-A8BB-4698-A756-DF9F11F64F84}" }, 16 { HKEY_CLASSES_ROOT, L"CLSID\\{45769bcc-e8fd-42d0-947e-02beef77a1f5}" }, 17 { HKEY_CLASSES_ROOT, L"AppID\\{CF142243-F059-45AF-8842-DBBE9783DB14}" }, 18 { HKEY_CLASSES_ROOT, L"CLSID\\{07665729-6243-4746-95b7-79579308d1b2}" }, 19 { HKEY_CLASSES_ROOT, L"CLSID\\{ec52dea8-7c9f-4130-a77b-1737d0418507}" }, 20 { HKEY_CLASSES_ROOT, L"CLSID\\{dd8de316-7b01-48e7-ba21-e92c646704af}" }, 21 { HKEY_CLASSES_ROOT, L"CLSID\\{8AA07897-C30B-4543-865B-00A0E5A1B32D}" }, 22 { HKEY_CLASSES_ROOT, L"CLSID\\{BCC13D15-9720-4CC4-8371-EA74A274741E}" }, 23 { HKEY_CLASSES_ROOT, L"CLSID\\{BFEE99B4-B74D-4348-BCA5-E757029647FF}" }, 24 { HKEY_CLASSES_ROOT, L"CLSID\\{c28761a0-8420-43ad-bff3-40400543e2d4}" }, 25 { HKEY_CLASSES_ROOT, L"CLSID\\{8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF}" }, 26 { HKEY_CLASSES_ROOT, L"CLSID\\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\\InprocServer32" }, 27 { HKEY_CLASSES_ROOT, L"CLSID\\{0440049F-D1DC-4E46-B27B-98393D79486B}" }, 28 { HKEY_CLASSES_ROOT, L"AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt" }, 29 { HKEY_CLASSES_ROOT, L".svg\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 30 { HKEY_CLASSES_ROOT, L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, 31 { HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 32 { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 33 { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, 34 { HKEY_CLASSES_ROOT, L".qoi\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 35 { HKEY_CLASSES_ROOT, L".qoi\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, 36 { HKEY_CLASSES_ROOT, L".gcode\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 37 { HKEY_CLASSES_ROOT, L".gcode\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, 38 { HKEY_CLASSES_ROOT, L".bgcode\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, 39 { HKEY_CLASSES_ROOT, L".bgcode\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, 40 { HKEY_CLASSES_ROOT, L".stl\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" } 41 }; 42 43 vector<tuple<HKEY, wstring, wstring>> registryValues = { 44 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{ddee2b8a-6807-48a6-bb20-2338174ff779}" }, 45 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}" }, 46 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{07665729-6243-4746-95b7-79579308d1b2}" }, 47 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{ec52dea8-7c9f-4130-a77b-1737d0418507}" }, 48 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{dd8de316-7b01-48e7-ba21-e92c646704af}" }, 49 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{8AA07897-C30B-4543-865B-00A0E5A1B32D}" }, 50 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"prevhost.exe" }, 51 { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"dllhost.exe" } 52 }; 53 54 // Is there a Windows API for this? 55 std::unordered_map<HKEY, wstring> hKeyToString = { 56 { HKEY_CLASSES_ROOT, L"HKEY_CLASSES_ROOT" }, 57 { HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" }, 58 { HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" }, 59 { HKEY_PERFORMANCE_DATA, L"HKEY_PERFORMANCE_DATA" }, 60 { HKEY_PERFORMANCE_NLSTEXT, L"HKEY_PERFORMANCE_NLSTEXT"}, 61 { HKEY_PERFORMANCE_TEXT, L"HKEY_PERFORMANCE_TEXT"}, 62 { HKEY_USERS, L"HKEY_USERS"}, 63 }; 64 65 vector<pair<wstring, wstring>> QueryValues(HKEY key) 66 { 67 DWORD cValues; 68 RegQueryInfoKeyW(key, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &cValues, nullptr, nullptr, nullptr, nullptr); 69 TCHAR achValue[255]; 70 DWORD cchValue = 255; 71 LPBYTE value; 72 vector<pair<wstring, wstring>> results; 73 // Values 74 if (cValues) 75 { 76 for (DWORD i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) 77 { 78 cchValue = 255; 79 achValue[0] = '\0'; 80 value = new BYTE[16383]; 81 retCode = RegEnumValueW(key, i, achValue, &cchValue, NULL, NULL, value, &cchValue); 82 83 if (retCode == ERROR_SUCCESS) 84 { 85 results.push_back({ achValue, (LPCTSTR)value }); 86 } 87 } 88 } 89 90 return results; 91 } 92 93 void QueryKey(HKEY key, wostream& stream, int indent = 1) 94 { 95 TCHAR achKey[255]; 96 DWORD cbName; 97 TCHAR achClass[MAX_PATH] = TEXT(""); 98 DWORD cchClassName = MAX_PATH; 99 DWORD cSubKeys = 0; 100 DWORD cbMaxSubKey; 101 DWORD cchMaxClass; 102 DWORD cValues; 103 DWORD cchMaxValue; 104 DWORD cbMaxValueData; 105 106 DWORD i, retCode; 107 108 TCHAR achValue[255]; 109 DWORD cchValue = 255; 110 LPBYTE value; 111 112 // Get the class name and the value count. 113 retCode = RegQueryInfoKeyW(key, achClass, &cchClassName, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, &cValues, &cchMaxValue, &cbMaxValueData, NULL, NULL); 114 115 // Values 116 if (cValues) 117 { 118 for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) 119 { 120 cchValue = 255; 121 achValue[0] = '\0'; 122 value = new BYTE[16383]; 123 retCode = RegEnumValueW(key, i, achValue, &cchValue, NULL, NULL, value, &cchValue); 124 125 if (retCode == ERROR_SUCCESS) 126 { 127 stream << wstring(indent, '\t'); 128 if (achValue[0] == '\0') 129 { 130 stream << "Default"; 131 } 132 else 133 { 134 stream << achValue; 135 } 136 137 stream << " > " << reinterpret_cast<LPCTSTR>(value) << "\n"; 138 } 139 else 140 { 141 stream << "Error " << retCode << "\n"; 142 } 143 } 144 } 145 146 // Keys 147 if (cSubKeys) 148 { 149 std::vector<wstring> vecKeys; 150 vecKeys.reserve(cSubKeys); 151 152 for (i = 0; i < cSubKeys; ++i) 153 { 154 cbName = 255; 155 retCode = RegEnumKeyExW(key, i, achKey, &cbName, NULL, NULL, NULL, NULL); 156 if (retCode == ERROR_SUCCESS) 157 { 158 vecKeys.push_back(achKey); 159 } 160 } 161 162 // Parsing subkeys recursively 163 for (auto& child : vecKeys) 164 { 165 HKEY hTestKey; 166 if (RegOpenKeyExW(key, child.c_str(), 0, KEY_READ, &hTestKey) == ERROR_SUCCESS) 167 { 168 stream << wstring(indent, '\t') << child << "\n"; 169 QueryKey(hTestKey, stream, indent + 1); 170 RegCloseKey(hTestKey); 171 } 172 else 173 { 174 stream << "Error " << retCode << "\n"; 175 } 176 } 177 } 178 } 179 } 180 181 void ReportCompatibilityTab(HKEY key, wofstream& report) 182 { 183 map<wstring, wstring> flags; 184 for (auto app : processes) 185 { 186 flags[app] = L""; 187 } 188 189 try 190 { 191 HKEY outKey; 192 LONG result = RegOpenKeyExW(key, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, KEY_READ, &outKey); 193 if (result == ERROR_SUCCESS) 194 { 195 auto values = QueryValues(outKey); 196 for (auto value : values) 197 { 198 for (auto app : processes) 199 { 200 if (value.first.find(app) != wstring::npos) 201 { 202 flags[app] += value.second; 203 } 204 } 205 } 206 } 207 else 208 { 209 report << "Failed to get the report. " << get_last_error_or_default(GetLastError()); 210 return; 211 } 212 } 213 catch (...) 214 { 215 report << "Failed to get the report"; 216 return; 217 } 218 219 for (auto flag : flags) 220 { 221 report << flag.first << ": " << flag.second << endl; 222 } 223 } 224 225 void ReportCompatibilityTab(const std::filesystem::path& tmpDir) 226 { 227 auto reportPath = tmpDir; 228 reportPath.append(L"compatibility-tab-info.txt"); 229 wofstream report(reportPath); 230 report << "Current user report" << endl; 231 ReportCompatibilityTab(HKEY_CURRENT_USER, report); 232 report << endl << endl; 233 report << "Local machine report" << endl; 234 ReportCompatibilityTab(HKEY_LOCAL_MACHINE, report); 235 } 236 237 void ReportRegistry(const filesystem::path& tmpDir) 238 { 239 auto registryReportPath = tmpDir; 240 registryReportPath.append("registry-report-info.txt"); 241 242 wofstream registryReport(registryReportPath); 243 try 244 { 245 for (auto [rootKey, subKey] : registryKeys) 246 { 247 registryReport << hKeyToString[rootKey] << "\\" << subKey << "\n"; 248 249 HKEY outKey; 250 LONG result = RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &outKey); 251 if (result == ERROR_SUCCESS) 252 { 253 QueryKey(outKey, registryReport); 254 RegCloseKey(rootKey); 255 } 256 else 257 { 258 registryReport << "ERROR " << result << "\n"; 259 } 260 261 registryReport << "\n"; 262 } 263 264 for (auto [rootKey, subKey, value] : registryValues) 265 { 266 registryReport << hKeyToString[rootKey] << "\\" << subKey << "\n"; 267 268 // Reading size 269 DWORD dataSize = 0; 270 DWORD flags = RRF_RT_ANY; 271 DWORD type; 272 LONG result = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, NULL, &dataSize); 273 if (result == ERROR_SUCCESS) 274 { 275 // Reading value 276 if (type == REG_SZ) // string 277 { 278 std::wstring data(dataSize / sizeof(wchar_t) + 1, L' '); 279 result = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, &data[0], &dataSize); 280 if (result == ERROR_SUCCESS) 281 { 282 registryReport << "\t" << value << " > " << data << "\n"; 283 } 284 else 285 { 286 registryReport << "ERROR " << result << "\n"; 287 } 288 } 289 else 290 { 291 DWORD data = 0; 292 dataSize = sizeof(data); 293 result = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, &data, &dataSize); 294 if (result == ERROR_SUCCESS) 295 { 296 registryReport << "\t" << value << " > " << data << "\n"; 297 } 298 else 299 { 300 registryReport << "ERROR " << result << "\n"; 301 } 302 } 303 304 RegCloseKey(rootKey); 305 } 306 else 307 { 308 registryReport << "ERROR " << result << "\n"; 309 } 310 311 registryReport << "\n"; 312 } 313 } 314 catch (...) 315 { 316 printf("Failed to get registry keys\n"); 317 } 318 }