From 88f6265a355676961e5f6ce936c4d26af61c3829 Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Mon, 15 Nov 2021 13:09:45 -0800 Subject: [PATCH 1/3] Make VT enablement/disablement work properly (#1699) --- src/AppInstallerCLICore/ChannelStreams.cpp | 5 +++++ src/AppInstallerCLICore/ChannelStreams.h | 4 +++- src/AppInstallerCLICore/ExecutionReporter.cpp | 15 +++++---------- src/AppInstallerCLICore/ExecutionReporter.h | 3 --- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/AppInstallerCLICore/ChannelStreams.cpp b/src/AppInstallerCLICore/ChannelStreams.cpp index 79a2ebed832..1fa1ec7d289 100644 --- a/src/AppInstallerCLICore/ChannelStreams.cpp +++ b/src/AppInstallerCLICore/ChannelStreams.cpp @@ -41,6 +41,11 @@ namespace AppInstaller::CLI::Execution return *this; } + void BaseStream::SetVTEnabled(bool enabled) + { + m_VTEnabled = enabled; + } + void BaseStream::RestoreDefault() { if (m_VTUpdated) diff --git a/src/AppInstallerCLICore/ChannelStreams.h b/src/AppInstallerCLICore/ChannelStreams.h index 2a0f323cc6b..0a2cbe8d1c6 100644 --- a/src/AppInstallerCLICore/ChannelStreams.h +++ b/src/AppInstallerCLICore/ChannelStreams.h @@ -57,6 +57,8 @@ namespace AppInstaller::CLI::Execution BaseStream& operator<<(const VirtualTerminal::Sequence& sequence); BaseStream& operator<<(const VirtualTerminal::ConstructedSequence& sequence); + void SetVTEnabled(bool enabled); + void RestoreDefault(); void Disable(); @@ -80,7 +82,7 @@ namespace AppInstaller::CLI::Execution // Holds output formatting information. struct OutputStream { - OutputStream(BaseStream& out, bool enabled, bool VTEnabled); + OutputStream(BaseStream& out, bool enabled, bool VTEnabled = true); // Adds a format to the current value. void AddFormat(const VirtualTerminal::Sequence& sequence); diff --git a/src/AppInstallerCLICore/ExecutionReporter.cpp b/src/AppInstallerCLICore/ExecutionReporter.cpp index 411323ca881..66adad14ad1 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.cpp +++ b/src/AppInstallerCLICore/ExecutionReporter.cpp @@ -19,7 +19,7 @@ namespace AppInstaller::CLI::Execution const Sequence& PromptEmphasis = TextFormat::Foreground::Bright; Reporter::Reporter(std::ostream& outStream, std::istream& inStream) : - Reporter(std::make_shared(outStream, true, IsVTEnabled()), inStream) + Reporter(std::make_shared(outStream, true, ConsoleModeRestore::Instance().IsVTEnabled()), inStream) { SetProgressSink(this); } @@ -27,8 +27,8 @@ namespace AppInstaller::CLI::Execution Reporter::Reporter(std::shared_ptr outStream, std::istream& inStream) : m_out(outStream), m_in(inStream), - m_progressBar(std::in_place, *m_out, IsVTEnabled()), - m_spinner(std::in_place, *m_out, IsVTEnabled()) + m_progressBar(std::in_place, *m_out, ConsoleModeRestore::Instance().IsVTEnabled()), + m_spinner(std::in_place, *m_out, ConsoleModeRestore::Instance().IsVTEnabled()) { SetProgressSink(this); } @@ -74,7 +74,7 @@ namespace AppInstaller::CLI::Execution OutputStream Reporter::GetBasicOutputStream() { - return {*m_out, m_channel == Channel::Output, IsVTEnabled() }; + return {*m_out, m_channel == Channel::Output }; } void Reporter::SetChannel(Channel channel) @@ -102,7 +102,7 @@ namespace AppInstaller::CLI::Execution } if (style == VisualStyle::NoVT) { - m_isVTEnabled = false; + m_out->SetVTEnabled(false); } } @@ -213,11 +213,6 @@ namespace AppInstaller::CLI::Execution } } - bool Reporter::IsVTEnabled() const - { - return m_isVTEnabled && ConsoleModeRestore::Instance().IsVTEnabled(); - } - void Reporter::CloseOutputStream(bool forceDisable) { if (forceDisable) diff --git a/src/AppInstallerCLICore/ExecutionReporter.h b/src/AppInstallerCLICore/ExecutionReporter.h index 812ba1a8766..258d4962083 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.h +++ b/src/AppInstallerCLICore/ExecutionReporter.h @@ -140,8 +140,6 @@ namespace AppInstaller::CLI::Execution private: Reporter(std::shared_ptr outStream, std::istream& inStream); - // Gets whether VT is enabled for this reporter. - bool IsVTEnabled() const; // Gets a stream for output for internal use. OutputStream GetBasicOutputStream(); @@ -149,7 +147,6 @@ namespace AppInstaller::CLI::Execution Channel m_channel = Channel::Output; std::shared_ptr m_out; std::istream& m_in; - bool m_isVTEnabled = true; std::optional m_style; std::optional m_spinner; std::optional m_progressBar; From 7d178a61e732e820bb562269ce0b59c982dcf905 Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Tue, 16 Nov 2021 18:42:10 -0800 Subject: [PATCH 2/3] Create shared DLL for winget.exe and COM server (#1687) --- .github/actions/spelling/allow.txt | 1 + .github/actions/spelling/expect.txt | 9 + azure-pipelines.yml | 40 ++- src/AppInstallerCLI.sln | 53 ++- src/AppInstallerCLI/AppInstallerCLI.vcxproj | 46 +-- src/AppInstallerCLI/main.cpp | 6 +- .../AppInstallerCLICore.vcxproj | 2 +- .../AppInstallerCLICore.vcxproj.filters | 6 +- src/AppInstallerCLICore/Core.cpp | 17 + .../Public/AppInstallerCLICore.h | 4 + src/AppInstallerCLIE2ETests/BaseCommand.cs | 30 +- src/AppInstallerCLIE2ETests/Constants.cs | 3 + src/AppInstallerCLIE2ETests/ListCommand.cs | 2 +- src/AppInstallerCLIE2ETests/SetUpFixture.cs | 29 +- src/AppInstallerCLIE2ETests/TestCommon.cs | 13 +- .../AppInstallerCLIPackage.wapproj | 9 + .../Package.appxmanifest | 2 +- .../AppInstallerCommonCore.vcxproj | 3 + .../AppInstallerCommonCore.vcxproj.filters | 6 + src/AppInstallerCommonCore/Debugging.cpp | 72 ++++ .../Public/winget/Debugging.h | 9 + .../Public/winget/UserSettings.h | 2 + src/AppInstallerCommonCore/UserSettings.cpp | 1 + src/AppInstallerCommonCore/pch.h | 1 + src/COMServer/COMServer.vcxitems | 13 + .../CreateCompositePackageCatalogOptions.cpp | 4 +- .../FindPackagesOptions.cpp | 4 +- src/Microsoft.Management.Deployment/Helpers.h | 26 +- .../InstallOptions.cpp | 4 +- .../Microsoft.Management.Deployment.vcxproj | 1 + .../PackageManager.cpp | 2 +- .../PackageMatchFilter.cpp | 4 +- src/WinGetServer/WinGetServer.vcxproj | 335 +++++++++--------- src/WinGetServer/WinMain.cpp | 45 +-- src/WindowsPackageManager/PropertySheet.props | 16 + src/WindowsPackageManager/Source.def | 7 + .../WindowsPackageManager.h | 26 ++ .../WindowsPackageManager.vcxproj | 325 +++++++++++++++++ .../WindowsPackageManager.vcxproj.filters | 34 ++ src/WindowsPackageManager/main.cpp | 53 +++ src/WindowsPackageManager/packages.config | 5 + 41 files changed, 978 insertions(+), 292 deletions(-) create mode 100644 src/AppInstallerCommonCore/Debugging.cpp create mode 100644 src/AppInstallerCommonCore/Public/winget/Debugging.h create mode 100644 src/COMServer/COMServer.vcxitems create mode 100644 src/WindowsPackageManager/PropertySheet.props create mode 100644 src/WindowsPackageManager/Source.def create mode 100644 src/WindowsPackageManager/WindowsPackageManager.h create mode 100644 src/WindowsPackageManager/WindowsPackageManager.vcxproj create mode 100644 src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters create mode 100644 src/WindowsPackageManager/main.cpp create mode 100644 src/WindowsPackageManager/packages.config diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index e8d7a2fc292..0f17c4188a8 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -575,6 +575,7 @@ UNICODESTRING uninstall uninstalling Unregister +Unregisters untimes updatemanifest UPLEVEL diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index fbc4a7c671b..1f26c71dd8a 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -88,6 +88,7 @@ ctc Ctx curated CYRL +Dbg debian deigh deleteifnotneeded @@ -150,6 +151,7 @@ htm IAttachment IConfiguration idx +IFACEMETHODIMP IGlobal IHelp IHost @@ -211,10 +213,12 @@ lw lz malware MBH +mdmp megamorf memcpy middleware midl +minidump minexample minschema missingdependency @@ -251,7 +255,9 @@ nuffing nullopt NX objbase +objidl ofile +Outptr Packagedx packageinuse pathparts @@ -288,10 +294,12 @@ rebootrequiredforinstall rebootrequiredtofinish redirector Redist +REFIID regexes REGSAM restsource rhs +riid roblox rosoft rowids @@ -333,6 +341,7 @@ SYD SYG sysrefcomp Tagit +TCpp Templating temppath testexampleinstaller diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1d6a188100b..6fa7b8b3090 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -111,6 +111,13 @@ jobs: /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' + - task: PublishBuildArtifacts@1 + displayName: Publish WindowsPackageManager.dll Symbols + inputs: + PathtoPublish: 'src\x64\Release\WindowsPackageManager\WindowsPackageManager.pdb' + ArtifactName: 'WindowsPackageManager.pdb' + publishLocation: 'Container' + - task: PowerShell@2 displayName: Install Tests Dependencies inputs: @@ -269,6 +276,16 @@ jobs: arguments: '-BuildRoot $(system.defaultWorkingDirectory)\src\x86\Release\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -CertPath $(HTTPSDevCert.secureFilePath) -CertPassword microsoft' condition: succeededOrFailed() + - task: CopyFiles@2 + displayName: 'Copy x64 Files to Package Output' + inputs: + SourceFolder: '$(system.defaultWorkingDirectory)\src\x64\Release\WindowsPackageManager' + TargetFolder: '$(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x64\Release' + Contents: WindowsPackageManager.dll + CleanTargetFolder: false + OverWrite: true + condition: succeededOrFailed() + - task: VSTest@2 displayName: Run E2E Tests Packaged x64 inputs: @@ -278,7 +295,7 @@ jobs: runSettingsFile: 'src\x64\Release\AppInstallerCLIE2ETests\Test.runsettings' overrideTestrunParameters: '-PackagedContext true -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x64\Release - -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -AICLIPath AppInstallerCLI\winget.exe -LooseFileRegistration true -InvokeCommandInDesktopPackage true -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex @@ -293,7 +310,17 @@ jobs: PathtoPublish: 'C:\Users\VssAdministrator\AppData\Local\Temp\E2ETestLogs' ArtifactName: 'E2ETestPackagedx64Log' publishLocation: 'Container' - condition: succeededOrFailed() + condition: succeededOrFailed() + + - task: CopyFiles@2 + displayName: 'Copy x86 Files to Package Output' + inputs: + SourceFolder: '$(system.defaultWorkingDirectory)\src\x86\Release\WindowsPackageManager' + TargetFolder: '$(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x86\Release' + Contents: WindowsPackageManager.dll + CleanTargetFolder: false + OverWrite: true + condition: succeededOrFailed() - task: VSTest@2 displayName: Run E2E Tests Packaged x86 @@ -304,7 +331,7 @@ jobs: runSettingsFile: 'src\x86\Release\AppInstallerCLIE2ETests\Test.runsettings' overrideTestrunParameters: '-PackagedContext true -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x86\Release - -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -AICLIPath AppInstallerCLI\winget.exe -LooseFileRegistration true -InvokeCommandInDesktopPackage true -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex @@ -352,13 +379,6 @@ jobs: configuration: '$(BuildConfiguration)' condition: succeededOrFailed() - - task: PublishBuildArtifacts@1 - displayName: Publish CLI Binary - inputs: - PathtoPublish: 'src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' - ArtifactName: 'AppInstallerCLI.exe' - publishLocation: 'Container' - - task: PublishBuildArtifacts@1 displayName: Publish Util Binary inputs: diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln index 86d76f011cf..8f7f2a61b0e 100644 --- a/src/AppInstallerCLI.sln +++ b/src/AppInstallerCLI.sln @@ -5,6 +5,7 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AppInstallerCLIPackage", "AppInstallerCLIPackage\AppInstallerCLIPackage.wapproj", "{6AA3791A-0713-4548-A357-87A323E7AC3A}" ProjectSection(ProjectDependencies) = postProject {4BC1F40B-36C2-4BBB-8306-76E490B13BBD} = {4BC1F40B-36C2-4BBB-8306-76E490B13BBD} + {2B00D362-AC92-41F3-A8D2-5B1599BDCA01} = {2B00D362-AC92-41F3-A8D2-5B1599BDCA01} {1CC41A9A-AE66-459D-9210-1E572DD7BE69} = {1CC41A9A-AE66-459D-9210-1E572DD7BE69} {5B6F90DF-FD19-4BAE-83D9-24DAD128E777} = {5B6F90DF-FD19-4BAE-83D9-24DAD128E777} EndProjectSection @@ -141,18 +142,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinGetUtilInterop", "WinGet EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinGetUtilInterop.UnitTests", "WinGetUtilInterop.UnitTests\WinGetUtilInterop.UnitTests.csproj", "{68808357-902B-406C-8C19-E8E26A69DE8A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsPackageManager", "WindowsPackageManager\WindowsPackageManager.vcxproj", "{2046B5AF-666D-4CE8-8D3E-C32C57908A56}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COMServer", "COMServer\COMServer.vcxitems", "{409CD681-22A4-469D-88AE-CB5E4836E07A}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution ManifestSchema\ManifestSchema.vcxitems*{1622da16-914f-4f57-a259-d5169003cc8c}*SharedItemsImports = 4 Valijson\Valijson.vcxitems*{1c6e0108-2860-4b17-9f7e-fa5c6c1f3d3d}*SharedItemsImports = 4 WinGetSchemas\WinGetSchemas.vcxitems*{1c6e0108-2860-4b17-9f7e-fa5c6c1f3d3d}*SharedItemsImports = 4 + COMServer\COMServer.vcxitems*{1cc41a9a-ae66-459d-9210-1e572dd7be69}*SharedItemsImports = 4 + binver\binver.vcxitems*{2046b5af-666d-4ce8-8d3e-c32c57908a56}*SharedItemsImports = 4 + COMServer\COMServer.vcxitems*{2046b5af-666d-4ce8-8d3e-c32c57908a56}*SharedItemsImports = 4 + ManifestSchema\ManifestSchema.vcxitems*{2046b5af-666d-4ce8-8d3e-c32c57908a56}*SharedItemsImports = 4 + WinGetSchemas\WinGetSchemas.vcxitems*{2046b5af-666d-4ce8-8d3e-c32c57908a56}*SharedItemsImports = 4 Valijson\Valijson.vcxitems*{358bc478-0624-4ad1-a933-0422b5292af8}*SharedItemsImports = 9 + COMServer\COMServer.vcxitems*{409cd681-22a4-469d-88ae-cb5e4836e07a}*SharedItemsImports = 9 catch2\catch2.vcxitems*{5295e21e-9868-4de2-a177-fbb97b36579b}*SharedItemsImports = 9 + COMServer\COMServer.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 ManifestSchema\ManifestSchema.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 Valijson\Valijson.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 binver\binver.vcxitems*{5b6f90df-fd19-4bae-83d9-24dad128e777}*SharedItemsImports = 4 - ManifestSchema\ManifestSchema.vcxitems*{5b6f90df-fd19-4bae-83d9-24dad128e777}*SharedItemsImports = 4 - WinGetSchemas\WinGetSchemas.vcxitems*{5b6f90df-fd19-4bae-83d9-24dad128e777}*SharedItemsImports = 4 binver\binver.vcxitems*{6e36ddd7-1602-474e-b1d7-d0a7e1d5ad86}*SharedItemsImports = 9 ManifestSchema\ManifestSchema.vcxitems*{7d05f64d-ce5a-42aa-a2c1-e91458f061cf}*SharedItemsImports = 9 catch2\catch2.vcxitems*{89b1aab4-2bbc-4b65-9ed7-a01d5cf88230}*SharedItemsImports = 4 @@ -955,6 +965,44 @@ Global {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x64.Build.0 = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x86.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x86.Build.0 = Release|Any CPU + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM.ActiveCfg = Debug|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM.Build.0 = Debug|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM64.Build.0 = Debug|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|x64.ActiveCfg = Debug|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|x64.Build.0 = Debug|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|x86.ActiveCfg = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|x86.Build.0 = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|Any CPU.ActiveCfg = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|Any CPU.Build.0 = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|ARM.ActiveCfg = Debug|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|ARM.Build.0 = Debug|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|ARM64.ActiveCfg = Debug|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|ARM64.Build.0 = Debug|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|x64.ActiveCfg = Debug|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|x64.Build.0 = Debug|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|x86.ActiveCfg = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Fuzzing|x86.Build.0 = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|Any CPU.ActiveCfg = Release|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|ARM.ActiveCfg = Release|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|ARM.Build.0 = Release|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|ARM64.ActiveCfg = Release|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|ARM64.Build.0 = Release|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|x64.ActiveCfg = Release|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|x64.Build.0 = Release|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|x86.ActiveCfg = Release|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Release|x86.Build.0 = Release|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|Any CPU.ActiveCfg = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|Any CPU.Build.0 = Debug|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|ARM.ActiveCfg = Release|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|ARM.Build.0 = Release|ARM + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|ARM64.ActiveCfg = Release|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|ARM64.Build.0 = Release|ARM64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|x64.ActiveCfg = Release|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|x64.Build.0 = Release|x64 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|x86.ActiveCfg = Release|Win32 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.TestRelease|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -977,6 +1025,7 @@ Global {1487DFBB-7C53-4BD3-9B2C-9B94C6C91528} = {F2149997-295A-4593-9282-4C675DFEB670} {F5CED6B6-C27F-4405-9033-6C273B8B129C} = {F2149997-295A-4593-9282-4C675DFEB670} {1A47951F-5C7A-4D6D-BB5F-D77484437940} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7} + {409CD681-22A4-469D-88AE-CB5E4836E07A} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B6FDB70C-A751-422C-ACD1-E35419495857} diff --git a/src/AppInstallerCLI/AppInstallerCLI.vcxproj b/src/AppInstallerCLI/AppInstallerCLI.vcxproj index d94ae121d58..96227482912 100644 --- a/src/AppInstallerCLI/AppInstallerCLI.vcxproj +++ b/src/AppInstallerCLI/AppInstallerCLI.vcxproj @@ -82,8 +82,6 @@ - - @@ -98,6 +96,7 @@ true true ..\CodeAnalysis.ruleset + winget true @@ -105,6 +104,7 @@ true true ..\CodeAnalysis.ruleset + winget true @@ -112,6 +112,7 @@ true true ..\CodeAnalysis.ruleset + winget true @@ -119,6 +120,7 @@ true true ..\CodeAnalysis.ruleset + winget false @@ -126,6 +128,7 @@ true false ..\CodeAnalysis.ruleset + winget false @@ -133,6 +136,7 @@ true false ..\CodeAnalysis.ruleset + winget false @@ -140,6 +144,7 @@ true false ..\CodeAnalysis.ruleset + winget false @@ -147,6 +152,7 @@ true false ..\CodeAnalysis.ruleset + winget @@ -162,9 +168,9 @@ Disabled _DEBUG;%(PreprocessorDefinitions) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) true true true @@ -199,7 +205,7 @@ WIN32;%(PreprocessorDefinitions) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -216,10 +222,10 @@ true true NDEBUG;%(PreprocessorDefinitions) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) - $(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\WindowsPackageManager\;%(AdditionalIncludeDirectories) true true true @@ -269,24 +275,8 @@ - - {1c6e0108-2860-4b17-9f7e-fa5c6c1f3d3d} - false - - - {5890d6ed-7c3b-40f3-b436-b54f640d9e65} - - - {5eb88068-5fb9-4e69-89b2-72dbc5e068f9} - - - {866c3f06-636f-4be8-bc24-5f86ecc606a1} - - - {82b39fda-e86b-4713-a873-9d56de00247a} - - - {8bb94bb8-374f-4294-bca1-c7811514a6b7} + + {2046b5af-666d-4ce8-8d3e-c32c57908a56} diff --git a/src/AppInstallerCLI/main.cpp b/src/AppInstallerCLI/main.cpp index 8b06f12292c..afbfaf02c2c 100644 --- a/src/AppInstallerCLI/main.cpp +++ b/src/AppInstallerCLI/main.cpp @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include +#define WIN32_LEAN_AND_MEAN +#include +#include int wmain(int argc, wchar_t const** argv) { - return AppInstaller::CLI::CoreMain(argc, argv); + return WindowsPackageManagerCLIMain(argc, argv); } diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj index ddac3d00af4..bdde3e2b533 100644 --- a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj +++ b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj @@ -239,7 +239,6 @@ - @@ -260,6 +259,7 @@ + diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters index 1255787d82f..84e809fde77 100644 --- a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters +++ b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters @@ -152,9 +152,6 @@ Header Files - - Public - Header Files @@ -176,6 +173,9 @@ Workflows + + Public + diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp index e2ac4439691..46efb7ede87 100644 --- a/src/AppInstallerCLICore/Core.cpp +++ b/src/AppInstallerCLICore/Core.cpp @@ -7,6 +7,11 @@ #include "Workflows/WorkflowBase.h" #include #include "Commands/InstallCommand.h" +#include "COMContext.h" + +#ifndef AICLI_DISABLE_TEST_HOOKS +#include +#endif using namespace winrt; using namespace winrt::Windows::Foundation; @@ -46,6 +51,13 @@ namespace AppInstaller::CLI { init_apartment(); +#ifndef AICLI_DISABLE_TEST_HOOKS + if (Settings::User().Get()) + { + Debugging::EnableSelfInitiatedMinidump(); + } +#endif + // Enable all logging for this phase; we will update once we have the arguments Logging::Log().EnableChannel(Logging::Channel::All); Logging::Log().SetLevel(Logging::Level::Info); @@ -133,4 +145,9 @@ namespace AppInstaller::CLI { return APPINSTALLER_CLI_ERROR_INTERNAL_ERROR; } + + void ServerInitialize() + { + AppInstaller::CLI::Execution::COMContext::SetLoggers(); + } } diff --git a/src/AppInstallerCLICore/Public/AppInstallerCLICore.h b/src/AppInstallerCLICore/Public/AppInstallerCLICore.h index 01db30f8003..e93643442ff 100644 --- a/src/AppInstallerCLICore/Public/AppInstallerCLICore.h +++ b/src/AppInstallerCLICore/Public/AppInstallerCLICore.h @@ -4,5 +4,9 @@ namespace AppInstaller::CLI { + // The core function to act against command line input. int CoreMain(int argc, wchar_t const** argv); + + // Initializes the Windows Package Manager COM server. + void ServerInitialize(); } diff --git a/src/AppInstallerCLIE2ETests/BaseCommand.cs b/src/AppInstallerCLIE2ETests/BaseCommand.cs index 33b7240646c..51ee2154595 100644 --- a/src/AppInstallerCLIE2ETests/BaseCommand.cs +++ b/src/AppInstallerCLIE2ETests/BaseCommand.cs @@ -12,11 +12,6 @@ namespace AppInstallerCLIE2ETests public class BaseCommand { - public string SettingsJsonFilePath => TestCommon.PackagedContext ? - @"Packages\WinGetDevCLI_8wekyb3d8bbwe\LocalState\settings.json" : - @"Microsoft\WinGet\Settings\settings.json"; - public readonly string LocalAppData = "LocalAppData"; - [OneTimeSetUp] public void BaseSetup() { @@ -40,31 +35,20 @@ public void ResetTestSource() public void ConfigureFeature(string featureName, bool status) { - string localAppDataPath = Environment.GetEnvironmentVariable(LocalAppData); - JObject settingsJson = JObject.Parse(File.ReadAllText(Path.Combine(localAppDataPath, SettingsJsonFilePath))); + string localAppDataPath = Environment.GetEnvironmentVariable(Constants.LocalAppData); + JObject settingsJson = JObject.Parse(File.ReadAllText(Path.Combine(localAppDataPath, TestCommon.SettingsJsonFilePath))); JObject experimentalFeatures = (JObject)settingsJson["experimentalFeatures"]; experimentalFeatures[featureName] = status; - File.WriteAllText(Path.Combine(localAppDataPath, SettingsJsonFilePath), settingsJson.ToString()); + File.WriteAllText(Path.Combine(localAppDataPath, TestCommon.SettingsJsonFilePath), settingsJson.ToString()); } public void InitializeAllFeatures(bool status) { - string localAppDataPath = Environment.GetEnvironmentVariable(LocalAppData); - - var settingsJson = new - { - experimentalFeatures = new - { - experimentalArg = status, - experimentalCmd = status, - dependencies = status, - directMSI = status, - } - }; - - var serializedSettingsJson = JsonConvert.SerializeObject(settingsJson, Formatting.Indented); - File.WriteAllText(Path.Combine(localAppDataPath, SettingsJsonFilePath), serializedSettingsJson); + ConfigureFeature("experimentalArg", status); + ConfigureFeature("experimentalCmd", status); + ConfigureFeature("dependencies", status); + ConfigureFeature("directMSI", status); } } } diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index 894774d53d6..c2ee32a362f 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -54,6 +54,9 @@ public class Constants public const string TestExeInstalledFileName = "TestExeInstalled.txt"; public const string TestExeUninstallerFileName = "UninstallTestExe.bat"; + // Locations + public const string LocalAppData = "LocalAppData"; + public class ErrorCode { public const int S_OK = 0; diff --git a/src/AppInstallerCLIE2ETests/ListCommand.cs b/src/AppInstallerCLIE2ETests/ListCommand.cs index 2de25930e6d..a6acc88ba3e 100644 --- a/src/AppInstallerCLIE2ETests/ListCommand.cs +++ b/src/AppInstallerCLIE2ETests/ListCommand.cs @@ -22,7 +22,7 @@ public void ListAfterInstall() string productCode = guid.ToString(); var installDir = TestCommon.GetRandomTestDir(); - string localAppDataPath = System.Environment.GetEnvironmentVariable(LocalAppData); + string localAppDataPath = System.Environment.GetEnvironmentVariable(Constants.LocalAppData); string logFilePath = System.IO.Path.Combine(localAppDataPath, Constants.E2ETestLogsPath); logFilePath = System.IO.Path.Combine(logFilePath, "ListAfterInstall-" + System.IO.Path.GetRandomFileName() + ".log"); diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs index 6830ca90891..61f9a9e0b3d 100644 --- a/src/AppInstallerCLIE2ETests/SetUpFixture.cs +++ b/src/AppInstallerCLIE2ETests/SetUpFixture.cs @@ -4,6 +4,8 @@ namespace AppInstallerCLIE2ETests { using Microsoft.Win32; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; using NUnit.Framework; using System; using System.IO; @@ -44,7 +46,7 @@ public void Setup() } else { - TestCommon.AICLIPath = TestCommon.GetTestFile("AppInstallerCli.exe"); + TestCommon.AICLIPath = TestCommon.GetTestFile("winget.exe"); } } @@ -97,6 +99,8 @@ public void Setup() ReadTestInstallerPaths(); TestIndexSetup.GenerateTestDirectory(); + + InitializeWingetSettings(); } [OneTimeTearDown] @@ -194,5 +198,28 @@ private void ReadTestInstallerPaths() TestCommon.MsixInstallerPath = TestContext.Parameters.Get(Constants.MsixInstallerPathParameter); } } + + public void InitializeWingetSettings() + { + string localAppDataPath = Environment.GetEnvironmentVariable(Constants.LocalAppData); + + var settingsJson = new + { + experimentalFeatures = new + { + experimentalArg = false, + experimentalCmd = false, + dependencies = false, + directMSI = false, + }, + debugging = new + { + enableSelfInitiatedMinidump = true + } + }; + + var serializedSettingsJson = JsonConvert.SerializeObject(settingsJson, Formatting.Indented); + File.WriteAllText(Path.Combine(localAppDataPath, TestCommon.SettingsJsonFilePath), serializedSettingsJson); + } } } diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs index 9b1d84f67b3..c1c6266bc3b 100644 --- a/src/AppInstallerCLIE2ETests/TestCommon.cs +++ b/src/AppInstallerCLIE2ETests/TestCommon.cs @@ -34,6 +34,15 @@ public class TestCommon public static string PackageCertificatePath { get; set; } + public static string SettingsJsonFilePath { + get + { + return PackagedContext ? + @"Packages\WinGetDevCLI_8wekyb3d8bbwe\LocalState\settings.json" : + @"Microsoft\WinGet\Settings\settings.json"; + } + } + public struct RunCommandResult { public int ExitCode; @@ -103,7 +112,7 @@ public static RunCommandResult RunAICLICommandViaDirectProcess(string command, s } else { - throw new TimeoutException("Command run timed out."); + throw new TimeoutException($"Direct winget command run timed out: {command} {parameters}"); } return result; @@ -155,7 +164,7 @@ public static RunCommandResult RunAICLICommandViaInvokeCommandInDesktopPackage(s if (waitedTime >= timeOut) { - throw new TimeoutException("Command run timed out."); + throw new TimeoutException($"Packaged winget command run timed out: {command} {parameters}"); } RunCommandResult result = new RunCommandResult(); diff --git a/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj b/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj index 54e089886b3..447a35e767c 100644 --- a/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj +++ b/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj @@ -151,16 +151,25 @@ + $(OutputPath)\..\WindowsPackageManager.dll + $(TargetDir)..\..\..\..\$(PlatformTarget)\$(Configuration)\WindowsPackageManager\WindowsPackageManager.dll + WindowsPackageManager.dll $(OutputPath)\..\Microsoft.Management.Deployment\Microsoft.Management.Deployment.winmd $(TargetDir)..\..\..\..\$(PlatformTarget)\$(Configuration)\Microsoft.Management.Deployment\Microsoft.Management.Deployment.winmd Microsoft.Management.Deployment.winmd + + + + + $(WindowsPackageManagerFileName) + $(MicrosoftManagementDeploymentFileName) diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest index d12541d4b31..b0a3134c61c 100644 --- a/src/AppInstallerCLIPackage/Package.appxmanifest +++ b/src/AppInstallerCLIPackage/Package.appxmanifest @@ -22,7 +22,7 @@ - + diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index cee48135683..146ae53d3ae 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -93,6 +93,7 @@ + @@ -277,6 +278,7 @@ + @@ -330,6 +332,7 @@ + diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters index 9a2a512f02c..20527b7be72 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -186,6 +186,9 @@ Public\winget + + Public\winget + @@ -320,6 +323,9 @@ Source Files + + Source Files + diff --git a/src/AppInstallerCommonCore/Debugging.cpp b/src/AppInstallerCommonCore/Debugging.cpp new file mode 100644 index 00000000000..6bfbf795d24 --- /dev/null +++ b/src/AppInstallerCommonCore/Debugging.cpp @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/winget/Debugging.h" +#include "Public/AppInstallerRuntime.h" +#include "Public/AppInstallerDateTime.h" + +namespace AppInstaller::Debugging +{ + namespace + { + constexpr std::string_view c_minidumpPrefix = "Minidump"; + constexpr std::string_view c_minidumpExtension = ".mdmp"; + + struct SelfInitiatedMinidumpHelper + { + SelfInitiatedMinidumpHelper() : m_keepFile(false) + { + m_filePath = Runtime::GetPathTo(Runtime::PathName::DefaultLogLocation); + m_filePath /= c_minidumpPrefix.data() + ('-' + Utility::GetCurrentTimeForFilename() + c_minidumpExtension.data()); + + m_file.reset(CreateFile(m_filePath.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)); + THROW_LAST_ERROR_IF(!m_file); + + SetUnhandledExceptionFilter(UnhandledExceptionCallback); + } + + ~SelfInitiatedMinidumpHelper() + { + if (!m_keepFile) + { + m_file.reset(); + DeleteFile(m_filePath.wstring().c_str()); + } + } + + static SelfInitiatedMinidumpHelper& Instance() + { + static SelfInitiatedMinidumpHelper instance; + return instance; + } + + static LONG WINAPI UnhandledExceptionCallback(EXCEPTION_POINTERS* ExceptionInfo) + { + MINIDUMP_EXCEPTION_INFORMATION exceptionInformation{}; + // The unhandled exception filter is executed in the context of the failing thread. + exceptionInformation.ThreadId = GetCurrentThreadId(); + exceptionInformation.ExceptionPointers = ExceptionInfo; + exceptionInformation.ClientPointers = FALSE; + + std::thread([&]() { + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), Instance().m_file.get(), MiniDumpNormal, &exceptionInformation, nullptr, nullptr); + Instance().m_keepFile = true; + }).join(); + + return EXCEPTION_CONTINUE_SEARCH; + } + + private: + std::filesystem::path m_filePath; + wil::unique_handle m_file; + std::atomic_bool m_keepFile; + }; + } + + void EnableSelfInitiatedMinidump() + { + // Force object creation and thus enabling of the crash detection. + SelfInitiatedMinidumpHelper::Instance(); + } +} diff --git a/src/AppInstallerCommonCore/Public/winget/Debugging.h b/src/AppInstallerCommonCore/Public/winget/Debugging.h new file mode 100644 index 00000000000..319c04a313b --- /dev/null +++ b/src/AppInstallerCommonCore/Public/winget/Debugging.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +namespace AppInstaller::Debugging +{ + // Enables a self initiated minidump on certain process level failures. + void EnableSelfInitiatedMinidump(); +} diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h index 5c6b745cb5f..fc5147c39a0 100644 --- a/src/AppInstallerCommonCore/Public/winget/UserSettings.h +++ b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -76,6 +76,7 @@ namespace AppInstaller::Settings InstallLocalePreference, InstallLocaleRequirement, EFDirectMSI, + EnableSelfInitiatedMinidump, Max }; @@ -122,6 +123,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocalePreference, std::vector, std::vector, {}, ".installBehavior.preferences.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector, std::vector, {}, ".installBehavior.requirements.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::EnableSelfInitiatedMinidump, bool, bool, false, ".debugging.enableSelfInitiatedMinidump"sv); // Used to deduce the SettingVariant type; making a variant that includes std::monostate and all SettingMapping types. template diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp index 22ac71f297e..62dd69ea6a3 100644 --- a/src/AppInstallerCommonCore/UserSettings.cpp +++ b/src/AppInstallerCommonCore/UserSettings.cpp @@ -227,6 +227,7 @@ namespace AppInstaller::Settings WINGET_VALIDATE_PASS_THROUGH(EFDependencies) WINGET_VALIDATE_PASS_THROUGH(TelemetryDisable) WINGET_VALIDATE_PASS_THROUGH(EFDirectMSI) + WINGET_VALIDATE_PASS_THROUGH(EnableSelfInitiatedMinidump) WINGET_VALIDATE_SIGNATURE(InstallScopePreference) { diff --git a/src/AppInstallerCommonCore/pch.h b/src/AppInstallerCommonCore/pch.h index 68cb4d9a6b1..0ef4c263c1a 100644 --- a/src/AppInstallerCommonCore/pch.h +++ b/src/AppInstallerCommonCore/pch.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "TraceLogging.h" diff --git a/src/COMServer/COMServer.vcxitems b/src/COMServer/COMServer.vcxitems new file mode 100644 index 00000000000..b5bfddd89be --- /dev/null +++ b/src/COMServer/COMServer.vcxitems @@ -0,0 +1,13 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {409cd681-22a4-469d-88ae-cb5e4836e07a} + + + + __WRL_DISABLE_STATIC_INITIALIZE__;%(PreprocessorDefinitions) + + + \ No newline at end of file diff --git a/src/Microsoft.Management.Deployment/CreateCompositePackageCatalogOptions.cpp b/src/Microsoft.Management.Deployment/CreateCompositePackageCatalogOptions.cpp index 07aebc20593..c4609596c57 100644 --- a/src/Microsoft.Management.Deployment/CreateCompositePackageCatalogOptions.cpp +++ b/src/Microsoft.Management.Deployment/CreateCompositePackageCatalogOptions.cpp @@ -9,6 +9,7 @@ #include "CreateCompositePackageCatalogOptions.h" #pragma warning( pop ) #include "CreateCompositePackageCatalogOptions.g.cpp" +#include "Helpers.h" namespace winrt::Microsoft::Management::Deployment::implementation { @@ -24,5 +25,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_compositeSearchBehavior = value; } - CoCreatableCppWinRtClass(CreateCompositePackageCatalogOptions); + + CoCreatableMicrosoftManagementDeploymentClass(CreateCompositePackageCatalogOptions); } diff --git a/src/Microsoft.Management.Deployment/FindPackagesOptions.cpp b/src/Microsoft.Management.Deployment/FindPackagesOptions.cpp index 02f6d725ca5..9c17269e024 100644 --- a/src/Microsoft.Management.Deployment/FindPackagesOptions.cpp +++ b/src/Microsoft.Management.Deployment/FindPackagesOptions.cpp @@ -9,6 +9,7 @@ #include "FindPackagesOptions.h" #pragma warning( pop ) #include "FindPackagesOptions.g.cpp" +#include "Helpers.h" namespace winrt::Microsoft::Management::Deployment::implementation { @@ -28,5 +29,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_resultLimit = value; } - CoCreatableCppWinRtClass(FindPackagesOptions); + + CoCreatableMicrosoftManagementDeploymentClass(FindPackagesOptions); } diff --git a/src/Microsoft.Management.Deployment/Helpers.h b/src/Microsoft.Management.Deployment/Helpers.h index 67f46410e35..2cf38ba7c41 100644 --- a/src/Microsoft.Management.Deployment/Helpers.h +++ b/src/Microsoft.Management.Deployment/Helpers.h @@ -1,7 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. #pragma once +#include +#include +#include namespace winrt::Microsoft::Management::Deployment::implementation { + // Enable custom code to run before creating any object through the factory. + // Currently that means requiring the overall WinGet policy to be enabled. + template + class wrl_factory_for_winrt_com_class : public ::wil::wrl_factory_for_winrt_com_class + { + public: + IFACEMETHODIMP CreateInstance(_In_opt_::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept try + { + *object = nullptr; + RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); + + return ::wil::wrl_factory_for_winrt_com_class::CreateInstance(unknownOuter, riid, object); + } + CATCH_RETURN() + }; + +#define CoCreatableMicrosoftManagementDeploymentClass(className) \ + CoCreatableClassWithFactory(className, ::winrt::Microsoft::Management::Deployment::implementation::wrl_factory_for_winrt_com_class) + enum class Capability { PackageManagement, @@ -12,4 +36,4 @@ namespace winrt::Microsoft::Management::Deployment::implementation HRESULT EnsureComCallerHasCapability(Capability requiredCapability); std::pair GetCallerProcessId(); std::wstring TryGetCallerProcessInfo(DWORD callerProcessId); -} \ No newline at end of file +} diff --git a/src/Microsoft.Management.Deployment/InstallOptions.cpp b/src/Microsoft.Management.Deployment/InstallOptions.cpp index d098d26f7ba..07814af6ccb 100644 --- a/src/Microsoft.Management.Deployment/InstallOptions.cpp +++ b/src/Microsoft.Management.Deployment/InstallOptions.cpp @@ -10,6 +10,7 @@ #pragma warning( pop ) #include "InstallOptions.g.cpp" #include "Converters.h" +#include "Helpers.h" #include @@ -103,5 +104,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation { return m_allowedArchitectures; } - CoCreatableCppWinRtClass(InstallOptions); + + CoCreatableMicrosoftManagementDeploymentClass(InstallOptions); } diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj index d70b4709da4..cc5df29c850 100644 --- a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj +++ b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj @@ -73,6 +73,7 @@ + diff --git a/src/Microsoft.Management.Deployment/PackageManager.cpp b/src/Microsoft.Management.Deployment/PackageManager.cpp index db1a68e29a4..2dee2ca3174 100644 --- a/src/Microsoft.Management.Deployment/PackageManager.cpp +++ b/src/Microsoft.Management.Deployment/PackageManager.cpp @@ -585,5 +585,5 @@ namespace winrt::Microsoft::Management::Deployment::implementation return GetInstallOperation(canCancelQueueItem, std::move(queueItem)); } - CoCreatableCppWinRtClass(PackageManager); + CoCreatableMicrosoftManagementDeploymentClass(PackageManager); } diff --git a/src/Microsoft.Management.Deployment/PackageMatchFilter.cpp b/src/Microsoft.Management.Deployment/PackageMatchFilter.cpp index 88678e8f199..208a87d0eab 100644 --- a/src/Microsoft.Management.Deployment/PackageMatchFilter.cpp +++ b/src/Microsoft.Management.Deployment/PackageMatchFilter.cpp @@ -12,6 +12,7 @@ #include "PackageMatchFilter.h" #pragma warning( pop ) #include "PackageMatchFilter.g.cpp" +#include "Helpers.h" namespace winrt::Microsoft::Management::Deployment::implementation { @@ -45,5 +46,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_value = value; } - CoCreatableCppWinRtClass(PackageMatchFilter); + + CoCreatableMicrosoftManagementDeploymentClass(PackageMatchFilter); } diff --git a/src/WinGetServer/WinGetServer.vcxproj b/src/WinGetServer/WinGetServer.vcxproj index aee34cc674b..fc09844083a 100644 --- a/src/WinGetServer/WinGetServer.vcxproj +++ b/src/WinGetServer/WinGetServer.vcxproj @@ -1,176 +1,161 @@ - - - - - true - true - true - true - 15.0 - {2b00d362-ac92-41f3-a8d2-5b1599bdca01} - Win32Proj - WinGetServer - 10.0.18362.0 - 10.0.17763.0 - true - true - WinGetServer - WindowsPackageManagerServer - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - Application - v140 - v141 - v142 - Unicode - - - true - true - - - false - true - false - Spectre - - - - - - - - - - - - - - - $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(ProjectName)\ - $(PlatformTarget)\$(Configuration)\ - $(OutDir)..\Microsoft.Management.Deployment;$(OutDir)..\AppInstallerCLICore;$(OutDir)..\JsonCppLib;$(OutDir)..\AppInstallerRepositoryCore;$(OutDir)..\YamlCppLib;$(OutDir)..\AppInstallerCommonCore;$(OutDir)..\cpprestsdk;$(LibraryPath) - true - false - ..\CodeAnalysis.ruleset - - - - NotUsing - pch.h - $(IntDir)pch.pch - _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) - Level4 - %(AdditionalOptions) /permissive- /bigobj - true - true - true - $(ProjectDir)..\AppInstallerCLICore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerRepositoryCore\Public;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - - - Windows - false - $(OutDir)..\Microsoft.Management.Deployment;$(OutDir)..\AppInstallerCLICore;$(OutDir)..\JsonCppLib;$(OutDir)..\AppInstallerRepositoryCore;$(OutDir)..\YamlCppLib;$(OutDir)..\AppInstallerCommonCore;$(OutDir)..\cpprestsdk;%(AdditionalLibraryDirectories) - Microsoft.Management.Deployment.Server.lib;AppInstallerCLICore.lib;AppInstallerCommonCore.lib;AppInstallerRepositoryCore.lib;JsonCppLib.lib;YamlCppLib.lib;cpprestsdk.lib;wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - WIN32;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - - {5890d6ed-7c3b-40f3-b436-b54f640d9e65} - - - {5eb88068-5fb9-4e69-89b2-72dbc5e068f9} - - - {866c3f06-636f-4be8-bc24-5f86ecc606a1} - - - {82b39fda-e86b-4713-a873-9d56de00247a} - - - {8bb94bb8-374f-4294-bca1-c7811514a6b7} - - - {1cc41a9a-ae66-459d-9210-1e572dd7be69} - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + true + true + true + true + 15.0 + {2b00d362-ac92-41f3-a8d2-5b1599bdca01} + Win32Proj + WinGetServer + 10.0.18362.0 + 10.0.17763.0 + true + true + WinGetServer + WindowsPackageManagerServer + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + Application + v140 + v141 + v142 + Unicode + + + true + true + + + false + true + false + Spectre + + + + + + + + + + + + + + + $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(PlatformTarget)\$(Configuration)\ + $(OutDir)..\Microsoft.Management.Deployment;$(OutDir)..\AppInstallerCLICore;$(OutDir)..\JsonCppLib;$(OutDir)..\AppInstallerRepositoryCore;$(OutDir)..\YamlCppLib;$(OutDir)..\AppInstallerCommonCore;$(OutDir)..\cpprestsdk;$(LibraryPath) + true + false + ..\CodeAnalysis.ruleset + + + + NotUsing + pch.h + $(IntDir)pch.pch + _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + Level4 + %(AdditionalOptions) /permissive- /bigobj + true + true + true + $(ProjectDir)..\WindowsPackageManager;%(AdditionalIncludeDirectories) + + + Windows + false + $(OutDir)..\Microsoft.Management.Deployment;$(OutDir)..\AppInstallerCLICore;$(OutDir)..\JsonCppLib;$(OutDir)..\AppInstallerRepositoryCore;$(OutDir)..\YamlCppLib;$(OutDir)..\AppInstallerCommonCore;$(OutDir)..\cpprestsdk;%(AdditionalLibraryDirectories) + Microsoft.Management.Deployment.Server.lib;AppInstallerCLICore.lib;AppInstallerCommonCore.lib;AppInstallerRepositoryCore.lib;JsonCppLib.lib;YamlCppLib.lib;cpprestsdk.lib;wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies) + + + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + + + + + WIN32;%(PreprocessorDefinitions) + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + + + {2046b5af-666d-4ce8-8d3e-c32c57908a56} + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/WinGetServer/WinMain.cpp b/src/WinGetServer/WinMain.cpp index 1a4ce09f656..2b341a30985 100644 --- a/src/WinGetServer/WinMain.cpp +++ b/src/WinGetServer/WinMain.cpp @@ -1,21 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. - -#include -#include -#include -#include -#include "COMContext.h" -#include "AppInstallerRuntime.h" -#include "AppInstallerVersions.h" - -using namespace winrt::Microsoft::Management::Deployment; - -CoCreatableClassWrlCreatorMapInclude(PackageManager); -CoCreatableClassWrlCreatorMapInclude(FindPackagesOptions); -CoCreatableClassWrlCreatorMapInclude(CreateCompositePackageCatalogOptions); -CoCreatableClassWrlCreatorMapInclude(InstallOptions); -CoCreatableClassWrlCreatorMapInclude(PackageMatchFilter); +#include +#include +#include +#include // Holds the wwinmain open until COM tells us there are no more server connections wil::unique_event _comServerExitEvent; @@ -27,17 +15,6 @@ static void _releaseNotifier() noexcept _comServerExitEvent.SetEvent(); } -// Check whether the packaged api is enabled and the overarching winget group policy is enabled. -bool IsServerEnabled() -{ - if (!::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)) - { - return false; - } - - return true; -} - int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int) { winrt::init_apartment(); @@ -49,22 +26,16 @@ int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int winrt::check_hresult(globalOptions->Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN)); } - AppInstaller::CLI::Execution::COMContext::SetLoggers(); + RETURN_IF_FAILED(WindowsPackageManagerServerInitialize()); _comServerExitEvent.create(); - auto& module = ::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::Create(&_releaseNotifier); + RETURN_IF_FAILED(WindowsPackageManagerServerModuleCreate(&_releaseNotifier)); try { - if (!IsServerEnabled()) - { - return 0; - } - // Register all the CoCreatableClassWrlCreatorMapInclude classes - RETURN_IF_FAILED(module.RegisterObjects()); + RETURN_IF_FAILED(WindowsPackageManagerServerModuleRegister()); _comServerExitEvent.wait(); - RETURN_IF_FAILED(module.UnregisterObjects()); - + RETURN_IF_FAILED(WindowsPackageManagerServerModuleUnregister()); } CATCH_RETURN() diff --git a/src/WindowsPackageManager/PropertySheet.props b/src/WindowsPackageManager/PropertySheet.props new file mode 100644 index 00000000000..c6b0691ddda --- /dev/null +++ b/src/WindowsPackageManager/PropertySheet.props @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/src/WindowsPackageManager/Source.def b/src/WindowsPackageManager/Source.def new file mode 100644 index 00000000000..c4fb8341770 --- /dev/null +++ b/src/WindowsPackageManager/Source.def @@ -0,0 +1,7 @@ +LIBRARY WindowsPackageManager +EXPORTS + WindowsPackageManagerCLIMain + WindowsPackageManagerServerInitialize + WindowsPackageManagerServerModuleCreate + WindowsPackageManagerServerModuleRegister + WindowsPackageManagerServerModuleUnregister diff --git a/src/WindowsPackageManager/WindowsPackageManager.h b/src/WindowsPackageManager/WindowsPackageManager.h new file mode 100644 index 00000000000..023197c9ed7 --- /dev/null +++ b/src/WindowsPackageManager/WindowsPackageManager.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +extern "C" +{ +#define WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION __stdcall +#define WINDOWS_PACKAGE_MANAGER_API HRESULT WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION + + using WindowsPackageManagerServerModuleTerminationCallback = void (*)(); + + // The core function to act against command line input. + int WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION WindowsPackageManagerCLIMain(int argc, wchar_t const** argv); + + // Initializes the Windows Package Manager COM server. + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerInitialize(); + + // Creates the server module with the given termination callback. + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleCreate(WindowsPackageManagerServerModuleTerminationCallback callback); + + // Registers the server module class factories. + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleRegister(); + + // Unregisters the server module class factories. + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleUnregister(); +} diff --git a/src/WindowsPackageManager/WindowsPackageManager.vcxproj b/src/WindowsPackageManager/WindowsPackageManager.vcxproj new file mode 100644 index 00000000000..80444562b74 --- /dev/null +++ b/src/WindowsPackageManager/WindowsPackageManager.vcxproj @@ -0,0 +1,325 @@ + + + + + true + true + true + 15.0 + {2046B5AF-666D-4CE8-8D3E-C32C57908A56} + Win32Proj + WindowsPackageManager + 10.0.18362.0 + 10.0.17763.0 + true + true + false + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + DynamicLibrary + v140 + v141 + v142 + Unicode + + + true + true + + + false + true + false + + + Spectre + + + Spectre + + + Spectre + + + Spectre + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + + NotUsing + _CONSOLE;%(PreprocessorDefinitions) + Level4 + %(AdditionalOptions) /permissive- /bigobj /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING + + + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories) + true + true + true + false + false + false + stdcpp17 + stdcpp17 + stdcpp17 + true + true + true + true + true + true + + + false + Windows + Windows + Windows + Windows + Source.def + Source.def + Source.def + Source.def + wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + + + WIN32;%(PreprocessorDefinitions) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories) + true + false + stdcpp17 + true + true + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;%(AdditionalIncludeDirectories) + true + true + true + true + Guard + Guard + Guard + Guard + stdcpp17 + stdcpp17 + stdcpp17 + stdcpp17 + true + true + true + true + false + false + false + false + + + true + true + false + Windows + Windows + Windows + Windows + Source.def + Source.def + Source.def + Source.def + wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + $(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles) + + + + + + + + + + + + + + + + {1c6e0108-2860-4b17-9f7e-fa5c6c1f3d3d} + + + {5890d6ed-7c3b-40f3-b436-b54f640d9e65} + + + {5eb88068-5fb9-4e69-89b2-72dbc5e068f9} + + + {866c3f06-636f-4be8-bc24-5f86ecc606a1} + + + {82b39fda-e86b-4713-a873-9d56de00247a} + + + {1cc41a9a-ae66-459d-9210-1e572dd7be69} + + + {8bb94bb8-374f-4294-bca1-c7811514a6b7} + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters b/src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters new file mode 100644 index 00000000000..71a758dc2a1 --- /dev/null +++ b/src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters @@ -0,0 +1,34 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + + + + + Source Files + + + \ No newline at end of file diff --git a/src/WindowsPackageManager/main.cpp b/src/WindowsPackageManager/main.cpp new file mode 100644 index 00000000000..7157f5be3ff --- /dev/null +++ b/src/WindowsPackageManager/main.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include +#include +#include + +#include "WindowsPackageManager.h" + +#include + +using namespace winrt::Microsoft::Management::Deployment; + +CoCreatableClassWrlCreatorMapInclude(PackageManager); +CoCreatableClassWrlCreatorMapInclude(FindPackagesOptions); +CoCreatableClassWrlCreatorMapInclude(CreateCompositePackageCatalogOptions); +CoCreatableClassWrlCreatorMapInclude(InstallOptions); +CoCreatableClassWrlCreatorMapInclude(PackageMatchFilter); + +extern "C" +{ + int WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION WindowsPackageManagerCLIMain(int argc, wchar_t const** argv) try + { + ::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::InProc>::Create(); + return AppInstaller::CLI::CoreMain(argc, argv); + } + CATCH_RETURN(); + + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerInitialize() try + { + AppInstaller::CLI::ServerInitialize(); + return S_OK; + } + CATCH_RETURN(); + + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleCreate(WindowsPackageManagerServerModuleTerminationCallback callback) try + { + ::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::Create(callback); + return S_OK; + } + CATCH_RETURN(); + + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleRegister() try + { + RETURN_HR(::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::GetModule().RegisterObjects()); + } + CATCH_RETURN(); + + WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleUnregister() try + { + RETURN_HR(::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::GetModule().UnregisterObjects()); + } + CATCH_RETURN(); +} diff --git a/src/WindowsPackageManager/packages.config b/src/WindowsPackageManager/packages.config new file mode 100644 index 00000000000..5e899619db1 --- /dev/null +++ b/src/WindowsPackageManager/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 39034e1e0bff692c40e964c1f1d5b177edef693b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chac=C3=B3n?= Date: Tue, 16 Nov 2021 18:57:58 -0800 Subject: [PATCH 3/3] Implement parallel downloads for COM scenarios (#1588) --- .github/actions/spelling/allow.txt | 2 +- .../Commands/COMInstallCommand.h | 6 +- .../ContextOrchestrator.cpp | 255 +++++++++++++----- src/AppInstallerCLICore/ContextOrchestrator.h | 81 +++++- .../Workflows/WorkflowBase.cpp | 2 +- .../Microsoft/SQLiteIndex.cpp | 13 + .../Microsoft/SQLiteIndex.h | 1 + 7 files changed, 281 insertions(+), 79 deletions(-) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 0f17c4188a8..7d044e24996 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -532,7 +532,7 @@ Testrun testsettingname TEXTFORMAT TEXTINCLUDE -there're +Threadpool Timeline todo tokenizer diff --git a/src/AppInstallerCLICore/Commands/COMInstallCommand.h b/src/AppInstallerCLICore/Commands/COMInstallCommand.h index f454f4e5b1f..b2d50c410bc 100644 --- a/src/AppInstallerCLICore/Commands/COMInstallCommand.h +++ b/src/AppInstallerCLICore/Commands/COMInstallCommand.h @@ -8,7 +8,8 @@ namespace AppInstaller::CLI // IMPORTANT: To use this command, the caller should have already retrieved the package manifest (GetManifest()) and added it to the Context Data struct COMDownloadCommand final : public Command { - COMDownloadCommand(std::string_view parent) : Command("download", parent) {} + constexpr static std::string_view CommandName = "download"sv; + COMDownloadCommand(std::string_view parent) : Command(CommandName, parent) {} protected: void ExecuteInternal(Execution::Context& context) const override; @@ -17,7 +18,8 @@ namespace AppInstaller::CLI // IMPORTANT: To use this command, the caller should have already retrieved the package manifest (GetManifest()) and added it to the Context Data struct COMInstallCommand final : public Command { - COMInstallCommand(std::string_view parent) : Command("install", parent) {} + constexpr static std::string_view CommandName = "install"sv; + COMInstallCommand(std::string_view parent) : Command(CommandName, parent) {} protected: void ExecuteInternal(Execution::Context& context) const override; diff --git a/src/AppInstallerCLICore/ContextOrchestrator.cpp b/src/AppInstallerCLICore/ContextOrchestrator.cpp index ccc6e35b95b..ca886259978 100644 --- a/src/AppInstallerCLICore/ContextOrchestrator.cpp +++ b/src/AppInstallerCLICore/ContextOrchestrator.cpp @@ -10,6 +10,21 @@ namespace AppInstaller::CLI::Execution { + namespace + { + // Callback function used by worker threads in the queue. + // context must be a pointer to a queue item. + void CALLBACK OrchestratorQueueWorkCallback(PTP_CALLBACK_INSTANCE, PVOID context, PTP_WORK) + { + auto queueItem = reinterpret_cast(context); + auto queue = queueItem->GetCurrentQueue(); + if (queue) + { + queue->RunItem(queueItem->GetId()); + } + } + } + ContextOrchestrator& ContextOrchestrator::Instance() { static ContextOrchestrator s_instance; @@ -21,90 +36,195 @@ namespace AppInstaller::CLI::Execution ProgressCallback progress; m_installingWriteableSource = Repository::Source(Repository::PredefinedSource::Installing); m_installingWriteableSource.Open(progress); + + // Decide how many threads to use for each command. + // We always allow only one install at a time. + // For download, if we can find the number of supported concurrent threads, + // use that as the maximum (up to 3); otherwise use a single thread. + const auto supportedConcurrentThreads = std::thread::hardware_concurrency(); + const UINT32 maxDownloadThreads = 3; + const UINT32 installThreads = 1; + const UINT32 downloadThreads = std::min(supportedConcurrentThreads ? supportedConcurrentThreads - 1 : 1, maxDownloadThreads); + + AddCommandQueue(COMDownloadCommand::CommandName, downloadThreads); + AddCommandQueue(COMInstallCommand::CommandName, installThreads); } - _Requires_lock_held_(m_queueLock) - std::deque>::iterator ContextOrchestrator::FindIteratorById(const OrchestratorQueueItemId& comparisonQueueItemId) + void ContextOrchestrator::AddCommandQueue(std::string_view commandName, UINT32 allowedThreads) { - return std::find_if(m_queueItems.begin(), m_queueItems.end(), [&comparisonQueueItemId](const std::shared_ptr& item) {return (item->GetId().IsSame(comparisonQueueItemId)); }); - + m_commandQueues.emplace(commandName, std::make_unique(commandName, allowedThreads)); } + _Requires_lock_held_(m_queueLock) std::shared_ptr ContextOrchestrator::FindById(const OrchestratorQueueItemId& comparisonQueueItemId) { - auto itr = FindIteratorById(comparisonQueueItemId); - if (itr != m_queueItems.end()) + for (const auto& queue : m_commandQueues) { - return *itr; + auto item = queue.second->FindById(comparisonQueueItemId); + if (item) + { + return item; + } } + return {}; } - - void ContextOrchestrator::EnqueueItem(std::shared_ptr item) + + void ContextOrchestrator::EnqueueAndRunItem(std::shared_ptr item) { - { - std::lock_guard lockQueue{ m_queueLock }; + std::lock_guard lockQueue{ m_queueLock }; + if (item->IsOnFirstCommand()) + { THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING), FindById(item->GetId())); - m_queueItems.push_back(item); } - // Add the package to the Installing source so that it can be queried using the Source interface. - const auto& manifest = item->GetContext().Get(); - m_installingWriteableSource.AddPackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version }); + m_commandQueues.at(std::string(item->GetNextCommand().Name()))->EnqueueAndRunItem(item); + } + void ContextOrchestrator::RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state) + { + std::lock_guard lockQueue{ m_queueLock }; + for (const auto& queue : m_commandQueues) { - std::lock_guard lockQueue{ m_queueLock }; - item->SetState(OrchestratorQueueItemState::Queued); + if (queue.second->RemoveItemInState(item, state, true)) + { + return; + } } } - void ContextOrchestrator::RequeueItem(OrchestratorQueueItem& item) + void ContextOrchestrator::CancelQueueItem(const OrchestratorQueueItem& item) { - std::lock_guard lockQueue{ m_queueLock }; + // Always cancel the item, even if it isn't running yet, to get the terminationHR set correctly. + item.GetContext().Cancel(false, true); - item.SetState(OrchestratorQueueItemState::Queued); + RemoveItemInState(item, OrchestratorQueueItemState::Queued); } - void ContextOrchestrator::EnqueueAndRunItem(std::shared_ptr item) + std::shared_ptr ContextOrchestrator::GetQueueItem(const OrchestratorQueueItemId& queueItemId) { - EnqueueItem(item); + std::lock_guard lock{ m_queueLock }; - std::thread runnerThread(&ContextOrchestrator::RunItems, this); - runnerThread.detach(); + return FindById(queueItemId); } - std::shared_ptr ContextOrchestrator::GetNextItem() + void ContextOrchestrator::AddItemManifestToInstallingSource(const OrchestratorQueueItem& queueItem) { - std::lock_guard lockQueue{ m_queueLock }; + const auto& manifest = queueItem.GetContext().Get(); + m_installingWriteableSource.AddPackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version }); + } + + void ContextOrchestrator::RemoveItemManifestFromInstallingSource(const OrchestratorQueueItem& queueItem) + { + const auto& manifest = queueItem.GetContext().Get(); + m_installingWriteableSource.RemovePackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version }); + } - if (m_queueItems.empty()) + _Requires_lock_held_(m_queueLock) + std::deque>::iterator OrchestratorQueue::FindIteratorById(const OrchestratorQueueItemId& comparisonQueueItemId) + { + return std::find_if(m_queueItems.begin(), m_queueItems.end(), [&comparisonQueueItemId](const std::shared_ptr& item) {return (item->GetId().IsSame(comparisonQueueItemId)); }); + } + + _Requires_lock_held_(m_queueLock) + std::shared_ptr OrchestratorQueue::FindById(const OrchestratorQueueItemId& comparisonQueueItemId) + { + auto itr = FindIteratorById(comparisonQueueItemId); + if (itr != m_queueItems.end()) { - return {}; + return *itr; } - std::shared_ptr item = m_queueItems.front(); + return {}; + } + + void OrchestratorQueue::EnqueueItem(std::shared_ptr item) + { + { + std::lock_guard lockQueue{ m_queueLock }; + m_queueItems.push_back(item); + } - // Check if item can be dequeued. - // Since only one item can be installed at a time currently the logic is very simple, - // and can just check if the first item is ready to run. This logic will need to become - // more complicated if multiple operation types (e.g. Download & Install) are added that can - // run simultaneously. - if (item->GetState() != OrchestratorQueueItemState::Queued) + // Add the package to the Installing source so that it can be queried using the Source interface. + // Only do this the first time the item is queued. + if (item->IsOnFirstCommand()) { - return {}; + ContextOrchestrator::Instance().AddItemManifestToInstallingSource(*item); } - // Running state must be set inside the queueLock so that multiple threads don't try to run the same item. - item->SetState(OrchestratorQueueItemState::Running); - return item; + { + std::lock_guard lockQueue{ m_queueLock }; + item->SetState(OrchestratorQueueItemState::Queued); + } + } + + OrchestratorQueue::OrchestratorQueue(std::string_view commandName, UINT32 allowedThreads) : + m_commandName(commandName), m_allowedThreads(allowedThreads) + { + m_threadPool.reset(CreateThreadpool(nullptr)); + THROW_LAST_ERROR_IF_NULL(m_threadPool); + m_threadPoolCleanupGroup.reset(CreateThreadpoolCleanupGroup()); + THROW_LAST_ERROR_IF_NULL(m_threadPoolCleanupGroup); + InitializeThreadpoolEnvironment(&m_threadPoolCallbackEnviron); + SetThreadpoolCallbackPool(&m_threadPoolCallbackEnviron, m_threadPool.get()); + SetThreadpoolCallbackCleanupGroup(&m_threadPoolCallbackEnviron, m_threadPoolCleanupGroup.get(), nullptr); + + THROW_LAST_ERROR_IF(!SetThreadpoolThreadMinimum(m_threadPool.get(), 1)); + SetThreadpoolThreadMaximum(m_threadPool.get(), m_allowedThreads); + } + + OrchestratorQueue::~OrchestratorQueue() + { + CloseThreadpoolCleanupGroupMembers(m_threadPoolCleanupGroup.get(), false, nullptr); + } + + void OrchestratorQueue::EnqueueAndRunItem(std::shared_ptr item) + { + EnqueueItem(item); + + item->SetCurrentQueue(this); + auto work = CreateThreadpoolWork(OrchestratorQueueWorkCallback, item.get(), &m_threadPoolCallbackEnviron); + SubmitThreadpoolWork(work); } - void ContextOrchestrator::RunItems() + void OrchestratorQueue::RunItem(const OrchestratorQueueItemId& itemId) { - std::shared_ptr item = GetNextItem(); - while(item != nullptr) + try { + std::shared_ptr item; + bool isCancelled = false; + + // Try to find the item in the queue. + { + std::lock_guard lockQueue{ m_queueLock }; + item = FindById(itemId); + + if (!item) + { + // Item should be in the queue; this shouldn't happen. + return; + } + + // Only run if the item is queued and not cancelled. + if (item->GetState() == OrchestratorQueueItemState::Queued) + { + // Mark it as running so that it cannot be cancelled by other threads. + item->SetState(OrchestratorQueueItemState::Running); + } + else if (item->GetState() == OrchestratorQueueItemState::Cancelled) + { + isCancelled = true; + } + } + + if (isCancelled) + { + // Do this separate from above block as the Remove function needs to manage the lock. + RemoveItemInState(*item, OrchestratorQueueItemState::Cancelled, true); + } + + // Get the item's command and execute it. HRESULT terminationHR = S_OK; try { @@ -133,21 +253,24 @@ namespace AppInstaller::CLI::Execution if (FAILED(terminationHR) || item->IsComplete()) { - RemoveItemInState(*item, OrchestratorQueueItemState::Running); + RemoveItemInState(*item, OrchestratorQueueItemState::Running, true); } else { - RequeueItem(*item); + // Remove item from this queue and add it to the queue for the next command. + RemoveItemInState(*item, OrchestratorQueueItemState::Running, false); + ContextOrchestrator::Instance().EnqueueAndRunItem(item); } - - item = GetNextItem(); + } + catch (...) + { } } - void ContextOrchestrator::RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state) + bool OrchestratorQueue::RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state, bool isGlobalRemove) { // OrchestratorQueueItemState::Running items should only be removed by the thread that ran the item. - // Queued items can be removed by any thread. + // Queued items can be removed by any thread. // NotQueued items should not be removed since, if found in the queue, they are in the process of being queued by another thread. bool foundItem = false; @@ -159,32 +282,29 @@ namespace AppInstaller::CLI::Execution if (itr != m_queueItems.end() && (*itr)->GetState() == state) { foundItem = true; - m_queueItems.erase(itr); + + // The item must only be removed from the queue by the thread that runs + // it, because the callback uses it. If any other thread tries to remove + // it, we simply mark it as cancelled. + if (state == OrchestratorQueueItemState::Running || state == OrchestratorQueueItemState::Cancelled) + { + (*itr)->SetCurrentQueue(nullptr); + m_queueItems.erase(itr); + } + else if (state == OrchestratorQueueItemState::Queued) + { + (*itr)->SetState(OrchestratorQueueItemState::Cancelled); + } } } - if (foundItem) + if (foundItem && isGlobalRemove) { - const auto& manifest = item.GetContext().Get(); - m_installingWriteableSource.RemovePackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version }); - + ContextOrchestrator::Instance().RemoveItemManifestFromInstallingSource(item); item.GetCompletedEvent().SetEvent(); } - } - void ContextOrchestrator::CancelQueueItem(const OrchestratorQueueItem& item) - { - // Always cancel the item, even if it isn't running yet, to get the terminationHR set correctly. - item.GetContext().Cancel(false, true); - - RemoveItemInState(item, OrchestratorQueueItemState::Queued); - } - - std::shared_ptr ContextOrchestrator::GetQueueItem(const OrchestratorQueueItemId& queueItemId) - { - std::lock_guard lock{ m_queueLock }; - - return FindById(queueItemId); + return foundItem; } bool OrchestratorQueueItemId::IsSame(const OrchestratorQueueItemId& comparedId) const @@ -200,5 +320,4 @@ namespace AppInstaller::CLI::Execution item->AddCommand(std::make_unique<::AppInstaller::CLI::COMInstallCommand>(RootCommand::CommandName)); return item; } - } diff --git a/src/AppInstallerCLICore/ContextOrchestrator.h b/src/AppInstallerCLICore/ContextOrchestrator.h index cb18b34f218..0aaadc04910 100644 --- a/src/AppInstallerCLICore/ContextOrchestrator.h +++ b/src/AppInstallerCLICore/ContextOrchestrator.h @@ -16,9 +16,14 @@ namespace AppInstaller::CLI::Execution { enum class OrchestratorQueueItemState { + // Created but not yet queued NotQueued, + // Queued and waiting to be run Queued, - Running + // Running in the thread pool + Running, + // Cancelled before it was run; will be deleted when we try to run it + Cancelled }; struct OrchestratorQueueItemId @@ -33,29 +38,43 @@ namespace AppInstaller::CLI::Execution std::wstring m_sourceId; }; + struct OrchestratorQueue; + struct OrchestratorQueueItem { OrchestratorQueueItem(OrchestratorQueueItemId id, std::unique_ptr context) : m_id(std::move(id)), m_context(std::move(context)) {} OrchestratorQueueItemState GetState() const { return m_state; } void SetState(OrchestratorQueueItemState state) { m_state = state; } + + OrchestratorQueue* GetCurrentQueue() const { return m_currentQueue; } + void SetCurrentQueue(OrchestratorQueue* currentQueue) { m_currentQueue = currentQueue; } + COMContext& GetContext() const { return *m_context; } const wil::unique_event& GetCompletedEvent() const { return m_completedEvent; } const OrchestratorQueueItemId& GetId() const { return m_id; } + void AddCommand(std::unique_ptr command) { m_commands.push_back(std::move(command)); } + const Command& GetNextCommand() const { return *m_commands.front(); } std::unique_ptr PopNextCommand() { + m_isOnFirstCommand = false; std::unique_ptr command = std::move(m_commands.front()); m_commands.pop_front(); return command; } + + bool IsOnFirstCommand() const { return m_isOnFirstCommand; } bool IsComplete() const { return m_commands.empty(); } + private: OrchestratorQueueItemState m_state = OrchestratorQueueItemState::NotQueued; std::unique_ptr m_context; wil::unique_event m_completedEvent{ wil::EventOptions::ManualReset }; OrchestratorQueueItemId m_id; std::deque> m_commands; + bool m_isOnFirstCommand = true; + OrchestratorQueue* m_currentQueue = nullptr; }; struct OrchestratorQueueItemFactory @@ -73,20 +92,68 @@ namespace AppInstaller::CLI::Execution std::shared_ptr GetQueueItem(const OrchestratorQueueItemId& queueItemId); + void AddItemManifestToInstallingSource(const OrchestratorQueueItem& queueItem); + void RemoveItemManifestFromInstallingSource(const OrchestratorQueueItem& queueItem); + private: std::mutex m_queueLock; - void RunItems(); - std::shared_ptr GetNextItem(); - void EnqueueItem(std::shared_ptr item); - void RequeueItem(OrchestratorQueueItem& item); + void AddCommandQueue(std::string_view commandName, UINT32 allowedThreads); void RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state); - _Requires_lock_held_(m_queueLock) - std::deque>::iterator FindIteratorById(const OrchestratorQueueItemId& queueItemId); _Requires_lock_held_(m_queueLock) std::shared_ptr FindById(const OrchestratorQueueItemId& queueItemId); Repository::Source m_installingWriteableSource; + std::map> m_commandQueues; + }; + + // One of the queues used by the orchestrator. + // All items in the queue execute the same command. + // The queue allows multiple items to run at the same time, up to a limit. + struct OrchestratorQueue + { + OrchestratorQueue(std::string_view commandName, UINT32 allowedThreads); + ~OrchestratorQueue(); + + // Name of the command this queue can execute + std::string_view CommandName() const { return m_commandName; } + + // Enqueues an item to be run when there are threads available. + void EnqueueAndRunItem(std::shared_ptr item); + + // Removes an item by id, provided that it is in the given state. + // Returns true if an item was removed. + // The item can be removed globally from the orchestrator, or from just this queue. + bool RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state, bool isGlobalRemove); + + // Finds an item by id, if it is in the queue. + _Requires_lock_held_(m_queueLock) + std::shared_ptr FindById(const OrchestratorQueueItemId& queueItemId); + + // Runs a single item from the queue. + void RunItem(const OrchestratorQueueItemId& itemId); + + private: + // Enqueues an item. + void EnqueueItem(std::shared_ptr item); + + _Requires_lock_held_(m_queueLock) + std::deque>::iterator FindIteratorById(const OrchestratorQueueItemId& comparisonQueueItemId); + + std::string_view m_commandName; + + // Number of threads allowed to run items in this queue. + const UINT32 m_allowedThreads; + + // Thread pool for this queue, and associated objects. + // All work items will be added to the callback environment, and the cleanup group + // will manage their closing. + // See https://docs.microsoft.com/windows/win32/procthread/using-the-thread-pool-functions + TP_CALLBACK_ENVIRON m_threadPoolCallbackEnviron; + wil::unique_any m_threadPool; + wil::unique_any m_threadPoolCleanupGroup; + + std::mutex m_queueLock; std::deque> m_queueItems; }; } diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp index 8b26adb99e2..fe6d602d4e4 100644 --- a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp +++ b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp @@ -1039,7 +1039,7 @@ namespace AppInstaller::CLI::Workflow // If we cannot find a package using PackageFamilyName or ProductId, try manifest Id and Name pair SearchRequest searchRequest; searchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::Id, MatchType::CaseInsensitive, manifest.Id)); - // In case there're same Ids from different sources, filter the result using package name + // In case there are same Ids from different sources, filter the result using package name searchRequest.Filters.emplace_back(PackageMatchFilter(PackageMatchField::Name, MatchType::CaseInsensitive, manifest.DefaultLocalization.Get())); context.Add(source.Search(searchRequest)); diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp index caff4957f41..ef19e9c73cb 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp @@ -151,6 +151,7 @@ namespace AppInstaller::Repository::Microsoft SQLiteIndex::IdType SQLiteIndex::AddManifestInternal(const Manifest::Manifest& manifest, const std::optional& relativePath) { + std::lock_guard lockInterface{ *m_interfaceLock }; AICLI_LOG(Repo, Verbose, << "Adding manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath.value_or("") << "]"); SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_addmanifest"); @@ -184,6 +185,7 @@ namespace AppInstaller::Repository::Microsoft bool SQLiteIndex::UpdateManifestInternal(const Manifest::Manifest& manifest, const std::optional& relativePath) { + std::lock_guard lockInterface{ *m_interfaceLock }; AICLI_LOG(Repo, Verbose, << "Updating manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath.value_or("") << "]"); SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_updatemanifest"); @@ -216,6 +218,7 @@ namespace AppInstaller::Repository::Microsoft void SQLiteIndex::RemoveManifest(const Manifest::Manifest& manifest) { + std::lock_guard lockInterface{ *m_interfaceLock }; SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_removemanifest"); m_interface->RemoveManifest(m_dbconn, manifest); @@ -238,6 +241,7 @@ namespace AppInstaller::Repository::Microsoft void SQLiteIndex::PrepareForPackaging() { + std::lock_guard lockInterface{ *m_interfaceLock }; AICLI_LOG(Repo, Info, << "Preparing index for packaging"); m_interface->PrepareForPackaging(m_dbconn); @@ -245,6 +249,7 @@ namespace AppInstaller::Repository::Microsoft bool SQLiteIndex::CheckConsistency(bool log) const { + std::lock_guard lockInterface{ *m_interfaceLock }; AICLI_LOG(Repo, Info, << "Checking index consistency..."); bool result = m_interface->CheckConsistency(m_dbconn, log); @@ -256,6 +261,7 @@ namespace AppInstaller::Repository::Microsoft Schema::ISQLiteIndex::SearchResult SQLiteIndex::Search(const SearchRequest& request) const { + std::lock_guard lockInterface{ *m_interfaceLock }; AICLI_LOG(Repo, Verbose, << "Performing search: " << request.ToString()); return m_interface->Search(m_dbconn, request); @@ -263,16 +269,19 @@ namespace AppInstaller::Repository::Microsoft std::optional SQLiteIndex::GetPropertyByManifestId(IdType manifestId, PackageVersionProperty property) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->GetPropertyByManifestId(m_dbconn, manifestId, property); } std::vector SQLiteIndex::GetMultiPropertyByManifestId(IdType manifestId, PackageVersionMultiProperty property) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->GetMultiPropertyByManifestId(m_dbconn, manifestId, property); } std::optional SQLiteIndex::GetManifestIdByKey(IdType id, std::string_view version, std::string_view channel) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->GetManifestIdByKey(m_dbconn, id, version, channel); } @@ -283,21 +292,25 @@ namespace AppInstaller::Repository::Microsoft std::vector SQLiteIndex::GetVersionKeysById(IdType id) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->GetVersionKeysById(m_dbconn, id); } SQLiteIndex::MetadataResult SQLiteIndex::GetMetadataByManifestId(SQLite::rowid_t manifestId) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->GetMetadataByManifestId(m_dbconn, manifestId); } void SQLiteIndex::SetMetadataByManifestId(IdType manifestId, PackageVersionMetadata metadata, std::string_view value) { + std::lock_guard lockInterface{ *m_interfaceLock }; m_interface->SetMetadataByManifestId(m_dbconn, manifestId, metadata, value); } Utility::NormalizedName SQLiteIndex::NormalizeName(std::string_view name, std::string_view publisher) const { + std::lock_guard lockInterface{ *m_interfaceLock }; return m_interface->NormalizeName(name, publisher); } diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h index 894f54fe94e..a19fb5b6e5c 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h @@ -163,5 +163,6 @@ namespace AppInstaller::Repository::Microsoft SQLite::Connection m_dbconn; Schema::Version m_version; std::unique_ptr m_interface; + std::unique_ptr m_interfaceLock = std::make_unique(); }; }