diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
index 580cb0be4b..e34f3bc6de 100644
--- a/.github/actions/spelling/expect.txt
+++ b/.github/actions/spelling/expect.txt
@@ -363,9 +363,14 @@ thiscouldbeapc
threehundred
Tlg
tombstoned
+TOptions
tpl
+TProgress
transitioning
+TResult
trimstart
+TState
+TStatus
UCase
ucasemap
UChars
diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj
index c2445f5371..4774f19379 100644
--- a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj
+++ b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj
@@ -241,7 +241,7 @@
-
+
@@ -293,7 +293,7 @@
-
+
diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters
index 7201125793..bf7879a49e 100644
--- a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters
+++ b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters
@@ -158,7 +158,7 @@
Workflows
-
+
Commands
@@ -301,7 +301,7 @@
Source Files
-
+
Commands
diff --git a/src/AppInstallerCLICore/Commands/COMInstallCommand.cpp b/src/AppInstallerCLICore/Commands/COMCommand.cpp
similarity index 76%
rename from src/AppInstallerCLICore/Commands/COMInstallCommand.cpp
rename to src/AppInstallerCLICore/Commands/COMCommand.cpp
index 57a4fc9bc4..8eabe18dca 100644
--- a/src/AppInstallerCLICore/Commands/COMInstallCommand.cpp
+++ b/src/AppInstallerCLICore/Commands/COMCommand.cpp
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
-#include "COMInstallCommand.h"
+#include "COMCommand.h"
#include "Workflows/DownloadFlow.h"
#include "Workflows/InstallFlow.h"
+#include "Workflows/UninstallFlow.h"
#include "Workflows/WorkflowBase.h"
using namespace AppInstaller::CLI::Execution;
@@ -30,4 +31,11 @@ namespace AppInstaller::CLI
Workflow::ReverifyInstallerHash <<
Workflow::InstallPackageInstaller;
}
+
+ // IMPORTANT: To use this command, the caller should have already retrieved the InstalledPackageVersion and added it to the Context Data
+ void COMUninstallCommand::ExecuteInternal(Execution::Context& context) const
+ {
+ context <<
+ Workflow::UninstallSinglePackage;
+ }
}
diff --git a/src/AppInstallerCLICore/Commands/COMInstallCommand.h b/src/AppInstallerCLICore/Commands/COMCommand.h
similarity index 69%
rename from src/AppInstallerCLICore/Commands/COMInstallCommand.h
rename to src/AppInstallerCLICore/Commands/COMCommand.h
index b2d50c410b..4ecedae490 100644
--- a/src/AppInstallerCLICore/Commands/COMInstallCommand.h
+++ b/src/AppInstallerCLICore/Commands/COMCommand.h
@@ -24,4 +24,14 @@ namespace AppInstaller::CLI
protected:
void ExecuteInternal(Execution::Context& context) const override;
};
+
+ // IMPORTANT: To use this command, the caller should have already retrieved the InstalledPackageVersion and added it to the Context Data
+ struct COMUninstallCommand final : public Command
+ {
+ constexpr static std::string_view CommandName = "uninstall"sv;
+ COMUninstallCommand(std::string_view parent) : Command(CommandName, parent) {}
+
+ protected:
+ void ExecuteInternal(Execution::Context& context) const override;
+ };
}
diff --git a/src/AppInstallerCLICore/Commands/UninstallCommand.cpp b/src/AppInstallerCLICore/Commands/UninstallCommand.cpp
index 18eddd30e7..1f6b3264f6 100644
--- a/src/AppInstallerCLICore/Commands/UninstallCommand.cpp
+++ b/src/AppInstallerCLICore/Commands/UninstallCommand.cpp
@@ -3,10 +3,8 @@
#include "pch.h"
#include "UninstallCommand.h"
#include "Workflows/UninstallFlow.h"
-#include "Workflows/InstallFlow.h"
#include "Workflows/CompletionFlow.h"
#include "Workflows/WorkflowBase.h"
-#include "Workflows/DependenciesFlow.h"
#include "Resources.h"
using AppInstaller::CLI::Execution::Args;
@@ -130,13 +128,6 @@ namespace AppInstaller::CLI
}
context <<
- Workflow::GetInstalledPackageVersion <<
- Workflow::GetUninstallInfo <<
- Workflow::GetDependenciesInfoForUninstall <<
- Workflow::ReportDependencies(Resource::String::UninstallCommandReportDependencies) <<
- Workflow::ReportExecutionStage(ExecutionStage::Execution) <<
- Workflow::ExecuteUninstaller <<
- Workflow::ReportExecutionStage(ExecutionStage::PostExecution) <<
- Workflow::RecordUninstall;
+ Workflow::UninstallSinglePackage;
}
}
\ No newline at end of file
diff --git a/src/AppInstallerCLICore/ContextOrchestrator.cpp b/src/AppInstallerCLICore/ContextOrchestrator.cpp
index 2cc38a8b42..8ac5baef8c 100644
--- a/src/AppInstallerCLICore/ContextOrchestrator.cpp
+++ b/src/AppInstallerCLICore/ContextOrchestrator.cpp
@@ -4,7 +4,7 @@
#include "ExecutionContext.h"
#include "ContextOrchestrator.h"
#include "COMContext.h"
-#include "Commands/COMInstallCommand.h"
+#include "Commands/COMCommand.h"
#include "winget/UserSettings.h"
#include
@@ -12,6 +12,9 @@ namespace AppInstaller::CLI::Execution
{
namespace
{
+ // Operation command queue used by install and uninstall commands.
+ constexpr static std::string_view OperationCommandQueueName = "operation"sv;
+
// 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)
@@ -23,6 +26,17 @@ namespace AppInstaller::CLI::Execution
queue->RunItem(queueItem->GetId());
}
}
+
+ // Get command queue name based on command name.
+ std::string_view GetCommandQueueName(std::string_view commandName)
+ {
+ if (commandName == COMInstallCommand::CommandName || commandName == COMUninstallCommand::CommandName)
+ {
+ return OperationCommandQueueName;
+ }
+
+ return commandName;
+ }
}
ContextOrchestrator& ContextOrchestrator::Instance()
@@ -43,11 +57,11 @@ namespace AppInstaller::CLI::Execution
// 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 operationThreads = 1;
const UINT32 downloadThreads = std::min(supportedConcurrentThreads ? supportedConcurrentThreads - 1 : 1, maxDownloadThreads);
AddCommandQueue(COMDownloadCommand::CommandName, downloadThreads);
- AddCommandQueue(COMInstallCommand::CommandName, installThreads);
+ AddCommandQueue(OperationCommandQueueName, operationThreads);
}
void ContextOrchestrator::AddCommandQueue(std::string_view commandName, UINT32 allowedThreads)
@@ -79,7 +93,8 @@ namespace AppInstaller::CLI::Execution
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING), FindById(item->GetId()));
}
- m_commandQueues.at(std::string(item->GetNextCommand().Name()))->EnqueueAndRunItem(item);
+ std::string commandQueueName{ GetCommandQueueName(item->GetNextCommand().Name()) };
+ m_commandQueues.at(commandQueueName)->EnqueueAndRunItem(item);
}
void ContextOrchestrator::RemoveItemInState(const OrchestratorQueueItem& item, OrchestratorQueueItemState state)
@@ -111,14 +126,20 @@ namespace AppInstaller::CLI::Execution
void ContextOrchestrator::AddItemManifestToInstallingSource(const OrchestratorQueueItem& queueItem)
{
- const auto& manifest = queueItem.GetContext().Get();
- m_installingWriteableSource.AddPackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version });
+ if (queueItem.IsApplicableForInstallingSource())
+ {
+ 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 (queueItem.IsApplicableForInstallingSource())
+ {
+ const auto& manifest = queueItem.GetContext().Get();
+ m_installingWriteableSource.RemovePackageVersion(manifest, std::filesystem::path{ manifest.Id + '.' + manifest.Version });
+ }
}
_Requires_lock_held_(m_queueLock)
@@ -313,11 +334,24 @@ namespace AppInstaller::CLI::Execution
(GetSourceId() == comparedId.GetSourceId()));
}
- std::unique_ptr OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context)
+ std::unique_ptr OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context, bool isUpgrade)
{
- std::unique_ptr item = std::make_unique(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context));
+ std::unique_ptr item = std::make_unique(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context), isUpgrade ? PackageOperationType::Upgrade : PackageOperationType::Install);
item->AddCommand(std::make_unique<::AppInstaller::CLI::COMDownloadCommand>(RootCommand::CommandName));
item->AddCommand(std::make_unique<::AppInstaller::CLI::COMInstallCommand>(RootCommand::CommandName));
return item;
}
+
+ std::unique_ptr OrchestratorQueueItemFactory::CreateItemForUninstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context)
+ {
+ std::unique_ptr item = std::make_unique(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context), PackageOperationType::Uninstall);
+ item->AddCommand(std::make_unique<::AppInstaller::CLI::COMUninstallCommand>(RootCommand::CommandName));
+ return item;
+ }
+
+ std::unique_ptr OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring packageId, std::wstring sourceId, std::unique_ptr context)
+ {
+ std::unique_ptr item = std::make_unique(OrchestratorQueueItemId(std::move(packageId), std::move(sourceId)), std::move(context), PackageOperationType::None);
+ return item;
+ }
}
diff --git a/src/AppInstallerCLICore/ContextOrchestrator.h b/src/AppInstallerCLICore/ContextOrchestrator.h
index 0aaadc0491..f4a2357a9c 100644
--- a/src/AppInstallerCLICore/ContextOrchestrator.h
+++ b/src/AppInstallerCLICore/ContextOrchestrator.h
@@ -40,9 +40,18 @@ namespace AppInstaller::CLI::Execution
struct OrchestratorQueue;
+ enum class PackageOperationType
+ {
+ None,
+ Install,
+ Upgrade,
+ Uninstall,
+ };
+
struct OrchestratorQueueItem
{
- OrchestratorQueueItem(OrchestratorQueueItemId id, std::unique_ptr context) : m_id(std::move(id)), m_context(std::move(context)) {}
+ OrchestratorQueueItem(OrchestratorQueueItemId id, std::unique_ptr context, PackageOperationType operationType) :
+ m_id(std::move(id)), m_context(std::move(context)), m_operationType(operationType) {}
OrchestratorQueueItemState GetState() const { return m_state; }
void SetState(OrchestratorQueueItemState state) { m_state = state; }
@@ -66,6 +75,8 @@ namespace AppInstaller::CLI::Execution
bool IsOnFirstCommand() const { return m_isOnFirstCommand; }
bool IsComplete() const { return m_commands.empty(); }
+ bool IsApplicableForInstallingSource() const { return m_operationType == PackageOperationType::Install || m_operationType == PackageOperationType::Upgrade; }
+ PackageOperationType GetPackageOperationType() const { return m_operationType; }
private:
OrchestratorQueueItemState m_state = OrchestratorQueueItemState::NotQueued;
@@ -75,11 +86,17 @@ namespace AppInstaller::CLI::Execution
std::deque> m_commands;
bool m_isOnFirstCommand = true;
OrchestratorQueue* m_currentQueue = nullptr;
+ PackageOperationType m_operationType = PackageOperationType::None;
};
struct OrchestratorQueueItemFactory
{
- static std::unique_ptr CreateItemForInstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context);
+ // Create queue item for install/upgrade
+ static std::unique_ptr CreateItemForInstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context, bool isUpgrade);
+ // Create queue item for uninstall
+ static std::unique_ptr CreateItemForUninstall(std::wstring packageId, std::wstring sourceId, std::unique_ptr context);
+ // Create queue item for finding existing entry from the orchestrator queue
+ static std::unique_ptr CreateItemForSearch(std::wstring packageId, std::wstring sourceId, std::unique_ptr context);
};
struct ContextOrchestrator
diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h
index d37abc7b12..9e26d2b191 100644
--- a/src/AppInstallerCLICore/ExecutionContextData.h
+++ b/src/AppInstallerCLICore/ExecutionContextData.h
@@ -33,7 +33,7 @@ namespace AppInstaller::CLI::Execution
InstallerPath,
LogPath,
InstallerArgs,
- InstallerReturnCode,
+ OperationReturnCode,
CompletionData,
InstalledPackageVersion,
UninstallString,
@@ -130,7 +130,7 @@ namespace AppInstaller::CLI::Execution
};
template <>
- struct DataMapping
+ struct DataMapping
{
using value_t = DWORD;
};
diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
index ebd5154f42..093d58e485 100644
--- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
+++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
@@ -302,7 +302,7 @@ namespace AppInstaller::CLI::Workflow
}
catch (const wil::ResultException& re)
{
- context.Add(re.GetErrorCode());
+ context.Add(re.GetErrorCode());
context << ReportInstallerResult("MSIX"sv, re.GetErrorCode(), /* isHResult */ true);
return;
}
@@ -319,7 +319,7 @@ namespace AppInstaller::CLI::Workflow
void ReportInstallerResult::operator()(Execution::Context& context) const
{
- DWORD installResult = context.Get();
+ DWORD installResult = context.Get();
const auto& additionalSuccessCodes = context.Get()->InstallerSuccessCodes;
if (installResult != 0 && (std::find(additionalSuccessCodes.begin(), additionalSuccessCodes.end(), installResult) == additionalSuccessCodes.end()))
{
diff --git a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp
index be0fd4e608..38c4021cff 100644
--- a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp
+++ b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp
@@ -49,7 +49,7 @@ namespace AppInstaller::CLI::Workflow
}
else
{
- context.Add(installResult.value());
+ context.Add(installResult.value());
}
}
}
diff --git a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h
index 7aac116148..4516c8b00a 100644
--- a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h
+++ b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h
@@ -8,6 +8,6 @@ namespace AppInstaller::CLI::Workflow
// Ensures that there is an applicable installer.
// Required Args: None
// Inputs: InstallerArgs, Installer, InstallerPath, Manifest
- // Outputs: InstallerReturnCode
+ // Outputs: OperationReturnCode
void DirectMSIInstallImpl(Execution::Context& context);
}
diff --git a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp
index 83ca60a863..c0849a6825 100644
--- a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp
+++ b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp
@@ -202,7 +202,7 @@ namespace AppInstaller::CLI::Workflow
}
else
{
- context.Add(installResult.value());
+ context.Add(installResult.value());
}
}
@@ -253,6 +253,7 @@ namespace AppInstaller::CLI::Workflow
"UninstallString",
uninstallResult.value());
+ context.Add(uninstallResult.value());
context.Reporter.Error() << Resource::String::UninstallFailedWithCode << ' ' << uninstallResult.value() << std::endl;
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED);
}
@@ -293,6 +294,7 @@ namespace AppInstaller::CLI::Workflow
"MsiExec",
uninstallResult.value());
+ context.Add(uninstallResult.value());
context.Reporter.Error() << Resource::String::UninstallFailedWithCode << ' ' << uninstallResult.value() << std::endl;
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED);
}
diff --git a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h
index ff5721e3d4..18c007dfe7 100644
--- a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h
+++ b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h
@@ -14,13 +14,13 @@ namespace AppInstaller::CLI::Workflow
// Install is done through invoking ShellExecute on downloaded installer.
// Required Args: None
// Inputs: Manifest?, InstallerPath, InstallerArgs
- // Outputs: InstallerReturnCode
+ // Outputs: OperationReturnCode
void ShellExecuteInstallImpl(Execution::Context& context);
// Uninstall is done through invoking ShellExecute on uninstall string.
// Required Args: None
// Inputs: UninstallString
- // Outputs: None
+ // Outputs: OperationReturnCode
void ShellExecuteUninstallImpl(Execution::Context& context);
// Removes the MSI
diff --git a/src/AppInstallerCLICore/Workflows/UninstallFlow.cpp b/src/AppInstallerCLICore/Workflows/UninstallFlow.cpp
index e1bdca3140..708753cd50 100644
--- a/src/AppInstallerCLICore/Workflows/UninstallFlow.cpp
+++ b/src/AppInstallerCLICore/Workflows/UninstallFlow.cpp
@@ -3,6 +3,7 @@
#include "pch.h"
#include "UninstallFlow.h"
#include "WorkflowBase.h"
+#include "DependenciesFlow.h"
#include "ShellExecuteInstallerHandler.h"
#include "AppInstallerMsixInfo.h"
@@ -51,6 +52,19 @@ namespace AppInstaller::CLI::Workflow
};
}
+ void UninstallSinglePackage(Execution::Context& context)
+ {
+ context <<
+ Workflow::GetInstalledPackageVersion <<
+ Workflow::GetUninstallInfo <<
+ Workflow::GetDependenciesInfoForUninstall <<
+ Workflow::ReportDependencies(Resource::String::UninstallCommandReportDependencies) <<
+ Workflow::ReportExecutionStage(ExecutionStage::Execution) <<
+ Workflow::ExecuteUninstaller <<
+ Workflow::ReportExecutionStage(ExecutionStage::PostExecution) <<
+ Workflow::RecordUninstall;
+ }
+
void GetUninstallInfo(Execution::Context& context)
{
auto installedPackageVersion = context.Get();
@@ -156,7 +170,16 @@ namespace AppInstaller::CLI::Workflow
}
AICLI_LOG(CLI, Info, << "Removing MSIX package: " << packageFullName.value());
- context.Reporter.ExecuteWithProgress(std::bind(Deployment::RemovePackage, packageFullName.value(), std::placeholders::_1));
+ try
+ {
+ context.Reporter.ExecuteWithProgress(std::bind(Deployment::RemovePackage, packageFullName.value(), std::placeholders::_1));
+ }
+ catch (const wil::ResultException& re)
+ {
+ context.Add(re.GetErrorCode());
+ context.Reporter.Error() << Resource::String::UninstallFailedWithCode << ' ' << re.GetErrorCode() << std::endl;
+ AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED);
+ }
}
context.Reporter.Info() << Resource::String::UninstallFlowUninstallSuccess << std::endl;
diff --git a/src/AppInstallerCLICore/Workflows/UninstallFlow.h b/src/AppInstallerCLICore/Workflows/UninstallFlow.h
index 6db0954cf9..21a12650f0 100644
--- a/src/AppInstallerCLICore/Workflows/UninstallFlow.h
+++ b/src/AppInstallerCLICore/Workflows/UninstallFlow.h
@@ -5,6 +5,13 @@
namespace AppInstaller::CLI::Workflow
{
+ // Uninstalls a single package. This also does the reporting, user interaction, and recording
+ // for single-package uninstallation.
+ // RequiredArgs: None
+ // Inputs: InstalledPackageVersion
+ // Outputs: None
+ void UninstallSinglePackage(Execution::Context& context);
+
// Gets the command string or package family names used to uninstall the package.
// Required Args: None
// Inputs: InstalledPackageVersion
diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest
index b0a3134c61..58a2ff098d 100644
--- a/src/AppInstallerCLIPackage/Package.appxmanifest
+++ b/src/AppInstallerCLIPackage/Package.appxmanifest
@@ -48,6 +48,8 @@
+
+
diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp
index 8edc977151..b2525934ad 100644
--- a/src/AppInstallerCLITests/WorkFlow.cpp
+++ b/src/AppInstallerCLITests/WorkFlow.cpp
@@ -551,7 +551,7 @@ void OverrideForDirectMsi(TestContext& context)
file << context.Get();
file.close();
- context.Add(0);
+ context.Add(0);
} });
}
diff --git a/src/Microsoft.Management.Deployment.Client/Client.UninstallOptions.h b/src/Microsoft.Management.Deployment.Client/Client.UninstallOptions.h
new file mode 100644
index 0000000000..f65e03ed3a
--- /dev/null
+++ b/src/Microsoft.Management.Deployment.Client/Client.UninstallOptions.h
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "UninstallOptions.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::factory_implementation
+{
+ struct UninstallOptions : UninstallOptionsT
+ {
+ auto ActivateInstance() const
+ {
+ return winrt::create_instance(__uuidof(implementation::UninstallOptions), CLSCTX_ALL);
+ }
+ };
+}
diff --git a/src/Microsoft.Management.Deployment.Client/Microsoft.Management.Deployment.Client.vcxproj b/src/Microsoft.Management.Deployment.Client/Microsoft.Management.Deployment.Client.vcxproj
index fc9db158eb..1994278418 100644
--- a/src/Microsoft.Management.Deployment.Client/Microsoft.Management.Deployment.Client.vcxproj
+++ b/src/Microsoft.Management.Deployment.Client/Microsoft.Management.Deployment.Client.vcxproj
@@ -129,6 +129,7 @@
+
@@ -146,6 +147,7 @@
+
diff --git a/src/Microsoft.Management.Deployment.Client/PackageManager.cpp b/src/Microsoft.Management.Deployment.Client/PackageManager.cpp
index 53a1a21ff0..7200a88eef 100644
--- a/src/Microsoft.Management.Deployment.Client/PackageManager.cpp
+++ b/src/Microsoft.Management.Deployment.Client/PackageManager.cpp
@@ -42,4 +42,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
throw hresult_not_implemented();
}
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::UninstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::UninstallOptions)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::GetUninstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo)
+ {
+ throw hresult_not_implemented();
+ }
}
diff --git a/src/Microsoft.Management.Deployment.Client/UninstallOptions.cpp b/src/Microsoft.Management.Deployment.Client/UninstallOptions.cpp
new file mode 100644
index 0000000000..61b99e3e76
--- /dev/null
+++ b/src/Microsoft.Management.Deployment.Client/UninstallOptions.cpp
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#pragma warning( push )
+#pragma warning ( disable : 4467 6388)
+#include
+#include
+#pragma warning( pop )
+#include "UninstallOptions.g.cpp"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ UninstallOptions::UninstallOptions()
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Microsoft::Management::Deployment::PackageVersionId UninstallOptions::PackageVersionId()
+ {
+ throw hresult_not_implemented();
+ }
+ void UninstallOptions::PackageVersionId(winrt::Microsoft::Management::Deployment::PackageVersionId const&)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Microsoft::Management::Deployment::PackageUninstallMode UninstallOptions::PackageUninstallMode()
+ {
+ throw hresult_not_implemented();
+ }
+ void UninstallOptions::PackageUninstallMode(winrt::Microsoft::Management::Deployment::PackageUninstallMode const&)
+ {
+ throw hresult_not_implemented();
+ }
+ hstring UninstallOptions::LogOutputPath()
+ {
+ throw hresult_not_implemented();
+ }
+ void UninstallOptions::LogOutputPath(hstring const&)
+ {
+ throw hresult_not_implemented();
+ }
+ hstring UninstallOptions::CorrelationData()
+ {
+ throw hresult_not_implemented();
+ }
+ void UninstallOptions::CorrelationData(hstring const&)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/CatalogPackage.cpp b/src/Microsoft.Management.Deployment/CatalogPackage.cpp
index 69f5aa38cf..56b1c4404e 100644
--- a/src/Microsoft.Management.Deployment/CatalogPackage.cpp
+++ b/src/Microsoft.Management.Deployment/CatalogPackage.cpp
@@ -96,4 +96,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
return m_package->IsUpdateAvailable();
}
+ std::shared_ptr<::AppInstaller::Repository::IPackage> CatalogPackage::GetRepositoryPackage()
+ {
+ return m_package;
+ }
}
diff --git a/src/Microsoft.Management.Deployment/CatalogPackage.h b/src/Microsoft.Management.Deployment/CatalogPackage.h
index a245b58e84..87a51fe254 100644
--- a/src/Microsoft.Management.Deployment/CatalogPackage.h
+++ b/src/Microsoft.Management.Deployment/CatalogPackage.h
@@ -13,6 +13,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
void Initialize(
::AppInstaller::Repository::Source source,
std::shared_ptr<::AppInstaller::Repository::IPackage> package);
+ std::shared_ptr<::AppInstaller::Repository::IPackage> GetRepositoryPackage();
#endif
hstring Id();
diff --git a/src/Microsoft.Management.Deployment/Converters.cpp b/src/Microsoft.Management.Deployment/Converters.cpp
index 29478b22f8..c45fbd3a1e 100644
--- a/src/Microsoft.Management.Deployment/Converters.cpp
+++ b/src/Microsoft.Management.Deployment/Converters.cpp
@@ -172,83 +172,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return metadataKey;
}
- winrt::Microsoft::Management::Deployment::InstallResultStatus GetInstallResultStatus(::AppInstaller::CLI::Workflow::ExecutionStage executionStage, winrt::hresult hresult)
- {
- winrt::Microsoft::Management::Deployment::InstallResultStatus resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::Ok;
-
- // Map some known hresults to specific statuses, otherwise use the execution stage to determine the status.
- switch (hresult)
- {
- case S_OK:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::Ok;
- break;
- case APPINSTALLER_CLI_ERROR_MSSTORE_BLOCKED_BY_POLICY:
- case APPINSTALLER_CLI_ERROR_MSSTORE_APP_BLOCKED_BY_POLICY:
- case APPINSTALLER_CLI_ERROR_EXPERIMENTAL_FEATURE_DISABLED:
- case APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::BlockedByPolicy;
- break;
- case APPINSTALLER_CLI_ERROR_INVALID_MANIFEST:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::ManifestError;
- break;
- case E_INVALIDARG:
- case APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InvalidOptions;
- break;
- case APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::NoApplicableInstallers;
- break;
- case APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE:
- case APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN:
- case APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::NoApplicableUpgrade;
- break;
- case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX:
- case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED:
- case APPINSTALLER_CLI_ERROR_YAML_INIT_FAILED:
- case APPINSTALLER_CLI_ERROR_YAML_INVALID_MAPPING_KEY:
- case APPINSTALLER_CLI_ERROR_YAML_DUPLICATE_MAPPING_KEY:
- case APPINSTALLER_CLI_ERROR_YAML_INVALID_OPERATION:
- case APPINSTALLER_CLI_ERROR_YAML_DOC_BUILD_FAILED:
- case APPINSTALLER_CLI_ERROR_YAML_INVALID_EMITTER_STATE:
- case APPINSTALLER_CLI_ERROR_YAML_INVALID_DATA:
- case APPINSTALLER_CLI_ERROR_LIBYAML_ERROR:
- case APPINSTALLER_CLI_ERROR_INTERNAL_ERROR:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InternalError;
- break;
- default:
- switch (executionStage)
- {
- case ::AppInstaller::CLI::Workflow::ExecutionStage::Initial:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InternalError;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::ParseArgs:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InvalidOptions;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::Discovery:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::CatalogError;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::Download:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::DownloadError;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::PreExecution:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InternalError;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::Execution:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InstallError;
- break;
- case ::AppInstaller::CLI::Workflow::ExecutionStage::PostExecution:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InternalError;
- break;
- default:
- resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::InternalError;
- break;
- }
- }
-
- return resultStatus;
- }
-
winrt::Microsoft::Management::Deployment::FindPackagesResultStatus FindPackagesResultStatus(winrt::hresult hresult)
{
winrt::Microsoft::Management::Deployment::FindPackagesResultStatus resultStatus = winrt::Microsoft::Management::Deployment::FindPackagesResultStatus::Ok;
diff --git a/src/Microsoft.Management.Deployment/Converters.h b/src/Microsoft.Management.Deployment/Converters.h
index bda1a927a6..1d81c32ee2 100644
--- a/src/Microsoft.Management.Deployment/Converters.h
+++ b/src/Microsoft.Management.Deployment/Converters.h
@@ -14,8 +14,99 @@ namespace winrt::Microsoft::Management::Deployment::implementation
::AppInstaller::Repository::MatchType GetRepositoryMatchType(winrt::Microsoft::Management::Deployment::PackageFieldMatchOption option);
::AppInstaller::Repository::CompositeSearchBehavior GetRepositoryCompositeSearchBehavior(winrt::Microsoft::Management::Deployment::CompositeSearchBehavior searchBehavior);
::AppInstaller::Repository::PackageVersionMetadata GetRepositoryPackageVersionMetadata(winrt::Microsoft::Management::Deployment::PackageVersionMetadataField packageVersionMetadataField);
- winrt::Microsoft::Management::Deployment::InstallResultStatus GetInstallResultStatus(::AppInstaller::CLI::Workflow::ExecutionStage executionStage, winrt::hresult hresult);
winrt::Microsoft::Management::Deployment::FindPackagesResultStatus FindPackagesResultStatus(winrt::hresult hresult);
std::optional<::AppInstaller::Utility::Architecture> GetUtilityArchitecture(winrt::Windows::System::ProcessorArchitecture architecture);
std::optional GetWindowsSystemProcessorArchitecture(::AppInstaller::Utility::Architecture architecture);
+
+#define WINGET_GET_OPERATION_RESULT_STATUS(_installResultStatus_, _uninstallResultStatus_) \
+ if constexpr (std::is_same_v) \
+ { \
+ resultStatus = TStatus::_installResultStatus_; \
+ } \
+ else if constexpr (std::is_same_v) \
+ { \
+ resultStatus = TStatus::_uninstallResultStatus_; \
+ } \
+
+ template
+ TStatus GetOperationResultStatus(::AppInstaller::CLI::Workflow::ExecutionStage executionStage, winrt::hresult hresult)
+ {
+ TStatus resultStatus = TStatus::Ok;
+
+ // Map some known hresults to specific statuses, otherwise use the execution stage to determine the status.
+ switch (hresult)
+ {
+ case S_OK:
+ resultStatus = TStatus::Ok;
+ break;
+ case APPINSTALLER_CLI_ERROR_MSSTORE_BLOCKED_BY_POLICY:
+ case APPINSTALLER_CLI_ERROR_MSSTORE_APP_BLOCKED_BY_POLICY:
+ case APPINSTALLER_CLI_ERROR_EXPERIMENTAL_FEATURE_DISABLED:
+ case APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY:
+ resultStatus = TStatus::BlockedByPolicy;
+ break;
+ case APPINSTALLER_CLI_ERROR_INVALID_MANIFEST:
+ resultStatus = TStatus::ManifestError;
+ break;
+ case E_INVALIDARG:
+ case APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS:
+ resultStatus = TStatus::InvalidOptions;
+ break;
+ case APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER:
+ WINGET_GET_OPERATION_RESULT_STATUS(NoApplicableInstallers, InternalError);
+ break;
+ case APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE:
+ case APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN:
+ case APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER:
+ WINGET_GET_OPERATION_RESULT_STATUS(NoApplicableUpgrade, InternalError);
+ break;
+ case APPINSTALLER_CLI_ERROR_NO_UNINSTALL_INFO_FOUND:
+ case APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED:
+ WINGET_GET_OPERATION_RESULT_STATUS(InstallError, UninstallError);
+ break;
+ case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX:
+ case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED:
+ case APPINSTALLER_CLI_ERROR_YAML_INIT_FAILED:
+ case APPINSTALLER_CLI_ERROR_YAML_INVALID_MAPPING_KEY:
+ case APPINSTALLER_CLI_ERROR_YAML_DUPLICATE_MAPPING_KEY:
+ case APPINSTALLER_CLI_ERROR_YAML_INVALID_OPERATION:
+ case APPINSTALLER_CLI_ERROR_YAML_DOC_BUILD_FAILED:
+ case APPINSTALLER_CLI_ERROR_YAML_INVALID_EMITTER_STATE:
+ case APPINSTALLER_CLI_ERROR_YAML_INVALID_DATA:
+ case APPINSTALLER_CLI_ERROR_LIBYAML_ERROR:
+ case APPINSTALLER_CLI_ERROR_INTERNAL_ERROR:
+ resultStatus = TStatus::InternalError;
+ break;
+ default:
+ switch (executionStage)
+ {
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::Initial:
+ resultStatus = TStatus::InternalError;
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::ParseArgs:
+ resultStatus = TStatus::InvalidOptions;
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::Discovery:
+ resultStatus = TStatus::CatalogError;
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::Download:
+ WINGET_GET_OPERATION_RESULT_STATUS(DownloadError, InternalError);
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::PreExecution:
+ resultStatus = TStatus::InternalError;
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::Execution:
+ WINGET_GET_OPERATION_RESULT_STATUS(InstallError, UninstallError);
+ break;
+ case ::AppInstaller::CLI::Workflow::ExecutionStage::PostExecution:
+ resultStatus = TStatus::InternalError;
+ break;
+ default:
+ resultStatus = TStatus::InternalError;
+ break;
+ }
+ }
+
+ return resultStatus;
+ }
}
diff --git a/src/Microsoft.Management.Deployment/InstallResult.h b/src/Microsoft.Management.Deployment/InstallResult.h
index 4010cbcbf0..ee09e6045f 100644
--- a/src/Microsoft.Management.Deployment/InstallResult.h
+++ b/src/Microsoft.Management.Deployment/InstallResult.h
@@ -8,7 +8,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
struct InstallResult : InstallResultT
{
InstallResult() = default;
-
+
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
void Initialize(
winrt::Microsoft::Management::Deployment::InstallResultStatus status,
diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
index 675325591d..1345c5a64f 100644
--- a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
+++ b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
@@ -154,6 +154,8 @@
+
+
@@ -177,6 +179,8 @@
Create
+
+
diff --git a/src/Microsoft.Management.Deployment/PackageManager.cpp b/src/Microsoft.Management.Deployment/PackageManager.cpp
index 7bb07ac71e..a4ec730dea 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.cpp
+++ b/src/Microsoft.Management.Deployment/PackageManager.cpp
@@ -9,7 +9,7 @@
#include "Workflows/WorkflowBase.h"
#include
#include
-#include "Commands/COMInstallCommand.h"
+#include "Commands/COMCommand.h"
#include
#include
#pragma warning( push )
@@ -20,7 +20,9 @@
#include "PackageManager.h"
#pragma warning( pop )
#include "PackageManager.g.cpp"
+#include "CatalogPackage.h"
#include "InstallResult.h"
+#include "UninstallResult.h"
#include "PackageCatalogInfo.h"
#include "PackageCatalogReference.h"
#include "PackageVersionInfo.h"
@@ -135,6 +137,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation
context->Add<::AppInstaller::CLI::Execution::Data::Manifest>(std::move(manifest));
context->Add<::AppInstaller::CLI::Execution::Data::PackageVersion>(std::move(internalPackageVersion));
}
+ void AddInstalledVersionToContext(winrt::Microsoft::Management::Deployment::PackageVersionInfo installedVersionInfo, ::AppInstaller::CLI::Execution::Context* context)
+ {
+ winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo* installedVersionInfoImpl = get_self(installedVersionInfo);
+ std::shared_ptr<::AppInstaller::Repository::IPackageVersion> internalInstalledVersion = installedVersionInfoImpl->GetRepositoryPackageVersion();
+ context->Add(internalInstalledVersion);
+ }
winrt::Microsoft::Management::Deployment::PackageCatalogReference PackageManager::CreateCompositePackageCatalog(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions const& options)
{
if (!options)
@@ -159,13 +167,45 @@ namespace winrt::Microsoft::Management::Deployment::implementation
winrt::Microsoft::Management::Deployment::InstallResult GetInstallResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t installerError, winrt::hstring correlationData, bool rebootRequired)
{
- winrt::Microsoft::Management::Deployment::InstallResultStatus installResultStatus = GetInstallResultStatus(executionStage, terminationHR);
+ winrt::Microsoft::Management::Deployment::InstallResultStatus installResultStatus = GetOperationResultStatus(executionStage, terminationHR);
auto installResult = winrt::make_self>();
installResult->Initialize(installResultStatus, terminationHR, installerError, correlationData, rebootRequired);
return *installResult;
}
- std::optional GetProgress(
+ winrt::Microsoft::Management::Deployment::UninstallResult GetUninstallResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t uninstallerError, winrt::hstring correlationData, bool rebootRequired)
+ {
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus uninstallResultStatus = GetOperationResultStatus(executionStage, terminationHR);
+ auto uninstallResult = winrt::make_self>();
+ uninstallResult->Initialize(uninstallResultStatus, terminationHR, uninstallerError, correlationData, rebootRequired);
+ return *uninstallResult;
+ }
+
+ template
+ TResult GetOperationResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t operationError, winrt::hstring correlationData, bool rebootRequired)
+ {
+ if constexpr (std::is_same_v)
+ {
+ return GetInstallResult(executionStage, terminationHR, operationError, correlationData, rebootRequired);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ return GetUninstallResult(executionStage, terminationHR, operationError, correlationData, rebootRequired);
+ }
+ }
+
+#define WINGET_GET_PROGRESS_STATE(_installState_, _uninstallState_) \
+ if constexpr (std::is_same_v) \
+ { \
+ progressState = TState::_installState_; \
+ } \
+ else if constexpr (std::is_same_v) \
+ { \
+ progressState = TState::_uninstallState_; \
+ }
+
+ template
+ std::optional GetProgress(
ReportType reportType,
uint64_t current,
uint64_t maximum,
@@ -173,9 +213,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation
::Workflow::ExecutionStage executionPhase)
{
bool reportProgress = false;
- PackageInstallProgressState progressState = PackageInstallProgressState::Queued;
+ TState progressState = TState::Queued;
double downloadProgress = 0;
- double installProgress = 0;
+ double operationProgress = 0;
uint64_t downloadBytesDownloaded = 0;
uint64_t downloadBytesRequired = 0;
switch (executionPhase)
@@ -186,46 +226,49 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// We already reported queued progress up front.
break;
case ::Workflow::ExecutionStage::Download:
- progressState = PackageInstallProgressState::Downloading;
- if (reportType == ReportType::BeginProgress)
+ if constexpr (std::is_same_v)
{
- reportProgress = true;
- }
- else if (progressType == ::AppInstaller::ProgressType::Bytes)
- {
- downloadBytesDownloaded = current;
- downloadBytesRequired = maximum;
- if (maximum > 0 && maximum >= current)
+ progressState = PackageInstallProgressState::Downloading;
+ if (reportType == ReportType::BeginProgress)
{
reportProgress = true;
- downloadProgress = static_cast(current) / static_cast(maximum);
+ }
+ else if (progressType == ::AppInstaller::ProgressType::Bytes)
+ {
+ downloadBytesDownloaded = current;
+ downloadBytesRequired = maximum;
+ if (maximum > 0 && maximum >= current)
+ {
+ reportProgress = true;
+ downloadProgress = static_cast(current) / static_cast(maximum);
+ }
}
}
break;
case ::Workflow::ExecutionStage::PreExecution:
- // Wait until installer starts to report Installing.
+ // Wait until installer starts to report operation.
break;
case ::Workflow::ExecutionStage::Execution:
- progressState = PackageInstallProgressState::Installing;
+ WINGET_GET_PROGRESS_STATE(Installing, Uninstalling);
downloadProgress = 1;
if (reportType == ReportType::ExecutionPhaseUpdate)
{
- // Install is starting. Send progress so callers know the AsyncOperation can't be cancelled.
+ // Operation is starting. Send progress so callers know the AsyncOperation can't be cancelled.
reportProgress = true;
}
else if (reportType == ReportType::EndProgress)
{
- // Install is "finished". May not have succeeded.
+ // Operation is "finished". May not have succeeded.
reportProgress = true;
- installProgress = 1;
+ operationProgress = 1;
}
else if (progressType == ::AppInstaller::ProgressType::Percent)
{
if (maximum > 0 && maximum >= current)
{
- // Install is progressing
+ // Operation is progressing
reportProgress = true;
- installProgress = static_cast(current) / static_cast(maximum);
+ operationProgress = static_cast(current) / static_cast(maximum);
}
}
break;
@@ -234,16 +277,24 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
// Send PostInstall progress when it switches to PostExecution phase.
reportProgress = true;
- progressState = PackageInstallProgressState::PostInstall;
+ WINGET_GET_PROGRESS_STATE(PostInstall, PostUninstall);
downloadProgress = 1;
- installProgress = 1;
+ operationProgress = 1;
}
break;
}
if (reportProgress)
{
- winrt::Microsoft::Management::Deployment::InstallProgress contextProgress{ progressState, downloadBytesDownloaded, downloadBytesRequired, downloadProgress, installProgress };
- return contextProgress;
+ if constexpr (std::is_same_v)
+ {
+ TProgress progress{ progressState, downloadBytesDownloaded, downloadBytesRequired, downloadProgress, operationProgress };
+ return progress;
+ }
+ else if constexpr (std::is_same_v)
+ {
+ TProgress progress{ progressState, operationProgress };
+ return progress;
+ }
}
else
{
@@ -271,16 +322,10 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return packageVersionInfo;
}
- std::unique_ptr CreateContextFromInstallOptions(
- winrt::Microsoft::Management::Deployment::CatalogPackage package,
- winrt::Microsoft::Management::Deployment::InstallOptions options,
- std::wstring callerProcessInfoString)
+ void PopulateContextFromInstallOptions(
+ ::AppInstaller::CLI::Execution::Context* context,
+ winrt::Microsoft::Management::Deployment::InstallOptions options)
{
- std::unique_ptr context = std::make_unique();
- hstring correlationData = (options) ? options.CorrelationData() : L"";
- context->SetContextLoggers(correlationData, ::AppInstaller::Utility::ConvertToUTF8(callerProcessInfoString));
-
- // Convert the options to arguments for the installer.
if (options)
{
if (!options.LogOutputPath().empty())
@@ -335,13 +380,53 @@ namespace winrt::Microsoft::Management::Deployment::implementation
}
context->Add(std::move(allowedArchitectures));
}
+
+ // Note: AdditionalPackageCatalogArguments is not needed during install since the manifest is already known so no additional calls to the source are needed. The property is deprecated.
}
+ }
- // If the version of the package is specified use that, otherwise use the default.
- Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options);
- AddPackageManifestToContext(packageVersionInfo, context.get());
+ void PopulateContextFromUninstallOptions(
+ ::AppInstaller::CLI::Execution::Context* context,
+ winrt::Microsoft::Management::Deployment::UninstallOptions options)
+ {
+ if (options)
+ {
+ if (!options.LogOutputPath().empty())
+ {
+ context->Args.AddArg(Execution::Args::Type::Log, ::AppInstaller::Utility::ConvertToUTF8(options.LogOutputPath()));
+ context->Args.AddArg(Execution::Args::Type::VerboseLogs);
+ }
+
+ if (options.PackageUninstallMode() == PackageUninstallMode::Interactive)
+ {
+ context->Args.AddArg(Execution::Args::Type::Interactive);
+ }
+ else if (options.PackageUninstallMode() == PackageUninstallMode::Silent)
+ {
+ context->Args.AddArg(Execution::Args::Type::Silent);
+ }
+ }
+ }
+
+ template
+ std::unique_ptr CreateContextFromOperationOptions(
+ TOptions options,
+ std::wstring callerProcessInfoString)
+ {
+ std::unique_ptr context = std::make_unique();
+ hstring correlationData = (options) ? options.CorrelationData() : L"";
+ context->SetContextLoggers(correlationData, ::AppInstaller::Utility::ConvertToUTF8(callerProcessInfoString));
+
+ // Convert the options to arguments for the installer.
+ if constexpr (std::is_same_v)
+ {
+ PopulateContextFromInstallOptions(context.get(), options);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ PopulateContextFromUninstallOptions(context.get(), options);
+ }
- // Note: AdditionalPackageCatalogArguments is not needed during install since the manifest is already known so no additional calls to the source are needed. The property is deprecated.
return context;
}
@@ -354,7 +439,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// If the caller has passed in the catalog they expect the package to have come from, then only look for an install from that catalog.
// Fail if they've used a catalog that doesn't have an Id. This can currently happen for Info objects that come from PackageCatalogReference objects for REST catalogs.
THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, catalogInfo.Id().empty());
- auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ catalogInfo.Id() }, std::move(context));
+ auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ catalogInfo.Id() }, std::move(context));
queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId());
return queueItem;
}
@@ -365,7 +450,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
Microsoft::Management::Deployment::PackageVersionInfo installedVersionInfo = package.InstalledVersion();
if (installedVersionInfo)
{
- auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ installedVersionInfo.PackageCatalog().Info().Id() }, std::move(context));
+ auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ installedVersionInfo.PackageCatalog().Info().Id() }, std::move(context));
queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId());
if (queueItem)
{
@@ -377,7 +462,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
Microsoft::Management::Deployment::PackageVersionInfo defaultInstallVersionInfo = package.DefaultInstallVersion();
if (defaultInstallVersionInfo)
{
- auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ defaultInstallVersionInfo.PackageCatalog().Info().Id() }, std::move(context));
+ auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ defaultInstallVersionInfo.PackageCatalog().Info().Id() }, std::move(context));
queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId());
if (queueItem)
{
@@ -388,7 +473,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// Finally check all catalogs in AvailableVersions.
for (Microsoft::Management::Deployment::PackageVersionId versionId : package.AvailableVersions())
{
- auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ package.GetPackageVersionInfo(versionId).PackageCatalog().Info().Id() }, std::move(context));
+ auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ package.GetPackageVersionInfo(versionId).PackageCatalog().Info().Id() }, std::move(context));
queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId());
if (queueItem)
{
@@ -397,16 +482,71 @@ namespace winrt::Microsoft::Management::Deployment::implementation
}
return nullptr;
}
- winrt::Windows::Foundation::IAsyncOperationWithProgress GetInstallOperation(
+
+ std::unique_ptr CreateQueueItemForInstall(
+ std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext,
+ winrt::Microsoft::Management::Deployment::CatalogPackage package,
+ winrt::Microsoft::Management::Deployment::InstallOptions options,
+ bool isUpgrade)
+ {
+ // Add manifest and PackageVersion to context for install/upgrade.
+ // If the version of the package is specified use that, otherwise use the default.
+ Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options);
+ AddPackageManifestToContext(packageVersionInfo, comContext.get());
+
+ if (isUpgrade)
+ {
+ AppInstaller::Utility::VersionAndChannel installedVersion{ winrt::to_string(package.InstalledVersion().Version()), winrt::to_string(package.InstalledVersion().Channel()) };
+ AppInstaller::Utility::VersionAndChannel upgradeVersion{ winrt::to_string(packageVersionInfo.Version()), winrt::to_string(packageVersionInfo.Channel()) };
+
+ // Perform upgrade version check
+ if (upgradeVersion.GetVersion().IsUnknown())
+ {
+ if (!(options.AllowUpgradeToUnknownVersion() &&
+ AppInstaller::Utility::ICUCaseInsensitiveEquals(installedVersion.GetChannel().ToString(), upgradeVersion.GetChannel().ToString())))
+ {
+ THROW_HR(APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN);
+ }
+ }
+ else if (!installedVersion.IsUpdatedBy(upgradeVersion))
+ {
+ THROW_HR(APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER);
+ }
+
+ // Set upgrade flag
+ comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerExecutionUseUpdate);
+ // Add installed version
+ AddInstalledVersionToContext(package.InstalledVersion(), comContext.get());
+ }
+
+ return Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ packageVersionInfo.PackageCatalog().Info().Id() }, std::move(comContext), isUpgrade);
+ }
+
+ std::unique_ptr CreateQueueItemForUninstall(
+ std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext,
+ winrt::Microsoft::Management::Deployment::CatalogPackage package)
+ {
+ // Add installed version
+ AddInstalledVersionToContext(package.InstalledVersion(), comContext.get());
+ // Add Package which is used by RecordUninstall later for removing from tracking catalog of correlated available sources as best effort
+ winrt::Microsoft::Management::Deployment::implementation::CatalogPackage* catalogPackageImpl = get_self(package);
+ std::shared_ptr<::AppInstaller::Repository::IPackage> internalPackage = catalogPackageImpl->GetRepositoryPackage();
+ comContext->Add(internalPackage);
+
+ return Execution::OrchestratorQueueItemFactory::CreateItemForUninstall(std::wstring{ package.Id() }, std::wstring{ package.InstalledVersion().PackageCatalog().Info().Id() }, std::move(comContext));
+ }
+
+ template
+ winrt::Windows::Foundation::IAsyncOperationWithProgress GetPackageOperation(
bool canCancelQueueItem,
std::shared_ptr queueItemParam,
winrt::Microsoft::Management::Deployment::CatalogPackage package = nullptr,
- winrt::Microsoft::Management::Deployment::InstallOptions options = nullptr,
+ TOptions options = nullptr,
std::wstring callerProcessInfoString = {},
bool isUpgrade = false)
{
winrt::hresult terminationHR = S_OK;
- uint32_t installerError = 0;
+ uint32_t operationError = 0;
hstring correlationData = (options) ? options.CorrelationData() : L"";
::Workflow::ExecutionStage executionStage = ::Workflow::ExecutionStage::Initial;
@@ -422,41 +562,29 @@ namespace winrt::Microsoft::Management::Deployment::implementation
if (queueItem == nullptr)
{
- Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options);
- std::unique_ptr comContext = CreateContextFromInstallOptions(package, options, callerProcessInfoString);
+ std::unique_ptr comContext = CreateContextFromOperationOptions(options, callerProcessInfoString);
- if (isUpgrade)
+ if constexpr (std::is_same_v)
{
- AppInstaller::Utility::VersionAndChannel installedVersion{ winrt::to_string(package.InstalledVersion().Version()), winrt::to_string(package.InstalledVersion().Channel()) };
- AppInstaller::Utility::VersionAndChannel upgradeVersion{ winrt::to_string(packageVersionInfo.Version()), winrt::to_string(packageVersionInfo.Channel()) };
-
- // Perform upgrade version check
- if (upgradeVersion.GetVersion().IsUnknown())
- {
- if (!(options.AllowUpgradeToUnknownVersion() &&
- AppInstaller::Utility::ICUCaseInsensitiveEquals(installedVersion.GetChannel().ToString(), upgradeVersion.GetChannel().ToString())))
- {
- co_return GetInstallResult(executionStage, APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN, 0, correlationData, false);
- }
- }
- else if (!installedVersion.IsUpdatedBy(upgradeVersion))
- {
- co_return GetInstallResult(executionStage, APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER, 0, correlationData, false);
- }
-
- // Set upgrade flag
- comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerExecutionUseUpdate);
- // Add installed version
- winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo* installedVersionInfoImpl = get_self(package.InstalledVersion());
- std::shared_ptr<::AppInstaller::Repository::IPackageVersion> internalInstalledVersion = installedVersionInfoImpl->GetRepositoryPackageVersion();
- comContext->Add(internalInstalledVersion);
+ queueItem = CreateQueueItemForInstall(std::move(comContext), package, options, isUpgrade);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ queueItem = CreateQueueItemForUninstall(std::move(comContext), package);
}
- queueItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ packageVersionInfo.PackageCatalog().Info().Id() }, std::move(comContext));
Execution::ContextOrchestrator::Instance().EnqueueAndRunItem(queueItem);
- InstallProgress queuedProgress{ PackageInstallProgressState::Queued, 0, 0, 0 };
- report_progress(queuedProgress);
+ if constexpr (std::is_same_v)
+ {
+ TProgress queuedProgress{ TProgressState::Queued, 0, 0, 0 };
+ report_progress(queuedProgress);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ TProgress queuedProgress{ TProgressState::Queued, 0};
+ report_progress(queuedProgress);
+ }
}
{
// correlation data is not passed in when retrieving an existing queue item, so get it from the existing context.
@@ -465,18 +593,18 @@ namespace winrt::Microsoft::Management::Deployment::implementation
wil::unique_event progressEvent{ wil::EventOptions::None };
- std::atomic installProgress;
- queueItem->GetContext().AddProgressCallbackFunction([&installProgress, &progressEvent](
+ std::atomic operationProgress;
+ queueItem->GetContext().AddProgressCallbackFunction([&operationProgress, &progressEvent](
ReportType reportType,
uint64_t current,
uint64_t maximum,
::AppInstaller::ProgressType progressType,
::Workflow::ExecutionStage executionPhase)
{
- std::optional installProgressOptional = GetProgress(reportType, current, maximum, progressType, executionPhase);
- if (installProgressOptional.has_value())
+ std::optional operationProgressOptional = GetProgress(reportType, current, maximum, progressType, executionPhase);
+ if (operationProgressOptional.has_value())
{
- installProgress = installProgressOptional.value();
+ operationProgress = operationProgressOptional.value();
progressEvent.SetEvent();
}
return;
@@ -519,7 +647,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// while the report_progress call is hung\in progress.
// Duplicate progress events can be fired if another progress event comes from the ComContext to the callback after the listener
// has been awaked, but before it has gotten the installProgress.
- report_progress(installProgress);
+ report_progress(operationProgress);
break;
// operationEvents[1] was signaled, operation completed
@@ -538,28 +666,29 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// The install command has finished, check for success/failure and how far it got.
terminationHR = queueItem->GetContext().GetTerminationHR();
executionStage = queueItem->GetContext().GetExecutionStage();
- if (queueItem->GetContext().Contains(Data::InstallerReturnCode))
+ if (queueItem->GetContext().Contains(Data::OperationReturnCode))
{
- installerError = static_cast(queueItem->GetContext().Get());
+ operationError = static_cast(queueItem->GetContext().Get());
}
}
}
WINGET_CATCH_STORE(terminationHR, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
// TODO - RebootRequired not yet populated, msi arguments not returned from Execute.
- co_return GetInstallResult(executionStage, terminationHR, installerError, correlationData, false);
+ co_return GetOperationResult(executionStage, terminationHR, operationError, correlationData, false);
}
- winrt::Windows::Foundation::IAsyncOperationWithProgress GetEmptyAsynchronousResultForInstallOperation(
+ template
+ winrt::Windows::Foundation::IAsyncOperationWithProgress GetEmptyAsynchronousResultForOperation(
HRESULT hr,
hstring correlationData)
{
// If a function uses co_await or co_return (i.e. if it is a co_routine), it cannot use return directly.
// This helper helps a function that is not a coroutine itself to return errors asynchronously.
- co_return GetInstallResult(::Workflow::ExecutionStage::Initial, hr, 0, correlationData, false);
+ co_return GetOperationResult(::Workflow::ExecutionStage::Initial, hr, 0, correlationData, false);
}
-#define WINGET_RETURN_INSTALL_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForInstallOperation(hr, correlationData); }}
+#define WINGET_RETURN_INSTALL_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation(hr, correlationData); }}
#define WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_INSTALL_RESULT_HR_IF(hr, FAILED(hr)) }
winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::InstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options)
@@ -583,7 +712,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr);
- return GetInstallOperation(true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString));
+ return GetPackageOperation(
+ true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString));
}
winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options)
@@ -609,7 +739,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr);
- return GetInstallOperation(true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString), true /* isUpgrade */);
+ return GetPackageOperation(
+ true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString), true /* isUpgrade */);
}
winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::GetInstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo)
@@ -634,7 +765,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// Get the queueItem synchronously.
queueItem = GetExistingQueueItemForPackage(package, catalogInfo);
- if (queueItem == nullptr)
+ if (queueItem == nullptr ||
+ (queueItem->GetPackageOperationType() != PackageOperationType::Install && queueItem->GetPackageOperationType() != PackageOperationType::Upgrade))
{
return nullptr;
}
@@ -642,7 +774,73 @@ namespace winrt::Microsoft::Management::Deployment::implementation
WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr);
- return GetInstallOperation(canCancelQueueItem, std::move(queueItem));
+ return GetPackageOperation(
+ canCancelQueueItem, std::move(queueItem));
+ }
+
+#define WINGET_RETURN_UNINSTALL_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation(hr, correlationData); }}
+#define WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_UNINSTALL_RESULT_HR_IF(hr, FAILED(hr)) }
+
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::UninstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::UninstallOptions options)
+ {
+ hstring correlationData = (options) ? options.CorrelationData() : L"";
+
+ // options and catalog can both be null, package must be set.
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package);
+ // the package should have an installed version to be uninstalled.
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package.InstalledVersion());
+
+ HRESULT hr = S_OK;
+ std::wstring callerProcessInfoString;
+ try
+ {
+ // Check for permissions and get caller info for telemetry.
+ // This must be done before any co_awaits since it requires info from the rpc caller thread.
+ auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hrGetCallerId);
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId));
+ callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId);
+ }
+ WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr);
+
+ return GetPackageOperation(
+ true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString));
+ }
+
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::GetUninstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo)
+ {
+ hstring correlationData;
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package);
+
+ HRESULT hr = S_OK;
+ std::shared_ptr queueItem = nullptr;
+ bool canCancelQueueItem = false;
+ try
+ {
+ // Check for permissions
+ // This must be done before any co_awaits since it requires info from the rpc caller thread.
+ auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hrGetCallerId);
+ canCancelQueueItem = SUCCEEDED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId));
+ if (!canCancelQueueItem)
+ {
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageQuery, callerProcessId));
+ }
+
+ // Get the queueItem synchronously.
+ queueItem = GetExistingQueueItemForPackage(package, catalogInfo);
+ if (queueItem == nullptr ||
+ queueItem->GetPackageOperationType() != PackageOperationType::Uninstall)
+ {
+ return nullptr;
+ }
+ }
+ WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
+ WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr);
+
+ return GetPackageOperation(
+ canCancelQueueItem, std::move(queueItem));
}
CoCreatableMicrosoftManagementDeploymentClass(PackageManager);
diff --git a/src/Microsoft.Management.Deployment/PackageManager.h b/src/Microsoft.Management.Deployment/PackageManager.h
index 879fb0a7a5..2d3086c7c9 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.h
+++ b/src/Microsoft.Management.Deployment/PackageManager.h
@@ -27,6 +27,10 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// Contract 4.0
winrt::Windows::Foundation::IAsyncOperationWithProgress
UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ UninstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::UninstallOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ GetUninstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo);
};
}
diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl
index c9888a020e..f39b28accd 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.idl
+++ b/src/Microsoft.Management.Deployment/PackageManager.idl
@@ -5,7 +5,7 @@ namespace Microsoft.Management.Deployment
[contractversion(4)]
apicontract WindowsPackageManagerContract{};
- /// State of the install.
+ /// State of the install
[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
enum PackageInstallProgressState
{
@@ -87,6 +87,66 @@ namespace Microsoft.Management.Deployment
}
}
+ /// State of the uninstall
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ enum PackageUninstallProgressState
+ {
+ /// The uninstall is queued but not yet active. Cancellation of the IAsyncOperationWithProgress in this
+ /// state will prevent the package from uninstalling.
+ Queued,
+ /// The uninstall is in progress. Cancellation of the IAsyncOperationWithProgress in this state will not
+ /// stop the installation or the post uninstall steps.
+ Uninstalling,
+ /// The uninstaller has completed and cleanup actions are in progress. Cancellation of the
+ /// IAsyncOperationWithProgress in this state will not stop cleanup or roll back the uninstall.
+ PostUninstall,
+ /// The operation has completed.
+ Finished,
+ };
+
+ /// Progress object for the uninstall
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ struct UninstallProgress
+ {
+ /// State of the uninstall
+ PackageUninstallProgressState State;
+ /// Uninstall percentage if known.
+ Double UninstallationProgress;
+ };
+
+ /// Status of the uninstall call
+ /// Implementation Note: Errors mapped from AppInstallerErrors.h
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ enum UninstallResultStatus
+ {
+ Ok,
+ BlockedByPolicy,
+ CatalogError,
+ InternalError,
+ InvalidOptions,
+ UninstallError,
+ ManifestError,
+ };
+
+ /// Result of the uninstall
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ runtimeclass UninstallResult
+ {
+ /// Used by a caller to correlate the install with a caller's data.
+ String CorrelationData{ get; };
+ /// Whether a restart is required to complete the install.
+ Boolean RebootRequired{ get; };
+
+ /// Batched error code, example APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED
+ UninstallResultStatus Status{ get; };
+ /// The error code of the overall operation.
+ HRESULT ExtendedErrorCode{ get; };
+
+ /// The error code from the uninstall attempt. Only valid if the Status is UninstallError.
+ /// This value's meaning will require knowledge of the specific uninstaller or install technology.
+ UInt32 UninstallerErrorCode{ get; };
+ }
+
/// IMPLEMENTATION NOTE: SourceOrigin from winget/RepositorySource.h
/// Defines the origin of the package catalog details.
[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
@@ -550,6 +610,39 @@ namespace Microsoft.Management.Deployment
}
}
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ enum PackageUninstallMode
+ {
+ /// The default experience for the installer. Installer may show some UI.
+ Default,
+ /// Runs the installer in silent mode. This suppresses the installer's UI to the extent
+ /// possible (installer may still show some required UI).
+ Silent,
+ /// Runs the installer in interactive mode.
+ Interactive,
+ };
+
+ /// Options when uninstalling a package.
+ /// Intended to allow full compatibility with the "winget uninstall" command line interface.
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
+ runtimeclass UninstallOptions
+ {
+ UninstallOptions();
+
+ /// Optionally specifies the version from the package to uninstall. If unspecified the version matching
+ /// CatalogPackage.GetLatestVersion() is used.
+ PackageVersionId PackageVersionId;
+
+ /// Silent, Interactive, or Default
+ PackageUninstallMode PackageUninstallMode;
+ /// Directs the logging to a log file. If provided, the installer must have have write access to the file
+ String LogOutputPath;
+
+ /// Used by a caller to correlate the install with a caller's data.
+ /// The string must be JSON encoded.
+ String CorrelationData;
+ }
+
[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
runtimeclass PackageManager
{
@@ -582,6 +675,12 @@ namespace Microsoft.Management.Deployment
{
/// Upgrade the specified package
Windows.Foundation.IAsyncOperationWithProgress UpgradePackageAsync(CatalogPackage package, InstallOptions options);
+
+ /// Uninstall the specified package
+ Windows.Foundation.IAsyncOperationWithProgress UninstallPackageAsync(CatalogPackage package, UninstallOptions options);
+
+ /// Get uninstall progress
+ Windows.Foundation.IAsyncOperationWithProgress GetUninstallProgress(CatalogPackage package, PackageCatalogInfo catalogInfo);
}
}
@@ -606,6 +705,10 @@ namespace Microsoft.Management.Deployment
interface Windows.Foundation.Collections.IVectorView;
interface Windows.Foundation.Collections.IVector;
interface Windows.Foundation.Collections.IVectorView;
+ interface Windows.Foundation.Collections.IVector;
+ interface Windows.Foundation.Collections.IVectorView;
+ interface Windows.Foundation.Collections.IVector;
+ interface Windows.Foundation.Collections.IVectorView;
interface Windows.Foundation.Collections.IVector;
interface Windows.Foundation.Collections.IVectorView;
interface Windows.Foundation.Collections.IVector;
diff --git a/src/Microsoft.Management.Deployment/UninstallOptions.cpp b/src/Microsoft.Management.Deployment/UninstallOptions.cpp
new file mode 100644
index 0000000000..6bf3912265
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/UninstallOptions.cpp
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#pragma warning( push )
+#pragma warning ( disable : 4467 6388)
+// 6388 Allow CreateInstance.
+#include
+// 4467 Allow use of uuid attribute for com object creation.
+#include "UninstallOptions.h"
+#pragma warning( pop )
+#include "UninstallOptions.g.cpp"
+#include "Converters.h"
+#include "Helpers.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ UninstallOptions::UninstallOptions()
+ {
+ }
+ winrt::Microsoft::Management::Deployment::PackageVersionId UninstallOptions::PackageVersionId()
+ {
+ return m_packageVersionId;
+ }
+ void UninstallOptions::PackageVersionId(winrt::Microsoft::Management::Deployment::PackageVersionId const& value)
+ {
+ m_packageVersionId = value;
+ }
+ winrt::Microsoft::Management::Deployment::PackageUninstallMode UninstallOptions::PackageUninstallMode()
+ {
+ return m_packageUninstallMode;
+ }
+ void UninstallOptions::PackageUninstallMode(winrt::Microsoft::Management::Deployment::PackageUninstallMode const& value)
+ {
+ m_packageUninstallMode = value;
+ }
+ hstring UninstallOptions::LogOutputPath()
+ {
+ return hstring(m_logOutputPath);
+ }
+ void UninstallOptions::LogOutputPath(hstring const& value)
+ {
+ m_logOutputPath = value;
+ }
+ hstring UninstallOptions::CorrelationData()
+ {
+ return hstring(m_correlationData);
+ }
+ void UninstallOptions::CorrelationData(hstring const& value)
+ {
+ m_correlationData = value;
+ }
+
+ CoCreatableMicrosoftManagementDeploymentClass(UninstallOptions);
+}
diff --git a/src/Microsoft.Management.Deployment/UninstallOptions.h b/src/Microsoft.Management.Deployment/UninstallOptions.h
new file mode 100644
index 0000000000..d56ecae072
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/UninstallOptions.h
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "UninstallOptions.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+#if USE_PROD_CLSIDS
+ [uuid("E1D9A11E-9F85-4D87-9C17-2B93143ADB8D")]
+#else
+ [uuid("AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C")]
+#endif
+ struct UninstallOptions : UninstallOptionsT
+ {
+ UninstallOptions();
+
+ winrt::Microsoft::Management::Deployment::PackageVersionId PackageVersionId();
+ void PackageVersionId(winrt::Microsoft::Management::Deployment::PackageVersionId const& value);
+ winrt::Microsoft::Management::Deployment::PackageUninstallMode PackageUninstallMode();
+ void PackageUninstallMode(winrt::Microsoft::Management::Deployment::PackageUninstallMode const& value);
+ hstring LogOutputPath();
+ void LogOutputPath(hstring const& value);
+ hstring CorrelationData();
+ void CorrelationData(hstring const& value);
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ winrt::Microsoft::Management::Deployment::PackageVersionId m_packageVersionId{ nullptr };
+ winrt::Microsoft::Management::Deployment::PackageUninstallMode m_packageUninstallMode = winrt::Microsoft::Management::Deployment::PackageUninstallMode::Default;
+ std::wstring m_logOutputPath = L"";
+ std::wstring m_correlationData = L"";
+#endif
+ };
+}
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+namespace winrt::Microsoft::Management::Deployment::factory_implementation
+{
+ struct UninstallOptions : UninstallOptionsT
+ {
+ };
+}
+#endif
diff --git a/src/Microsoft.Management.Deployment/UninstallResult.cpp b/src/Microsoft.Management.Deployment/UninstallResult.cpp
new file mode 100644
index 0000000000..cc0830646e
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/UninstallResult.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "UninstallResult.h"
+#include "UninstallResult.g.cpp"
+#include
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ void UninstallResult::Initialize(
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus status,
+ winrt::hresult extendedErrorCode,
+ uint32_t uninstallerErrorCode,
+ hstring const& correlationData,
+ bool rebootRequired)
+ {
+ m_status = status;
+ m_extendedErrorCode = extendedErrorCode;
+ m_uninstallerErrorCode = uninstallerErrorCode;
+ m_correlationData = correlationData;
+ m_rebootRequired = rebootRequired;
+ }
+ hstring UninstallResult::CorrelationData()
+ {
+ return hstring(m_correlationData);
+ }
+ bool UninstallResult::RebootRequired()
+ {
+ return m_rebootRequired;
+ }
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus UninstallResult::Status()
+ {
+ return m_status;
+ }
+ winrt::hresult UninstallResult::ExtendedErrorCode()
+ {
+ return m_extendedErrorCode;
+ }
+
+ uint32_t UninstallResult::UninstallerErrorCode()
+ {
+ return m_uninstallerErrorCode;
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/UninstallResult.h b/src/Microsoft.Management.Deployment/UninstallResult.h
new file mode 100644
index 0000000000..2b3ac1a780
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/UninstallResult.h
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "UninstallResult.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ struct UninstallResult : UninstallResultT
+ {
+ UninstallResult() = default;
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ void Initialize(
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus status,
+ winrt::hresult extendedErrorCode,
+ uint32_t uninstallerErrorCode,
+ hstring const& correlationData,
+ bool rebootRequired);
+#endif
+
+ hstring CorrelationData();
+ bool RebootRequired();
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus Status();
+ winrt::hresult ExtendedErrorCode();
+ uint32_t UninstallerErrorCode();
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ std::wstring m_correlationData = L"";
+ bool m_rebootRequired = false;
+ winrt::Microsoft::Management::Deployment::UninstallResultStatus m_status = winrt::Microsoft::Management::Deployment::UninstallResultStatus::Ok;
+ winrt::hresult m_extendedErrorCode = S_OK;
+ uint32_t m_uninstallerErrorCode = 0;
+#endif
+ };
+}
diff --git a/src/WindowsPackageManager/main.cpp b/src/WindowsPackageManager/main.cpp
index 791b0d829c..972176038a 100644
--- a/src/WindowsPackageManager/main.cpp
+++ b/src/WindowsPackageManager/main.cpp
@@ -17,6 +17,7 @@ CoCreatableClassWrlCreatorMapInclude(PackageManager);
CoCreatableClassWrlCreatorMapInclude(FindPackagesOptions);
CoCreatableClassWrlCreatorMapInclude(CreateCompositePackageCatalogOptions);
CoCreatableClassWrlCreatorMapInclude(InstallOptions);
+CoCreatableClassWrlCreatorMapInclude(UninstallOptions);
CoCreatableClassWrlCreatorMapInclude(PackageMatchFilter);
extern "C"