ConfigurationProcessor.cpp (50842B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "ConfigurationProcessor.h" 5 #include "ConfigurationProcessor.g.cpp" 6 #include "ConfigurationSet.h" 7 #include "OpenConfigurationSetResult.h" 8 #include "ConfigurationSetParser.h" 9 #include "DiagnosticInformationInstance.h" 10 #include "ApplyConfigurationSetResult.h" 11 #include "ApplyConfigurationUnitResult.h" 12 #include "TestConfigurationSetResult.h" 13 #include "TestConfigurationUnitResult.h" 14 #include "ConfigurationUnitResultInformation.h" 15 #include "GetConfigurationUnitSettingsResult.h" 16 #include "GetAllConfigurationUnitSettingsResult.h" 17 #include "GetAllConfigurationUnitsResult.h" 18 #include "ExceptionResultHelpers.h" 19 #include "ConfigurationSetChangeData.h" 20 #include "GetConfigurationUnitDetailsResult.h" 21 #include "GetConfigurationSetDetailsResult.h" 22 #include "DefaultSetGroupProcessor.h" 23 #include "ConfigurationSequencer.h" 24 #include "ConfigurationStatus.h" 25 26 #include <AppInstallerErrors.h> 27 #include <AppInstallerStrings.h> 28 #include <AppInstallerSHA256.h> 29 #include <winget/GroupPolicy.h> 30 31 using namespace std::chrono_literals; 32 33 namespace winrt::Microsoft::Management::Configuration::implementation 34 { 35 namespace 36 { 37 AppInstaller::Logging::Level ConvertLevel(DiagnosticLevel level) 38 { 39 switch (level) 40 { 41 case DiagnosticLevel::Verbose: return AppInstaller::Logging::Level::Verbose; 42 case DiagnosticLevel::Informational: return AppInstaller::Logging::Level::Info; 43 case DiagnosticLevel::Warning: return AppInstaller::Logging::Level::Warning; 44 case DiagnosticLevel::Error: return AppInstaller::Logging::Level::Error; 45 case DiagnosticLevel::Critical: return AppInstaller::Logging::Level::Crit; 46 default: return AppInstaller::Logging::Level::Warning; 47 } 48 } 49 50 DiagnosticLevel ConvertLevel(AppInstaller::Logging::Level level) 51 { 52 switch (level) 53 { 54 case AppInstaller::Logging::Level::Verbose: return DiagnosticLevel::Verbose; 55 case AppInstaller::Logging::Level::Info: return DiagnosticLevel::Informational; 56 case AppInstaller::Logging::Level::Warning: return DiagnosticLevel::Warning; 57 case AppInstaller::Logging::Level::Error: return DiagnosticLevel::Error; 58 case AppInstaller::Logging::Level::Crit: return DiagnosticLevel::Critical; 59 default: return DiagnosticLevel::Warning; 60 } 61 } 62 63 // ILogger that sends data back to the Diagnostics event of the ConfigurationProcessor. 64 struct ConfigurationProcessorDiagnosticsLogger : public AppInstaller::Logging::ILogger 65 { 66 ConfigurationProcessorDiagnosticsLogger(ConfigurationProcessor& processor) : m_processor(processor) {} 67 68 std::string GetName() const override 69 { 70 return "ConfigurationProcessorDiagnosticsLogger"; 71 } 72 73 void Write(AppInstaller::Logging::Channel channel, AppInstaller::Logging::Level level, std::string_view message) noexcept override try 74 { 75 std::ostringstream strstr; 76 strstr << '[' << AppInstaller::Logging::GetChannelName(channel) << "] " << message; 77 m_processor.SendDiagnostics(ConvertLevel(level), strstr.str()); 78 } 79 catch (...) {} 80 81 void WriteDirect(AppInstaller::Logging::Channel, AppInstaller::Logging::Level level, std::string_view message) noexcept override try 82 { 83 m_processor.SendDiagnostics(ConvertLevel(level), message); 84 } 85 catch (...) {} 86 87 private: 88 ConfigurationProcessor& m_processor; 89 }; 90 91 // Helper to ensure a one-time callback attach 92 struct AttachWilFailureCallback 93 { 94 AttachWilFailureCallback() 95 { 96 wil::SetResultLoggingCallback(wilResultLoggingCallback); 97 } 98 99 ~AttachWilFailureCallback() = default; 100 101 static void __stdcall wilResultLoggingCallback(const wil::FailureInfo& info) noexcept 102 { 103 AICLI_LOG(Fail, Error, << [&]() { 104 wchar_t message[2048]; 105 GetFailureLogString(message, ARRAYSIZE(message), info); 106 return AppInstaller::Utility::ConvertToUTF8(message); 107 }()); 108 } 109 110 static void Ensure() 111 { 112 static AttachWilFailureCallback s_callbackAttach; 113 } 114 }; 115 } 116 117 ConfigurationProcessor::ConfigurationProcessor() 118 { 119 THROW_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); 120 THROW_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::Configuration)); 121 122 AppInstaller::Logging::DiagnosticLogger& logger = m_threadGlobals.GetDiagnosticLogger(); 123 logger.SetEnabledChannels(AppInstaller::Logging::Channel::All); 124 logger.SetLevel(AppInstaller::Logging::Level::Verbose); 125 logger.AddLogger(std::make_unique<ConfigurationProcessorDiagnosticsLogger>(*this)); 126 } 127 128 ConfigurationProcessor::ConfigurationProcessor(const IConfigurationSetProcessorFactory& factory) : ConfigurationProcessor() 129 { 130 ConfigurationSetProcessorFactory(factory); 131 } 132 133 event_token ConfigurationProcessor::Diagnostics(const Windows::Foundation::EventHandler<IDiagnosticInformation>& handler) 134 { 135 AttachWilFailureCallback::Ensure(); 136 return m_diagnostics.add(handler); 137 } 138 139 void ConfigurationProcessor::Diagnostics(const event_token& token) noexcept 140 { 141 m_diagnostics.remove(token); 142 } 143 144 DiagnosticLevel ConfigurationProcessor::MinimumLevel() 145 { 146 return m_minimumLevel; 147 } 148 149 void ConfigurationProcessor::MinimumLevel(DiagnosticLevel value) 150 { 151 m_minimumLevel = value; 152 m_threadGlobals.GetDiagnosticLogger().SetLevel(ConvertLevel(value)); 153 if (m_factory) 154 { 155 m_factory.MinimumLevel(value); 156 } 157 } 158 159 hstring ConfigurationProcessor::Caller() const 160 { 161 return hstring{ AppInstaller::Utility::ConvertToUTF16(m_threadGlobals.GetTelemetryLogger().GetCaller()) }; 162 } 163 164 void ConfigurationProcessor::Caller(hstring value) 165 { 166 m_threadGlobals.GetTelemetryLogger().SetCaller(AppInstaller::Utility::ConvertToUTF8(value)); 167 } 168 169 guid ConfigurationProcessor::ActivityIdentifier() 170 { 171 return *m_threadGlobals.GetTelemetryLogger().GetActivityId(); 172 } 173 174 void ConfigurationProcessor::ActivityIdentifier(const guid& value) 175 { 176 m_threadGlobals.GetTelemetryLogger().SetActivityId(value); 177 } 178 179 bool ConfigurationProcessor::GenerateTelemetryEvents() 180 { 181 return m_threadGlobals.GetTelemetryLogger().IsEnabled(); 182 } 183 184 void ConfigurationProcessor::GenerateTelemetryEvents(bool value) 185 { 186 std::ignore = m_threadGlobals.GetTelemetryLogger().EnableRuntime(value); 187 } 188 189 event_token ConfigurationProcessor::ConfigurationChange(const Windows::Foundation::TypedEventHandler<Configuration::ConfigurationSet, Configuration::ConfigurationChangeData>& handler) 190 { 191 if (!m_configurationChange) 192 { 193 auto status = ConfigurationStatus::Instance(); 194 std::atomic_store(&m_changeRegistration, status->RegisterForChange(*this)); 195 } 196 197 return m_configurationChange.add(handler); 198 } 199 200 void ConfigurationProcessor::ConfigurationChange(const event_token& token) noexcept 201 { 202 m_configurationChange.remove(token); 203 204 if (!m_configurationChange) 205 { 206 std::atomic_store(&m_changeRegistration, {}); 207 } 208 } 209 210 void ConfigurationProcessor::ConfigurationChange(const Configuration::ConfigurationSet& set, const Configuration::ConfigurationChangeData& data) try 211 { 212 m_configurationChange(set, data); 213 } 214 CATCH_LOG(); 215 216 Windows::Foundation::Collections::IVector<Configuration::ConfigurationSet> ConfigurationProcessor::GetConfigurationHistory() 217 { 218 return GetConfigurationHistoryImpl(); 219 } 220 221 Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVector<Configuration::ConfigurationSet>> ConfigurationProcessor::GetConfigurationHistoryAsync() 222 { 223 auto strong_this{ get_strong() }; 224 co_await winrt::resume_background(); 225 co_return GetConfigurationHistoryImpl({ co_await winrt::get_cancellation_token() }); 226 } 227 228 Configuration::OpenConfigurationSetResult ConfigurationProcessor::OpenConfigurationSet(const Windows::Storage::Streams::IInputStream& stream) 229 { 230 return OpenConfigurationSetAsync(stream).get(); 231 } 232 233 Windows::Foundation::IAsyncOperation<Configuration::OpenConfigurationSetResult> ConfigurationProcessor::OpenConfigurationSetAsync(const Windows::Storage::Streams::IInputStream& stream) 234 { 235 auto strong_this{ get_strong() }; 236 Windows::Storage::Streams::IInputStream localStream = stream; 237 238 co_await winrt::resume_background(); 239 auto cancellation = co_await winrt::get_cancellation_token(); 240 241 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 242 auto result = make_self<wil::details::module_count_wrapper<OpenConfigurationSetResult>>(); 243 244 if (!localStream) 245 { 246 result->Initialize(E_POINTER, {}); 247 co_return *result; 248 } 249 250 try 251 { 252 // Read the entire file into memory as we expect them to be small and 253 // our YAML parser doesn't support streaming at this time. 254 // This is done here to enable easy cancellation propagation to the stream reads. 255 uint32_t bufferSize = 1 << 20; 256 Windows::Storage::Streams::Buffer buffer(bufferSize); 257 258 // Memory stream in mixed elevation does not support InputStreamOptions as flags. 259 Windows::Storage::Streams::InputStreamOptions readOptions = Windows::Storage::Streams::InputStreamOptions::Partial; 260 std::string inputString; 261 262 for (;;) 263 { 264 auto asyncOperation = localStream.ReadAsync(buffer, bufferSize, readOptions); 265 266 // Manually poll status and propagate cancellation to stay on this thread for thread globals 267 while (asyncOperation.Status() == Windows::Foundation::AsyncStatus::Started) 268 { 269 if (cancellation()) 270 { 271 asyncOperation.Cancel(); 272 } 273 274 std::this_thread::sleep_for(100ms); 275 } 276 277 Windows::Storage::Streams::IBuffer readBuffer = asyncOperation.GetResults(); 278 279 size_t readSize = static_cast<size_t>(readBuffer.Length()); 280 if (readSize) 281 { 282 static_assert(sizeof(char) == sizeof(*readBuffer.data())); 283 inputString.append(reinterpret_cast<char*>(readBuffer.data()), readSize); 284 } 285 else 286 { 287 break; 288 } 289 } 290 291 std::unique_ptr<ConfigurationSetParser> parser = ConfigurationSetParser::Create(inputString); 292 293 if (FAILED(parser->Result())) 294 { 295 result->Initialize(parser->Result(), parser->Field(), parser->Value(), parser->Line(), parser->Column()); 296 co_return *result; 297 } 298 299 parser->Parse(); 300 if (FAILED(parser->Result())) 301 { 302 result->Initialize(parser->Result(), parser->Field(), parser->Value(), parser->Line(), parser->Column()); 303 co_return *result; 304 } 305 306 auto configurationSet = parser->GetConfigurationSet(); 307 PropagateLifetimeWatcher(configurationSet.as<Windows::Foundation::IUnknown>()); 308 configurationSet->SetInputHash(AppInstaller::Utility::SHA256::ConvertToString(AppInstaller::Utility::SHA256::ComputeHash(inputString))); 309 310 result->Initialize(*configurationSet); 311 } 312 catch (const wil::ResultException& resultException) 313 { 314 result->Initialize(resultException.GetErrorCode()); 315 } 316 catch (...) 317 { 318 result->Initialize(WINGET_CONFIG_ERROR_INVALID_CONFIGURATION_FILE); 319 LOG_CAUGHT_EXCEPTION(); 320 } 321 322 co_return *result; 323 } 324 325 Windows::Foundation::Collections::IVector<ConfigurationConflict> ConfigurationProcessor::CheckForConflicts( 326 const Windows::Foundation::Collections::IVectorView<Configuration::ConfigurationSet>& configurationSets, 327 bool includeConfigurationHistory) 328 { 329 UNREFERENCED_PARAMETER(configurationSets); 330 UNREFERENCED_PARAMETER(includeConfigurationHistory); 331 THROW_HR(E_NOTIMPL); 332 } 333 334 Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVector<ConfigurationConflict>> ConfigurationProcessor::CheckForConflictsAsync( 335 const Windows::Foundation::Collections::IVectorView<Configuration::ConfigurationSet>& configurationSets, 336 bool includeConfigurationHistory) 337 { 338 co_return CheckForConflicts(configurationSets, includeConfigurationHistory); 339 } 340 341 Configuration::GetConfigurationSetDetailsResult ConfigurationProcessor::GetSetDetails(const Configuration::ConfigurationSet& configurationSet, ConfigurationUnitDetailFlags detailFlags) 342 { 343 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 344 return GetSetDetailsImpl(configurationSet, detailFlags); 345 } 346 347 Windows::Foundation::IAsyncOperationWithProgress<Configuration::GetConfigurationSetDetailsResult, Configuration::GetConfigurationUnitDetailsResult> ConfigurationProcessor::GetSetDetailsAsync( 348 const Configuration::ConfigurationSet& configurationSet, 349 ConfigurationUnitDetailFlags detailFlags) 350 { 351 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 352 353 auto strong_this{ get_strong() }; 354 Configuration::ConfigurationSet localSet = configurationSet; 355 356 co_await winrt::resume_background(); 357 358 co_return GetSetDetailsImpl(localSet, detailFlags, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token()}); 359 } 360 361 Windows::Foundation::Collections::IVector<Configuration::ConfigurationSet> ConfigurationProcessor::GetConfigurationHistoryImpl(ShutdownAwareAsyncCancellation cancellation) 362 { 363 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 364 365 m_database.EnsureOpened(false); 366 cancellation.ThrowIfCancelled(); 367 368 std::vector<Configuration::ConfigurationSet> result; 369 for (const auto& set : m_database.GetSetHistory()) 370 { 371 PropagateLifetimeWatcher(*set); 372 result.emplace_back(*set); 373 } 374 375 return multi_threaded_vector(std::move(result)); 376 } 377 378 Configuration::GetConfigurationSetDetailsResult ConfigurationProcessor::GetSetDetailsImpl( 379 const Configuration::ConfigurationSet& configurationSet, 380 ConfigurationUnitDetailFlags detailFlags, 381 ShutdownAwareAsyncProgress<GetConfigurationSetDetailsResult, GetConfigurationUnitDetailsResult> progress) 382 { 383 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 384 385 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(configurationSet); 386 387 auto result = make_self<wil::details::module_count_wrapper<implementation::GetConfigurationSetDetailsResult>>(); 388 progress.Result(*result); 389 390 for (const auto& unit : configurationSet.Units()) 391 { 392 progress.ThrowIfCancelled(); 393 394 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::GetConfigurationUnitDetailsResult>>(); 395 auto unitResultInformation = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 396 unitResult->Unit(unit); 397 unitResult->ResultInformation(*unitResultInformation); 398 399 try 400 { 401 IConfigurationUnitProcessorDetails details = setProcessor.GetUnitProcessorDetails(unit, detailFlags); 402 unitResult->Details(details); 403 get_self<implementation::ConfigurationUnit>(unit)->Details(std::move(details)); 404 } 405 catch (...) 406 { 407 ExtractUnitResultInformation(std::current_exception(), unitResultInformation); 408 } 409 410 result->UnitResultsVector().Append(*unitResult); 411 progress.Progress(*unitResult); 412 } 413 414 return *result; 415 } 416 417 Configuration::GetConfigurationUnitDetailsResult ConfigurationProcessor::GetUnitDetails(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags) 418 { 419 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 420 return GetUnitDetailsImpl(unit, detailFlags); 421 } 422 423 Windows::Foundation::IAsyncOperation<Configuration::GetConfigurationUnitDetailsResult> ConfigurationProcessor::GetUnitDetailsAsync(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags) 424 { 425 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 426 427 auto strong_this{ get_strong() }; 428 ConfigurationUnit localUnit = unit; 429 430 co_await winrt::resume_background(); 431 432 co_return GetUnitDetailsImpl(localUnit, detailFlags); 433 } 434 435 Configuration::GetConfigurationUnitDetailsResult ConfigurationProcessor::GetUnitDetailsImpl(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags) 436 { 437 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 438 439 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 440 441 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::GetConfigurationUnitDetailsResult>>(); 442 auto unitResultInformation = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 443 unitResult->Unit(unit); 444 unitResult->ResultInformation(*unitResultInformation); 445 446 try 447 { 448 IConfigurationUnitProcessorDetails details = setProcessor.GetUnitProcessorDetails(unit, detailFlags); 449 unitResult->Details(details); 450 get_self<implementation::ConfigurationUnit>(unit)->Details(std::move(details)); 451 } 452 catch (...) 453 { 454 ExtractUnitResultInformation(std::current_exception(), unitResultInformation); 455 } 456 457 return *unitResult; 458 } 459 460 Configuration::ApplyConfigurationSetResult ConfigurationProcessor::ApplySet(const Configuration::ConfigurationSet& configurationSet, ApplyConfigurationSetFlags flags) 461 { 462 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 463 return ApplySetImpl(configurationSet, flags); 464 } 465 466 Windows::Foundation::IAsyncOperationWithProgress<Configuration::ApplyConfigurationSetResult, Configuration::ConfigurationSetChangeData> ConfigurationProcessor::ApplySetAsync( 467 const Configuration::ConfigurationSet& configurationSet, 468 ApplyConfigurationSetFlags flags) 469 { 470 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 471 472 auto strong_this{ get_strong() }; 473 Configuration::ConfigurationSet localSet = configurationSet; 474 475 co_await winrt::resume_background(); 476 477 co_return ApplySetImpl(localSet, flags, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token() }); 478 } 479 480 Configuration::ApplyConfigurationSetResult ConfigurationProcessor::ApplySetImpl( 481 const Configuration::ConfigurationSet& configurationSet, 482 ApplyConfigurationSetFlags flags, 483 ShutdownAwareAsyncProgress<ApplyConfigurationSetResult, ConfigurationSetChangeData> progress) 484 { 485 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 486 487 IConfigurationGroupProcessor groupProcessor; 488 bool recordHistoryAndStatus = false; 489 490 if (WI_IsFlagSet(flags, ApplyConfigurationSetFlags::PerformConsistencyCheckOnly)) 491 { 492 // If performing a consistency check, always use the default processor and let it know as well 493 auto defaultGroupProcessor = make_self<wil::details::module_count_wrapper<implementation::DefaultSetGroupProcessor>>(); 494 defaultGroupProcessor->Initialize(configurationSet, nullptr, m_threadGlobals, true); 495 groupProcessor = *defaultGroupProcessor; 496 } 497 else 498 { 499 groupProcessor = GetSetGroupProcessor(configurationSet); 500 501 // Write this set to the database history 502 // This is a somewhat arbitrary time to write it, but it should not be done if PerformConsistencyCheckOnly is passed, so this is convenient. 503 recordHistoryAndStatus = true; 504 m_database.EnsureOpened(); 505 progress.ThrowIfCancelled(); 506 m_database.WriteSetHistory(configurationSet, WI_IsFlagSet(flags, ApplyConfigurationSetFlags::DoNotOverwriteMatchingOriginSet)); 507 } 508 509 auto result = make_self<wil::details::module_count_wrapper<implementation::ApplyConfigurationSetResult>>(); 510 511 // Build out the unit results and a map to find them quickly 512 using UnitResultType = decltype(make_self<wil::details::module_count_wrapper<implementation::ApplyConfigurationUnitResult>>()); 513 std::map<guid, UnitResultType> unitResultMap; 514 515 std::function<void(const winrt::Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>&)> createUnitResults = 516 [&](const winrt::Windows::Foundation::Collections::IVector<Configuration::ConfigurationUnit>& units) 517 { 518 for (const Configuration::ConfigurationUnit& unit : units) 519 { 520 // Add to result 521 UnitResultType applyUnitResult = make_self<wil::details::module_count_wrapper<implementation::ApplyConfigurationUnitResult>>(); 522 applyUnitResult->Unit(unit); 523 result->UnitResultsVector().Append(*applyUnitResult); 524 525 // Add to map 526 unitResultMap.emplace(unit.InstanceIdentifier(), applyUnitResult); 527 528 // Handle members if present 529 if (unit.IsGroup()) 530 { 531 createUnitResults(unit.Units()); 532 } 533 } 534 }; 535 536 createUnitResults(configurationSet.Units()); 537 538 progress.Result(*result); 539 540 try 541 { 542 ConfigurationSequencer sequencer{ m_database }; 543 auto status = ConfigurationStatus::Instance(); 544 guid setInstanceIdentifier = configurationSet.InstanceIdentifier(); 545 auto updateState = [&](ConfigurationSetState state) 546 { 547 try 548 { 549 progress.Progress(implementation::ConfigurationSetChangeData::Create(state)); 550 } 551 CATCH_LOG(); 552 553 if (recordHistoryAndStatus) 554 { 555 status->UpdateSetState(setInstanceIdentifier, state); 556 } 557 }; 558 559 if (!WI_IsFlagSet(flags, ApplyConfigurationSetFlags::PerformConsistencyCheckOnly)) 560 { 561 if (sequencer.Enqueue(configurationSet)) 562 { 563 updateState(ConfigurationSetState::Pending); 564 sequencer.Wait(progress.GetCancellation()); 565 } 566 } 567 568 progress.ThrowIfCancelled(); 569 570 updateState(ConfigurationSetState::InProgress); 571 572 // Forward unit result progress to caller 573 auto applyOperation = groupProcessor.ApplyGroupSettingsAsync([&](const auto&, const IApplyGroupMemberSettingsResult& unitResult) 574 { 575 auto itr = unitResultMap.find(unitResult.Unit().InstanceIdentifier()); 576 if (itr != unitResultMap.end()) 577 { 578 itr->second->Initialize(unitResult); 579 } 580 581 // Create progress object 582 auto applyResult = make_self<implementation::ConfigurationSetChangeData>(); 583 applyResult->Initialize(unitResult); 584 progress.Progress(*applyResult); 585 586 if (recordHistoryAndStatus) 587 { 588 status->UpdateUnitState(setInstanceIdentifier, applyResult); 589 } 590 }); 591 592 // Cancel the inner operation if we are cancelled 593 progress.Callback([applyOperation]() { applyOperation.Cancel(); }); 594 595 IApplyGroupSettingsResult applyResult = applyOperation.get(); 596 597 // Place all results from the processor into our result 598 if (applyResult.ResultInformation()) 599 { 600 result->ResultCode(applyResult.ResultInformation().ResultCode()); 601 } 602 603 for (const IApplyGroupMemberSettingsResult& unitResult : applyResult.UnitResults()) 604 { 605 // Update overall result 606 auto itr = unitResultMap.find(unitResult.Unit().InstanceIdentifier()); 607 if (itr == unitResultMap.end()) 608 { 609 continue; 610 } 611 612 itr->second->Initialize(unitResult); 613 614 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate( 615 configurationSet.InstanceIdentifier(), 616 itr->second->Unit(), 617 ConfigurationUnitIntent::Apply, 618 TelemetryTraceLogger::ApplyAction, 619 itr->second->ResultInformation()); 620 } 621 622 updateState(ConfigurationSetState::Completed); 623 624 m_threadGlobals.GetTelemetryLogger().LogConfigProcessingSummaryForApply(*winrt::get_self<implementation::ConfigurationSet>(configurationSet), *result); 625 return *result; 626 } 627 catch (...) 628 { 629 m_threadGlobals.GetTelemetryLogger().LogConfigProcessingSummaryForApplyException( 630 *winrt::get_self<implementation::ConfigurationSet>(configurationSet), 631 LOG_CAUGHT_EXCEPTION(), 632 *result); 633 throw; 634 } 635 } 636 637 Configuration::TestConfigurationSetResult ConfigurationProcessor::TestSet(const Configuration::ConfigurationSet& configurationSet) 638 { 639 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 640 return TestSetImpl(configurationSet); 641 } 642 643 Windows::Foundation::IAsyncOperationWithProgress<Configuration::TestConfigurationSetResult, Configuration::TestConfigurationUnitResult> ConfigurationProcessor::TestSetAsync(const Configuration::ConfigurationSet& configurationSet) 644 { 645 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 646 647 auto strong_this{ get_strong() }; 648 Configuration::ConfigurationSet localSet = configurationSet; 649 650 co_await winrt::resume_background(); 651 652 co_return TestSetImpl(localSet, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token() }); 653 } 654 655 Configuration::TestConfigurationSetResult ConfigurationProcessor::TestSetImpl( 656 const Configuration::ConfigurationSet& configurationSet, 657 ShutdownAwareAsyncProgress<TestConfigurationSetResult, TestConfigurationUnitResult> progress) 658 { 659 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 660 661 IConfigurationGroupProcessor groupProcessor = GetSetGroupProcessor(configurationSet); 662 auto result = make_self<wil::details::module_count_wrapper<implementation::TestConfigurationSetResult>>(); 663 result->TestResult(ConfigurationTestResult::NotRun); 664 progress.Result(*result); 665 666 try 667 { 668 // Forward unit result progress to caller 669 auto testOperation = groupProcessor.TestGroupSettingsAsync([&](const auto&, const ITestSettingsResult& unitResult) 670 { 671 auto testResult = make_self<wil::details::module_count_wrapper<implementation::TestConfigurationUnitResult>>(); 672 testResult->Initialize(unitResult); 673 674 result->AppendUnitResult(*testResult); 675 progress.Progress(*testResult); 676 }); 677 678 // Cancel the inner operation if we are cancelled 679 progress.Callback([testOperation]() { testOperation.Cancel(); }); 680 681 ITestGroupSettingsResult testResult = testOperation.get(); 682 683 // Send telemetry for all results 684 for (const ITestSettingsResult& unitResult : testResult.UnitResults()) 685 { 686 auto testUnitResult = make_self<wil::details::module_count_wrapper<implementation::TestConfigurationUnitResult>>(); 687 testUnitResult->Initialize(unitResult); 688 689 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate( 690 configurationSet.InstanceIdentifier(), 691 testUnitResult->Unit(), 692 ConfigurationUnitIntent::Assert, 693 TelemetryTraceLogger::TestAction, 694 testUnitResult->ResultInformation()); 695 } 696 697 m_threadGlobals.GetTelemetryLogger().LogConfigProcessingSummaryForTest(*winrt::get_self<implementation::ConfigurationSet>(configurationSet), *result); 698 return *result; 699 } 700 catch (...) 701 { 702 m_threadGlobals.GetTelemetryLogger().LogConfigProcessingSummaryForTestException( 703 *winrt::get_self<implementation::ConfigurationSet>(configurationSet), 704 LOG_CAUGHT_EXCEPTION(), 705 *result); 706 throw; 707 } 708 } 709 710 Configuration::GetConfigurationUnitSettingsResult ConfigurationProcessor::GetUnitSettings(const ConfigurationUnit& unit) 711 { 712 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 713 return GetUnitSettingsImpl(unit); 714 } 715 716 Windows::Foundation::IAsyncOperation<Configuration::GetConfigurationUnitSettingsResult> ConfigurationProcessor::GetUnitSettingsAsync(const ConfigurationUnit& unit) 717 { 718 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 719 720 auto strong_this{ get_strong() }; 721 ConfigurationUnit localUnit = unit; 722 723 co_await winrt::resume_background(); 724 725 co_return GetUnitSettingsImpl(localUnit, { co_await winrt::get_cancellation_token() }); 726 } 727 728 Configuration::GetConfigurationUnitSettingsResult ConfigurationProcessor::GetUnitSettingsImpl( 729 const ConfigurationUnit& unit, 730 ShutdownAwareAsyncCancellation cancellation) 731 { 732 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 733 734 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 735 auto result = make_self<wil::details::module_count_wrapper<implementation::GetConfigurationUnitSettingsResult>>(); 736 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 737 result->ResultInformation(*unitResult); 738 739 cancellation.ThrowIfCancelled(); 740 741 IConfigurationUnitProcessor unitProcessor; 742 743 try 744 { 745 unitProcessor = setProcessor.CreateUnitProcessor(unit); 746 } 747 catch (...) 748 { 749 ExtractUnitResultInformation(std::current_exception(), unitResult); 750 } 751 752 cancellation.ThrowIfCancelled(); 753 754 if (unitProcessor) 755 { 756 try 757 { 758 IGetSettingsResult settingsResult = unitProcessor.GetSettings(); 759 result->Settings(settingsResult.Settings()); 760 result->ResultInformation(settingsResult.ResultInformation()); 761 } 762 catch (...) 763 { 764 ExtractUnitResultInformation(std::current_exception(), unitResult); 765 } 766 767 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Inform, TelemetryTraceLogger::GetAction, result->ResultInformation()); 768 } 769 770 return *result; 771 } 772 773 Configuration::GetAllConfigurationUnitSettingsResult ConfigurationProcessor::GetAllUnitSettings(const ConfigurationUnit& unit) 774 { 775 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 776 return GetAllUnitSettingsImpl(unit); 777 } 778 779 Windows::Foundation::IAsyncOperation<Configuration::GetAllConfigurationUnitSettingsResult> ConfigurationProcessor::GetAllUnitSettingsAsync(const ConfigurationUnit& unit) 780 { 781 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 782 783 auto strong_this{ get_strong() }; 784 ConfigurationUnit localUnit = unit; 785 786 co_await winrt::resume_background(); 787 788 co_return GetAllUnitSettingsImpl(localUnit, { co_await winrt::get_cancellation_token() }); 789 } 790 791 Configuration::GetAllConfigurationUnitSettingsResult ConfigurationProcessor::GetAllUnitSettingsImpl( 792 const ConfigurationUnit& unit, 793 ShutdownAwareAsyncCancellation cancellation) 794 { 795 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 796 797 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 798 auto result = make_self<wil::details::module_count_wrapper<implementation::GetAllConfigurationUnitSettingsResult>>(); 799 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 800 result->ResultInformation(*unitResult); 801 802 cancellation.ThrowIfCancelled(); 803 804 IConfigurationUnitProcessor unitProcessor; 805 806 try 807 { 808 unitProcessor = setProcessor.CreateUnitProcessor(unit); 809 } 810 catch (...) 811 { 812 ExtractUnitResultInformation(std::current_exception(), unitResult); 813 } 814 815 cancellation.ThrowIfCancelled(); 816 817 IGetAllSettingsConfigurationUnitProcessor getAllSettingsUnitProcessor; 818 if (unitProcessor.try_as<IGetAllSettingsConfigurationUnitProcessor>(getAllSettingsUnitProcessor)) 819 { 820 cancellation.ThrowIfCancelled(); 821 822 try 823 { 824 IGetAllSettingsResult allSettingsResult = getAllSettingsUnitProcessor.GetAllSettings(); 825 result->Settings(allSettingsResult.Settings()); 826 result->ResultInformation(allSettingsResult.ResultInformation()); 827 } 828 catch (...) 829 { 830 ExtractUnitResultInformation(std::current_exception(), unitResult); 831 } 832 833 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Inform, TelemetryTraceLogger::ExportAction, result->ResultInformation()); 834 } 835 else 836 { 837 AICLI_LOG(Config, Error, << "Unit Processor does not support GetAllSettings operation"); 838 unitResult->Initialize(WINGET_CONFIG_ERROR_NOT_SUPPORTED_BY_PROCESSOR, hstring{}); 839 } 840 841 return *result; 842 } 843 844 Configuration::GetAllConfigurationUnitsResult ConfigurationProcessor::GetAllUnits(const ConfigurationUnit& unit) 845 { 846 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 847 return GetAllUnitsImpl(unit); 848 } 849 850 Windows::Foundation::IAsyncOperation<Configuration::GetAllConfigurationUnitsResult> ConfigurationProcessor::GetAllUnitsAsync(const ConfigurationUnit& unit) 851 { 852 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 853 854 auto strong_this{ get_strong() }; 855 ConfigurationUnit localUnit = unit; 856 857 co_await winrt::resume_background(); 858 859 co_return GetAllUnitsImpl(localUnit, { co_await winrt::get_cancellation_token() }); 860 } 861 862 Configuration::GetAllConfigurationUnitsResult ConfigurationProcessor::GetAllUnitsImpl( 863 const ConfigurationUnit& unit, 864 ShutdownAwareAsyncCancellation cancellation) 865 { 866 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 867 868 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 869 auto result = make_self<wil::details::module_count_wrapper<implementation::GetAllConfigurationUnitsResult>>(); 870 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 871 result->ResultInformation(*unitResult); 872 873 cancellation.ThrowIfCancelled(); 874 875 IConfigurationUnitProcessor unitProcessor; 876 877 try 878 { 879 unitProcessor = setProcessor.CreateUnitProcessor(unit); 880 } 881 catch (...) 882 { 883 ExtractUnitResultInformation(std::current_exception(), unitResult); 884 } 885 886 cancellation.ThrowIfCancelled(); 887 888 IGetAllUnitsConfigurationUnitProcessor getAllUnitsUnitProcessor; 889 IGetAllSettingsConfigurationUnitProcessor getAllSettingsUnitProcessor; 890 891 if (unitProcessor.try_as<IGetAllUnitsConfigurationUnitProcessor>(getAllUnitsUnitProcessor)) 892 { 893 cancellation.ThrowIfCancelled(); 894 895 try 896 { 897 IGetAllUnitsResult allUnitsResult = getAllUnitsUnitProcessor.GetAllUnits(); 898 result->Units(allUnitsResult.Units()); 899 result->ResultInformation(allUnitsResult.ResultInformation()); 900 } 901 catch (...) 902 { 903 ExtractUnitResultInformation(std::current_exception(), unitResult); 904 } 905 906 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Inform, TelemetryTraceLogger::ExportAction, result->ResultInformation()); 907 } 908 else if (unitProcessor.try_as<IGetAllSettingsConfigurationUnitProcessor>(getAllSettingsUnitProcessor)) 909 { 910 cancellation.ThrowIfCancelled(); 911 912 try 913 { 914 IGetAllSettingsResult allSettingsResult = getAllSettingsUnitProcessor.GetAllSettings(); 915 916 auto allSettings = allSettingsResult.Settings(); 917 if (allSettings) 918 { 919 std::vector<Configuration::ConfigurationUnit> units; 920 921 size_t index = 0; 922 auto currentType = unit.Type(); 923 auto currentDetails = unit.Details(); 924 925 for (const auto& settings : allSettings) 926 { 927 auto newUnit = make_self<implementation::ConfigurationUnit>(); 928 929 newUnit->Type(currentType); 930 newUnit->Settings(settings); 931 newUnit->Details(currentDetails); 932 933 std::wostringstream identifierStream; 934 identifierStream << static_cast<std::wstring_view>(currentType) << L'-' << index++; 935 newUnit->Identifier(hstring{ identifierStream.str() }); 936 937 units.push_back(*newUnit); 938 } 939 940 result->Units(single_threaded_vector(std::move(units))); 941 } 942 943 result->ResultInformation(allSettingsResult.ResultInformation()); 944 } 945 catch (...) 946 { 947 ExtractUnitResultInformation(std::current_exception(), unitResult); 948 } 949 950 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Inform, TelemetryTraceLogger::ExportAction, result->ResultInformation()); 951 } 952 else 953 { 954 AICLI_LOG(Config, Error, << "Unit Processor does not support GetAllUnits or GetAllSettings operation"); 955 unitResult->Initialize(WINGET_CONFIG_ERROR_NOT_SUPPORTED_BY_PROCESSOR, hstring{}); 956 } 957 958 return *result; 959 } 960 961 Windows::Foundation::Collections::IVector<IConfigurationUnitProcessorDetails> ConfigurationProcessor::FindUnitProcessors(const FindUnitProcessorsOptions& findOptions) 962 { 963 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 964 return FindUnitProcessorsImpl(findOptions); 965 } 966 967 Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVector<IConfigurationUnitProcessorDetails>> ConfigurationProcessor::FindUnitProcessorsAsync(const FindUnitProcessorsOptions& findOptions) 968 { 969 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 970 971 auto strong_this{ get_strong() }; 972 FindUnitProcessorsOptions localOptions = findOptions; 973 974 co_await winrt::resume_background(); 975 976 co_return FindUnitProcessorsImpl(localOptions, { co_await winrt::get_cancellation_token() }); 977 } 978 979 Windows::Foundation::Collections::IVector<IConfigurationUnitProcessorDetails> ConfigurationProcessor::FindUnitProcessorsImpl( 980 const FindUnitProcessorsOptions& findOptions, 981 ShutdownAwareAsyncCancellation cancellation) 982 { 983 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 984 985 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 986 987 cancellation.ThrowIfCancelled(); 988 989 IFindUnitProcessorsSetProcessor findUnitProcessorsSetProcessor; 990 991 if (setProcessor.try_as<IFindUnitProcessorsSetProcessor>(findUnitProcessorsSetProcessor)) 992 { 993 return findUnitProcessorsSetProcessor.FindUnitProcessors(findOptions); 994 } 995 else 996 { 997 AICLI_LOG(Config, Error, << "Set Processor does not support FindUnitProcessors operation"); 998 THROW_HR(WINGET_CONFIG_ERROR_NOT_SUPPORTED_BY_PROCESSOR); 999 } 1000 } 1001 1002 Configuration::ApplyConfigurationUnitResult ConfigurationProcessor::ApplyUnit(const ConfigurationUnit& unit) 1003 { 1004 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 1005 return ApplyUnitImpl(unit); 1006 } 1007 1008 Windows::Foundation::IAsyncOperation<Configuration::ApplyConfigurationUnitResult> ConfigurationProcessor::ApplyUnitAsync(const ConfigurationUnit& unit) 1009 { 1010 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 1011 1012 auto strong_this{ get_strong() }; 1013 ConfigurationUnit localUnit = unit; 1014 1015 co_await winrt::resume_background(); 1016 1017 co_return ApplyUnitImpl(localUnit, { co_await winrt::get_cancellation_token() }); 1018 } 1019 1020 Configuration::ApplyConfigurationUnitResult ConfigurationProcessor::ApplyUnitImpl( 1021 const ConfigurationUnit& unit, 1022 ShutdownAwareAsyncCancellation cancellation) 1023 { 1024 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 1025 1026 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 1027 auto result = make_self<wil::details::module_count_wrapper<implementation::ApplyConfigurationUnitResult>>(); 1028 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 1029 result->Unit(unit); 1030 result->ResultInformation(*unitResult); 1031 1032 cancellation.ThrowIfCancelled(); 1033 1034 IConfigurationUnitProcessor unitProcessor; 1035 1036 try 1037 { 1038 unitProcessor = setProcessor.CreateUnitProcessor(unit); 1039 } 1040 catch (...) 1041 { 1042 ExtractUnitResultInformation(std::current_exception(), unitResult); 1043 } 1044 1045 cancellation.ThrowIfCancelled(); 1046 1047 if (unitProcessor) 1048 { 1049 try 1050 { 1051 auto applyResult = unitProcessor.ApplySettings(); 1052 result->Unit(applyResult.Unit()); 1053 result->State(Configuration::ConfigurationUnitState::Completed); 1054 result->ResultInformation(applyResult.ResultInformation()); 1055 result->RebootRequired(applyResult.RebootRequired()); 1056 } 1057 catch (...) 1058 { 1059 ExtractUnitResultInformation(std::current_exception(), unitResult); 1060 } 1061 1062 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Apply, TelemetryTraceLogger::ApplyAction, result->ResultInformation()); 1063 } 1064 1065 return *result; 1066 } 1067 1068 Configuration::TestConfigurationUnitResult ConfigurationProcessor::TestUnit(const ConfigurationUnit& unit) 1069 { 1070 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 1071 return TestUnitImpl(unit); 1072 } 1073 1074 Windows::Foundation::IAsyncOperation<Configuration::TestConfigurationUnitResult> ConfigurationProcessor::TestUnitAsync(const ConfigurationUnit& unit) 1075 { 1076 THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); 1077 1078 auto strong_this{ get_strong() }; 1079 ConfigurationUnit localUnit = unit; 1080 1081 co_await winrt::resume_background(); 1082 1083 co_return TestUnitImpl(localUnit, { co_await winrt::get_cancellation_token() }); 1084 } 1085 1086 Configuration::TestConfigurationUnitResult ConfigurationProcessor::TestUnitImpl( 1087 const ConfigurationUnit& unit, 1088 ShutdownAwareAsyncCancellation cancellation) 1089 { 1090 auto threadGlobals = m_threadGlobals.SetForCurrentThread(); 1091 1092 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(nullptr); 1093 auto result = make_self<wil::details::module_count_wrapper<implementation::TestConfigurationUnitResult>>(); 1094 auto unitResult = make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>(); 1095 result->Unit(unit); 1096 result->ResultInformation(*unitResult); 1097 1098 cancellation.ThrowIfCancelled(); 1099 1100 IConfigurationUnitProcessor unitProcessor; 1101 1102 try 1103 { 1104 unitProcessor = setProcessor.CreateUnitProcessor(unit); 1105 } 1106 catch (...) 1107 { 1108 ExtractUnitResultInformation(std::current_exception(), unitResult); 1109 } 1110 1111 cancellation.ThrowIfCancelled(); 1112 1113 if (unitProcessor) 1114 { 1115 try 1116 { 1117 auto testResult = unitProcessor.TestSettings(); 1118 result->Unit(testResult.Unit()); 1119 result->TestResult(testResult.TestResult()); 1120 result->ResultInformation(testResult.ResultInformation()); 1121 } 1122 catch (...) 1123 { 1124 ExtractUnitResultInformation(std::current_exception(), unitResult); 1125 } 1126 1127 m_threadGlobals.GetTelemetryLogger().LogConfigUnitRunIfAppropriate(GUID_NULL, unit, ConfigurationUnitIntent::Assert, TelemetryTraceLogger::TestAction, result->ResultInformation()); 1128 } 1129 1130 return *result; 1131 } 1132 1133 IConfigurationGroupProcessor ConfigurationProcessor::GetSetGroupProcessor(const Configuration::ConfigurationSet& configurationSet) 1134 { 1135 IConfigurationSetProcessor setProcessor = m_factory.CreateSetProcessor(configurationSet); 1136 1137 IConfigurationGroupProcessor result = setProcessor.try_as<IConfigurationGroupProcessor>(); 1138 if (!result) 1139 { 1140 auto groupProcessor = make_self<wil::details::module_count_wrapper<implementation::DefaultSetGroupProcessor>>(); 1141 groupProcessor->Initialize(configurationSet, setProcessor, m_threadGlobals); 1142 result = *groupProcessor; 1143 } 1144 1145 return result; 1146 } 1147 1148 HRESULT STDMETHODCALLTYPE ConfigurationProcessor::SetLifetimeWatcher(IUnknown* watcher) 1149 { 1150 return AppInstaller::WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher); 1151 } 1152 1153 void ConfigurationProcessor::ConfigurationSetProcessorFactory(const IConfigurationSetProcessorFactory& value) 1154 { 1155 m_factory = value; 1156 1157 if (m_factory) 1158 { 1159 m_factoryDiagnosticsEventRevoker = m_factory.Diagnostics(winrt::auto_revoke, 1160 [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information) 1161 { 1162 if (auto strong_this{ weak_this.get() }) 1163 { 1164 strong_this->SendDiagnostics(information); 1165 } 1166 }); 1167 } 1168 } 1169 1170 void ConfigurationProcessor::SendDiagnostics(DiagnosticLevel level, std::string_view message) try 1171 { 1172 if (level >= m_minimumLevel) 1173 { 1174 auto diagnostics = make_self<wil::details::module_count_wrapper<implementation::DiagnosticInformationInstance>>(); 1175 diagnostics->Initialize(level, AppInstaller::Utility::ConvertToUTF16(message)); 1176 SendDiagnosticsImpl(*diagnostics); 1177 } 1178 } 1179 // While diagnostics can be important, a failure to send them should not cause additional issues. 1180 catch (...) {} 1181 1182 void ConfigurationProcessor::SendDiagnostics(const IDiagnosticInformation& information) try 1183 { 1184 if (information.Level() >= m_minimumLevel) 1185 { 1186 SendDiagnosticsImpl(information); 1187 } 1188 } 1189 // While diagnostics can be important, a failure to send them should not cause additional issues. 1190 catch (...) {} 1191 1192 void ConfigurationProcessor::SendDiagnosticsImpl(const IDiagnosticInformation& information) 1193 { 1194 std::lock_guard<std::recursive_mutex> lock{ m_diagnosticsMutex }; 1195 1196 // Prevent a winrt/wil error recursion here by detecting that this thread failed to send a previous message. 1197 if (m_isHandlingDiagnostics) 1198 { 1199 std::wstring debugMessage = L"An error occurred while trying to send a previous diagnostics message:\n"; 1200 debugMessage.append(information.Message()); 1201 OutputDebugStringW(debugMessage.c_str()); 1202 return; 1203 } 1204 1205 m_isHandlingDiagnostics = true; 1206 auto notHandling = wil::scope_exit([&] { m_isHandlingDiagnostics = false; }); 1207 1208 m_diagnostics(*this, information); 1209 } 1210 }