commit 3cea563a94951955b99fea0a72558c84a91e5900 parent f8aec5e67a10fe133c58781139e886e2fe345123 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Mon, 3 Jul 2023 22:12:26 -0700 Improve packaged test log collection and fix crash (#3395) Diffstat:
21 files changed, 204 insertions(+), 53 deletions(-)
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt @@ -92,6 +92,7 @@ Dbg debian deigh deleteifnotneeded +DENYWR desktopappinstaller devhome dic @@ -465,6 +466,7 @@ websites WERSJA wesome wfopen +wfsopen wgetenv Whatif winapifamily diff --git a/azure-pipelines.yml b/azure-pipelines.yml @@ -304,28 +304,13 @@ jobs: configuration: '$(BuildConfiguration)' condition: succeededOrFailed() - - task: CopyFiles@2 - displayName: 'Copy Microsoft.Management.Configuration.winmd' - inputs: - Contents: | - $(buildOutDir)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd - TargetFolder: '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0' - condition: succeededOrFailed() - - task: PowerShell@2 - displayName: 'Copy Microsoft.Management.Configuration.OutOfProc.dll as Microsoft.Management.Configuration.dll' + displayName: Prepare for Microsoft.Management.Configuration.UnitTests (OutOfProc) inputs: - targetType: 'inline' - script: Copy-Item '$(buildOutDir)\Microsoft.Management.Configuration.OutOfProc\Microsoft.Management.Configuration.OutOfProc.dll' '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0\Microsoft.Management.Configuration.dll' -Force + filePath: 'src\Microsoft.Management.Configuration.OutOfProc\Prepare-ConfigurationOOPTests.ps1' + arguments: '-BuildOutputPath $(buildOutDir) -PackageLayoutPath $(packageLayoutDir)' condition: succeededOrFailed() - - - task: PowerShell@2 - displayName: 'Register the Dev package for OOP configuration tests' - inputs: - targetType: 'inline' - script: Add-AppxPackage -Register $(packageLayoutDir)\AppxManifest.xml - condition: succeededOrFailed() - + - task: VSTest@2 displayName: 'Run tests: Microsoft.Management.Configuration.UnitTests (OutOfProc)' inputs: @@ -339,6 +324,13 @@ jobs: configuration: '$(BuildConfiguration)' condition: succeededOrFailed() + - task: PowerShell@2 + displayName: Collect logs for Microsoft.Management.Configuration.UnitTests (OutOfProc) + inputs: + filePath: 'src\Microsoft.Management.Configuration.OutOfProc\Collect-ConfigurationOOPTests.ps1' + arguments: '-TargetLocation $(artifactsDir)\ConfigOOPTestsLog' + condition: succeededOrFailed() + - task: CopyFiles@2 displayName: 'Copy Util to artifacts folder' inputs: diff --git a/src/AppInstallerCLICore/COMContext.cpp b/src/AppInstallerCLICore/COMContext.cpp @@ -82,7 +82,14 @@ namespace AppInstaller::CLI::Execution // TODO: Log to file for COM API calls only when debugging in visual studio Logging::FileLogger::Add(s_comLogFileNamePrefix); - Logging::FileLogger::BeginCleanup(); + +#ifndef AICLI_DISABLE_TEST_HOOKS + if (!Settings::User().Get<Settings::Setting::KeepAllLogFiles>()) +#endif + { + // Initiate the background cleanup of the log file location. + Logging::FileLogger::BeginCleanup(); + } Logging::TraceLogger::Add(); diff --git a/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.cpp b/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.cpp @@ -44,7 +44,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting constexpr std::wstring_view s_RemoteServerFileName = L"ConfigurationRemotingServer\\ConfigurationRemotingServer.exe"; // Represents a remote factory object that was created from a specific process. - struct RemoteFactory : winrt::implements<RemoteFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, WinRT::ILifetimeWatcher>, WinRT::LifetimeWatcherBase + struct RemoteFactory : winrt::implements<RemoteFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase { RemoteFactory() { diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp @@ -77,8 +77,13 @@ namespace AppInstaller::CLI Logging::Telemetry().SetCaller("winget-cli"); Logging::Telemetry().LogStartup(); - // Initiate the background cleanup of the log file location. - Logging::FileLogger::BeginCleanup(); +#ifndef AICLI_DISABLE_TEST_HOOKS + if (!Settings::User().Get<Settings::Setting::KeepAllLogFiles>()) +#endif + { + // Initiate the background cleanup of the log file location. + Logging::FileLogger::BeginCleanup(); + } context << Workflow::ReportExecutionStage(Workflow::ExecutionStage::ParseArgs); @@ -152,6 +157,13 @@ namespace AppInstaller::CLI void ServerInitialize() { +#ifndef AICLI_DISABLE_TEST_HOOKS + if (Settings::User().Get<Settings::Setting::EnableSelfInitiatedMinidump>()) + { + Debugging::EnableSelfInitiatedMinidump(); + } +#endif + AppInstaller::CLI::Execution::COMContext::SetLoggers(); } } diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs @@ -538,12 +538,6 @@ namespace AppInstallerCLIE2ETests string testLogsPackagedDestPath = Path.Combine(testLogsDestPath, "Packaged"); string testLogsUnpackagedDestPath = Path.Combine(testLogsDestPath, "Unpackaged"); - if (Directory.Exists(testLogsDestPath)) - { - TestIndexSetup.DeleteDirectoryContents(new DirectoryInfo(testLogsDestPath)); - Directory.Delete(testLogsDestPath); - } - if (Directory.Exists(testLogsPackagedSourcePath)) { TestIndexSetup.CopyDirectory(testLogsPackagedSourcePath, testLogsPackagedDestPath); diff --git a/src/AppInstallerCLIE2ETests/WinGetSettingsHelper.cs b/src/AppInstallerCLIE2ETests/WinGetSettingsHelper.cs @@ -49,7 +49,8 @@ namespace AppInstallerCLIE2ETests "debugging", new Hashtable() { - { "enableSelfInitiatedMinidump", false }, + { "enableSelfInitiatedMinidump", true }, + { "keepAllLogFiles", true }, } }, { diff --git a/src/AppInstallerCommonCore/FileLogger.cpp b/src/AppInstallerCommonCore/FileLogger.cpp @@ -126,19 +126,23 @@ namespace AppInstaller::Logging void FileLogger::OpenFileLoggerStream() { - // Prevent inheritance to ensure log file handle is not opened by other processes. - FILE* filePtr; - errno_t fopenError = _wfopen_s(&filePtr, m_filePath.wstring().c_str(), L"w"); - if (!fopenError) + // Prevent other writers to our log file, but allow readers + FILE* filePtr = _wfsopen(m_filePath.wstring().c_str(), L"w", _SH_DENYWR); + + if (filePtr) { - THROW_HR_IF(E_UNEXPECTED, filePtr == nullptr); + auto closeFile = wil::scope_exit([&]() { fclose(filePtr); }); + + // Prevent inheritance to ensure log file handle is not opened by other processes THROW_IF_WIN32_BOOL_FALSE(SetHandleInformation(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(filePtr))), HANDLE_FLAG_INHERIT, 0)); + m_stream = std::ofstream{ filePtr }; + closeFile.release(); } else { AICLI_LOG(Core, Error, << "Failed to open log file " << m_filePath.u8string()); - throw std::system_error(fopenError, std::generic_category()); + throw std::system_error(errno, std::generic_category()); } } } diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -99,6 +99,7 @@ namespace AppInstaller::Settings InteractivityDisable, // Debug EnableSelfInitiatedMinidump, + KeepAllLogFiles, Max }; @@ -164,8 +165,11 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDownloader, std::string, InstallerDownloader, InstallerDownloader::Default, ".network.downloader"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDOProgressTimeoutInSeconds, uint32_t, std::chrono::seconds, 60s, ".network.doProgressTimeoutInSeconds"sv); SETTINGMAPPING_SPECIALIZATION(Setting::NetworkWingetAlternateSourceURL, bool, bool, true, ".network.enableWingetAlternateSourceURL"sv); +#ifndef AICLI_DISABLE_TEST_HOOKS // Debug SETTINGMAPPING_SPECIALIZATION(Setting::EnableSelfInitiatedMinidump, bool, bool, false, ".debugging.enableSelfInitiatedMinidump"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::KeepAllLogFiles, bool, bool, false, ".debugging.keepAllLogFiles"sv); +#endif // Logging SETTINGMAPPING_SPECIALIZATION(Setting::LoggingLevelPreference, std::string, Logging::Level, Logging::Level::Info, ".logging.level"sv); // Interactivity diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp @@ -265,12 +265,16 @@ namespace AppInstaller::Settings WINGET_VALIDATE_PASS_THROUGH(AnonymizePathForDisplay) WINGET_VALIDATE_PASS_THROUGH(TelemetryDisable) WINGET_VALIDATE_PASS_THROUGH(InteractivityDisable) - WINGET_VALIDATE_PASS_THROUGH(EnableSelfInitiatedMinidump) WINGET_VALIDATE_PASS_THROUGH(InstallSkipDependencies) WINGET_VALIDATE_PASS_THROUGH(DisableInstallNotes) WINGET_VALIDATE_PASS_THROUGH(UninstallPurgePortablePackage) WINGET_VALIDATE_PASS_THROUGH(NetworkWingetAlternateSourceURL) +#ifndef AICLI_DISABLE_TEST_HOOKS + WINGET_VALIDATE_PASS_THROUGH(EnableSelfInitiatedMinidump) + WINGET_VALIDATE_PASS_THROUGH(KeepAllLogFiles) +#endif + WINGET_VALIDATE_SIGNATURE(PortablePackageUserRoot) { return ValidatePathValue(value); diff --git a/src/AppInstallerSharedLib/Public/winget/SharedThreadGlobals.h b/src/AppInstallerSharedLib/Public/winget/SharedThreadGlobals.h @@ -30,9 +30,10 @@ namespace AppInstaller::ThreadLocalStorage { ~PreviousThreadGlobals(); - PreviousThreadGlobals(ThreadGlobals* previous) : m_previous(previous) {}; + PreviousThreadGlobals(ThreadGlobals* previous); private: ThreadGlobals* m_previous; + DWORD m_threadId; }; } diff --git a/src/AppInstallerSharedLib/SharedThreadGlobals.cpp b/src/AppInstallerSharedLib/SharedThreadGlobals.cpp @@ -31,8 +31,15 @@ namespace AppInstaller::ThreadLocalStorage return SetOrGetThreadGlobals(false); } + PreviousThreadGlobals::PreviousThreadGlobals(ThreadGlobals* previous) : m_previous(previous) + { + m_threadId = GetCurrentThreadId(); + } + PreviousThreadGlobals::~PreviousThreadGlobals() { + // Not remaining on the same thread is a serious issue that must be resolved + FAIL_FAST_IF(GetCurrentThreadId() != m_threadId); std::ignore = SetOrGetThreadGlobals(true, m_previous); } } diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Collect-ConfigurationOOPTests.ps1 b/src/Microsoft.Management.Configuration.OutOfProc/Collect-ConfigurationOOPTests.ps1 @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +[CmdletBinding()] +param( + [string]$TargetLocation +) + +$Local:settingsExport = ConvertFrom-Json (wingetdev.exe settings export) +$Local:logsFilePath = Join-Path (Split-Path $Local:settingsExport.userSettingsFile -Parent) "DiagOutputDir" + +Get-AppxPackage WinGetDevCLI | Remove-AppxPackage + +Copy-Item $Local:logsFilePath $TargetLocation -Recurse -Force -ErrorAction Ignore diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj b/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj @@ -471,7 +471,9 @@ </ClCompile> </ItemGroup> <ItemGroup> + <None Include="Collect-ConfigurationOOPTests.ps1" /> <None Include="packages.config" /> + <None Include="Prepare-ConfigurationOOPTests.ps1" /> <None Include="PropertySheet.props" /> <None Include="Source.def" /> </ItemGroup> diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj.filters b/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj.filters @@ -51,5 +51,7 @@ <None Include="Source.def"> <Filter>Source Files</Filter> </None> + <None Include="Collect-ConfigurationOOPTests.ps1" /> + <None Include="Prepare-ConfigurationOOPTests.ps1" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Prepare-ConfigurationOOPTests.ps1 b/src/Microsoft.Management.Configuration.OutOfProc/Prepare-ConfigurationOOPTests.ps1 @@ -0,0 +1,32 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +[CmdletBinding()] +param( + [string]$BuildOutputPath, + + [string]$PackageLayoutPath +) + +# Copy the winmd into the unit test directory since it will be needed for marshalling +$Local:winmdSourcePath = Join-Path $BuildOutputPath "Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd" +$Local:winmdTargetPath = Join-Path $BuildOutputPath "Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0\Microsoft.Management.Configuration.winmd" + +Copy-Item $Local:winmdSourcePath $Local:winmdTargetPath -Force + +# Copy the OOP helper dll into the unit test directory to make activation look the same as in-proc +$Local:dllSourcePath = Join-Path $BuildOutputPath "Microsoft.Management.Configuration.OutOfProc\Microsoft.Management.Configuration.OutOfProc.dll" +$Local:dllTargetPath = Join-Path $BuildOutputPath "Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0\Microsoft.Management.Configuration.dll" + +Copy-Item $Local:dllSourcePath $Local:dllTargetPath -Force + +# Register the package +$Local:packageManifestPath = Join-Path $PackageLayoutPath "AppxManifest.xml" + +Add-AppxPackage -Register $Local:packageManifestPath + +# Configure crash dump and log file settings +$Local:settingsExport = ConvertFrom-Json (wingetdev.exe settings export) +$Local:settingsFilePath = $Local:settingsExport.userSettingsFile +$Local:settingsFileContent = ConvertTo-Json @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + +Set-Content -Path $Local:settingsFilePath -Value $Local:settingsFileContent diff --git a/src/Microsoft.Management.Configuration/ConfigurationProcessor.cpp b/src/Microsoft.Management.Configuration/ConfigurationProcessor.cpp @@ -21,6 +21,8 @@ #include <AppInstallerErrors.h> #include <AppInstallerStrings.h> +using namespace std::chrono_literals; + namespace winrt::Microsoft::Management::Configuration::implementation { namespace @@ -65,13 +67,13 @@ namespace winrt::Microsoft::Management::Configuration::implementation { std::ostringstream strstr; strstr << '[' << AppInstaller::Logging::GetChannelName(channel) << "] " << message; - m_processor.Diagnostics(ConvertLevel(level), strstr.str()); + m_processor.SendDiagnostics(ConvertLevel(level), strstr.str()); } catch (...) {} void WriteDirect(AppInstaller::Logging::Channel, AppInstaller::Logging::Level level, std::string_view message) noexcept override try { - m_processor.Diagnostics(ConvertLevel(level), message); + m_processor.SendDiagnostics(ConvertLevel(level), message); } catch (...) {} @@ -97,6 +99,11 @@ namespace winrt::Microsoft::Management::Configuration::implementation return AppInstaller::Utility::ConvertToUTF8(message); }()); } + + static void Ensure() + { + static AttachWilFailureCallback s_callbackAttach; + } }; // Specifies the set of intents that should execute during a Test request @@ -121,7 +128,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation event_token ConfigurationProcessor::Diagnostics(const Windows::Foundation::EventHandler<IDiagnosticInformation>& handler) { - static AttachWilFailureCallback s_callbackAttach; + AttachWilFailureCallback::Ensure(); return m_diagnostics.add(handler); } @@ -202,10 +209,11 @@ namespace winrt::Microsoft::Management::Configuration::implementation Windows::Foundation::IAsyncOperation<Configuration::OpenConfigurationSetResult> ConfigurationProcessor::OpenConfigurationSetAsync(const Windows::Storage::Streams::IInputStream& stream) { + auto strong_this{ get_strong() }; Windows::Storage::Streams::IInputStream localStream = stream; + co_await winrt::resume_background(); - auto cancellation = co_await get_cancellation_token(); - cancellation.enable_propagation(); + auto cancellation = co_await winrt::get_cancellation_token(); auto threadGlobals = m_threadGlobals.SetForCurrentThread(); auto result = make_self<wil::details::module_count_wrapper<OpenConfigurationSetResult>>(); @@ -229,7 +237,20 @@ namespace winrt::Microsoft::Management::Configuration::implementation for (;;) { - Windows::Storage::Streams::IBuffer readBuffer = co_await localStream.ReadAsync(buffer, bufferSize, readOptions); + auto asyncOperation = localStream.ReadAsync(buffer, bufferSize, readOptions); + + // Manually poll status and propagate cancellation to stay on this thread for thread globals + while (asyncOperation.Status() == Windows::Foundation::AsyncStatus::Started) + { + if (cancellation()) + { + asyncOperation.Cancel(); + } + + std::this_thread::sleep_for(100ms); + } + + Windows::Storage::Streams::IBuffer readBuffer = asyncOperation.GetResults(); size_t readSize = static_cast<size_t>(readBuffer.Length()); if (readSize) @@ -302,7 +323,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); + auto strong_this{ get_strong() }; ConfigurationSet localSet = configurationSet; + co_await winrt::resume_background(); co_return GetSetDetailsImpl(localSet, detailLevel, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token()}); @@ -356,7 +379,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); + auto strong_this{ get_strong() }; ConfigurationUnit localUnit = unit; + co_await winrt::resume_background(); co_return GetUnitDetailsImpl(localUnit, detailLevel); @@ -381,7 +406,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); + auto strong_this{ get_strong() }; ConfigurationSet localSet = configurationSet; + co_await winrt::resume_background(); co_return ApplySetImpl(localSet, flags, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token() }); @@ -413,7 +440,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); + auto strong_this{ get_strong() }; ConfigurationSet localSet = configurationSet; + co_await winrt::resume_background(); co_return TestSetImpl(localSet, { co_await winrt::get_progress_token(), co_await winrt::get_cancellation_token() }); @@ -517,7 +546,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR_IF(E_NOT_VALID_STATE, !m_factory); + auto strong_this{ get_strong() }; ConfigurationUnit localUnit = unit; + co_await winrt::resume_background(); co_return GetUnitSettingsImpl(localUnit, { co_await winrt::get_cancellation_token() }); @@ -581,20 +612,54 @@ namespace winrt::Microsoft::Management::Configuration::implementation if (m_factory) { m_factoryDiagnosticsEventRevoker = m_factory.Diagnostics(winrt::auto_revoke, - [this](const IInspectable&, const IDiagnosticInformation& information) + [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information) { - m_diagnostics(*this, information); + if (auto strong_this{ weak_this.get() }) + { + strong_this->SendDiagnostics(information); + } }); } } - void ConfigurationProcessor::Diagnostics(DiagnosticLevel level, std::string_view message) + void ConfigurationProcessor::SendDiagnostics(DiagnosticLevel level, std::string_view message) try { if (level >= m_minimumLevel) { auto diagnostics = make_self<wil::details::module_count_wrapper<implementation::DiagnosticInformationInstance>>(); diagnostics->Initialize(level, AppInstaller::Utility::ConvertToUTF16(message)); - m_diagnostics(*this, *diagnostics); + SendDiagnosticsImpl(*diagnostics); + } + } + // While diagnostics can be important, a failure to send them should not cause additional issues. + catch (...) {} + + void ConfigurationProcessor::SendDiagnostics(const IDiagnosticInformation& information) try + { + if (information.Level() >= m_minimumLevel) + { + SendDiagnosticsImpl(information); } } + // While diagnostics can be important, a failure to send them should not cause additional issues. + catch (...) {} + + void ConfigurationProcessor::SendDiagnosticsImpl(const IDiagnosticInformation& information) + { + std::lock_guard<std::recursive_mutex> lock{ m_diagnosticsMutex }; + + // Prevent a winrt/wil error recursion here by detecting that this thread failed to send a previous message. + if (m_isHandlingDiagnostics) + { + std::wstring debugMessage = L"An error occurred while trying to send a previous diagnostics message:\n"; + debugMessage.append(information.Message()); + OutputDebugStringW(debugMessage.c_str()); + return; + } + + m_isHandlingDiagnostics = true; + auto notHandling = wil::scope_exit([&] { m_isHandlingDiagnostics = false; }); + + m_diagnostics(*this, information); + } } diff --git a/src/Microsoft.Management.Configuration/ConfigurationProcessor.h b/src/Microsoft.Management.Configuration/ConfigurationProcessor.h @@ -9,12 +9,13 @@ #include <winget/AsyncTokens.h> #include <winget/ILifetimeWatcher.h> -#include <string_view> #include <functional> +#include <mutex> +#include <string_view> namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationProcessor : ConfigurationProcessorT<ConfigurationProcessor, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase + struct ConfigurationProcessor : ConfigurationProcessorT<ConfigurationProcessor, winrt::cloaked<AppInstaller::WinRT::ILifetimeWatcher>>, AppInstaller::WinRT::LifetimeWatcherBase { using ConfigurationSet = Configuration::ConfigurationSet; using ConfigurationSetChangeData = Configuration::ConfigurationSetChangeData; @@ -84,7 +85,10 @@ namespace winrt::Microsoft::Management::Configuration::implementation void ConfigurationSetProcessorFactory(const IConfigurationSetProcessorFactory& value); // Sends diagnostics objects to the event. - void Diagnostics(DiagnosticLevel level, std::string_view message); + void SendDiagnostics(DiagnosticLevel level, std::string_view message); + + // Sends diagnostics objects to the event. + void SendDiagnostics(const IDiagnosticInformation& information); private: GetConfigurationSetDetailsResult GetSetDetailsImpl( @@ -105,12 +109,16 @@ namespace winrt::Microsoft::Management::Configuration::implementation GetConfigurationUnitSettingsResult GetUnitSettingsImpl(const ConfigurationUnit& unit, AppInstaller::WinRT::AsyncCancellation cancellation = {}); + void SendDiagnosticsImpl(const IDiagnosticInformation& information); + IConfigurationSetProcessorFactory m_factory = nullptr; event<Windows::Foundation::EventHandler<IDiagnosticInformation>> m_diagnostics; event<Windows::Foundation::TypedEventHandler<ConfigurationSet, ConfigurationChangeData>> m_configurationChange; ConfigThreadGlobals m_threadGlobals; IConfigurationSetProcessorFactory::Diagnostics_revoker m_factoryDiagnosticsEventRevoker; DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational; + std::recursive_mutex m_diagnosticsMutex; + bool m_isHandlingDiagnostics = false; #endif }; } diff --git a/src/Microsoft.Management.Configuration/ConfigurationSet.h b/src/Microsoft.Management.Configuration/ConfigurationSet.h @@ -10,7 +10,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationSet : ConfigurationSetT<ConfigurationSet, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase + struct ConfigurationSet : ConfigurationSetT<ConfigurationSet, winrt::cloaked<AppInstaller::WinRT::ILifetimeWatcher>>, AppInstaller::WinRT::LifetimeWatcherBase { using WinRT_Self = ::winrt::Microsoft::Management::Configuration::ConfigurationSet; using ConfigurationUnit = ::winrt::Microsoft::Management::Configuration::ConfigurationUnit; diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnit.h b/src/Microsoft.Management.Configuration/ConfigurationUnit.h @@ -9,7 +9,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationUnit : ConfigurationUnitT<ConfigurationUnit, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase + struct ConfigurationUnit : ConfigurationUnitT<ConfigurationUnit, winrt::cloaked<AppInstaller::WinRT::ILifetimeWatcher>>, AppInstaller::WinRT::LifetimeWatcherBase { ConfigurationUnit(); diff --git a/src/WindowsPackageManager/ConfigurationStaticFunctions.cpp b/src/WindowsPackageManager/ConfigurationStaticFunctions.cpp @@ -44,6 +44,7 @@ namespace ConfigurationShim winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory> CreateConfigurationSetProcessorFactoryAsync(winrt::hstring const& handler) { + auto strong_this{ get_strong() }; std::wstring lowerHandler = AppInstaller::Utility::ToLower(handler); co_await winrt::resume_background();