diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json
index 9590e04d11..82c2bbbd50 100644
--- a/.config/tsaoptions.json
+++ b/.config/tsaoptions.json
@@ -1,8 +1,8 @@
{
"instanceUrl": "https://microsoft.visualstudio.com",
"projectName": "os",
- "areaPath": "OS\\Windows Client and Services\\ADEPT\\OWL (Open Windows pLatform)\\Rendering\\WinAppSDK Engineering System",
- "iterationPath": "OS\\2211",
+ "areaPath": "OS\\Windows Client and Services\\ADEPT\\NEON\\Windex\\WinAppSDK Engineering System",
+ "iterationPath": "OS\\2311",
"notificationAliases": [ "WinAppSDK-Build@microsoft.com" ],
"ignoreBranchName": true,
"codebaseName": "WinAppSDK-Foundation"
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml
index a5669abb00..bbbc4f3e37 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug-report.yaml
@@ -35,8 +35,7 @@ body:
label: NuGet package version
description: Specify the version of Windows App SDK (or Project Reunion) you're using.
options:
- - "Windows App SDK 1.3.2: 1.3.230602002"
- - "Windows App SDK 1.4 Preview 1: 1.4.230628000-preview1"
+ - "Windows App SDK 1.4.2: 1.4.231008000"
- "Windows App SDK 1.4 Experimental 1: 1.4.230518007-experimental1"
- type: dropdown
attributes:
diff --git a/Directory.Build.props b/Directory.Build.props
index eda87b76b3..91952db2eb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -19,6 +19,8 @@
true
$(RepoRoot)\packages
+ true
+ $(RepoRoot)\WasdkStrongNameSign.snk
diff --git a/NuGet.config b/NuGet.config
index d0813052b1..454c97cd1a 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -7,7 +7,7 @@
-
+
diff --git a/TestAll.ps1 b/TestAll.ps1
index 9703d76314..7243526981 100644
--- a/TestAll.ps1
+++ b/TestAll.ps1
@@ -1,16 +1,33 @@
<#
.SYNOPSIS
- Run the TAEF dlls generated by WinAppSDK
+ Run the WinAppSDK tests
.DESCRIPTION
The TestAll script will take the folder input and look for subfolders containing a .testdef file. WinAppSDK
- components define a testdef with the following schema and runs the TAEF dll in the subfolder.
+ components define a testdef with the following schema and runs the test in the subfolder.
+
+ *.testdef are JSON files with the schema per JSON Schema 2020-12 (https://json-schema.org):
+ {
+ "$id": "https://microsoft.com/windowsappsdk/schemas/testdef/2023/08",
+
+ "type": "object",
+ "properties": {
+ "Description": { "type": "string" },
+ "Type": { "enum": ["TAEF", "Powershell"], "default": "TAEF" },
+ "Filename": { "type": "string" },
+ "Parameters": { "type": "string" },
+ "Architectures": { "type": "array", "items": { "type": "string" } },
+ "Status": { "enum": ["Enabled", "Disabled"] },
+ },
+ "required": ["Description", "Filename", "Architectures", "Status"]
+ }
Example:
{
"Tests": [
{
"Description": "This module tests the push notifications component in WinAppSDK.",
+ "Type": "TAEF",
"Filename": "PushNotificationTests.dll",
"Parameters": "",
"Architectures": ["x86", "x64", "arm64"],
@@ -38,12 +55,16 @@
param(
[Parameter(Mandatory=$true)]
[string]$OutputFolder,
+
[Parameter(Mandatory=$true)]
[string]$Platform,
+
[Parameter(Mandatory=$true)]
[string]$Configuration,
+
[Parameter(Mandatory=$false)]
[Switch]$Test,
+
[Parameter(Mandatory=$false)]
[Switch]$List
)
@@ -52,7 +73,7 @@ $StartTime = Get-Date
$lastexitcode = 0
Set-StrictMode -Version 3.0
-function Get-TaefTests
+function Get-Tests
{
$configPlat = Join-Path $Configuration $Platform
$outputFolderPath = Join-Path $OutputFolder $configPlat
@@ -66,6 +87,16 @@ function Get-TaefTests
$baseId = $testdef.BaseName
foreach ($testConfig in $testJson.Tests)
{
+ $testConfig | Write-Host
+ if ($testConfig -contains 'Type')
+ {
+ $testType = $testConfig.Type
+ }
+ else
+ {
+ $testType = 'TAEF'
+ }
+
$id = $baseId + "-Test$count"
$t = [PSCustomObject]@{}
$t | Add-Member -MemberType NoteProperty -Name 'Test' -Value $id
@@ -75,6 +106,7 @@ function Get-TaefTests
$t | Add-Member -MemberType NoteProperty -Name 'Architectures' -Value $testConfig.Architectures
$t | Add-Member -MemberType NoteProperty -Name 'Status' -Value $testConfig.Status
$t | Add-Member -MemberType NoteProperty -Name 'TestDef' -Value $testdef.FullName
+ $t | Add-Member -MemberType NoteProperty -Name 'Type' -Value $testType
$tests += $t
$count += 1
@@ -84,15 +116,32 @@ function Get-TaefTests
$tests
}
-function List-TaefTests
+function List-Tests
+{
+ $tests = Get-Tests
+ $tests | Sort-Object -Property Test | Format-Table Test,Description,Type,Filename,Parameters,Architectures,Status -AutoSize | Out-String -Width 512
+}
+
+function Run-TaefTest
{
- $tests = Get-TaefTests
- $tests | Sort-Object -Property Test | Format-Table Test,Description,Filename,Parameters,Architectures,Status -AutoSize | Out-String -Width 512
+ param($test)
+
+ $testFolder = Split-Path -parent $test.TestDef
+ $tePath = Join-Path $testFolder "te.exe"
+ $dllFile = Join-Path $testFolder $test.Filename
+ & $tePath $dllFile $test.Parameters
+}
+
+function Run-PowershellTest
+{
+ param($test)
+
+ Write-Host "Powershell tests not supported"
}
-function Run-TaefTests
+function Run-Tests
{
- $tests = Get-TaefTests
+ $tests = Get-Tests
foreach ($test in $tests)
{
Write-Host "$($test.Filename) - $($test.Description)"
@@ -100,10 +149,19 @@ function Run-TaefTests
$testEnabled = $test.Status -eq "Enabled"
if ($validPlatform -and $testEnabled)
{
- $testFolder = Split-Path -parent $test.TestDef
- $tePath = Join-Path $testFolder "te.exe"
- $dllFile = Join-Path $testFolder $test.Filename
- & $tePath $dllFile $test.Parameters
+ if ($test.Type -eq 'TAEF')
+ {
+ Run-TaefTest $test
+ }
+ elseif ($test.Type -eq 'Powershell')
+ {
+ Run-PowershellTest $test
+ }
+ else
+ {
+ Write-Host "Unknown test type '$test.Type'. Not running."
+ Exit 1
+ }
}
elseif (-not($validPlatform))
{
@@ -118,12 +176,12 @@ function Run-TaefTests
if ($List -eq $true)
{
- $null = List-TaefTests
+ List-Tests | Out-String
}
if ($Test -eq $true)
{
- Run-TaefTests
+ Run-Tests
}
$TotalTime = (Get-Date)-$StartTime
diff --git a/WasdkStrongNameSign.snk b/WasdkStrongNameSign.snk
new file mode 100644
index 0000000000..b8a8d1e871
Binary files /dev/null and b/WasdkStrongNameSign.snk differ
diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln
index 906f760725..e9bd3244f5 100644
--- a/WindowsAppRuntime.sln
+++ b/WindowsAppRuntime.sln
@@ -192,10 +192,19 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS", "CS", "{716C26A0-E6B0-4981-8412-D14A4D410531}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.ApplicationModel.DynamicDependency.Projection", "dev\Projections\CS\Microsoft.Windows.ApplicationModel.DynamicDependency\Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.csproj", "{47D8D21D-F022-4D58-8DB2-8B467756E08C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection", "dev\Projections\CS\Microsoft.Windows.ApplicationModel.WindowsAppRuntime\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.csproj", "{4782BB2A-2968-44B4-867C-5FAEB7A51C6B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.AppLifecycle.Projection", "dev\Projections\CS\Microsoft.Windows.AppLifecycle\Microsoft.Windows.AppLifecycle.Projection.csproj", "{D417EDBE-D783-484F-83F3-710DEC7CB585}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsAppRuntime.Test.Singleton.Msix", "test\DynamicDependency\data\WindowsAppRuntime.Test.Singleton.Msix\WindowsAppRuntime.Test.Singleton.Msix.vcxproj", "{8F2C21F1-47AB-428C-A110-EE33FD7D9493}"
EndProject
@@ -220,10 +229,19 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.WindowsAppRuntime.Bootstrap.Net", "dev\Bootstrap\CS\Microsoft.WindowsAppRuntime.Bootstrap.Net\Microsoft.WindowsAppRuntime.Bootstrap.Net.csproj", "{D6574FD6-8D13-4412-9FCB-308D44063CDA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.System.Power.Projection", "dev\Projections\CS\Microsoft.Windows.System.Power\Microsoft.Windows.System.Power.Projection.csproj", "{63ACBA4F-385A-4D04-98AD-263FED501A19}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.System.Projection", "dev\Projections\CS\Microsoft.Windows.System\Microsoft.Windows.System.Projection.csproj", "{85E9BB46-7841-4732-A039-9C902B71DEC3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.PushNotifications.Projection", "dev\Projections\CS\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.csproj", "{F1F2F3A6-A7DE-45D1-9E96-E28171FD3147}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deployment", "Deployment", "{68E63911-6283-4212-BFFE-3F972AF8F835}"
EndProject
@@ -301,6 +319,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppNotifications", "dev\AppNotifications\AppNotifications.vcxitems", "{B4824897-88E0-4927-8FB9-E60106F01ED9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.AppNotifications.Projection", "dev\Projections\CS\Microsoft.Windows.AppNotifications.Projection\Microsoft.Windows.AppNotifications.Projection.csproj", "{2385A443-A1C2-4562-8D28-D0AD239EE5E7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{82A73181-EA4A-431A-B82B-BE6734604CC9}"
EndProject
@@ -344,6 +365,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppNotificationBuilderTests", "test\AppNotificationBuilderTests\AppNotificationBuilderTests.vcxproj", "{131DE0C4-AA1E-4649-B5BC-7B43508FA93A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.Security.AccessControl.Projection", "dev\Projections\CS\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.csproj", "{E6D59245-696F-4D13-ACF6-7ECE6E653367}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{0D6B1FF3-A075-4194-9FC0-AF7BB89D0519}"
EndProject
@@ -401,6 +425,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test_DeploymentManagerAutoI
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.AppNotifications.Builder.Projection", "dev\Projections\CS\Microsoft.Windows.AppNotifications.Builder.Projection\Microsoft.Windows.AppNotifications.Builder.Projection.csproj", "{50BF3E96-3050-4053-B012-BF6993483DA5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NotificationTests", "NotificationTests", "{1FDC307C-2DB7-4B40-8F18-F1057E9E0969}"
EndProject
@@ -626,6 +653,9 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "KozaniRemoteManagerLauncher", "KozaniRemoteManagerLauncher", "{C5408A09-CDB4-41C1-8766-7677757EB7F2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KozaniRemoteManagerLauncher", "dev\Kozani\KozaniRemoteManagerLauncher\KozaniRemoteManagerLauncher.vcxproj", "{45C50DA4-F2C7-4A4B-8493-50E5DF17B527}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KozaniRemoteManager.Msix", "test\Kozani\data\KozaniRemoteManager.Msix\KozaniRemoteManager.Msix.vcxproj", "{A18E00C4-3668-4289-ABFC-D1DF330DA6BF}"
EndProject
@@ -633,6 +663,46 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "KozaniProtocol", "KozaniPro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KozaniProtocol", "dev\Kozani\KozaniProtocol\KozaniProtocol.vcxproj", "{3F28C3ED-2548-4530-8B6C-832FAE0E993D}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager", "PackageManager", "{380C8BE1-1868-4860-BD32-ADCD8683285D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{CC969A0B-9B01-479D-A563-C9866BCC6F83}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManager", "dev\PackageManager\API\PackageManager.vcxitems", "{8A9A0C85-65A8-4BCA-A49E-45FC4FDBC7D2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager", "PackageManager", "{B03C7C69-0A52-4553-B465-04C995161E42}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{4B85FB26-28B6-4072-85C2-DB7B5FEB98BE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManagerTests", "test\PackageManager\API\PackageManagerTests.vcxproj", "{4A38CB80-3580-4960-9B31-3301058B7AFE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {09DDAE21-397F-4263-8561-7F2FF28127CF} = {09DDAE21-397F-4263-8561-7F2FF28127CF}
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC} = {4626E11F-A7A4-41A2-B22D-5A108BC369AC}
+ {58E95711-A12F-4C0E-A978-C6B4A0842AC8} = {58E95711-A12F-4C0E-A978-C6B4A0842AC8}
+ {66D0D8B1-FAF4-4C6A-8303-07F3BA356FE3} = {66D0D8B1-FAF4-4C6A-8303-07F3BA356FE3}
+ {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1}
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2} = {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}
+ {F2946790-DAF7-4DFF-A754-BA471A12E494} = {F2946790-DAF7-4DFF-A754-BA471A12E494}
+ {FBAE1876-C50A-4EFC-A686-3008B6438731} = {FBAE1876-C50A-4EFC-A686-3008B6438731}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "data", "data", "{6213B1A3-E854-498F-AAFA-4CFC1E71023E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager.Test.F.Red.Msix", "PackageManager.Test.F.Red.Msix", "{5188EBDF-87AE-4CA1-AA44-AD743583FF2D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManager.Test.F.Red.Msix", "test\PackageManager\data\PackageManager.Test.F.Red.Msix\PackageManager.Test.F.Red.Msix.vcxproj", "{F2946790-DAF7-4DFF-A754-BA471A12E494}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager.Test.F.Green.Msix", "PackageManager.Test.F.Green.Msix", "{266AE21F-0D59-4422-A95C-4B3D2BA32A4C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManager.Test.F.Green.msix", "test\PackageManager\data\PackageManager.Test.F.Green.msix\PackageManager.Test.F.Green.msix.vcxproj", "{4626E11F-A7A4-41A2-B22D-5A108BC369AC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager.Test.F.Blue.Msix", "PackageManager.Test.F.Blue.Msix", "{39A17DBB-F1DB-4D0C-B90E-D5F9BEC2283A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManager.Test.F.Blue.msix", "test\PackageManager\data\PackageManager.Test.F.Blue.msix\PackageManager.Test.F.Blue.msix.vcxproj", "{FBAE1876-C50A-4EFC-A686-3008B6438731}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManager.Test.F.Redder.Msix", "PackageManager.Test.F.Redder.Msix", "{B6B68924-6A0B-457E-AD53-018696EC8889}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageManager.Test.F.Redder.msix", "test\PackageManager\data\PackageManager.Test.F.Redder.msix\PackageManager.Test.F.Redder.msix.vcxproj", "{D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -2147,8 +2217,8 @@ Global
{FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|ARM64.Build.0 = Release|x64
{FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x64.ActiveCfg = Release|x64
{FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x64.Build.0 = Release|x64
- {FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x86.ActiveCfg = Release|Any CPU
- {FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x86.Build.0 = Release|Any CPU
+ {FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x86.ActiveCfg = Release|x64
+ {FD0CC14A-ED4B-4936-B68B-F31E58372E32}.Release|x86.Build.0 = Release|x64
{4B4667B2-94DB-4A19-8270-0FDB1676C27B}.Debug|Any CPU.ActiveCfg = Debug|x64
{4B4667B2-94DB-4A19-8270-0FDB1676C27B}.Debug|Any CPU.Build.0 = Debug|x64
{4B4667B2-94DB-4A19-8270-0FDB1676C27B}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -2243,6 +2313,86 @@ Global
{3F28C3ED-2548-4530-8B6C-832FAE0E993D}.Release|x64.Build.0 = Release|x64
{3F28C3ED-2548-4530-8B6C-832FAE0E993D}.Release|x86.ActiveCfg = Release|Win32
{3F28C3ED-2548-4530-8B6C-832FAE0E993D}.Release|x86.Build.0 = Release|Win32
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|Any CPU.Build.0 = Debug|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|ARM64.Build.0 = Debug|ARM64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|x64.ActiveCfg = Debug|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|x64.Build.0 = Debug|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|x86.ActiveCfg = Debug|Win32
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Debug|x86.Build.0 = Debug|Win32
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|Any CPU.ActiveCfg = Release|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|Any CPU.Build.0 = Release|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|ARM64.ActiveCfg = Release|ARM64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|ARM64.Build.0 = Release|ARM64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|x64.ActiveCfg = Release|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|x64.Build.0 = Release|x64
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|x86.ActiveCfg = Release|Win32
+ {4A38CB80-3580-4960-9B31-3301058B7AFE}.Release|x86.Build.0 = Release|Win32
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|Any CPU.Build.0 = Debug|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|x64.ActiveCfg = Debug|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|x64.Build.0 = Debug|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|x86.ActiveCfg = Debug|Win32
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Debug|x86.Build.0 = Debug|Win32
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|Any CPU.ActiveCfg = Release|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|Any CPU.Build.0 = Release|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|ARM64.Build.0 = Release|ARM64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|x64.ActiveCfg = Release|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|x64.Build.0 = Release|x64
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|x86.ActiveCfg = Release|Win32
+ {F2946790-DAF7-4DFF-A754-BA471A12E494}.Release|x86.Build.0 = Release|Win32
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|Any CPU.Build.0 = Debug|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|x64.ActiveCfg = Debug|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|x64.Build.0 = Debug|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|x86.ActiveCfg = Debug|Win32
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Debug|x86.Build.0 = Debug|Win32
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|Any CPU.ActiveCfg = Release|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|Any CPU.Build.0 = Release|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|ARM64.Build.0 = Release|ARM64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|x64.ActiveCfg = Release|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|x64.Build.0 = Release|x64
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|x86.ActiveCfg = Release|Win32
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC}.Release|x86.Build.0 = Release|Win32
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|Any CPU.Build.0 = Debug|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|x64.ActiveCfg = Debug|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|x64.Build.0 = Debug|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|x86.ActiveCfg = Debug|Win32
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Debug|x86.Build.0 = Debug|Win32
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|Any CPU.ActiveCfg = Release|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|Any CPU.Build.0 = Release|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|ARM64.Build.0 = Release|ARM64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|x64.ActiveCfg = Release|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|x64.Build.0 = Release|x64
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|x86.ActiveCfg = Release|Win32
+ {FBAE1876-C50A-4EFC-A686-3008B6438731}.Release|x86.Build.0 = Release|Win32
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|Any CPU.Build.0 = Debug|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|ARM64.Build.0 = Debug|ARM64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|x64.ActiveCfg = Debug|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|x64.Build.0 = Debug|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|x86.ActiveCfg = Debug|Win32
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Debug|x86.Build.0 = Debug|Win32
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|Any CPU.ActiveCfg = Release|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|Any CPU.Build.0 = Release|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|ARM64.ActiveCfg = Release|ARM64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|ARM64.Build.0 = Release|ARM64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|x64.ActiveCfg = Release|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|x64.Build.0 = Release|x64
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|x86.ActiveCfg = Release|Win32
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2436,6 +2586,21 @@ Global
{A18E00C4-3668-4289-ABFC-D1DF330DA6BF} = {9CE0ED94-078A-405F-8599-BFC2D8D6E537}
{82197F64-3A88-4C48-AEF9-7E62E71D75BB} = {84F66485-4391-41C7-89CB-D5006EDF1383}
{3F28C3ED-2548-4530-8B6C-832FAE0E993D} = {82197F64-3A88-4C48-AEF9-7E62E71D75BB}
+ {380C8BE1-1868-4860-BD32-ADCD8683285D} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A}
+ {CC969A0B-9B01-479D-A563-C9866BCC6F83} = {380C8BE1-1868-4860-BD32-ADCD8683285D}
+ {8A9A0C85-65A8-4BCA-A49E-45FC4FDBC7D2} = {CC969A0B-9B01-479D-A563-C9866BCC6F83}
+ {B03C7C69-0A52-4553-B465-04C995161E42} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D}
+ {4B85FB26-28B6-4072-85C2-DB7B5FEB98BE} = {B03C7C69-0A52-4553-B465-04C995161E42}
+ {4A38CB80-3580-4960-9B31-3301058B7AFE} = {4B85FB26-28B6-4072-85C2-DB7B5FEB98BE}
+ {6213B1A3-E854-498F-AAFA-4CFC1E71023E} = {B03C7C69-0A52-4553-B465-04C995161E42}
+ {5188EBDF-87AE-4CA1-AA44-AD743583FF2D} = {6213B1A3-E854-498F-AAFA-4CFC1E71023E}
+ {F2946790-DAF7-4DFF-A754-BA471A12E494} = {5188EBDF-87AE-4CA1-AA44-AD743583FF2D}
+ {266AE21F-0D59-4422-A95C-4B3D2BA32A4C} = {6213B1A3-E854-498F-AAFA-4CFC1E71023E}
+ {4626E11F-A7A4-41A2-B22D-5A108BC369AC} = {266AE21F-0D59-4422-A95C-4B3D2BA32A4C}
+ {39A17DBB-F1DB-4D0C-B90E-D5F9BEC2283A} = {6213B1A3-E854-498F-AAFA-4CFC1E71023E}
+ {FBAE1876-C50A-4EFC-A686-3008B6438731} = {39A17DBB-F1DB-4D0C-B90E-D5F9BEC2283A}
+ {B6B68924-6A0B-457E-AD53-018696EC8889} = {B03C7C69-0A52-4553-B465-04C995161E42}
+ {D0A1DFB8-8CEE-4CFC-B57B-B7C574B411C2} = {B6B68924-6A0B-457E-AD53-018696EC8889}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77}
@@ -2454,6 +2619,7 @@ Global
dev\Kozani\Common\Common.vcxitems*{829cdb09-eefe-4188-a045-3fc6be7bd96b}*SharedItemsImports = 4
dev\Common\Common.vcxitems*{8828053c-d6ec-4744-8624-f8c676c2d4df}*SharedItemsImports = 9
dev\Licensing\Licensing.vcxitems*{885a43fa-052d-4b0d-a2dc-13ee15796435}*SharedItemsImports = 9
+ dev\PackageManager\API\PackageManager.vcxitems*{8a9a0c85-65a8-4bca-a49e-45fc4fdbc7d2}*SharedItemsImports = 9
test\inc\inc.vcxitems*{8e52d7ea-a200-4a6b-ba74-8efb49468caf}*SharedItemsImports = 4
dev\Kozani\Common\Common.vcxitems*{a11c6664-f26a-4e71-b440-2e4e1ba09a93}*SharedItemsImports = 4
dev\AppNotifications\AppNotifications.vcxitems*{b4824897-88e0-4927-8fb9-e60106f01ed9}*SharedItemsImports = 9
@@ -2461,6 +2627,7 @@ Global
dev\Common\Common.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
dev\DynamicDependency\API\DynamicDependency.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
dev\Licensing\Licensing.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
+ dev\PackageManager\API\PackageManager.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
dev\PowerNotifications\PowerNotifications.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
dev\UndockedRegFreeWinRT\UndockedRegFreeWinRT.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
dev\PowerNotifications\PowerNotifications.vcxitems*{b75c1b22-553c-40e4-b38e-6ab4d01fdb9d}*SharedItemsImports = 9
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildBinaries-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildBinaries-Steps.yml
index 271df68e72..3ee7d5fdc7 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildBinaries-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildBinaries-Steps.yml
@@ -38,6 +38,7 @@ steps:
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: RestoreNuGetPackages
+ retryCountOnTaskFailure: 10
inputs:
restoreSolution: build/packages.config
feedsToUse: config
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildMRT-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildMRT-Steps.yml
index 701463aafc..3f003fa029 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildMRT-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildMRT-Steps.yml
@@ -47,6 +47,7 @@ steps:
- ${{ if not( parameters.RunPrefast ) }}:
- task: PowerShell@2
name: BuildBinaries
+ retryCountOnTaskFailure: 10
inputs:
filePath: 'BuildAll.ps1'
arguments: -Platform "$(buildPlatform)" -Configuration "$(buildConfiguration)" -AzureBuildStep "BuildMRT"
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildTransportPackage-Stage.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildTransportPackage-Stage.yml
index ed4356a52d..96c341f0e4 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-BuildTransportPackage-Stage.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-BuildTransportPackage-Stage.yml
@@ -2,6 +2,9 @@ parameters:
- name: "PublishToMaestro"
type: boolean
default: False
+- name: "PublishPackage"
+ type: boolean
+ default: False
- name: "IgnoreFailures"
type: boolean
default: False
@@ -163,6 +166,7 @@ stages:
parameters:
SignOutput: ${{ parameters.SignOutput }}
IsOneBranch: ${{ parameters.IsOneBranch }}
+ PublishPackage: ${{ parameters.PublishPackage }}
# Build WinAppSDK and Run Integration Test from TestAll.ps1
- job: WinAppSDKIntegrationBuildAndTest
@@ -174,7 +178,7 @@ stages:
name: 'ProjectReunionESPool-2022'
variables:
WindowsAppSDKTransportPackageVersion: $[ dependencies.NugetPackage.outputs['SetVersion.packageVersion'] ]
- VersionWithDevTag: $[format('{0}.{1}.{2}-{3}.{4}.{5}', variables['major'], variables['minor'], variables['patch'], 'dev', variables['versionDate'], variables['versionCounter'])]
+ VersionWithDevTag: $[format('{0}.{1}.{2}-{3}', variables['major'], variables['minor'], variables['versionDate'], 'dev')]
ob_outputDirectory: '$(REPOROOT)\out'
ob_artifactBaseName: "WindowsAppSDKNugetPackage"
steps:
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-PackNuget-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-PackNuget-Steps.yml
index e5fd2da6ee..cb10ed5a19 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-PackNuget-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-PackNuget-Steps.yml
@@ -2,6 +2,9 @@ parameters:
- name: "SignOutput"
type: boolean
default: False
+- name: "PublishPackage"
+ type: boolean
+ default: False
- name: "IsOneBranch"
type: boolean
default: True
@@ -154,7 +157,7 @@ steps:
displayName: MoveToOutputDirectory
inputs:
SourceFolder: '$(build.artifactStagingDirectory)\FullNuget'
- TargetFolder: '$(ob_outputDirectory)\TransportPackage'
+ TargetFolder: '$(ob_outputDirectory)'
- ${{ if not( parameters.IsOneBranch ) }}:
- task: PublishBuildArtifacts@1
@@ -162,13 +165,14 @@ steps:
PathtoPublish: '$(ob_outputDirectory)'
artifactName: '$(ob_artifactBaseName)'
-# this mysterious guid fixes the "NuGetCommand@2 is ambiguous" error :-(
-- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
- displayName: 'NuGet push to ProjectReunion.nuget.internal'
- inputs:
- command: 'push'
- packagesToPush: '$(ob_outputDirectory)\TransportPackage\*.nupkg'
- verbosityPush: 'Detailed'
- nuGetFeedType: 'internal'
- #Note: The project qualifier is always required when using a feed name. Also, do not use organization scoped feeds.
- publishVstsFeed: 'ProjectReunion/Project.Reunion.nuget.internal'
\ No newline at end of file
+- ${{ if eq(parameters.PublishPackage, 'true') }}:
+ # this mysterious guid fixes the "NuGetCommand@2 is ambiguous" error :-(
+ - task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
+ displayName: 'NuGet push to ProjectReunion.nuget.internal'
+ inputs:
+ command: 'push'
+ packagesToPush: '$(ob_outputDirectory)\*.nupkg'
+ verbosityPush: 'Detailed'
+ nuGetFeedType: 'internal'
+ #Note: The project qualifier is always required when using a feed name. Also, do not use organization scoped feeds.
+ publishVstsFeed: 'ProjectReunion/Project.Reunion.nuget.internal'
\ No newline at end of file
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-RunTests-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-RunTests-Steps.yml
index efd3462651..8210a16bfd 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-RunTests-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-RunTests-Steps.yml
@@ -1,10 +1,10 @@
parameters:
buildPlatform: ''
buildConfiguration: ''
- ImageName: ''
TaefSelect: '*'
BinaryCompatSwitch: ''
testLocale: ''
+
steps:
- task: powershell@2
displayName: 'DevCheck: Setup/Verify development environment'
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-RunTestsInPipeline-Job.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-RunTestsInPipeline-Job.yml
index 1c846355f3..af0b02eecb 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-RunTestsInPipeline-Job.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-RunTestsInPipeline-Job.yml
@@ -53,11 +53,6 @@ jobs:
buildPlatform: x64
buildConfiguration: release
testLocale: ja-JP
- 21H1_x64fre:
- imageName: Windows.10.Enterprise.21h1
- buildPlatform: x64
- buildConfiguration: release
- testLocale: en-US
21H2_MS_x64fre:
imageName: Windows.11.Enterprise.MultiSession.21h2
buildPlatform: x64
@@ -68,11 +63,6 @@ jobs:
buildPlatform: x86
buildConfiguration: release
testLocale: en-US
- co_refresh_x64fre:
- imageName: co_refresh
- buildPlatform: x64
- buildConfiguration: release
- testLocale: en-US
rs_prerelease_x64fre:
imageName: rs_prerelease
buildPlatform: x64
@@ -95,11 +85,6 @@ jobs:
buildPlatform: arm64
buildConfiguration: release
testLocale: en-US
- Server22_DC_arm64fre:
- imageName: Windows.11.Server2022.DataCenter.arm64
- buildPlatform: arm64
- buildConfiguration: release
- testLocale: en-US
pool:
type: windows
isCustom: true
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
index 7f7f78ae71..e91f722390 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
@@ -4,15 +4,10 @@ parameters:
default: True
steps:
-- task: UseDotNet@2
- displayName: Use .NET Core SDK 5
- inputs:
- version: 5.0.407
-
- task: UseDotNet@2
displayName: Use .NET Core SDK 6
inputs:
- version: 6.0.401
+ version: 6.0.414
# Extract the build revision number from Build.BuildNumber. This is needed to pass to build-nupkg.
# This relies on the format of the pipeline name being of the format: $(date:yyMM).$(date:dd)$(rev:rrr)
diff --git a/build/CopyFilesToStagingDir.ps1 b/build/CopyFilesToStagingDir.ps1
index 73d84a35b4..86d240c80a 100644
--- a/build/CopyFilesToStagingDir.ps1
+++ b/build/CopyFilesToStagingDir.ps1
@@ -39,15 +39,16 @@ PublishFile $OverrideDir\PushNotifications-Override.json $FullPublishDir\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\Microsoft.WindowsAppRuntime.dll $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\Microsoft.WindowsAppRuntime.pdb $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\Microsoft.WindowsAppRuntime.lib $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.DynamicDependency.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppLifecycle.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.Builder.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.DynamicDependency.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.Power.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.Power.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\MsixDynamicDependency.h $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\wil_msixdynamicdependency.h $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\Security.AccessControl.h $FullPublishDir\Microsoft.WindowsAppRuntime\
@@ -56,7 +57,6 @@ PublishFile $FullBuildOutput\RestartAgent\RestartAgent.pdb $FullPublishDir\Micro
PublishFile $FullBuildOutput\DeploymentAgent\DeploymentAgent.exe $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\DeploymentAgent\DeploymentAgent.pdb $FullPublishDir\Microsoft.WindowsAppRuntime\
-
#
PublishFile $FullBuildOutput\DynamicDependency.DataStore\DynamicDependency.DataStore.exe $FullPublishDir\DynamicDependency.DataStore\
PublishFile $FullBuildOutput\DynamicDependency.DataStore\DynamicDependency.DataStore.pdb $FullPublishDir\DynamicDependency.DataStore\
@@ -104,18 +104,18 @@ PublishFile $FullBuildOutput\Microsoft.Windows.ApplicationModel.WindowsAppRuntim
PublishFile $FullBuildOutput\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.AppLifecycle.Projection\Microsoft.Windows.AppLifecycle.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.AppLifecycle.Projection\Microsoft.Windows.AppLifecycle.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Projection\Microsoft.Windows.AppNotifications.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Projection\Microsoft.Windows.AppNotifications.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Builder.Projection\Microsoft.Windows.AppNotifications.Builder.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Builder.Projection\Microsoft.Windows.AppNotifications.Builder.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Projection\Microsoft.Windows.AppNotifications.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.AppNotifications.Projection\Microsoft.Windows.AppNotifications.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.System.Projection\Microsoft.Windows.System.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.System.Projection\Microsoft.Windows.System.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.System.Power.Projection\Microsoft.Windows.System.Power.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
-PublishFile $FullBuildOutput\Microsoft.Windows.System.Power.Projection\Microsoft.Windows.System.Power.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.System.Power.Projection\Microsoft.Windows.System.Power.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.System.Power.Projection\Microsoft.Windows.System.Power.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.System.Projection\Microsoft.Windows.System.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.System.Projection\Microsoft.Windows.System.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
#
# Dynamic Dependency build overrides
@@ -174,15 +174,16 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_MSIXInstallFromPath\WindowsAppRun
PublishFile $FullBuildOutput\WindowsAppRuntime_MSIXInstallFromPath\WindowsAppRuntime_MSIXInstallFromPath.pdb $NugetDir\tools\$Platform
#
# WinMD for UWP apps
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.DynamicDependency.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppLifecycle.winmd $NugetDir\lib\uap10.0
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.Builder.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $NugetDir\lib\uap10.0
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.DynamicDependency.winmd $NugetDir\lib\uap10.0
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.winmd $NugetDir\lib\uap10.0
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.winmd $NugetDir\lib\uap10.0
-PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.Power.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.Power.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.System.winmd $NugetDir\lib\uap10.0
#
# Bootstrap Auto-Initializer Files
PublishFile $FullBuildOutput\WindowsAppRuntime_BootstrapDLL\MddBootstrapAutoInitializer.cpp $NugetDir\include
diff --git a/build/NuSpecs/AppxManifest.xml b/build/NuSpecs/AppxManifest.xml
index ef35e49436..a4c68722d5 100644
--- a/build/NuSpecs/AppxManifest.xml
+++ b/build/NuSpecs/AppxManifest.xml
@@ -27,6 +27,8 @@
Microsoft.WindowsAppRuntime.dll
+
+
@@ -34,7 +36,7 @@
-
+
@@ -47,6 +49,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -64,19 +100,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build/NuSpecs/Microsoft.WindowsAppSDK.Bootstrap.CS.targets b/build/NuSpecs/Microsoft.WindowsAppSDK.Bootstrap.CS.targets
index 07f0ccdd5c..1a7f16ab5e 100644
--- a/build/NuSpecs/Microsoft.WindowsAppSDK.Bootstrap.CS.targets
+++ b/build/NuSpecs/Microsoft.WindowsAppSDK.Bootstrap.CS.targets
@@ -8,13 +8,14 @@
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_BOOTSTRAP_AUTO_INITIALIZE_OPTIONS_ONERROR_FAILFAST
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_BOOTSTRAP_AUTO_INITIALIZE_OPTIONS_ONNOMATCH_SHOWUI
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_BOOTSTRAP_AUTO_INITIALIZE_OPTIONS_ONPACKAGEIDENTITY_NOOP
+ true
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/build/NuSpecs/Microsoft.WindowsAppSDK.DeploymentManager.CS.targets b/build/NuSpecs/Microsoft.WindowsAppSDK.DeploymentManager.CS.targets
index 4524c2766a..d4bda4c0b7 100644
--- a/build/NuSpecs/Microsoft.WindowsAppSDK.DeploymentManager.CS.targets
+++ b/build/NuSpecs/Microsoft.WindowsAppSDK.DeploymentManager.CS.targets
@@ -4,13 +4,14 @@
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_DEPLOYMENTMANAGER_AUTO_INITIALIZE_OPTIONS_DEFAULT
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_DEPLOYMENTMANAGER_AUTO_INITIALIZE_OPTIONS_NONE
$(DefineConstants);MICROSOFT_WINDOWSAPPSDK_DEPLOYMENTMANAGER_AUTO_INITIALIZE_OPTIONS_ONERRORSHOWUI
+ true
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/build/NuSpecs/Microsoft.WindowsAppSDK.Foundation.targets b/build/NuSpecs/Microsoft.WindowsAppSDK.Foundation.targets
index 11a6d03861..73434d043d 100644
--- a/build/NuSpecs/Microsoft.WindowsAppSDK.Foundation.targets
+++ b/build/NuSpecs/Microsoft.WindowsAppSDK.Foundation.targets
@@ -1,4 +1,4 @@
-
+
@@ -13,4 +13,8 @@
+
+
+
+
diff --git a/build/ProjectReunion-BuildFoundation.yml b/build/ProjectReunion-BuildFoundation.yml
index f741dc5448..84f5510b8f 100644
--- a/build/ProjectReunion-BuildFoundation.yml
+++ b/build/ProjectReunion-BuildFoundation.yml
@@ -11,4 +11,5 @@ stages:
parameters:
PublishToMaestro: False
SignOutput: False
- IsOneBranch: False
\ No newline at end of file
+ IsOneBranch: False
+ PublishPackage: False
\ No newline at end of file
diff --git a/build/ProjectReunion-CI.yml b/build/ProjectReunion-CI.yml
index 40ed8edb4a..85114d6b5f 100644
--- a/build/ProjectReunion-CI.yml
+++ b/build/ProjectReunion-CI.yml
@@ -55,16 +55,17 @@ jobs:
targetType: filePath
filePath: tools\VerifyCopyrightHeaders.ps1
-- job: Build
+- job: BuildBinaries
pool:
vmImage: 'windows-2022'
timeoutInMinutes: 120
strategy:
maxParallel: 10
matrix:
- Debug_x86:
- buildPlatform: 'x86'
- buildConfiguration: 'Debug'
+ # TODO: Reenable when LNK2019 error is fixed Bug#46043382
+ # Debug_x86:
+ # buildPlatform: 'x86'
+ # buildConfiguration: 'Debug'
Release_x86:
buildPlatform: 'x86'
buildConfiguration: 'Release'
@@ -84,6 +85,8 @@ jobs:
- task: NuGetToolInstaller@1
- template: AzurePipelinesTemplates\WindowsAppSDK-SetupBuildEnvironment-Steps.yml
+ parameters:
+ IsOneBranch: false
- task: PowerShell@2
name: BuildBinaries
@@ -91,19 +94,27 @@ jobs:
filePath: 'BuildAll.ps1'
arguments: -Platform "$(buildPlatform)" -Configuration "$(buildConfiguration)" -AzureBuildStep "BuildBinaries"
+ - task: CopyFiles@2
+ displayName: MoveToOutputDirectory
+ inputs:
+ SourceFolder: '$(build.SourcesDirectory)\packages'
+ TargetFolder: '$(build.SourcesDirectory)\BuildOutput\packages'
+
- task: PublishBuildArtifacts@1
displayName: 'Publish artifact: Full Nuget'
inputs:
PathtoPublish: '$(build.SourcesDirectory)\BuildOutput'
- artifactName: 'BuildOutput'
+ artifactName: 'FoundationBinaries_$(buildConfiguration)_$(buildPlatform)'
-- job: BuildAnyCPU
+- job: BuildBinaries_release_anycpu
pool:
vmImage: 'windows-2022'
steps:
- task: NuGetToolInstaller@1
- template: AzurePipelinesTemplates\WindowsAppSDK-SetupBuildEnvironment-Steps.yml
+ parameters:
+ IsOneBranch: false
- task: PowerShell@2
name: BuildBinaries
@@ -115,7 +126,7 @@ jobs:
displayName: 'Publish artifact: Full Nuget'
inputs:
PathtoPublish: '$(build.SourcesDirectory)\BuildOutput'
- artifactName: 'BuildOutput'
+ artifactName: 'FoundationBinaries_Release_AnyCPU'
- job: BuildMRT
pool:
@@ -132,96 +143,42 @@ jobs:
Release_Arm64:
buildPlatform: 'ARM64'
buildConfiguration: 'Release'
+ variables:
+ ob_artifactBaseName: "MrtBinaries_$(buildConfiguration)_$(buildPlatform)" # For BuildMRT to publish t
steps:
- task: NuGetToolInstaller@1
- template: AzurePipelinesTemplates\WindowsAppSDK-BuildMRT-Steps.yml
+ parameters:
+ IsOneBranch: false
- - task: PublishBuildArtifacts@1
- displayName: 'Publish BuildOutput'
- inputs:
- artifactName: BuildOutput
- PathtoPublish: '$(buildOutputDir)'
-
-# We no longer run MRT tests in Helix here, due to dwindling Helix support. But one MRT test suite
-# is still being run in WindowsAppSDK-BuildMRT-Steps.yml.
-
-- job: StageAndPack
+- job: Test
pool:
vmImage: 'windows-2022'
- timeoutInMinutes: 120
+ strategy:
+ maxParallel: 10
+ matrix:
+ Release_x86:
+ buildPlatform: 'x86'
+ buildConfiguration: 'Release'
+ testLocale: en-US
+ Release_x64:
+ buildPlatform: 'x64'
+ buildConfiguration: 'Release'
+ testLocale: en-US
+ Release_Arm64:
+ buildPlatform: 'ARM64'
+ buildConfiguration: 'Release'
+ testLocale: en-US
dependsOn:
- - Build
- - BuildMRT
+ - BuildBinaries
+ - BuildBinaries_release_anycpu
+ - BuildMRT
+ variables:
+ testPayloadArtifactDir: $(Build.SourcesDirectory)\BuildOutput\$(buildConfiguration)\$(buildPlatform)
steps:
- - task: DownloadBuildArtifacts@0
- inputs:
- artifactName: BuildOutput
- downloadPath: '$(Build.SourcesDirectory)'
-
- - task: PowerShell@2
- name: StageFiles
- inputs:
- filePath: 'BuildAll.ps1'
- arguments: -Platform "x86,x64,arm64" -Configuration "release" -AzureBuildStep "StageFiles"
-
- - task: PowerShell@2
- name: SetVersion
- displayName: Update metapackage version
- inputs:
- targetType: 'inline'
- script: |
- $packageVersion = '$(version)'
- $pipelineType = '$(PipelineType)'
- $sourceBranchName = '$(Build.SourceBranchName)'
- if ($sourceBranchName -eq 'main' -or $sourceBranchName -eq 'develop')
- {
- $packageVersion = $packageVersion + '.' + $sourceBranchName + '.' + $pipelineType
- }
- Write-Host "##vso[task.setvariable variable=packageVersion;]$packageVersion"
- Write-Host $packageVersion
- [xml]$publicNuspec = Get-Content -Path $(Build.SourcesDirectory)\build\NuSpecs\Microsoft.WindowsAppSDK.Foundation.nuspec
- $publicNuspec.package.metadata.version = $packageVersion
- Set-Content -Value $publicNuspec.OuterXml $(Build.SourcesDirectory)\build\NuSpecs\Microsoft.WindowsAppSDK.Foundation.nuspec
- - task: PowerShell@2
- name: PackNuget
- inputs:
- filePath: 'BuildAll.ps1'
- arguments: -Platform "x64" -Configuration "release" -AzureBuildStep "PackNuget" -OutputDirectory "$(build.artifactStagingDirectory)\FullNuget" -PackageVersion "$(packageVersion)"
-
- - task: BinSkim@3
- inputs:
- InputType: 'Basic'
- Function: 'analyze'
- AnalyzeTarget: '$(build.SourcesDirectory)\BuildOutput\FullNuget\*.dll;$(build.SourcesDirectory)\BuildOutput\FullNuget\*.exe'
- AnalyzeVerbose: true
-
- - task: PostAnalysis@1
- inputs:
- AllTools: false
- APIScan: false
- BinSkim: true
- BinSkimBreakOn: 'Error'
- CodesignValidation: false
- CredScan: false
- FortifySCA: false
- FxCop: false
- ModernCop: false
- PoliCheck: false
- RoslynAnalyzers: false
- SDLNativeRules: false
- Semmle: false
- TSLint: false
- ToolLogsNotFoundAction: 'Standard'
-
- - task: PublishBuildArtifacts@1
- displayName: 'Publish artifact: NugetContent'
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\BuildOutput\FullNuget'
- artifactName: 'NugetContent'
-
- - task: PublishBuildArtifacts@1
- displayName: 'Publish artifact: TransportPackage'
- inputs:
- PathtoPublish: '$(build.artifactStagingDirectory)\FullNuget'
- artifactName: 'TransportPackage'
+ - template: AzurePipelinesTemplates\WindowsAppSDK-RunTests-Steps.yml
+ parameters:
+ buildPlatform: $(buildPlatform)
+ buildConfiguration: $(buildConfiguration)
+ testLocale: $(testLocale)
diff --git a/build/WindowsAppSDK-CommonVariables.yml b/build/WindowsAppSDK-CommonVariables.yml
index 0445b50b0f..32e2f8a0b5 100644
--- a/build/WindowsAppSDK-CommonVariables.yml
+++ b/build/WindowsAppSDK-CommonVariables.yml
@@ -13,7 +13,7 @@ variables:
Codeql.Enabled: true # CodeQL runs every 3 days on the default branch for all languages its applicable to in that pipeline.
- channel: 'preview'
+ channel: 'experimental'
rerunPassesRequiredToAvoidFailure: 5
versionDate: $[format('{0:yyyyMMdd}', pipeline.startTime)]
versionCounter: $[counter(variables['versionDate'], 0)]
diff --git a/build/WindowsAppSDK-Foundation-Nightly.yml b/build/WindowsAppSDK-Foundation-Nightly.yml
index 3c2d7b38c0..7ecd4ff3ef 100644
--- a/build/WindowsAppSDK-Foundation-Nightly.yml
+++ b/build/WindowsAppSDK-Foundation-Nightly.yml
@@ -76,4 +76,5 @@ extends:
parameters:
PublishToMaestro: ${{ parameters.PublishToMaestro }}
IgnoreFailures: ${{ parameters.IgnoreFailures }}
- SignOutput: ${{ parameters.SignOutput }}
\ No newline at end of file
+ SignOutput: ${{ parameters.SignOutput }}
+ PublishPackage: true
\ No newline at end of file
diff --git a/build/WindowsAppSDK-Foundation-PR.yml b/build/WindowsAppSDK-Foundation-PR.yml
index b97204c142..e982969d97 100644
--- a/build/WindowsAppSDK-Foundation-PR.yml
+++ b/build/WindowsAppSDK-Foundation-PR.yml
@@ -51,5 +51,6 @@ extends:
stages:
- template: AzurePipelinesTemplates\WindowsAppSDK-BuildTransportPackage-Stage.yml@self
parameters:
- PublishToMaestro: False
- SignOutput: False
\ No newline at end of file
+ PublishToMaestro: false
+ SignOutput: false
+ PublishPackage: false
\ No newline at end of file
diff --git a/build/WindowsAppSDK-Foundation-Release.yml b/build/WindowsAppSDK-Foundation-Release.yml
index b8f74fe2f6..38f2caeeec 100644
--- a/build/WindowsAppSDK-Foundation-Release.yml
+++ b/build/WindowsAppSDK-Foundation-Release.yml
@@ -64,4 +64,5 @@ extends:
parameters:
PublishToMaestro: ${{ parameters.PublishToMaestro }}
IgnoreFailures: ${{ parameters.IgnoreFailures }}
- SignOutput: ${{ parameters.SignOutput }}
\ No newline at end of file
+ SignOutput: ${{ parameters.SignOutput }}
+ PublishPackage: true
\ No newline at end of file
diff --git a/build/WindowsAppSDK-Versions.yml b/build/WindowsAppSDK-Versions.yml
index faf7fe6fb3..2d35180d18 100644
--- a/build/WindowsAppSDK-Versions.yml
+++ b/build/WindowsAppSDK-Versions.yml
@@ -1,5 +1,5 @@
variables:
# Version Control
major: "1"
- minor: "4"
+ minor: "5"
patch: "0"
diff --git a/dev/Common/AppModel.Identity.h b/dev/Common/AppModel.Identity.h
index d975c4e82f..fa0f646b29 100644
--- a/dev/Common/AppModel.Identity.h
+++ b/dev/Common/AppModel.Identity.h
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation and Contributors.
+// Copyright (c) Microsoft Corporation and Contributors.
// Licensed under the MIT License.
#ifndef __APPMODEL_IDENTITY_H
@@ -6,6 +6,9 @@
#include
+#include
+#include
+
namespace AppModel::Identity
{
inline bool IsPackagedProcess()
@@ -46,6 +49,34 @@ constexpr PCWSTR GetCurrentArchitectureAsString()
#endif
}
+constexpr PCWSTR GetArchitectureAsString(const std::uint32_t architecture)
+{
+ switch (architecture)
+ {
+ case PROCESSOR_ARCHITECTURE_AMD64: return L"x64";
+ case PROCESSOR_ARCHITECTURE_ARM: return L"arm";
+ case PROCESSOR_ARCHITECTURE_ARM64: return L"arm64";
+ case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: return L"x86onArm64";
+ case PROCESSOR_ARCHITECTURE_INTEL: return L"x86";
+ case PROCESSOR_ARCHITECTURE_NEUTRAL: return L"neutral";
+ case PROCESSOR_ARCHITECTURE_UNKNOWN: return L"unknown";
+ default: THROW_HR_MSG(E_UNEXPECTED, "Unknown architecture 0x%X", architecture);
+ }
+}
+
+constexpr PCWSTR GetArchitectureAsString(const winrt::Windows::System::ProcessorArchitecture architecture)
+{
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::Arm) == static_cast(PROCESSOR_ARCHITECTURE_ARM), "winrt::Windows::System::ProcessorArchitecture::Arm != PROCESSOR_ARCHITECTURE_ARM");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::Arm64) == static_cast(PROCESSOR_ARCHITECTURE_ARM64), "winrt::Windows::System::ProcessorArchitecture::Arm64 != PROCESSOR_ARCHITECTURE_ARM64");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::Neutral) == static_cast(PROCESSOR_ARCHITECTURE_NEUTRAL), "winrt::Windows::System::ProcessorArchitecture::Neutral != PROCESSOR_ARCHITECTURE_NEUTRAL");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::Unknown) == static_cast(PROCESSOR_ARCHITECTURE_UNKNOWN), "winrt::Windows::System::ProcessorArchitecture::Unknown != PROCESSOR_ARCHITECTURE_UNKNOWN");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::X64) == static_cast(PROCESSOR_ARCHITECTURE_AMD64), "winrt::Windows::System::ProcessorArchitecture::X64 != PROCESSOR_ARCHITECTURE_AMD64");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::X86) == static_cast(PROCESSOR_ARCHITECTURE_INTEL), "winrt::Windows::System::ProcessorArchitecture::X86 != PROCESSOR_ARCHITECTURE_INTEL");
+ static_assert(static_cast(winrt::Windows::System::ProcessorArchitecture::X86OnArm64) == static_cast(PROCESSOR_ARCHITECTURE_IA32_ON_ARM64), "winrt::Windows::System::ProcessorArchitecture::X86OnArm64 != PROCESSOR_ARCHITECTURE_IA32_ON_ARM64");
+
+ return GetArchitectureAsString(static_cast(architecture));
+}
+
inline winrt::Windows::System::ProcessorArchitecture ParseArchitecture(_In_ PCWSTR architecture)
{
if (CompareStringOrdinal(architecture, -1, L"x64", -1, TRUE) == CSTR_EQUAL)
@@ -109,6 +140,109 @@ inline winrt::Windows::System::ProcessorArchitecture ParseShortArchitecture(_In_
}
}
+class PackageVersion : public PACKAGE_VERSION
+{
+public:
+ PackageVersion(const PackageVersion&) = default;
+
+ // Create an instance with the value `major.minor.build.revision`.
+ PackageVersion(std::uint16_t major, std::uint16_t minor = 0, std::uint16_t build = 0, std::uint16_t revision = 0) :
+ PACKAGE_VERSION()
+ {
+ Major = major;
+ Minor = minor;
+ Build = build;
+ Revision = revision;
+ }
+
+ // Create an instance from a version as a uint64.
+ PackageVersion(std::uint64_t version = 0)
+ {
+ Version = version;
+ }
+
+ template
+ PackageVersion(TVersion const& t) :
+ PackageVersion(t.Major, t.Minor, t.Build, t.Revision)
+ {
+ }
+
+#if defined(WINRT_Windows_ApplicationModel_2_H)
+ PackageVersion(winrt::Windows::ApplicationModel::PackageVersion packageVersion) :
+ PACKAGE_VERSION()
+ {
+ Major = packageVersion.Major;
+ Minor = packageVersion.Minor;
+ Build = packageVersion.Build;
+ Revision = packageVersion.Revision;
+ }
+#endif // defined(WINRT_Windows_ApplicationModel_2_H)
+
+ PackageVersion& operator=(const PackageVersion&) = default;
+
+ // Return the version as a uint64.
+ std::uint64_t ToVersion() const
+ {
+ return Version;
+ }
+
+#if defined(____x_ABI_CWindows_CApplicationModel_CIPackageId_INTERFACE_DEFINED__)
+ ABI::Windows::ApplicationModel::PackageVersion ToPackageVersion() const
+ {
+ return ABI::Windows::ApplicationModel::PackageVersion{ Major, Minor, Build, Revision };
+ }
+#endif // defined(____x_ABI_CWindows_CApplicationModel_CIPackageId_INTERFACE_DEFINED__)
+
+#if defined(WINRT_Windows_ApplicationModel_2_H)
+ winrt::Windows::ApplicationModel::PackageVersion ToWinrtPackageVersion() const
+ {
+ return winrt::Windows::ApplicationModel::PackageVersion{ Major, Minor, Build, Revision };
+ }
+#endif // defined(WINRT_Windows_ApplicationModel_2_H)
+
+#if defined(_XSTRING_)
+ // Return the string as a formatted value "major.minor.build.revision".
+ std::wstring ToString() const
+ {
+ return ToString(Major, Minor, Build, Revision);
+ }
+
+ static std::wstring ToString(std::uint16_t major, std::uint16_t minor, std::uint16_t build, std::uint16_t revision)
+ {
+#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L))
+ return std::format(L"{}.{}.{}.{}", major, minor, build, revision);
+#else
+ return std::to_wstring(major) + L"." + std::to_wstring(minor) + L"." + std::to_wstring(build) + L"." + std::to_wstring(revision);
+#endif
+ }
+#endif defined(_XSTRING_)
+};
+
+inline bool operator==(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version == packageVersion2.Version;
+}
+inline bool operator!=(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version != packageVersion2.Version;
+}
+inline bool operator<(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version < packageVersion2.Version;
+}
+inline bool operator<=(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version <= packageVersion2.Version;
+}
+inline bool operator>(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version > packageVersion2.Version;
+}
+inline bool operator>=(const PackageVersion& packageVersion1, const PackageVersion& packageVersion2)
+{
+ return packageVersion1.Version >= packageVersion2.Version;
+}
+
inline bool IsValidVersionShortTag(
const std::wstring& versionShortTag)
{
diff --git a/dev/Common/AppModel.Package.h b/dev/Common/AppModel.Package.h
index 1dd596db3b..772091840a 100644
--- a/dev/Common/AppModel.Package.h
+++ b/dev/Common/AppModel.Package.h
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation and Contributors.
+// Copyright (c) Microsoft Corporation and Contributors.
// Licensed under the MIT License.
#ifndef __APPMODEL_PACKAGE_H
@@ -6,6 +6,8 @@
#include
+#include
+
namespace AppModel::Package
{
/// Find all Main+Framework packages in a package family registered to the current user
@@ -52,6 +54,31 @@ inline PACKAGE_VERSION ToPackageVersion(winrt::Windows::ApplicationModel::Packag
to.Revision = from.Revision;
return to;
}
+
+inline std::tuple ParsePackageFullName(PCWSTR packageFullName)
+{
+ BYTE buffer[
+ sizeof(PACKAGE_ID) +
+ sizeof(WCHAR) * (PACKAGE_NAME_MAX_LENGTH + 1) +
+ sizeof(WCHAR) * (PACKAGE_VERSION_MAX_LENGTH + 1) +
+ sizeof(WCHAR) * (PACKAGE_ARCHITECTURE_MAX_LENGTH + 1) +
+ sizeof(WCHAR) * (PACKAGE_RESOURCEID_MAX_LENGTH + 1) +
+ sizeof(WCHAR) * (PACKAGE_PUBLISHERID_MAX_LENGTH + 1)]{};
+ UINT32 bufferLength{ ARRAYSIZE(buffer) };
+ THROW_IF_WIN32_ERROR_MSG(::PackageIdFromFullName(packageFullName, PACKAGE_INFORMATION_BASIC, &bufferLength, buffer), "%ls", packageFullName);
+ const auto& packageId{ *reinterpret_cast(buffer) };
+
+ WCHAR packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1]{};
+ UINT32 packageFamilyNameLength{ ARRAYSIZE(packageFamilyName) };
+ THROW_IF_WIN32_ERROR_MSG(::PackageFamilyNameFromId(&packageId, &packageFamilyNameLength, packageFamilyName), "%ls", packageFullName);
+
+ return { std::wstring(packageId.name), packageId.version, packageId.processorArchitecture, std::wstring(packageId.resourceId ? packageId.resourceId : L""), std::wstring(packageId.publisherId), std::wstring(packageFamilyName) };
+}
+
+inline std::tuple ParsePackageFullName(const std::wstring& packageFullName)
+{
+ return ParsePackageFullName(packageFullName.c_str());
+}
}
#endif // __APPMODEL_PACKAGE_H
diff --git a/dev/Common/Common.vcxitems b/dev/Common/Common.vcxitems
index e3bb682e8b..1de21b01e5 100644
--- a/dev/Common/Common.vcxitems
+++ b/dev/Common/Common.vcxitems
@@ -29,5 +29,6 @@
+
\ No newline at end of file
diff --git a/dev/Common/Common.vcxitems.filters b/dev/Common/Common.vcxitems.filters
index 1fccf173f1..7a346b9426 100644
--- a/dev/Common/Common.vcxitems.filters
+++ b/dev/Common/Common.vcxitems.filters
@@ -41,6 +41,9 @@
Header Files
+
+ Header Files
+
diff --git a/dev/Common/TerminalVelocityFeatures-PackageManager.h b/dev/Common/TerminalVelocityFeatures-PackageManager.h
new file mode 100644
index 0000000000..99edf97bbd
--- /dev/null
+++ b/dev/Common/TerminalVelocityFeatures-PackageManager.h
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT IT
+
+// INPUT FILE: dev\common\TerminalVelocityFeatures-PackageManager.xml
+// OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.Management.Deployment -Path dev\common\TerminalVelocityFeatures-PackageManager.xml -Output dev\common\TerminalVelocityFeatures-PackageManager.h
+
+#if defined(__midlrt)
+namespace features
+{
+ feature_name Feature_PackageManager = { DisabledByDefault, FALSE };
+}
+#endif // defined(__midlrt)
+
+// Feature constants
+#define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_MANAGEMENT_DEPLOYMENT_FEATURE_PACKAGEMANAGER_ENABLED 1
+
+#if defined(__cplusplus)
+
+namespace Microsoft::Windows::Management::Deployment
+{
+
+__pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_MANAGEMENT_DEPLOYMENT_FEATURE_PACKAGEMANAGER_ENABLED_mismatch", "AlwaysEnabled"))
+struct Feature_PackageManager
+{
+ static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_MANAGEMENT_DEPLOYMENT_FEATURE_PACKAGEMANAGER_ENABLED == 1; }
+};
+
+} // namespace Microsoft.Windows.Management.Deployment
+
+#endif // defined(__cplusplus)
diff --git a/dev/Common/TerminalVelocityFeatures-PackageManager.xml b/dev/Common/TerminalVelocityFeatures-PackageManager.xml
new file mode 100644
index 0000000000..932aa39394
--- /dev/null
+++ b/dev/Common/TerminalVelocityFeatures-PackageManager.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+ Feature_PackageManager
+ Package Management APIs
+ AlwaysEnabled
+
+ Preview
+ Stable
+
+
+
diff --git a/dev/Common/winrt_WindowsAppRuntime.h b/dev/Common/winrt_WindowsAppRuntime.h
new file mode 100644
index 0000000000..d986617997
--- /dev/null
+++ b/dev/Common/winrt_WindowsAppRuntime.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#ifndef __WINRT_WINDOWS_APP_RUNTIME_H
+#define __WINRT_WINDOWS_APP_RUNTIME_H
+
+namespace winrt
+{
+ // Per https://docs.microsoft.com/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi#convert_from_abi-function
+ template
+ T convert_from_abi(::IUnknown* from)
+ {
+ T to{ nullptr }; // `T` is a projected type.
+
+ winrt::check_hresult(from->QueryInterface(winrt::guid_of(),
+ winrt::put_abi(to)));
+
+ return to;
+ }
+
+ template
+ T convert_from_abi(::IInspectable* from)
+ {
+ T to{ nullptr }; // `T` is a projected type.
+
+ winrt::check_hresult(from->QueryInterface(winrt::guid_of(),
+ winrt::put_abi(to)));
+
+ return to;
+ }
+}
+
+#endif // __WINRT_WINDOWS_APP_RUNTIME_H
\ No newline at end of file
diff --git a/dev/DeploymentAgent/packages.config b/dev/DeploymentAgent/packages.config
index 2305cb7181..9ba3aa91dd 100644
--- a/dev/DeploymentAgent/packages.config
+++ b/dev/DeploymentAgent/packages.config
@@ -1,5 +1,5 @@
-
+
diff --git a/dev/DynamicDependency/API/DataStore.cpp b/dev/DynamicDependency/API/DataStore.cpp
index 50d18dfab9..65ba3a97e8 100644
--- a/dev/DynamicDependency/API/DataStore.cpp
+++ b/dev/DynamicDependency/API/DataStore.cpp
@@ -6,7 +6,7 @@
#include "DataStore.h"
#include "DynamicDependencyDataStore_h.h"
-#include "winrt_msixdynamicdependency.h"
+#include "winrt_WindowsAppRuntime.h"
#include
diff --git a/dev/DynamicDependency/API/DynamicDependency.vcxitems b/dev/DynamicDependency/API/DynamicDependency.vcxitems
index 091653b2b9..e5f3fa55ae 100644
--- a/dev/DynamicDependency/API/DynamicDependency.vcxitems
+++ b/dev/DynamicDependency/API/DynamicDependency.vcxitems
@@ -23,6 +23,7 @@
+
@@ -46,6 +47,7 @@
+
@@ -60,7 +62,6 @@
-
@@ -70,6 +71,7 @@
+
diff --git a/dev/DynamicDependency/API/DynamicDependency.vcxitems.filters b/dev/DynamicDependency/API/DynamicDependency.vcxitems.filters
index 587277fc02..293f21384c 100644
--- a/dev/DynamicDependency/API/DynamicDependency.vcxitems.filters
+++ b/dev/DynamicDependency/API/DynamicDependency.vcxitems.filters
@@ -50,6 +50,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -127,6 +130,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -148,9 +154,6 @@
Header Files
-
- Header Files
-
diff --git a/dev/DynamicDependency/API/MddWin11.cpp b/dev/DynamicDependency/API/MddWin11.cpp
new file mode 100644
index 0000000000..cca5dad052
--- /dev/null
+++ b/dev/DynamicDependency/API/MddWin11.cpp
@@ -0,0 +1,256 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+
+#include "MddWin11.h"
+
+namespace MddCore::Win11
+{
+static HMODULE g_dllApisetAppmodelRuntime_1_6{};
+static decltype(&::TryCreatePackageDependency) g_win11TryCreatePackageDependency{};
+static decltype(&::DeletePackageDependency) g_win11DeletePackageDependency{};
+static decltype(&::AddPackageDependency) g_win11AddPackageDependency{};
+static decltype(&::RemovePackageDependency) g_win11RemovePackageDependency{};
+static decltype(&::GetResolvedPackageFullNameForPackageDependency) g_win11GetResolvedPackageFullNameForPackageDependency{};
+static decltype(&::GetIdForPackageDependencyContext) g_win11GetIdForPackageDependencyContext{};
+static decltype(&::GetPackageGraphRevisionId) g_win11GetPackageGraphRevisionId{};
+
+constexpr PackageDependencyLifetimeKind ToLifetimeKind(MddPackageDependencyLifetimeKind lifetimeKind)
+{
+ switch (lifetimeKind)
+ {
+ case MddPackageDependencyLifetimeKind::Process: return PackageDependencyLifetimeKind_Process;
+ case MddPackageDependencyLifetimeKind::FilePath: return PackageDependencyLifetimeKind_FilePath;
+ case MddPackageDependencyLifetimeKind::RegistryKey: return PackageDependencyLifetimeKind_RegistryKey;
+ default: THROW_HR_MSG(E_UNEXPECTED, "Unknown MddPackageDependencyLifetimeKind (%d)", lifetimeKind);
+ };
+}
+
+constexpr PackageDependencyLifetimeKind ToLifetimeKind(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyLifetimeArtifactKind lifetimeKind)
+{
+ switch (lifetimeKind)
+ {
+ case winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyLifetimeArtifactKind::Process: return PackageDependencyLifetimeKind_Process;
+ case winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyLifetimeArtifactKind::FilePath: return PackageDependencyLifetimeKind_FilePath;
+ case winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyLifetimeArtifactKind::RegistryKey: return PackageDependencyLifetimeKind_RegistryKey;
+ default: THROW_HR_MSG(E_UNEXPECTED, "Unknown winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyLifetimeKind (%d)", lifetimeKind);
+ };
+}
+}
+
+HRESULT WINAPI MddWin11Initialize() noexcept
+{
+ if (!MddCore::Win11::IsSupported())
+ {
+ return S_OK;
+ }
+
+ HMODULE dllApisetAppmodelRuntime_1_6{ LoadLibraryExW(L"api-ms-win-appmodel-runtime-l1-1-6.dll", nullptr, 0) };
+ FAIL_FAST_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), dllApisetAppmodelRuntime_1_6);
+
+ auto win11TryCreatePackageDependency{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, TryCreatePackageDependency) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11TryCreatePackageDependency);
+ auto win11DeletePackageDependency{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, DeletePackageDependency) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11DeletePackageDependency);
+ auto win11AddPackageDependency{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, AddPackageDependency) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11AddPackageDependency);
+ auto win11RemovePackageDependency{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, RemovePackageDependency) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11RemovePackageDependency);
+ auto win11GetResolvedPackageFullNameForPackageDependency{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, GetResolvedPackageFullNameForPackageDependency) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11GetResolvedPackageFullNameForPackageDependency);
+ auto win11GetIdForPackageDependencyContext{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, GetIdForPackageDependencyContext) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11GetIdForPackageDependencyContext);
+ auto win11GetPackageGraphRevisionId{ GetProcAddressByFunctionDeclaration(dllApisetAppmodelRuntime_1_6, GetPackageGraphRevisionId) };
+ RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(GetLastError()), win11GetPackageGraphRevisionId);
+
+ MddCore::Win11::g_dllApisetAppmodelRuntime_1_6 = dllApisetAppmodelRuntime_1_6;
+ MddCore::Win11::g_win11TryCreatePackageDependency = win11TryCreatePackageDependency;
+ MddCore::Win11::g_win11DeletePackageDependency = win11DeletePackageDependency;
+ MddCore::Win11::g_win11AddPackageDependency = win11AddPackageDependency;
+ MddCore::Win11::g_win11RemovePackageDependency = win11RemovePackageDependency;
+ MddCore::Win11::g_win11GetResolvedPackageFullNameForPackageDependency = win11GetResolvedPackageFullNameForPackageDependency;
+ MddCore::Win11::g_win11GetIdForPackageDependencyContext = win11GetIdForPackageDependencyContext;
+ MddCore::Win11::g_win11GetPackageGraphRevisionId = win11GetPackageGraphRevisionId;
+ return S_OK;
+}
+
+HRESULT WINAPI MddWin11Shutdown() noexcept
+{
+ if (MddCore::Win11::g_dllApisetAppmodelRuntime_1_6)
+ {
+ MddCore::Win11::g_win11TryCreatePackageDependency = nullptr;
+ MddCore::Win11::g_win11DeletePackageDependency = nullptr;
+ MddCore::Win11::g_win11AddPackageDependency = nullptr;
+ MddCore::Win11::g_win11RemovePackageDependency = nullptr;
+ MddCore::Win11::g_win11GetResolvedPackageFullNameForPackageDependency = nullptr;
+ MddCore::Win11::g_win11GetIdForPackageDependencyContext = nullptr;
+ MddCore::Win11::g_win11GetPackageGraphRevisionId = nullptr;
+ FreeLibrary(MddCore::Win11::g_dllApisetAppmodelRuntime_1_6);
+ MddCore::Win11::g_dllApisetAppmodelRuntime_1_6 = nullptr;
+ }
+ return S_OK;
+}
+
+bool MddCore::Win11::IsSupported()
+{
+ static bool s_isSupported{ WindowsVersion::IsWindows11_22H2OrGreater() };
+ return s_isSupported;
+}
+
+HRESULT MddCore::Win11::TryCreatePackageDependency(
+ PSID user,
+ const winrt::hstring& packageFamilyName,
+ const winrt::Windows::ApplicationModel::PackageVersion& minVersion,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures packageDependencyProcessorArchitectures,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& options,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId)
+{
+ PCWSTR win11PackageFamilyName{ packageFamilyName.c_str() };
+
+ const ::AppModel::Identity::PackageVersion minPackageVersion{ minVersion };
+ const PACKAGE_VERSION win11MinVersion{ minPackageVersion };
+
+ auto win11PackageDependencyProcessorArchitectures{ PackageDependencyProcessorArchitectures_None };
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Neutral, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::Neutral));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X86, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::X86));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X64, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::X64));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Arm, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::Arm));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Arm64, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::Arm64));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X86A64, WI_IsFlagSet(packageDependencyProcessorArchitectures, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures::X86OnArm64));
+
+ const auto win11LifetimeKind{ ToLifetimeKind(options.LifetimeArtifactKind()) };
+
+ PCWSTR win11LifetimeArtifact{ options.LifetimeArtifact().c_str() };
+
+ auto win11Options{ CreatePackageDependencyOptions_None };
+ WI_SetFlagIf(win11Options, CreatePackageDependencyOptions_DoNotVerifyDependencyResolution, !options.VerifyDependencyResolution());
+ //TODO CreatePackageDependencyOptions_ScopeIsSystem
+
+ RETURN_IF_FAILED(g_win11TryCreatePackageDependency(user, win11PackageFamilyName, win11MinVersion,
+ win11PackageDependencyProcessorArchitectures, win11LifetimeKind, win11LifetimeArtifact,
+ win11Options, packageDependencyId));
+ return S_OK;
+}
+
+HRESULT MddCore::Win11::TryCreatePackageDependency(
+ PSID user,
+ _In_ PCWSTR packageFamilyName,
+ PACKAGE_VERSION minVersion,
+ MddPackageDependencyProcessorArchitectures packageDependencyProcessorArchitectures,
+ MddPackageDependencyLifetimeKind lifetimeKind,
+ PCWSTR lifetimeArtifact,
+ MddCreatePackageDependencyOptions options,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId)
+{
+ const ::AppModel::Identity::PackageVersion win11MinVersion{ minVersion };
+
+ auto win11PackageDependencyProcessorArchitectures{ PackageDependencyProcessorArchitectures_None };
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Neutral, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::Neutral));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X86, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::X86));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X64, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::X64));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Arm, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::Arm));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_Arm64, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::Arm64));
+ WI_SetFlagIf(win11PackageDependencyProcessorArchitectures, PackageDependencyProcessorArchitectures_X86A64, WI_IsFlagSet(packageDependencyProcessorArchitectures, MddPackageDependencyProcessorArchitectures::X86OnArm64));
+
+ const auto win11LifetimeKind{ ToLifetimeKind(lifetimeKind) };
+
+ auto win11Options{ CreatePackageDependencyOptions_None };
+ WI_SetFlagIf(win11Options, CreatePackageDependencyOptions_DoNotVerifyDependencyResolution, WI_IsFlagSet(options, MddCreatePackageDependencyOptions::DoNotVerifyDependencyResolution));
+ WI_SetFlagIf(win11Options, CreatePackageDependencyOptions_ScopeIsSystem, WI_IsFlagSet(options, MddCreatePackageDependencyOptions::ScopeIsSystem));
+
+ RETURN_IF_FAILED(g_win11TryCreatePackageDependency(user, packageFamilyName, win11MinVersion,
+ win11PackageDependencyProcessorArchitectures, win11LifetimeKind, lifetimeArtifact,
+ win11Options, packageDependencyId));
+ return S_OK;
+}
+
+void MddCore::Win11::DeletePackageDependency(
+ const winrt::hstring& packageDependencyId)
+{
+ DeletePackageDependency(packageDependencyId.c_str());
+}
+
+void MddCore::Win11::DeletePackageDependency(
+ _In_ PCWSTR packageDependencyId)
+{
+ (void)LOG_IF_FAILED(g_win11DeletePackageDependency(packageDependencyId));
+}
+
+HRESULT MddCore::Win11::AddPackageDependency(
+ const winrt::hstring& packageDependencyId,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& options,
+ _Out_ MDD_PACKAGEDEPENDENCY_CONTEXT* packageDependencyContext,
+ _Outptr_opt_result_maybenull_ PWSTR* packageFullName)
+{
+ PCWSTR win11PackageDependencyId{ packageDependencyId.c_str() };
+
+ const auto win11Rank{ options.Rank() };
+
+ auto win11Options{ AddPackageDependencyOptions_None };
+ WI_SetFlagIf(win11Options, AddPackageDependencyOptions_PrependIfRankCollision, options.PrependIfRankCollision());
+
+ static_assert(sizeof(MDD_PACKAGEDEPENDENCY_CONTEXT) == sizeof(PACKAGEDEPENDENCY_CONTEXT));
+ auto win11PackageDependencyContext{ reinterpret_cast(packageDependencyContext) };
+
+ RETURN_IF_FAILED(g_win11AddPackageDependency(win11PackageDependencyId, win11Rank, win11Options, win11PackageDependencyContext, packageFullName));
+ return S_OK;
+}
+
+HRESULT MddCore::Win11::AddPackageDependency(
+ _In_ PCWSTR packageDependencyId,
+ INT32 rank,
+ MddAddPackageDependencyOptions options,
+ _Out_ MDD_PACKAGEDEPENDENCY_CONTEXT* packageDependencyContext,
+ _Outptr_opt_result_maybenull_ PWSTR* packageFullName)
+{
+ auto win11Options{ AddPackageDependencyOptions_None };
+ WI_SetFlagIf(win11Options, AddPackageDependencyOptions_PrependIfRankCollision, WI_IsFlagSet(options, MddAddPackageDependencyOptions::PrependIfRankCollision));
+
+ static_assert(sizeof(MDD_PACKAGEDEPENDENCY_CONTEXT) == sizeof(PACKAGEDEPENDENCY_CONTEXT));
+ auto win11PackageDependencyContext{ reinterpret_cast(packageDependencyContext) };
+
+ RETURN_IF_FAILED(g_win11AddPackageDependency(packageDependencyId, rank, win11Options, win11PackageDependencyContext, packageFullName));
+ return S_OK;
+}
+
+void MddCore::Win11::RemovePackageDependency(
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId packageDependencyContextId)
+{
+ return RemovePackageDependency(ToContext(packageDependencyContextId));
+}
+
+void MddCore::Win11::RemovePackageDependency(
+ _In_ MDD_PACKAGEDEPENDENCY_CONTEXT packageDependencyContext)
+{
+ static_assert(sizeof(MDD_PACKAGEDEPENDENCY_CONTEXT) == sizeof(PACKAGEDEPENDENCY_CONTEXT));
+ auto win11PackageDependencyContext{ reinterpret_cast(packageDependencyContext) };
+
+ g_win11RemovePackageDependency(win11PackageDependencyContext);
+}
+
+HRESULT MddCore::Win11::GetResolvedPackageFullNameForPackageDependency(
+ _In_ PCWSTR packageDependencyId,
+ _Outptr_result_maybenull_ PWSTR* packageFullName)
+{
+ RETURN_IF_FAILED(g_win11GetResolvedPackageFullNameForPackageDependency(packageDependencyId, packageFullName));
+ return S_OK;
+}
+
+HRESULT MddCore::Win11::GetIdForPackageDependencyContext(
+ _In_ MDD_PACKAGEDEPENDENCY_CONTEXT packageDependencyContext,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId)
+{
+ static_assert(sizeof(MDD_PACKAGEDEPENDENCY_CONTEXT) == sizeof(PACKAGEDEPENDENCY_CONTEXT));
+ auto win11PackageDependencyContext{ reinterpret_cast(packageDependencyContext) };
+
+ RETURN_IF_FAILED(g_win11GetIdForPackageDependencyContext(win11PackageDependencyContext, packageDependencyId));
+ return S_OK;
+}
+
+UINT32 MddCore::Win11::GetPackageGraphRevisionId()
+{
+ return g_win11GetPackageGraphRevisionId();
+}
diff --git a/dev/DynamicDependency/API/MddWin11.h b/dev/DynamicDependency/API/MddWin11.h
new file mode 100644
index 0000000000..8b0f6bef92
--- /dev/null
+++ b/dev/DynamicDependency/API/MddWin11.h
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#if !defined(MDDWIN11DYNAMICDEPENDENCY_H)
+#define MDDWIN11DYNAMICDEPENDENCY_H
+
+#include
+#include
+
+HRESULT WINAPI MddWin11Initialize() noexcept;
+
+HRESULT WINAPI MddWin11Shutdown() noexcept;
+
+namespace MddCore::Win11
+{
+bool IsSupported();
+
+HRESULT TryCreatePackageDependency(
+ PSID user,
+ const winrt::hstring& packageFamilyName,
+ const winrt::Windows::ApplicationModel::PackageVersion& minVersion,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures packageDependencyProcessorArchitectures,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& options,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId);
+
+HRESULT TryCreatePackageDependency(
+ PSID user,
+ _In_ PCWSTR packageFamilyName,
+ PACKAGE_VERSION minVersion,
+ MddPackageDependencyProcessorArchitectures packageDependencyProcessorArchitectures,
+ MddPackageDependencyLifetimeKind lifetimeKind,
+ PCWSTR lifetimeArtifact,
+ MddCreatePackageDependencyOptions options,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId);
+
+void DeletePackageDependency(
+ const winrt::hstring& packageDependencyId);
+
+void DeletePackageDependency(
+ _In_ PCWSTR packageDependencyId);
+
+HRESULT AddPackageDependency(
+ const winrt::hstring& packageDependencyId,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& options,
+ _Out_ MDD_PACKAGEDEPENDENCY_CONTEXT* packageDependencyContext,
+ _Outptr_opt_result_maybenull_ PWSTR* packageFullName);
+
+HRESULT AddPackageDependency(
+ _In_ PCWSTR packageDependencyId,
+ std::int32_t rank,
+ MddAddPackageDependencyOptions options,
+ _Out_ MDD_PACKAGEDEPENDENCY_CONTEXT* packageDependencyContext,
+ _Outptr_opt_result_maybenull_ PWSTR* packageFullName);
+
+void RemovePackageDependency(
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId packageDependencyContextId);
+
+void RemovePackageDependency(
+ _In_ MDD_PACKAGEDEPENDENCY_CONTEXT packageDependencyContext);
+
+HRESULT GetResolvedPackageFullNameForPackageDependency(
+ _In_ PCWSTR packageDependencyId,
+ _Outptr_result_maybenull_ PWSTR* packageFullName);
+
+HRESULT GetIdForPackageDependencyContext(
+ _In_ MDD_PACKAGEDEPENDENCY_CONTEXT packageDependencyContext,
+ _Outptr_result_maybenull_ PWSTR* packageDependencyId);
+
+UINT32 GetPackageGraphRevisionId();
+
+inline winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId ToContextId(MDD_PACKAGEDEPENDENCY_CONTEXT context)
+{
+ return winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId{ static_cast(reinterpret_cast(context)) };
+}
+
+inline MDD_PACKAGEDEPENDENCY_CONTEXT ToContext(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId contextId)
+{
+ return reinterpret_cast(static_cast(contextId.Id));
+}
+}
+
+#endif // MDDWIN11DYNAMICDEPENDENCY_H
diff --git a/dev/DynamicDependency/API/winrt_msixdynamicdependency.h b/dev/DynamicDependency/API/winrt_msixdynamicdependency.h
deleted file mode 100644
index 394d6022dc..0000000000
--- a/dev/DynamicDependency/API/winrt_msixdynamicdependency.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) Microsoft Corporation and Contributors.
-// Licensed under the MIT License.
-
-#pragma once
-
-namespace winrt
-{
- // Per https://docs.microsoft.com/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi#convert_from_abi-function
- template
- T convert_from_abi(::IUnknown* from)
- {
- T to{ nullptr }; // `T` is a projected type.
-
- winrt::check_hresult(from->QueryInterface(winrt::guid_of(),
- winrt::put_abi(to)));
-
- return to;
- }
-}
diff --git a/dev/DynamicDependency/Powershell/Add-PackageDependency.ps1 b/dev/DynamicDependency/Powershell/Add-PackageDependency.ps1
new file mode 100644
index 0000000000..2360e510a4
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Add-PackageDependency.ps1
@@ -0,0 +1,71 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Add to the current process' package graph.
+
+.DESCRIPTION
+ Add a run-time reference for the package dependency created earlier via
+ the TryCreate-PackageDependency cmdlet, with the specified options. After
+ successful completion you can use content from the package.
+
+.PARAMETER PackageDependencyId
+ ID of the package dependency to be resolved and added to the invoking
+ process' package graph. This parameter must match a package dependency
+ defined by the TryCreate-PackageDependency cmdlet for the calling
+ user or the system (via the TryCreate-PackageDependencyOptions -ScopeIsSystem option).
+
+.PARAMETER Rank
+ The rank to add the resolved package to the caller's package graph.
+ For more information, see https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-addpackagedependency#remarks
+
+.PARAMETER PrependIfRankCollision
+ If multiple packages are present in the package graph with the same rank,
+ the resolved package is added before others of the same rank. For more
+ information, see https://learn.microsoft.com/windows/win32/api/appmodel/ne-appmodel-addpackagedependencyoptions
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-addpackagedependency
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [string]$PackageDependencyId,
+
+ [int]$Rank=0,
+
+ [switch]$PrependIfRankCollision
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$options = [Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions]::None
+if ($PrependIfRankCollision -eq $true)
+{
+ $options = $options -bor [Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions]::PrependIfRankCollision
+}
+
+$packageDependencyContext = [IntPtr]0
+$packageFullName = ""
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Add(
+ $PackageDependencyId, $Rank, $options, [ref] $packageDependencyContext, [ref] $packageFullName)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
+
+$o = New-Object System.Object
+$o | Add-Member -type NoteProperty -name "PackageDependencyContext" -value $packageDependencyContext
+$o | Add-Member -type NoteProperty -name "PackageFullName" -value $packageFullName
+$o
diff --git a/dev/DynamicDependency/Powershell/Delete-PackageDependency.ps1 b/dev/DynamicDependency/Powershell/Delete-PackageDependency.ps1
new file mode 100644
index 0000000000..d52bdaafde
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Delete-PackageDependency.ps1
@@ -0,0 +1,36 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Delete the package dependency.
+
+.PARAMETER
+ The ID of the package dependency to remove.
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-deletepackagedependency
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [string]$PackageDependencyId
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Delete($PackageDependencyId)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
diff --git a/dev/DynamicDependency/Powershell/Get-PackageDependencyIdForContext.ps1 b/dev/DynamicDependency/Powershell/Get-PackageDependencyIdForContext.ps1
new file mode 100644
index 0000000000..b5670630b2
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Get-PackageDependencyIdForContext.ps1
@@ -0,0 +1,40 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Return the package dependency for the specified context handle.
+
+.PARAMETER PackageDependencyContext
+ The handle of the package dependency.
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getidforpackagedependencycontext
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [int64]$PackageDependencyContext
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$packageDependencyId = ""
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::GetIdForContext(
+ $PackageDependencyContext, [ref] $packageDependencyId)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
+
+$packageDependencyId
diff --git a/dev/DynamicDependency/Powershell/Get-PackageDependencyResolved.ps1 b/dev/DynamicDependency/Powershell/Get-PackageDependencyResolved.ps1
new file mode 100644
index 0000000000..c0d8ceb32e
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Get-PackageDependencyResolved.ps1
@@ -0,0 +1,46 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Return the package full name if the package dependency is resolved.
+
+.DESCRIPTION
+ Return the package full name that would be used if the package dependency
+ were to be resolved.
+
+ This does not add the package to the invoking process' package graph.
+
+.PARAMETER PackageDependencyId
+ The ID of the resolved package dependency.
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getresolvedpackagefullnameforpackagedependency
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [string]$PackageDependencyId
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$packageFullName = ""
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::GetResolvedPackageFullName(
+ $PackageDependencyId, [ref] $packageFullName)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
+
+$packageFullName
diff --git a/dev/DynamicDependency/Powershell/Get-PackageGraphRevisionId.ps1 b/dev/DynamicDependency/Powershell/Get-PackageGraphRevisionId.ps1
new file mode 100644
index 0000000000..a9bb8fcffe
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Get-PackageGraphRevisionId.ps1
@@ -0,0 +1,23 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+TODO
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+[Microsoft.Windows.ApplicationModel.DynamicDependency.PackageGraph]::RevisionId
diff --git a/dev/DynamicDependency/Powershell/MsixDynamicDependency.psm1 b/dev/DynamicDependency/Powershell/MsixDynamicDependency.psm1
new file mode 100644
index 0000000000..2590b6c6f2
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/MsixDynamicDependency.psm1
@@ -0,0 +1,341 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+Functions to use Windows' Dynamic Dependency API.
+
+.DESCRIPTION
+TBD
+
+.INPUTS
+None
+
+.OUTPUTS
+None
+
+.NOTES
+ Version : 0.1.0
+#>
+
+Add-Type -TypeDefinition @"
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Windows.ApplicationModel.DynamicDependency
+{
+ public enum CreatePackageDependencyOptions
+ {
+ None = 0,
+
+ // Disable dependency resolution when pinning a package dependency.
+ DoNotVerifyDependencyResolution = 0x00000001,
+
+ // Define the package dependency for the system, accessible to all users
+ // (default is the package dependency is defined for a specific user).
+ // This option requires the caller has adminitrative privileges.
+ ScopeIsSystem = 0x00000002,
+ }
+
+ public enum PackageDependencyLifetimeKind
+ {
+ // The current process is the lifetime artifact. The package dependency
+ // is implicitly deleted when the process terminates.
+ Process = 0,
+
+ // The lifetime artifact is an absolute filename or path.
+ // The package dependency is implicitly deleted when this is deleted.
+ FilePath = 1,
+
+ // The lifetime artifact is a registry key in the format
+ // 'root\\subkey' where root is one of the following: HKLM, HKCU, HKCR, HKU.
+ // The package dependency is implicitly deleted when this is deleted.
+ RegistryKey = 2,
+ }
+
+ public enum AddPackageDependencyOptions
+ {
+ None = 0,
+ PrependIfRankCollision = 0x00000001,
+ };
+
+ public class Rank
+ {
+ public const int Default = 0;
+ }
+
+ public enum PackageDependencyProcessorArchitectures
+ {
+ None = 0,
+ Neutral = 0x00000001,
+ X86 = 0x00000002,
+ X64 = 0x00000004,
+ Arm = 0x00000008,
+ Arm64 = 0x00000010,
+ X86A64 = 0x00000020,
+ };
+
+ public class PackageDependency
+ {
+ [DllImport("kernelbase.dll", EntryPoint="GetProcessHeap", ExactSpelling=true, SetLastError=true)]
+ public static extern IntPtr kernel32_GetProcessHeap();
+
+ [DllImport("kernelbase.dll", EntryPoint="HeapFree", ExactSpelling=true, SetLastError=true)]
+ private static extern bool kernel32_HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem);
+
+ private static bool HeapFree(IntPtr p)
+ {
+ return kernel32_HeapFree(kernel32_GetProcessHeap(), 0, p);
+ }
+
+ // Define a package dependency. The criteria for a PackageDependency
+ // (package family name, minimum version, etc)
+ // may match multiple packages, but ensures Deployment won't remove
+ // a package if it's the only one satisfying the PackageDependency.
+ //
+ // @note A package matching a PackageDependency pin can still be removed
+ // as long as there's another package that satisfies the PackageDependency.
+ // For example, if Fwk-v1 is installed and a PackageDependency specifies
+ // MinVersion=1 and then Fwk-v2 is installed, Deployment could remove
+ // Fwk-v1 because Fwk-v2 will satisfy the PackageDependency. After Fwk-v1
+ // is removed Deployment won't remove Fwk-v2 because it's the only package
+ // satisfying the PackageDependency. Thus Fwk-v1 and Fwk-v2 (and any other
+ // package matching the PackageDependency) are 'loosely pinned'. Deployment
+ // guarantees it won't remove a package if it would make a PackageDependency
+ // unsatisfied.
+ //
+ // A PackageDependency specifies criteria (package family, minimum version, etc)
+ // and not a specific package. Deployment reserves the right to use a different
+ // package (e.g. higher version) to satisfy the PackageDependency if/when
+ // one becomes available.
+ //
+ // @param user the user scope of the package dependency. If NULL the caller's
+ // user context is used. MUST be NULL if CreatePackageDependencyOptions_ScopeIsSystem
+ // is specified
+ // @param lifetimeArtifact MUST be NULL if lifetimeKind=Process
+ // @param packageDependencyId allocated via HeapAlloc; use HeapFree to deallocate
+ //
+ // @note TryCreatePackageDependency() fails if the PackageDependency cannot be resolved to a specific
+ // package. This package resolution check is skipped if
+ // CreatePackageDependencyOptions_DoNotVerifyDependencyResolution is specified. This is useful
+ // for installers running as user contexts other than the target user (e.g. installers
+ // running as LocalSystem).
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int TryCreatePackageDependency(
+ /*PSID*/ IntPtr user,
+ string packageFamilyName,
+ /*PACKAGE_VERSION*/ long minVersion,
+ /*PackageDependencyProcessorArchitectures*/ int packageDependencyProcessorArchitectures,
+ /*PackageDependencyLifetimeKind*/ int lifetimeKind,
+ string lifetimeArtifact,
+ /*CreatePackageDependencyOptions*/ int options,
+ /*_Outptr_result_maybenull_ PWSTR* */ out IntPtr packageDependencyId);
+
+ public static int TryCreate(
+ string packageFamilyName,
+ long minVersion,
+ /*PackageDependencyProcessorArchitectures*/ int packageDependencyProcessorArchitectures,
+ /*PackageDependencyLifetimeKind*/ int lifetimeKind,
+ string lifetimeArtifact,
+ /*CreatePackageDependencyOptions*/ int options,
+ /*_Outptr_result_maybenull_ PWSTR* */ out string packageDependencyId)
+ {
+ packageDependencyId = null;
+
+ IntPtr pdi = IntPtr.Zero;
+ int hr = TryCreatePackageDependency(IntPtr.Zero, packageFamilyName, minVersion, packageDependencyProcessorArchitectures,
+ lifetimeKind, lifetimeArtifact, options, out pdi);
+ if (hr >= 0)
+ {
+ packageDependencyId = Marshal.PtrToStringUni(pdi);
+ }
+ if (pdi != IntPtr.Zero)
+ {
+ HeapFree(pdi);
+ }
+ return hr;
+ }
+
+ // Undefine a package dependency. Removing a pin on a PackageDependency is typically done at uninstall-time.
+ // This implicitly occurs if the package dependency's 'lifetime artifact' (specified via TryCreatePackageDependency)
+ // is deleted. Packages that are not referenced by other packages and have no pins are elegible to be removed.
+ //
+ // @warn DeletePackageDependency() requires the caller have administrative privileges
+ // if the package dependency was pinned with CreatePackageDependencyOptions_ScopeIsSystem.
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int DeletePackageDependency(
+ string packageDependencyId);
+
+ public static int Delete(
+ string packageDependencyId)
+ {
+ return DeletePackageDependency(packageDependencyId);
+ }
+
+ // Resolve a previously-pinned PackageDependency to a specific package and
+ // add it to the invoking process' package graph. Once the dependency has
+ // been added other code-loading methods (LoadLibrary, CoCreateInstance, etc)
+ // can find the binaries in the resolved package.
+ //
+ // Package resolution is specific to a user and can return different values
+ // for different users on a system.
+ //
+ // Each successful AddPackageDependency() adds the resolve packaged to the
+ // calling process' package graph, even if already present. There is no
+ // duplicate 'detection' or 'filtering' applied by the API (multiple
+ // references from a package is not harmful). Once resolution is complete
+ // the package dependency stays resolved for that user until the last reference across
+ // all processes for that user is removed via RemovePackageDependency (or
+ // process termination).
+ //
+ // AddPackageDependency() adds the resolved package to the caller's package graph,
+ // per the rank specified. A process' package graph is a list of packages sorted by
+ // rank in ascending order (-infinity...0...+infinity). If package(s) are present in the
+ // package graph with the same rank as the call to AddPackageDependency the resolved
+ // package is (by default) added after others of the same rank. To add a package
+ // before others of the same rank, specify AddPackageDependencyOptions_PrependIfRankCollision.
+ //
+ // Every AddPackageDependency can be balanced by a RemovePackageDependency
+ // to remove the entry from the package graph. If the process terminates all package
+ // references are removed, but any pins stay behind.
+ //
+ // AddPackageDependency adds the resolved package to the process' package
+ // graph, per the rank and options parameters. The process' package
+ // graph is used to search for DLLs (per Dynamic-Link Library Search Order),
+ // WinRT objects and other resources; the caller can now load DLLs, activate
+ // WinRT objects and use other resources from the framework package until
+ // RemovePackageDependency is called. The packageDependencyId parameter
+ // must match a package dependency defined for the calling user or the
+ // system (i.e. pinned with CreatePackageDependencyOptions_ScopeIsSystem) else
+ // an error is returned.
+ //
+ // @param packageDependencyContext valid until passed to RemovePackageDependency()
+ // @param packageFullName allocated via HeapAlloc; use HeapFree to deallocate
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int AddPackageDependency(
+ string packageDependencyId,
+ int rank,
+ /*AddPackageDependencyOptions*/ int options,
+ /*_Out_ PACKAGEDEPENDENCY_CONTEXT* */ out IntPtr packageDependencyContext,
+ /*_Outptr_opt_result_maybenull_ PWSTR* */ out IntPtr packageFullName);
+
+ public static int Add(
+ string packageDependencyId,
+ int rank,
+ /*AddPackageDependencyOptions*/ int options,
+ /*_Out_ PACKAGEDEPENDENCY_CONTEXT* */ out IntPtr packageDependencyContext,
+ out string packageFullName)
+ {
+ packageDependencyContext = IntPtr.Zero;
+ packageFullName = null;
+
+ IntPtr pdc = IntPtr.Zero;
+ IntPtr pfn = IntPtr.Zero;
+ int hr = AddPackageDependency(packageDependencyId, rank, options, out pdc, out pfn);
+ if (hr >= 0)
+ {
+ packageDependencyContext = pdc;
+ packageFullName = Marshal.PtrToStringUni(pfn);
+ }
+ if (pfn != IntPtr.Zero)
+ {
+ HeapFree(pfn);
+ }
+ return hr;
+ }
+
+ // Remove a resolved PackageDependency from the current process' package graph
+ // (i.e. undo AddPackageDependency). Used at runtime (i.e. the moral equivalent
+ // of Windows' RemoveDllDirectory()).
+ //
+ // @note This does not unload loaded resources (DLLs etc). After removing
+ // a package dependency any files loaded from the package can continue
+ // to be used; future file resolution will fail to see the removed
+ // package dependency.
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int RemovePackageDependency(
+ /*PACKAGEDEPENDENCY_CONTEXT*/ IntPtr packageDependencyContext);
+
+ public static int Remove(
+ IntPtr packageDependencyContext)
+ {
+ return RemovePackageDependency(packageDependencyContext);
+ }
+
+ // Return the package full name that would be used if the
+ // PackageDependency were to be resolved. Does not add the
+ // package to the process graph.
+ //
+ // @param packageFullName allocated via HeapAlloc; use HeapFree to deallocate.
+ // If the package dependency cannot be resolved the function
+ // succeeds but packageFullName is nullptr.
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int GetResolvedPackageFullNameForPackageDependency(
+ string packageDependencyId,
+ /*_Outptr_result_maybenull_ PWSTR* */ out IntPtr packageFullName);
+
+ public static int GetResolvedPackageFullName(
+ string packageDependencyId,
+ out string packageFullName)
+ {
+ packageFullName = null;
+
+ IntPtr pfn = IntPtr.Zero;
+ int hr = GetResolvedPackageFullNameForPackageDependency(packageDependencyId, out pfn);
+ if (hr >= 0)
+ {
+ packageFullName = Marshal.PtrToStringUni(pfn);
+ }
+ if (pfn != IntPtr.Zero)
+ {
+ HeapFree(pfn);
+ }
+ return hr;
+ }
+
+ // Return the package dependency for the context.
+ //
+ // @param packageDependencyId allocated via HeapAlloc; use HeapFree to deallocate.
+ // If the package dependency context cannot be resolved
+ // the function succeeds but packageDependencyId is nullptr.
+ [DllImport("kernelbase.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
+ private static extern int GetIdForPackageDependencyContext(
+ /*PACKAGEDEPENDENCY_CONTEXT*/ IntPtr packageDependencyContext,
+ /*_Outptr_result_maybenull_ PWSTR* */ out IntPtr packageDependencyId);
+
+ public static int GetIdForContext(
+ /*PACKAGEDEPENDENCY_CONTEXT*/ IntPtr packageDependencyContext,
+ /*_Outptr_result_maybenull_ PWSTR* */ out string packageDependencyId)
+ {
+ packageDependencyId = null;
+
+ IntPtr pdi = IntPtr.Zero;
+ int hr = GetIdForPackageDependencyContext(packageDependencyContext, out pdi);
+ if (hr >= 0)
+ {
+ packageDependencyId = Marshal.PtrToStringUni(pdi);
+ }
+ if (pdi != IntPtr.Zero)
+ {
+ HeapFree(pdi);
+ }
+ return hr;
+ }
+ }
+
+ public class PackageGraph
+ {
+ // Returns the package graph's current revision ID.
+ [DllImport("kernelbase.dll")]
+ private static extern uint GetPackageGraphRevisionId();
+
+ public static uint RevisionId
+ {
+ get
+ {
+ return GetPackageGraphRevisionId();
+ }
+ }
+ }
+}
+"@
diff --git a/dev/DynamicDependency/Powershell/Remove-PackageDependency.ps1 b/dev/DynamicDependency/Powershell/Remove-PackageDependency.ps1
new file mode 100644
index 0000000000..583600f910
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/Remove-PackageDependency.ps1
@@ -0,0 +1,37 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Remove a resolved package dependency from the current process' package graph.
+
+.PARAMETER PackageDependencyContext
+ The handle of the package dependency to remove.
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-removepackagedependency
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [int64]$PackageDependencyContext
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$context = [IntPtr]$PackageDependencyContext
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Remove($context)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
diff --git a/dev/DynamicDependency/Powershell/TryCreate-PackageDependency.ps1 b/dev/DynamicDependency/Powershell/TryCreate-PackageDependency.ps1
new file mode 100644
index 0000000000..f92153acc4
--- /dev/null
+++ b/dev/DynamicDependency/Powershell/TryCreate-PackageDependency.ps1
@@ -0,0 +1,100 @@
+# Copyright (c) Microsoft Corporation and Contributors.
+# Licensed under the MIT License.
+
+<#
+.SYNOPSIS
+ Dynamically create a package dependency.
+
+.DESCRIPTION
+ Create a package dependency, using package family name, minimum version,
+ and additional criteria.
+
+.PARAMETER PackageDependencyId
+ ID of the package dependency to be resolved and added to the invoking
+ process' package graph. This parameter must match a package dependency
+ defined by the TryCreate-PackageDependency cmdlet for the calling
+ user or the system (via the TryCreate-PackageDependencyOptions -ScopeIsSystem option).
+
+.PARAMETER MinVersion
+ The minimum version of the target package on which to take a dependency.
+
+.PARAMETER NoVerifyDependencyResolution
+ Disables dependency resolution when pinning a package dependency. This is
+ useful for installers running as user contexts other than the target user
+ (for example, installers running as LocalSystem).
+
+.PARAMETER System
+ Defines the package dependency for the system, accessible to all users (by
+ default, the package dependency is defined for a specific user). This
+ option requires the caller has administrative privileges.
+
+.PARAMETER LifetimeKind
+ The type of artifact to use to define the lifetime of the package
+ dependency. For more information, see
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-trycreatepackagedependency#remarks
+
+.PARAMETER LifetimeArtifact
+ The name of the artifact used to define the lifetime of the package
+ dependency. N/A -LifetimeKind=Process. For more information, see
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-trycreatepackagedependency#remarks
+
+.LINK
+ https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-addpackagedependency
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+param(
+ [Parameter(Mandatory=$true)]
+ [string]$PackageFamilyName,
+
+ [long]$MinVersion,
+
+ [switch]$NoVerifyDependencyResolution,
+ [switch]$System,
+
+ [ValidateSet('Process', 'File', 'Registry')]
+ [string]$LifetimeKind,
+ [string]$LifetimeArtifact
+)
+
+Set-StrictMode -Version 3.0
+
+$ErrorActionPreference = "Stop"
+
+# Import the MSIX Dynamic Dependency module
+if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
+{
+ $module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
+ Import-Module -Name $module -ErrorAction Stop
+}
+
+$options = [Microsoft.Windows.ApplicationModel.DynamicDependency.CreatePackageDependencyOptions]::None
+if ($NoVerifyDependencyResolution -eq $true)
+{
+ $options = $options -bor [Microsoft.Windows.ApplicationModel.DynamicDependency.CreatePackageDependencyOptions]::DoNotVerifyDependencyResolution
+}
+if ($System -eq $true)
+{
+ $options = $options -bor [Microsoft.Windows.ApplicationModel.DynamicDependency.CreatePackageDependencyOptions]::ScopeIsSystem
+}
+
+$lifetime = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyLifetimeKind]::Process
+if ($LifetimeKind -eq 'File')
+{
+ $lifetime = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyLifetimeKind]::FilePath
+}
+elseif ($LifetimeKind -eq 'Registry')
+{
+ $lifetime = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyLifetimeKind]::RegistryKey
+}
+
+$architectures = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyProcessorArchitectures]::None
+$pdid = ""
+$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::TryCreate(
+ $PackageFamilyName, $MinVersion, $architectures, $lifetime, $LifetimeArtifact, $options, [ref] $pdid)
+if ($hr -lt 0)
+{
+ $win32ex = [System.ComponentModel.Win32Exception]::new($hr)
+ Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
+}
+
+$pdid
diff --git a/dev/Kozani/Common/KozaniDvc-Constants.h b/dev/Kozani/Common/KozaniDvc-Constants.h
index 2716d7d659..f91a633e93 100644
--- a/dev/Kozani/Common/KozaniDvc-Constants.h
+++ b/dev/Kozani/Common/KozaniDvc-Constants.h
@@ -6,6 +6,4 @@
namespace Microsoft::Kozani::DVC::Constants
{
const char ConnectionIdSwitch[] = "-connectionId";
-
- const WCHAR RemoteDesktopClientExe[] = L"mstsc.exe";
}
\ No newline at end of file
diff --git a/dev/Kozani/Common/KozaniDvcProtocol.cpp b/dev/Kozani/Common/KozaniDvcProtocol.cpp
index 8feeaf1b36..a47db90115 100644
--- a/dev/Kozani/Common/KozaniDvcProtocol.cpp
+++ b/dev/Kozani/Common/KozaniDvcProtocol.cpp
@@ -2,30 +2,15 @@
// Licensed under the MIT License.
#include
+#include
#include "KozaniDvcProtocol.h"
namespace Microsoft::Kozani::DvcProtocol
{
- bool IsEmptyPayloadProtocolDataUnitType(Dvc::ProtocolDataUnit::DataType type)
+ std::string CreatePdu(UINT64 activityId, Dvc::ProtocolDataUnit::DataType type, const std::string& payload)
{
- switch (type)
- {
- case Dvc::ProtocolDataUnit::AppTerminationNotice:
- return true;
- }
-
- return false;
- }
-
- std::string CreatePdu(UINT64 activityId, Dvc::ProtocolDataUnit::DataType type, const std::string& payload = std::string())
- {
- if (!IsEmptyPayloadProtocolDataUnitType(type))
- {
- // Payload data of the Pdu should not be empty. It catches a failure condition when empty string is returned
- // from a failed SerializeAsString call before calling into this method.
- THROW_HR_IF(KOZANI_E_PDU_SERIALIZATION, payload.empty());
- }
-
+ // Do not check payload.empty() because if the payload message only contains default values, it can be empty after SerializeAsString().
+
Dvc::ProtocolDataUnit pdu;
pdu.set_activity_id(activityId);
pdu.set_type(type);
@@ -36,8 +21,9 @@ namespace Microsoft::Kozani::DvcProtocol
}
std::string rawPdu{ pdu.SerializeAsString() };
- THROW_HR_IF(KOZANI_E_PDU_SERIALIZATION, rawPdu.empty());
+ // rawPdu should never be empty as the activityId must not be default value (0).
+ THROW_HR_IF(KOZANI_E_PDU_SERIALIZATION, rawPdu.empty());
return rawPdu;
}
@@ -53,15 +39,43 @@ namespace Microsoft::Kozani::DvcProtocol
switch (args.Kind())
{
case winrt::Windows::ApplicationModel::Activation::ActivationKind::Launch:
- auto specificArgs{ args.as() };
- if (!specificArgs.Arguments().empty())
{
- const std::string argsUtf8{ ::Microsoft::Utf8::ToUtf8(specificArgs.Arguments().c_str()) };
- Dvc::LaunchActivationArgs launchArgs;
- launchArgs.set_arguments(std::move(argsUtf8));
- return launchArgs.SerializeAsString();
+ auto specificArgs{ args.as() };
+ if (!specificArgs.Arguments().empty())
+ {
+ const std::string argsUtf8{ ::Microsoft::Utf8::ToUtf8(specificArgs.Arguments().c_str()) };
+ Dvc::LaunchActivationArgs launchArgs;
+ launchArgs.set_arguments(std::move(argsUtf8));
+ return launchArgs.SerializeAsString();
+ }
+ break;
+ }
+
+ case winrt::Windows::ApplicationModel::Activation::ActivationKind::File:
+ {
+ auto specificArgs{ args.as() };
+ const std::string verbUtf8{ ::Microsoft::Utf8::ToUtf8(specificArgs.Verb().c_str()) };
+ Dvc::FileActivationArgs fileArgs;
+ fileArgs.set_verb(std::move(verbUtf8));
+
+ auto files{ specificArgs.Files() };
+ for (auto const& file : specificArgs.Files())
+ {
+ const std::string filePathUtf8{ ::Microsoft::Utf8::ToUtf8(file.Path().c_str()) };
+ fileArgs.add_file_paths(std::move(filePathUtf8));
+ }
+
+ return fileArgs.SerializeAsString();
+ }
+ case winrt::Windows::ApplicationModel::Activation::ActivationKind::Protocol:
+ {
+ auto specificArgs{ args.as() };
+ const std::string uriUtf8{ ::Microsoft::Utf8::ToUtf8(specificArgs.Uri().AbsoluteUri().c_str())};
+ Dvc::ProtocolActivationArgs protocolArgs;
+ protocolArgs.set_uri(std::move(uriUtf8));
+
+ return protocolArgs.SerializeAsString();
}
- break;
}
return std::string();
}
@@ -70,16 +84,16 @@ namespace Microsoft::Kozani::DvcProtocol
UINT64 activityId,
PCWSTR appUserModelId,
winrt::Windows::ApplicationModel::Activation::ActivationKind activationKind,
- winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs& args)
+ const std::string& serializedArgs)
{
Dvc::ActivateAppRequest activateAppRequest;
activateAppRequest.set_activation_kind(static_cast(activationKind));
const std::string appUserModelIdUtf8{ ::Microsoft::Utf8::ToUtf8(appUserModelId) };
activateAppRequest.set_app_user_model_id(std::move(appUserModelIdUtf8));
- if (args)
+ if (!serializedArgs.empty())
{
- activateAppRequest.set_arguments(SerializeActivatedEventArgs(args));
+ activateAppRequest.set_arguments(serializedArgs);
}
return CreatePdu(activityId, Dvc::ProtocolDataUnit::ActivateAppRequest, activateAppRequest.SerializeAsString());
diff --git a/dev/Kozani/Common/KozaniDvcProtocol.h b/dev/Kozani/Common/KozaniDvcProtocol.h
index 6b9a2a8234..cdb75ba87c 100644
--- a/dev/Kozani/Common/KozaniDvcProtocol.h
+++ b/dev/Kozani/Common/KozaniDvcProtocol.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include
#include
#include
@@ -13,7 +14,7 @@ namespace Microsoft::Kozani::DvcProtocol
{
const char DvcChannelName[] = "KozaniDvc";
- std::string CreatePdu(UINT64 activityId, Dvc::ProtocolDataUnit::DataType type, const std::string& payload);
+ std::string CreatePdu(UINT64 activityId, Dvc::ProtocolDataUnit::DataType type, const std::string& payload = std::string());
std::string CreateConnectionAckPdu(PCSTR connectionId, UINT64 activityId);
@@ -23,7 +24,7 @@ namespace Microsoft::Kozani::DvcProtocol
UINT64 activityId,
PCWSTR appUserModelId,
winrt::Windows::ApplicationModel::Activation::ActivationKind activationKind,
- winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs& args);
+ const std::string& serializedArgs);
std::string CreateActivateAppResultPdu(
UINT64 activityId,
diff --git a/dev/Kozani/Common/Logging.h b/dev/Kozani/Common/Logging.h
index 2e7ba64fa1..a1ea414173 100644
--- a/dev/Kozani/Common/Logging.h
+++ b/dev/Kozani/Common/Logging.h
@@ -7,9 +7,11 @@
// According to https://learn.microsoft.com/en-us/windows/win32/com/codes-in-facility-itf, all the COM-defined FACILITY_ITF codes have a code value
// in the range of 0x0000-0x01FF. It is recommended that only code values in the range of 0x0200-0xFFFF be used for 3rd party FACILITY_ITF codes.
-// Success HRESULT used for Kozani information logging purpose.
-// 0x00040201 (262657)
-constexpr HRESULT KOZANI_S_INFO{ MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0x0201) };
+// HRESULT used for Kozani information logging purpose. Note that it does NOT mean there is an error. WIL logging requires a failure HRESULT as the input
+// to the LOG_HR_MSG() macro. Passing in a successful HRESULT to the macro will cause fail fast crash in Debug build, or it will log XS_STATUS_ASSERTION_FAILURE
+// in released build. So it has to be a failure HRESULT, although it does not mean failure in this case.
+// 0x80040201 (-2147220991)
+constexpr HRESULT KOZANI_E_INFO{ MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0201) };
// Bad/malformatted PDU that cannot be parsed successfully.
// 0x80040202 (-2147220990)
@@ -22,3 +24,45 @@ constexpr HRESULT KOZANI_E_UNSUPPORTED_ACTIVATION_KIND{ MAKE_HRESULT(SEVERITY_ER
// Bad/malformatted PDU that cannot be parsed successfully.
// 0x80040204 (-2147220988)
constexpr HRESULT KOZANI_E_PDU_SERIALIZATION{ MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0204) };
+
+#if RESULT_DIAGNOSTICS_LEVEL > 3
+
+#define TRACELOGGING_FAILURE_CONTEXT(failure) \
+ TraceLoggingHResult(failure.hr, "HResult"), \
+ TraceLoggingString(failure.pszFile, "File"), \
+ TraceLoggingUInt32(failure.uLineNumber, "LineNumber"), \
+ TraceLoggingString(failure.pszFunction, "Function"), \
+ TraceLoggingWideString(failure.pszMessage, "Message"), \
+ TraceLoggingString(failure.pszCallContext, "CallingContext"), \
+ TraceLoggingString(failure.pszModule, "Module"), \
+ TraceLoggingPointer(failure.returnAddress, "Site"), \
+ TraceLoggingString(failure.pszCode, "Code") \
+
+#else
+
+#define TRACELOGGING_FAILURE_CONTEXT(failure) \
+ TraceLoggingHResult(failure.hr, "HResult"), \
+ TraceLoggingString(failure.pszFile, "File"), \
+ TraceLoggingUInt32(failure.uLineNumber, "LineNumber"), \
+ TraceLoggingWideString(failure.pszMessage, "Message") \
+
+#endif
+
+template
+void __stdcall TraceFailureFromProvider(const wil::FailureInfo& failure) WI_NOEXCEPT
+{
+ if (failure.hr == KOZANI_E_INFO)
+ {
+ TraceLoggingWrite(
+ TProvider::Provider(),
+ "Info",
+ TRACELOGGING_FAILURE_CONTEXT(failure));
+ }
+ else
+ {
+ TraceLoggingWrite(
+ TProvider::Provider(),
+ "Failure",
+ TRACELOGGING_FAILURE_CONTEXT(failure));
+ }
+}
diff --git a/dev/Kozani/KozaniAppGraph/packages.config b/dev/Kozani/KozaniAppGraph/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniAppGraph/packages.config
+++ b/dev/Kozani/KozaniAppGraph/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj b/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj
index be045d3361..4f37ec3f1c 100644
--- a/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj
+++ b/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj
@@ -92,7 +92,7 @@
- (MSBuildThisFileDirectory);$(OutDir)\..\WindowsAppRuntime_DLL;$(RepoRoot)\dev\WindowsAppRuntime_Insights;$(RepoRoot)\dev\common;$(IntDir);%(AdditionalIncludeDirectories)
+ (MSBuildThisFileDirectory);$(OutDir)\..\WindowsAppRuntime_DLL;$(RepoRoot)\dev\WindowsAppRuntime_Insights;$(RepoRoot)\dev\common;$(IntDir);$(OutDir)..\KozaniManagerProxyStub;$(RepoRoot)\dev\Kozani\common;%(AdditionalIncludeDirectories)
Use
pch.h
KOZANIHOSTRUNTIMEDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
@@ -186,6 +186,11 @@
$(RepoRoot)\dev\Common;$(RepoRoot);%(AdditionalIncludeDirectories)
+
+
+ {400ed5ec-4530-4adb-8dce-9d1e6708a1f5}
+
+
@@ -208,4 +213,4 @@
-
+
\ No newline at end of file
diff --git a/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj.filters b/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj.filters
index ac929245b8..c88628f9f2 100644
--- a/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj.filters
+++ b/dev/Kozani/KozaniHostRuntime/KozaniHostRuntime.vcxproj.filters
@@ -27,6 +27,9 @@
Header Files
+
+ Header Files
+
@@ -59,4 +62,7 @@
Resource Files
-
+
+
+
+
\ No newline at end of file
diff --git a/dev/Kozani/KozaniHostRuntime/framework.h b/dev/Kozani/KozaniHostRuntime/framework.h
index 4c430d5b39..296665aad1 100644
--- a/dev/Kozani/KozaniHostRuntime/framework.h
+++ b/dev/Kozani/KozaniHostRuntime/framework.h
@@ -21,8 +21,10 @@
#include
#include
+#include
#include
#include
+#include
#include
#include
diff --git a/dev/Kozani/KozaniHostRuntime/main.cpp b/dev/Kozani/KozaniHostRuntime/main.cpp
index dd3f63d8e8..5f76ad67e4 100644
--- a/dev/Kozani/KozaniHostRuntime/main.cpp
+++ b/dev/Kozani/KozaniHostRuntime/main.cpp
@@ -3,11 +3,210 @@
#include "pch.h"
+#include
+
// Including this file once per binary will automatically opt WIL error handling macros into calling RoOriginateError when they
// begin logging a new error. This greatly improves the debuggability of errors that propagate before a failfast.
#include
+#include
+#include "winrt/Microsoft.Kozani.ManagerRuntime.h"
+
+#include "Logging.h"
+
+// Uncomment to enable wait for debugger when the local variant app is launched. We can attach debugger to the KozaniHostRuntime.exe while it is waiting.
+//#define WAIT_FOR_DEBUGGER
+
+using namespace winrt;
using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Windows::Storage;
+using namespace winrt::Windows::ApplicationModel;
+using namespace winrt::Windows::ApplicationModel::Activation;
+using namespace winrt::Windows::Data::Xml::Dom;
+
+constexpr PCWSTR c_kozaniSettingsFolderName{ L"KozaniSettings" };
+constexpr PCWSTR c_rdpFileName{ L"connection.rdp" };
+constexpr PCWSTR c_additionalSettingsFileName{ L"AdditionalSettings.txt" };
+constexpr PCWSTR c_manifestFileName{ L"AppxManifest.xml" };
+
+enum KozaniStatus
+{
+ None = 0,
+ Activated = 1,
+ Failed = 2,
+ Closed = 3
+};
+
+struct KozaniStatusCallbackHandler : winrt::implements
+{
+ KozaniStatusCallbackHandler(PCWSTR aumid) : m_aumid(aumid)
+ {
+ m_eventExitProcess.create();
+ }
+
+#pragma region IKozaniStatusCallback_methods
+ STDMETHODIMP OnActivated(DWORD pid, boolean isNewInstance)
+ {
+ LOG_HR_MSG(KOZANI_E_INFO, "[ActivationSuccess] IKozaniStausCallback::OnActivated is called. Remote app aumid = %ls, pid = %u, isNewInstance = %u",
+ m_aumid.c_str(), pid, isNewInstance);
+
+ m_remoteAppProcessId = pid;
+ m_status = KozaniStatus::Activated;
+
+ if (!isNewInstance)
+ {
+ // This activation does not launch a new app process. Exit this process as there is already another one tracking the remote process.
+ // Example: Calculator app has single process for multiple app windows.
+ m_eventExitProcess.SetEvent();
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP OnActivationFailed(
+ DWORD errorCode,
+ PCWSTR errorMessage)
+ {
+ LOG_HR_MSG(KOZANI_E_INFO, "[ActivationFailed] IKozaniStausCallback::OnActivationFailed is called. Remote app aumid = %ls, errorCode = 0x%x, errorMessage: %s",
+ m_aumid.c_str(), errorCode, errorMessage);
+
+ m_status = KozaniStatus::Failed;
+ m_eventExitProcess.SetEvent();
+ return S_OK;
+ }
+
+ STDMETHODIMP OnClosed()
+ {
+ LOG_HR_MSG(KOZANI_E_INFO, "[App Terminated] IKozaniStausCallback::OnClosed is called. Remote app aumid = %ls, pid=%u",
+ m_aumid.c_str(), m_remoteAppProcessId);
+
+ m_status = KozaniStatus::Closed;
+ m_eventExitProcess.SetEvent();
+ return S_OK;
+ }
+#pragma endregion IKozaniStatusCallback_methods
+
+ bool WaitForExitProcessEvent(DWORD timeout)
+ {
+ return m_eventExitProcess.wait(timeout);
+ }
+
+ KozaniStatus GetStatus()
+ {
+ return m_status;
+ }
+
+private:
+ std::wstring m_aumid;
+ DWORD m_remoteAppProcessId{};
+ KozaniStatus m_status{};
+ wil::unique_event m_eventExitProcess;
+};
+
+void LogArgs(int argc, PWSTR* argv)
+{
+ TraceLoggingWrite(Microsoft_Kozani_HostRuntime_TraceLogger::Provider(), "argc",
+ TraceLoggingValue(argc, "argc"));
+ for (int i = 0; i < argc; i++)
+ {
+ TraceLoggingWrite(Microsoft_Kozani_HostRuntime_TraceLogger::Provider(), "argv",
+ TraceLoggingValue(i, "index"),
+ TraceLoggingValue(argv[i], "argv"));
+ }
+}
+
+// Remote app AUMID is stored in an app extension of the local variant package (LVP). The app extension name is formatted as:
+// com.microsoft.kozani.localvariant.remoteapp.
+// and the app extension Id is the package-relative application identifier (PRAID) of the LVP app being activated.
+// : we replace the '_' character in the package family name with '-' as '_' is not allowed in the app extension name.
+//
+// For example:
+//
+//
+//
+// Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
+//
+//
+//
+winrt::hstring GetRemoteAumid()
+{
+ WCHAR lvpAumid[APPLICATION_USER_MODEL_ID_MAX_LENGTH + 1]{};
+ UINT32 lvpAumidLength{ ARRAYSIZE(lvpAumid) };
+ THROW_IF_WIN32_ERROR(GetCurrentApplicationUserModelId(&lvpAumidLength, lvpAumid));
+
+ WCHAR lvpFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1]{};
+ WCHAR lvpPraid[PACKAGE_RELATIVE_APPLICATION_ID_MAX_LENGTH + 1]{};
+ UINT32 lvpFamilyNameLength{ ARRAYSIZE(lvpFamilyName) };
+ UINT32 lvpPraidLength{ ARRAYSIZE(lvpPraid) };
+ THROW_IF_WIN32_ERROR(ParseApplicationUserModelId(lvpAumid, &lvpFamilyNameLength, lvpFamilyName, &lvpPraidLength, lvpPraid));
+
+ // Replace '_' in the family name with '-' as '_' cannot be used in the app extension name.
+ for (UINT32 i = 0; i < lvpFamilyNameLength; i++)
+ {
+ if (lvpFamilyName[i] == L'_')
+ {
+ lvpFamilyName[i] = L'-';
+ break;
+ }
+ }
+
+ std::wstring appExtensionName{ L"com.microsoft.kozani.localvariant.remoteapp." };
+ appExtensionName += lvpFamilyName;
+
+ auto catalog{ AppExtensions::AppExtensionCatalog::Open(appExtensionName.c_str()) };
+ IVectorView appExtensions{ catalog.FindAllAsync().get() };
+ for (const auto appExtension : appExtensions)
+ {
+ if (appExtension.Id() == lvpPraid)
+ {
+ const auto properties{ appExtension.GetExtensionPropertiesAsync().get() };
+ const auto property{ properties.Lookup(L"RemoteAppAumid").as>() };
+ const auto remoteAumid{ winrt::unbox_value(property.Lookup(L"#text")) };
+ return remoteAumid;
+ }
+ }
+
+ THROW_WIN32_MSG(ERROR_NOT_FOUND, "Cannot find remote app aumid from app extension with name: %ls, Id: %ls", appExtensionName.c_str(), lvpPraid);
+}
+
+void GetConfigurationFiles(std::wstring& rdpFilePath, std::wstring& additionalSettingsFilePath)
+{
+ StorageFolder localFolder{ ApplicationData::Current().LocalFolder() };
+ // This hostRuntime exe should run with the identity of the hosted app (localvariant) package that activated
+ // Logging the AppData local folder path thus indicates the identity of the hosted app.
+ TraceLoggingWrite(Microsoft_Kozani_HostRuntime_TraceLogger::Provider(), "localFolder",
+ TraceLoggingValue(localFolder.Path().c_str(), "path"));
+
+ auto settingsFolder{ localFolder.GetFolderAsync(c_kozaniSettingsFolderName).get() };
+ auto rdpFile{ settingsFolder.GetFileAsync(c_rdpFileName).get() };
+ THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), !rdpFile.IsOfType(StorageItemTypes::File));
+
+ rdpFilePath = rdpFile.Path();
+
+ auto additionalSettingsFile{ settingsFolder.TryGetItemAsync(c_additionalSettingsFileName).get() };
+ if (additionalSettingsFile)
+ {
+ THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), !additionalSettingsFile.IsOfType(StorageItemTypes::File));
+ additionalSettingsFilePath = additionalSettingsFile.Path();
+ }
+ else
+ {
+ additionalSettingsFilePath.clear();
+ }
+}
+
+#ifdef WAIT_FOR_DEBUGGER
+void WaitForDebugger()
+{
+ while (!IsDebuggerPresent())
+ {
+ Sleep(3000);
+ }
+}
+#endif
int APIENTRY wWinMain(
HINSTANCE /*hInstance*/,
@@ -15,10 +214,43 @@ int APIENTRY wWinMain(
PWSTR /*pCmdLine*/,
int /*nCmdShow*/) try
{
- int argc{};
- const wil::unique_hlocal_ptr argv{ CommandLineToArgvW(GetCommandLineW(), &argc) };
- wprintf(L"argc: %d\nargv[0]: %ls\n", argc, argv[0]);
+ wil::SetResultLoggingCallback(&TraceFailureFromProvider);
+ winrt::init_apartment();
+
+#ifdef WAIT_FOR_DEBUGGER
+ WaitForDebugger();
+#endif
+
+ winrt::hstring remoteAumid{ GetRemoteAumid() };
+ LOG_HR_MSG(KOZANI_E_INFO, "remoteAumid=%ls", remoteAumid.c_str());
+
+ std::wstring rdpFilePath;
+ std::wstring additionalSettingsFilePath;
+ GetConfigurationFiles(rdpFilePath, additionalSettingsFilePath);
+ LOG_HR_MSG(KOZANI_E_INFO, "rdpFilePath=%ls, additionalSettingsFilePath=%ls", rdpFilePath.c_str(), additionalSettingsFilePath.c_str());
+
+ auto activatedEventArgs{ AppInstance::GetActivatedEventArgs() };
+ auto runtimeManager{ winrt::Microsoft::Kozani::ManagerRuntime::ManagerRuntimeManager::Create() };
+ auto statusCallback{ winrt::make_self(remoteAumid.c_str()) };
+
+ runtimeManager.ActivateRemoteApplication(
+ activatedEventArgs.Kind(),
+ remoteAumid.c_str(),
+ rdpFilePath.c_str(),
+ GetCurrentProcessId(),
+ activatedEventArgs,
+ statusCallback.as(),
+ additionalSettingsFilePath.c_str());
+
+ // Release the IManagerRuntimeManager object so the host runtime does not hold on to it while waiting for process termination event.
+ // In case this process is killed by the user (i.e., from Task Manager), holding the IManagerRuntimeManager object will leak the ref count
+ // and prevent KozaniManager.exe from exiting after all remote apps are closed.
+ runtimeManager = nullptr;
+
+ statusCallback->WaitForExitProcessEvent(INFINITE);
+ TraceLoggingWrite(Microsoft_Kozani_HostRuntime_TraceLogger::Provider(), "Exiting instance");
+ winrt::uninit_apartment();
return S_OK;
}
CATCH_RETURN()
diff --git a/dev/Kozani/KozaniHostRuntime/packages.config b/dev/Kozani/KozaniHostRuntime/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniHostRuntime/packages.config
+++ b/dev/Kozani/KozaniHostRuntime/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniManager/ConnectionManager.cpp b/dev/Kozani/KozaniManager/ConnectionManager.cpp
index 2196a4987f..569cf33dcc 100644
--- a/dev/Kozani/KozaniManager/ConnectionManager.cpp
+++ b/dev/Kozani/KozaniManager/ConnectionManager.cpp
@@ -35,6 +35,8 @@ namespace Microsoft::Kozani::Manager
if (requestInfo->statusCallback)
{
+ // The following call can fail with RPC_E_SERVER_UNAVAILABLE (0x800706BA) if the statusCallback client is hosted in the
+ // process that has been terminated. Ignore the failure - best effort to deliver the status update.
(void)requestInfo->statusCallback->OnClosed();
requestInfo->statusCallback.reset();
}
@@ -42,14 +44,7 @@ namespace Microsoft::Kozani::Manager
switch (requestInfo->status)
{
case RequestStatus::Connecting:
- for (auto it = connectionManager->m_requestsPendingConnection.begin(); it != connectionManager->m_requestsPendingConnection.end(); it++)
- {
- if (requestInfo == *it)
- {
- connectionManager->m_requestsPendingConnection.erase(it);
- break;
- }
- }
+ connectionManager->RemoveRequestFromPendingConnectionList(requestInfo);
break;
case RequestStatus::Connected:
@@ -70,13 +65,10 @@ namespace Microsoft::Kozani::Manager
FAIL_FAST_MSG("Unhandled RequestStatus: %u", requestInfo->status);
}
- // ActivityId_Unknown (0) is reserved for uninitialized state (ConnectionAck has not been received from DVC server yet) and will not be in m_activityMap.
- if (requestInfo->activityId != ActivationRequestInfo::ActivityId_Unknown)
- {
- connectionManager->m_activityMap.erase(requestInfo->activityId);
- }
+ requestInfo->status = RequestStatus::Closed;
+ requestInfo->statusReporter->SetStatus(RequestStatus::Closed);
- connectionManager->m_activationRequests.erase(requestInfo->listPosition);
+ connectionManager->RemoveRequest(requestInfo, true /* removeFromMainList */);
}
CATCH_LOG_RETURN()
@@ -156,11 +148,14 @@ namespace Microsoft::Kozani::Manager
requestInfo->connectionId = std::move(connectionId);
requestInfo->activationKind = activationKind;
requestInfo->appUserModelId.assign(appUserModelId);
- requestInfo->args = activatedEventArgs;
- requestInfo->statusCallback = statusCallback;
- requestInfo->statusReporter = std::make_shared();
+ if (activatedEventArgs)
+ {
+ requestInfo->serializedActivationArgs = DvcProtocol::SerializeActivatedEventArgs(activatedEventArgs);
+ }
+ requestInfo->statusCallback = statusCallback;
+ requestInfo->statusReporter = std::make_shared();
requestInfo->connectionManager = this;
if (associatedLocalProcessHandle)
@@ -170,8 +165,6 @@ namespace Microsoft::Kozani::Manager
{
THROW_LAST_ERROR_MSG("RegisterWaitForSingleObject failed. Cannot track lifetime of the associated local proess pid=%u", associatedLocalProcessId);
}
-
- requestInfo->associatedLocalProcessHandle = std::move(associatedLocalProcessHandle);
}
m_requestsPendingConnection.push_back(requestInfo);
@@ -181,6 +174,23 @@ namespace Microsoft::Kozani::Manager
return requestInfo->statusReporter;
}
+ void ConnectionManager::CleanupActivationRequest(_In_ const ActivationRequestStatusReporter* statusReporter)
+ {
+ auto lock{ m_requestsLock.lock_exclusive() };
+
+ for (auto& request : m_activationRequests)
+ {
+ // Locate the request object based on its statusReporter pointer.
+ if (request.statusReporter.get() == statusReporter)
+ {
+ bool localProcessTerminationCallbackPending{};
+ const HRESULT hrDisableProcessLifetimeTracker{ LOG_IF_FAILED(DisableProcessLifetimeTracker(&request, localProcessTerminationCallbackPending)) };
+ RemoveRequest(&request, SUCCEEDED(hrDisableProcessLifetimeTracker) && !localProcessTerminationCallbackPending);
+ break;
+ }
+ }
+ }
+
void ConnectionManager::ProcessProtocolDataUnit(
_In_reads_(size) BYTE* data,
UINT32 size,
@@ -299,7 +309,7 @@ namespace Microsoft::Kozani::Manager
errorMessage = L"Failed to process DVC server connection.";
}
- ProcessAppActivationFailure(hrOnDvcServerConnected, activityId, requestInfo, errorMessage.c_str());
+ ProcessAppActivationFailure(hrOnDvcServerConnected, requestInfo, errorMessage.c_str());
}
THROW_HR(hrOnDvcServerConnected);
@@ -333,78 +343,110 @@ namespace Microsoft::Kozani::Manager
ActivationRequestInfo* requestInfo{ iter->second };
if (SUCCEEDED(activateAppResult.hresult()))
{
- requestInfo->status = RequestStatus::AppActivationSucceeded;
- requestInfo->statusReporter->SetStatus(RequestStatus::AppActivationSucceeded);
+ if (activateAppResult.is_new_instance())
+ {
+ requestInfo->status = RequestStatus::AppActivationSucceeded;
+ requestInfo->statusReporter->SetStatus(RequestStatus::AppActivationSucceeded);
- if (requestInfo->statusCallback != nullptr)
+ if (requestInfo->statusCallback != nullptr)
+ {
+ LOG_IF_FAILED(requestInfo->statusCallback->OnActivated(activateAppResult.process_id(), activateAppResult.is_new_instance()));
+ }
+ }
+ else
{
- (void)requestInfo->statusCallback->OnActivated(activateAppResult.process_id(), activateAppResult.is_new_instance());
+ // We no longer need to track the associated local process as the remote app activation does not create a new remote process.
+ bool localProcessTerminationCallbackPending{};
+ const HRESULT hrDisableProcessLifetimeTracker{ LOG_IF_FAILED(DisableProcessLifetimeTracker(requestInfo, localProcessTerminationCallbackPending)) };
+
+ requestInfo->status = RequestStatus::Closed;
+ requestInfo->statusReporter->SetStatus(RequestStatus::Closed);
+
+ if (requestInfo->statusCallback != nullptr)
+ {
+ LOG_IF_FAILED(requestInfo->statusCallback->OnActivated(activateAppResult.process_id(), activateAppResult.is_new_instance()));
+ requestInfo->statusCallback.reset();
+ }
+
+ // No longer need to track the request so remove it from the tracking mechanism. We only remove the requestInfo object from
+ // main list (owning storage) if it is safe to do so: after the process lifetime tracker is successfully disabled and there
+ // are no pending process termination callbacks. Otherwise, the callbacks will need to access the object. We will delay the
+ // cleanup later in the next remote app termination with MinCleanupDelay, or during the local process termination callback.
+ RemoveRequest(requestInfo, SUCCEEDED(hrDisableProcessLifetimeTracker) && !localProcessTerminationCallbackPending);
}
}
else
{
std::wstring errorMessage{ ::Microsoft::Utf8::ToUtf16(activateAppResult.error_message()) };
- ProcessAppActivationFailure(activateAppResult.hresult(), pdu.activity_id(), requestInfo, errorMessage.c_str());
+ ProcessAppActivationFailure(activateAppResult.hresult(), requestInfo, errorMessage.c_str());
}
}
// Must be called with m_requestsLock.lock_exclusive() done in caller.
void ConnectionManager::ProcessAppActivationFailure(
HRESULT hrActivation,
- uint64_t activityId,
_In_ ActivationRequestInfo* requestInfo,
_In_ PCWSTR errorMessage)
{
+ // We no longer need to track the associated local process as remote app activation failed.
+ // Disabling the associated local process tracker also prevents unnecessary handling if the associated local process
+ // is terminated due to us calling IKozaniStatusCallback::OnActivationFailed() to report the failure to our client,
+ // which may cause it to terminate the associated local process.
+ bool localProcessTerminationCallbackPending{};
+ const HRESULT hrDisableProcessLifetimeTracker{ LOG_IF_FAILED(DisableProcessLifetimeTracker(requestInfo, localProcessTerminationCallbackPending)) };
+
+ // Change status to Failed AFTER disabling local process lifetime tracker to avoid triggering the local process to exit
+ // before the tracker is disabled.
+ requestInfo->status = RequestStatus::Failed;
requestInfo->statusReporter->SetStatus(RequestStatus::Failed);
+
if (requestInfo->statusCallback != nullptr)
{
- (void)requestInfo->statusCallback->OnActivationFailed(hrActivation, errorMessage);
+ LOG_IF_FAILED(requestInfo->statusCallback->OnActivationFailed(hrActivation, errorMessage));
+ requestInfo->statusCallback.reset();
}
- // Remove the request from all tracking mechanism.
- m_activityMap.erase(activityId);
- m_activationRequests.erase(requestInfo->listPosition);
+ // Remove the request from all tracking mechanism. We only remove the requestInfo object from
+ // main list (owning storage) if it is safe to do so: after the process lifetime tracker is successfully disabled and there
+ // are no pending process termination callbacks. Otherwise, the callbacks will need to access the object. We will delay the
+ // cleanup later in the next remote app termination with MinCleanupDelay, or during the local process termination callback.
+ RemoveRequest(requestInfo, SUCCEEDED(hrDisableProcessLifetimeTracker) && !localProcessTerminationCallbackPending);
}
- void ConnectionManager::DisableProcessLifetimeTracker(uint64_t activityId)
+ // Must be called with m_requestsLock.lock_exclusive() done in caller.
+ HRESULT ConnectionManager::DisableProcessLifetimeTracker(ActivationRequestInfo* requestInfo, _Out_ bool& callbackPending) noexcept try
{
- auto lock{ m_requestsLock.lock_exclusive() };
- if (m_closing)
- {
- // We are closing, no more processing.
- return;
- }
-
- auto iter{ m_activityMap.find(activityId) };
- if (iter == m_activityMap.end())
- {
- return;
- }
-
- ActivationRequestInfo* requestInfo{ iter->second };
+ callbackPending = false;
if (requestInfo->processLifetimeTrackerHandle)
{
- requestInfo->processLifetimeTrackerDisabled = true;
+ BOOL unregisterWaitSuccess{ UnregisterWait(requestInfo->processLifetimeTrackerHandle.get()) };
+ if (!unregisterWaitSuccess)
+ {
+ DWORD error{ GetLastError() };
+ if (error == ERROR_IO_PENDING)
+ {
+ // If there are outstanding callbacks when UnregisterWait is called, UnregisterWait unregisters the wait on the callback functions
+ // and fails with the ERROR_IO_PENDING error code. The error code does not indicate that the function has failed, and the function
+ // does not need to be called again.
+ callbackPending = true;
+ }
+ else
+ {
+ RETURN_WIN32_MSG(error, "UnregisterWait failed");
+ }
+ }
- // Call UnregisterWaitEx with INVALID_HANDLE_VALUE so it will wait for any pending callback to finish before returning.
- // Release the m_requestsLock before calling blocking UnregisterWaitEx, which will deadlock if the other thread calling the
- // ProcessTerminationCallback function is trying to get the lock. We are safe here as requestInfo->processLifetimeTrackerDisabled
- // is set to true above, which will prevent the process lifetime tracker thread from modifying the requestInfo object.
- lock.reset();
- THROW_IF_WIN32_BOOL_FALSE(UnregisterWaitEx(requestInfo->processLifetimeTrackerHandle.get(), INVALID_HANDLE_VALUE));
+ requestInfo->processLifetimeTrackerDisabled = true;
+ requestInfo->processLifetimeTrackerDisabledTime = GetTickCount64();
requestInfo->processLifetimeTrackerHandle.release();
}
+ return S_OK;
}
+ CATCH_RETURN()
void ConnectionManager::ProcessAppTerminationNotice(_In_ const Dvc::ProtocolDataUnit& pdu)
{
- // We no longer need to track the associated local process as we know the remote process has been terminated.
- // Disabling the associated local process tracker also prevents unnecessary handling if the associated local process
- // is terminated due to us calling IKozaniStatusCallback::OnClosed() to report the remote app termination to our client,
- // which may cause it to terminate the associated local process.
- DisableProcessLifetimeTracker(pdu.activity_id());
-
auto lock{ m_requestsLock.lock_exclusive() };
if (m_closing)
{
@@ -423,6 +465,13 @@ namespace Microsoft::Kozani::Manager
ActivationRequestInfo* requestInfo{ iter->second };
+ // We no longer need to track the associated local process as we know the remote process has been terminated.
+ // Disabling the associated local process tracker also prevents unnecessary handling if the associated local process
+ // is terminated due to us calling IKozaniStatusCallback::OnClosed() to report the remote app termination to our client,
+ // which may cause it to terminate the associated local process.
+ bool localProcessTerminationCallbackPending{};
+ const HRESULT hrDisableProcessLifetimeTracker{ LOG_IF_FAILED(DisableProcessLifetimeTracker(requestInfo, localProcessTerminationCallbackPending)) };
+
requestInfo->status = RequestStatus::Closed;
requestInfo->statusReporter->SetStatus(RequestStatus::Closed);
@@ -432,14 +481,19 @@ namespace Microsoft::Kozani::Manager
requestInfo->statusCallback.reset();
}
- m_activityMap.erase(iter);
- m_activationRequests.erase(requestInfo->listPosition);
+ // Remove the request from the tracking mechanism. We only remove the requestInfo object from
+ // main list (owning storage) if it is safe to do so: after the process lifetime tracker is successfully disabled and there
+ // are no pending process termination callbacks. Otherwise, the callbacks will need to access the object. We will delay the
+ // cleanup later in the next remote app termination with MinCleanupDelay, or during the local process termination callback.
+ RemoveRequest(requestInfo, SUCCEEDED(hrDisableProcessLifetimeTracker) && !localProcessTerminationCallbackPending);
+
+ CleanupOutdatedRequests();
}
HRESULT ConnectionManager::SendActivateAppRequest(_In_ ActivationRequestInfo* requestInfo) noexcept try
{
std::string pdu{ DvcProtocol::CreateActivateAppRequestPdu(
- requestInfo->activityId, requestInfo->appUserModelId.c_str(), requestInfo->activationKind, requestInfo->args) };
+ requestInfo->activityId, requestInfo->appUserModelId.c_str(), requestInfo->activationKind, requestInfo->serializedActivationArgs) };
RETURN_IF_FAILED(requestInfo->dvcChannel->Write(
static_cast(pdu.size()), reinterpret_cast(pdu.data()), nullptr /* pReserved - must be nullptr */));
return S_OK;
@@ -469,18 +523,15 @@ namespace Microsoft::Kozani::Manager
{
if (it->dvcChannel == channel)
{
- if (it->statusCallback != nullptr)
- {
- LOG_IF_FAILED(it->statusCallback->OnClosed());
- it->statusCallback.reset();
- }
- it = m_activationRequests.erase(it);
+ CloseRequest(it);
}
else
{
it++;
}
}
+
+ CleanupOutdatedRequests();
}
void ConnectionManager::OnRemoteDesktopInitializeConnection(_In_ IWTSVirtualChannelManager* channelManager)
@@ -522,17 +573,107 @@ namespace Microsoft::Kozani::Manager
{
if (it->dvcChannelManager == channelManager)
{
- if (it->statusCallback != nullptr)
- {
- LOG_IF_FAILED(it->statusCallback->OnClosed());
- it->statusCallback.reset();
- }
- it = m_activationRequests.erase(it);
+ CloseRequest(it);
}
else
{
it++;
}
}
+
+ CleanupOutdatedRequests();
+ }
+
+ // Caller must have m_requestsLock in lock_exclusive() state.
+ void ConnectionManager::CloseRequest(std::list::iterator& it)
+ {
+ // We no longer need to track the associated local process as the request is closed.
+ // Disabling the associated local process tracker also prevents unnecessary handling if the associated local process
+ // is terminated due to us calling IKozaniStatusCallback::OnClosed() to report the activation request is closed,
+ // which may cause it to terminate the associated local process.
+ bool localProcessTerminationCallbackPending{};
+ const HRESULT hrDisableProcessLifetimeTracker{ LOG_IF_FAILED(DisableProcessLifetimeTracker(&(*it), localProcessTerminationCallbackPending)) };
+
+ if (it->status == RequestStatus::Connecting)
+ {
+ RemoveRequestFromPendingConnectionList(&(*it));
+ }
+
+ // Report status change AFTER disabling the local process tracker to avoid triggering the local process to exit before the
+ // tracker is disabled.
+ it->status = RequestStatus::Closed;
+ it->statusReporter->SetStatus(RequestStatus::Closed);
+
+ if (it->statusCallback != nullptr)
+ {
+ LOG_IF_FAILED(it->statusCallback->OnClosed());
+ it->statusCallback.reset();
+ }
+
+ if (it->activityId != ActivationRequestInfo::ActivityId_Unknown)
+ {
+ m_activityMap.erase(it->activityId);
+ }
+
+ if (SUCCEEDED(hrDisableProcessLifetimeTracker) && !localProcessTerminationCallbackPending)
+ {
+ it = m_activationRequests.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+
+ // Caller must have m_requestsLock in lock_exclusive() state.
+ void ConnectionManager::RemoveRequestFromPendingConnectionList(_In_ const ActivationRequestInfo* request)
+ {
+ for (auto it = m_requestsPendingConnection.begin(); it != m_requestsPendingConnection.end(); it++)
+ {
+ if (request == *it)
+ {
+ m_requestsPendingConnection.erase(it);
+ break;
+ }
+ }
+ }
+
+ // Caller must have m_requestsLock in lock_exclusive() state.
+ void ConnectionManager::RemoveRequest(_In_ const ActivationRequestInfo* request, bool removeFromMainList)
+ {
+ if (request->status == RequestStatus::Connecting)
+ {
+ RemoveRequestFromPendingConnectionList(request);
+ }
+
+ // ActivityId_Unknown (0) is reserved for uninitialized state (ConnectionAck has not been received from DVC server yet) and will not be in m_activityMap.
+ if (request->activityId != ActivationRequestInfo::ActivityId_Unknown)
+ {
+ m_activityMap.erase(request->activityId);
+ }
+
+ if (removeFromMainList)
+ {
+ m_activationRequests.erase(request->listPosition);
+ }
+ }
+
+ // Caller must have m_requestsLock in lock_exclusive() state.
+ void ConnectionManager::CleanupOutdatedRequests()
+ {
+ uint64_t currentTickCount{ GetTickCount64() };
+ for (auto it = m_activationRequests.begin(); it != m_activationRequests.end();)
+ {
+ if (it->processLifetimeTrackerDisabled && (it->status == RequestStatus::Closed || it->status == RequestStatus::Failed))
+ {
+ uint64_t timePassed{ currentTickCount - it->processLifetimeTrackerDisabledTime };
+ if (timePassed > ActivationRequestInfo::MinCleanupDelay)
+ {
+ it = m_activationRequests.erase(it);
+ continue;
+ }
+ }
+ it++;
+ }
}
}
diff --git a/dev/Kozani/KozaniManager/ConnectionManager.h b/dev/Kozani/KozaniManager/ConnectionManager.h
index 258b540392..89e6d2eefa 100644
--- a/dev/Kozani/KozaniManager/ConnectionManager.h
+++ b/dev/Kozani/KozaniManager/ConnectionManager.h
@@ -3,6 +3,8 @@
#pragma once
+#include
+
namespace Microsoft::Kozani::Manager
{
// Max amount of time we will wait for the DVC plugin to be loaded by the remote desktop client (RDC) since we launches it.
@@ -68,12 +70,19 @@ namespace Microsoft::Kozani::Manager
{
static const uint64_t ActivityId_Unknown{};
+ // Minimum cleanup delay after the associated local process lifetime tracker is disabled: 60 seconds.
+ // When the request status becomes Closed or Failed, we want to unregister the wait handle for tracking the associated local process.
+ // However, the unregistration can fail with ERROR_IO_PENDING if there is an outstanding callback to be made. In such a case, we cannot
+ // clean up the ActivationRequestInfo object as it will be accessed from the callback function. We will clean up the object later with
+ // this minimum delay to allow the callbak to finish.
+ static const int MinCleanupDelay{ 60 * 1000 };
+
uint64_t activityId{};
RequestStatus status{};
std::string connectionId;
std::wstring appUserModelId;
winrt::Windows::ApplicationModel::Activation::ActivationKind activationKind{};
- winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs args;
+ std::string serializedActivationArgs;
wil::com_ptr statusCallback;
wil::com_ptr dvcChannelManager;
wil::com_ptr dvcChannel;
@@ -81,9 +90,9 @@ namespace Microsoft::Kozani::Manager
std::shared_ptr statusReporter;
ConnectionManager* connectionManager{};
DWORD associatedLocalProcessId{};
- wil::unique_handle associatedLocalProcessHandle;
unique_wait_handle processLifetimeTrackerHandle;
bool processLifetimeTrackerDisabled{};
+ uint64_t processLifetimeTrackerDisabledTime{};
};
class ConnectionManager
@@ -97,6 +106,8 @@ namespace Microsoft::Kozani::Manager
_In_ IKozaniStatusCallback* statusCallback,
DWORD associatedLocalProcessId);
+ void CleanupActivationRequest(_In_ const ActivationRequestStatusReporter* statusReporter);
+
void Close();
void ProcessProtocolDataUnit(
@@ -129,17 +140,23 @@ namespace Microsoft::Kozani::Manager
void ProcessAppActivationFailure(
HRESULT hrActivation,
- uint64_t activityId,
_In_ ActivationRequestInfo* requestInfo,
_In_ PCWSTR errorMessage);
- void DisableProcessLifetimeTracker(uint64_t activityId);
+ HRESULT DisableProcessLifetimeTracker(ActivationRequestInfo* requestInfo, _Out_ bool& callbackPending) noexcept;
+
void ProcessAppTerminationNotice(_In_ const Dvc::ProtocolDataUnit& pdu);
HRESULT SendActivateAppRequest(_In_ ActivationRequestInfo* requestInfo) noexcept;
HRESULT SendAppTerminationNotice(_In_ ActivationRequestInfo* requestInfo) noexcept;
+ void CloseRequest(std::list::iterator& it);
+
+ void RemoveRequestFromPendingConnectionList(_In_ const ActivationRequestInfo* request);
+ void RemoveRequest(_In_ const ActivationRequestInfo* request, bool removeFromMainList);
+ void CleanupOutdatedRequests();
+
private:
std::list m_activationRequests;
std::list m_requestsPendingConnection;
diff --git a/dev/Kozani/KozaniManager/KozaniManager.vcxproj b/dev/Kozani/KozaniManager/KozaniManager.vcxproj
index db99763373..fec423d525 100644
--- a/dev/Kozani/KozaniManager/KozaniManager.vcxproj
+++ b/dev/Kozani/KozaniManager/KozaniManager.vcxproj
@@ -171,6 +171,9 @@
{400ed5ec-4530-4adb-8dce-9d1e6708a1f5}
+
+ {3f28c3ed-2548-4530-8b6c-832fae0e993d}
+
diff --git a/dev/Kozani/KozaniManager/KozaniManagerActivity.cpp b/dev/Kozani/KozaniManager/KozaniManagerActivity.cpp
index c3d37bac0e..23fe9fb567 100644
--- a/dev/Kozani/KozaniManager/KozaniManagerActivity.cpp
+++ b/dev/Kozani/KozaniManager/KozaniManagerActivity.cpp
@@ -32,7 +32,7 @@ class KozaniDvcCallback : public Microsoft::WRL::RuntimeClass<
//
HRESULT STDMETHODCALLTYPE OnDataReceived(ULONG size, _In_reads_(size) BYTE* data) override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSVirtualChannelCallback::OnDataReceived(), cbSize = %u, pChannelMgr=0x%p, pChannel=0x%p",
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSVirtualChannelCallback::OnDataReceived(), cbSize = %u, pChannelMgr=0x%p, pChannel=0x%p",
size, m_channelManager.get(), m_channel.get());
g_connectionManager.ProcessProtocolDataUnit(data, size, m_channelManager.get(), m_channel.get());
@@ -42,7 +42,7 @@ class KozaniDvcCallback : public Microsoft::WRL::RuntimeClass<
HRESULT STDMETHODCALLTYPE OnClose() override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSVirtualChannelCallback::OnClose() - pChannelMgr=0x%p, pChannel=0x%p",
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSVirtualChannelCallback::OnClose() - pChannelMgr=0x%p, pChannel=0x%p",
m_channelManager.get(), m_channel.get());
g_connectionManager.OnDvcChannelClose(m_channel.get());
@@ -64,7 +64,7 @@ struct __declspec(uuid(PR_KOZANIDVC_CLSID_STRING)) KozaniDvcImpl WrlFinal : Runt
STDMETHODIMP Initialize(IWTSVirtualChannelManager* pChannelMgr) override try
{
// Called early in MSRDC launch, before a connection to a new remote session.
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSPlugin::Initialize() - pChannelMgr=0x%p", pChannelMgr);
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSPlugin::Initialize() - pChannelMgr=0x%p", pChannelMgr);
m_channelManager = pChannelMgr;
@@ -84,14 +84,14 @@ struct __declspec(uuid(PR_KOZANIDVC_CLSID_STRING)) KozaniDvcImpl WrlFinal : Runt
STDMETHODIMP Connected() override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSPlugin::Connected() - pChannelMgr=0x%p", m_channelManager.get());
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSPlugin::Connected() - pChannelMgr=0x%p", m_channelManager.get());
return S_OK;
}
CATCH_RETURN()
STDMETHODIMP Disconnected(DWORD dwDisconnectCode) override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSPlugin::Disconnected() - pChannelMgr=0x%p, dwDisconnectCode = %u", m_channelManager.get(), dwDisconnectCode);
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSPlugin::Disconnected() - pChannelMgr=0x%p, dwDisconnectCode = %u", m_channelManager.get(), dwDisconnectCode);
g_connectionManager.OnRemoteDesktopDisconnect(m_channelManager.get());
return S_OK;
}
@@ -99,7 +99,7 @@ struct __declspec(uuid(PR_KOZANIDVC_CLSID_STRING)) KozaniDvcImpl WrlFinal : Runt
STDMETHODIMP Terminated() override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSPlugin::Terminated() - pChannelMgr=0x%p", m_channelManager.get());
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSPlugin::Terminated() - pChannelMgr=0x%p", m_channelManager.get());
g_connectionManager.OnRemoteDesktopDisconnect(m_channelManager.get());
return S_OK;
}
@@ -114,7 +114,7 @@ struct __declspec(uuid(PR_KOZANIDVC_CLSID_STRING)) KozaniDvcImpl WrlFinal : Runt
_Out_ BOOL* pbAccept,
_Out_ IWTSVirtualChannelCallback** ppCallback) override try
{
- LOG_HR_MSG(KOZANI_S_INFO, "IWTSListenerCallback::OnNewChannelConnection is called! pChannelMgr=0x%p, pChannel=0x%p",
+ LOG_HR_MSG(KOZANI_E_INFO, "IWTSListenerCallback::OnNewChannelConnection is called! pChannelMgr=0x%p, pChannel=0x%p",
m_channelManager.get(), pChannel);
auto pConnection = Make(pChannel, m_channelManager.get());
diff --git a/dev/Kozani/KozaniManager/main.cpp b/dev/Kozani/KozaniManager/main.cpp
index 31da9e4636..60174a6b13 100644
--- a/dev/Kozani/KozaniManager/main.cpp
+++ b/dev/Kozani/KozaniManager/main.cpp
@@ -15,6 +15,8 @@
#include
+#include
+
#include
#include "KozaniDvc-Constants.h"
#include "ConnectionManager.h"
@@ -85,23 +87,27 @@ struct __declspec(uuid(PR_KOZANIMANAGER_CLSID_STRING)) KozaniManagerImpl WrlFina
{
STDMETHODIMP ActivateRemoteApplication(
INT32 activationKind,
- PCWSTR appUserModelId,
- PCWSTR connectionRdpFilePath,
- PCWSTR additionalSettingsFilePath,
- ::IInspectable* activatedEventArgs,
- IKozaniStatusCallback* statusCallback,
- DWORD associatedLocalProcessId) noexcept try
+ _In_ PCWSTR appUserModelId,
+ _In_ PCWSTR connectionRdpFilePath,
+ _In_ IKozaniRemoteDesktopClientLauncher* rdcLauncher,
+ DWORD associatedLocalProcessId,
+ _In_opt_::IInspectable* activatedEventArgs,
+ _In_opt_ IKozaniStatusCallback* statusCallback,
+ _In_opt_ PCWSTR additionalSettingsFilePath) noexcept try
{
+ RETURN_HR_IF_NULL(E_INVALIDARG, appUserModelId);
+ RETURN_HR_IF_NULL(E_INVALIDARG, connectionRdpFilePath);
+ RETURN_HR_IF_NULL(E_INVALIDARG, rdcLauncher);
+
const auto activationKindLocal{ static_cast(activationKind) };
RETURN_HR_IF_MSG(KOZANI_E_UNSUPPORTED_ACTIVATION_KIND,
!IsActivationKindSupported(activationKindLocal),
"Activation kind: %d", activationKind);
winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs args;
- if (!activatedEventArgs)
+ if (activatedEventArgs)
{
- winrt::com_ptr<::IInspectable> inspectable(activatedEventArgs, winrt::take_ownership_from_abi);
- args = inspectable.as();
+ args = winrt::convert_from_abi(activatedEventArgs);
}
std::string connectionId{ GetConnectionId(connectionRdpFilePath) };
@@ -110,16 +116,15 @@ struct __declspec(uuid(PR_KOZANIMANAGER_CLSID_STRING)) KozaniManagerImpl WrlFina
std::shared_ptr requestStatusReporter{
g_connectionManager.AddNewActivationRequest(connectionId, activationKindLocal, appUserModelId, args, statusCallback, associatedLocalProcessId) };
- const LONG connectionCountBeforeRDCLaunch{ InterlockedAdd(&g_newConnectionCount, 0) };
+ // If failure happens after this point, we will automatically cleanup the new request from tracking mechanism.
+ auto cleanupRequestOnFailure = wil::scope_exit([&]()
+ {
+ g_connectionManager.CleanupActivationRequest(requestStatusReporter.get());
+ });
- SHELLEXECUTEINFO shellExecuteInfo{};
- shellExecuteInfo.cbSize = sizeof(shellExecuteInfo);
- shellExecuteInfo.fMask = SEE_MASK_NOASYNC; // Will wait for ShellExecuteEx to finish launching the remote desktop client.
- shellExecuteInfo.lpFile = Dvc::Constants::RemoteDesktopClientExe;
- shellExecuteInfo.lpParameters = connectionRdpFilePath;
- shellExecuteInfo.nShow = SW_NORMAL;
+ const LONG connectionCountBeforeRDCLaunch{ InterlockedAdd(&g_newConnectionCount, 0) };
- RETURN_IF_WIN32_BOOL_FALSE_MSG(ShellExecuteEx(&shellExecuteInfo), "ShellExecuteEx failed to launch %ls", Dvc::Constants::RemoteDesktopClientExe);
+ RETURN_IF_FAILED(rdcLauncher->Launch(connectionRdpFilePath, nullptr));
// Wait for request status change or time out to ensure this module is alive for RDC to load the DVC plugin hosted by the module.
// If the module is exiting while RDC is loading the DVC plugin, the DVC loading will fail and RDC will ignore the failure and
@@ -141,6 +146,7 @@ struct __declspec(uuid(PR_KOZANIMANAGER_CLSID_STRING)) KozaniManagerImpl WrlFina
// finish cannot be determined. The user may take some time to enter the password to login and the login can take time
// to finish depending on the server's workload. The IKozaniStatusCallback object will be used by the DVC to communicate
// any issues in this longer process.
+ cleanupRequestOnFailure.release();
return S_OK;
}
}
@@ -159,6 +165,8 @@ struct __declspec(uuid(PR_KOZANIMANAGER_CLSID_STRING)) KozaniManagerImpl WrlFina
RETURN_HR(E_APPLICATION_ACTIVATION_TIMED_OUT);
}
+ // No failures before returning - disable the auto cleanup on failure logic.
+ cleanupRequestOnFailure.release();
return S_OK;
} CATCH_RETURN()
@@ -168,6 +176,10 @@ struct __declspec(uuid(PR_KOZANIMANAGER_CLSID_STRING)) KozaniManagerImpl WrlFina
switch (kind)
{
case winrt::Windows::ApplicationModel::Activation::ActivationKind::Launch:
+ [[fallthrough]];
+ case winrt::Windows::ApplicationModel::Activation::ActivationKind::File:
+ [[fallthrough]];
+ case winrt::Windows::ApplicationModel::Activation::ActivationKind::Protocol:
return true;
}
@@ -185,6 +197,9 @@ void EndOfTheLine()
int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PSTR /*lpCmdLine*/, int /*nCmdShow*/)
{
+ // Hook up wil logging MACROs to trace provider.
+ wil::SetResultLoggingCallback(&TraceFailureFromProvider);
+
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
diff --git a/dev/Kozani/KozaniManager/packages.config b/dev/Kozani/KozaniManager/packages.config
index ba003992c7..8d63d7f888 100644
--- a/dev/Kozani/KozaniManager/packages.config
+++ b/dev/Kozani/KozaniManager/packages.config
@@ -3,7 +3,7 @@
-
+
diff --git a/dev/Kozani/KozaniManager/pch.h b/dev/Kozani/KozaniManager/pch.h
index aeb83e0f15..3628c2b6e9 100644
--- a/dev/Kozani/KozaniManager/pch.h
+++ b/dev/Kozani/KozaniManager/pch.h
@@ -36,6 +36,7 @@
#include
+#include "KozaniManagerTracelogging.h"
#include "KozaniProtobufMessages.h"
#include "KozaniDvcProtocol.h"
#include "Logging.h"
diff --git a/dev/Kozani/KozaniManagerInterface/KozaniManagerInterface.idl b/dev/Kozani/KozaniManagerInterface/KozaniManagerInterface.idl
index 79421278f3..cb752270dd 100644
--- a/dev/Kozani/KozaniManagerInterface/KozaniManagerInterface.idl
+++ b/dev/Kozani/KozaniManagerInterface/KozaniManagerInterface.idl
@@ -19,6 +19,16 @@ interface IKozaniStatusCallback : IInspectable
HRESULT OnClosed();
};
+[object]
+[uuid(43665c78-faf6-4534-9411-321147fc80ea)]
+[pointer_default(unique)]
+interface IKozaniRemoteDesktopClientLauncher : IUnknown
+{
+ HRESULT Launch(
+ [in, string] LPCWSTR connectionRdpFilePath,
+ [in, string, unique] LPCWSTR userName);
+};
+
[object]
[uuid(5882f14f-f954-4af9-bbeb-a7c1a2a6357e)]
[pointer_default(unique)]
@@ -28,8 +38,10 @@ interface IKozaniManager : IUnknown
INT32 activationKind,
[in, string] LPCWSTR appUserModelId,
[in, string] LPCWSTR connectionRdpFilePath,
- [in, string] LPCWSTR additionalSettingsFilePath,
- [in] IInspectable* activatedEventArgs,
- [in] IKozaniStatusCallback* statusCallback,
- DWORD associatedLocalProcessId);
+ [in] IKozaniRemoteDesktopClientLauncher* rdcLauncher,
+ DWORD associatedLocalProcessId, // Use 0 if the remote app is not associated with a local process (no tracking local process for lifetime management).
+ [in, unique] IInspectable* activatedEventArgs, // optional - can be nullptr if there are no activatedEventArgs
+ [in, unique] IKozaniStatusCallback* statusCallback, // optional - can be nullptr if the caller does not need status update callbacks
+ [in, string, unique] LPCWSTR additionalSettingsFilePath // optional - can be nullptr if the additional settings file does not exist
+ );
};
diff --git a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.idl b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.idl
index 7329be07ee..b5a7cffb6e 100644
--- a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.idl
+++ b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.idl
@@ -15,10 +15,10 @@ namespace Microsoft.Kozani.ManagerRuntime
Windows.ApplicationModel.Activation.ActivationKind activationKind,
String appUserModelId,
String connectionRdpFilePath,
- String additionalSettingsFilePath,
- Windows.ApplicationModel.Activation.IActivatedEventArgs args, // optional, can be nullptr
- IInspectable statusCallback,
- UInt32 associatedLocalProcessId // optional, use 0 if you don't want the remote app lifetime to be tied to the lifetime of an associated local process
+ UInt32 associatedLocalProcessId, // optional, use 0 if you don't want the remote app lifetime to be tied to the lifetime of an associated local process
+ Windows.ApplicationModel.Activation.IActivatedEventArgs args, // optional - can be nullptr if there are no activatedEventArgs for Launch ActivationKind
+ IInspectable statusCallback, // optional - can be nullptr if the caller does not need status update callbacks
+ String additionalSettingsFilePath // optional - can be empty String if the additional settings file does not exist
);
};
}
diff --git a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj
index c6a3bf3240..4f9f83ecd7 100644
--- a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj
+++ b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj
@@ -92,7 +92,7 @@
- (MSBuildThisFileDirectory);$(OutDir)..\KozaniManagerProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(RepoRoot)\dev\WindowsAppRuntime_Insights;$(RepoRoot)\dev\common;$(IntDir);%(AdditionalIncludeDirectories)
+ (MSBuildThisFileDirectory);$(OutDir)..\KozaniManagerProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(RepoRoot)\dev\WindowsAppRuntime_Insights;$(RepoRoot)\dev\common;$(IntDir);$(RepoRoot)\dev\Kozani\common;%(AdditionalIncludeDirectories)
Use
pch.h
KOZANIMANAGERRUNTIMEDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
diff --git a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj.filters b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj.filters
index c120a9f8e2..95a6c26388 100644
--- a/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj.filters
+++ b/dev/Kozani/KozaniManagerRuntime/KozaniManagerRuntime.vcxproj.filters
@@ -71,4 +71,7 @@
Resource Files
-
+
+
+
+
\ No newline at end of file
diff --git a/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.cpp b/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.cpp
index eded8cdd46..eb5ac32d20 100644
--- a/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.cpp
+++ b/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.cpp
@@ -2,13 +2,31 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "pch.h"
-
#include "M.K.MR.ManagerRuntimeManager.h"
-
#include "ManagerRuntimeManager.g.cpp"
namespace winrt::Microsoft::Kozani::ManagerRuntime::implementation
{
+ constexpr PCWSTR c_remoteDesktopClientExe = L"mstsc.exe";
+
+ struct KozaniRemoteDesktopClientLauncher : winrt::implements
+ {
+ STDMETHODIMP Launch(_In_ PCWSTR connectionRdpFilePath, _In_opt_ PCWSTR /* userName */)
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, connectionRdpFilePath);
+
+ SHELLEXECUTEINFO shellExecuteInfo{};
+ shellExecuteInfo.cbSize = sizeof(shellExecuteInfo);
+ shellExecuteInfo.fMask = SEE_MASK_NOASYNC; // Will wait for ShellExecuteEx to finish launching the remote desktop client.
+ shellExecuteInfo.lpFile = c_remoteDesktopClientExe;
+ shellExecuteInfo.lpParameters = connectionRdpFilePath;
+ shellExecuteInfo.nShow = SW_NORMAL;
+
+ RETURN_IF_WIN32_BOOL_FALSE_MSG(ShellExecuteEx(&shellExecuteInfo), "ShellExecuteEx failed to launch %ls", c_remoteDesktopClientExe);
+ return S_OK;
+ }
+ };
+
ManagerRuntimeManager::ManagerRuntimeManager()
{
m_kozaniManager = wil::CoCreateInstance(CLSCTX_LOCAL_SERVER);
@@ -23,18 +41,27 @@ namespace winrt::Microsoft::Kozani::ManagerRuntime::implementation
Windows::ApplicationModel::Activation::ActivationKind activationKind,
winrt::hstring appUserModelId,
winrt::hstring connectionRdpFilePath,
- winrt::hstring additionalSettingsFilePath,
+ UINT32 associatedLocalProcessId,
Windows::ApplicationModel::Activation::IActivatedEventArgs args,
IInspectable statusCallback,
- UINT32 associatedLocalProcessId)
+ winrt::hstring additionalSettingsFilePath)
{
+ // The purpose of IKozaniRemoteDesktopClientLauncher is to allow the caller of the IKozaniManager::ActivateRemoteApplication API
+ // to launch remote desktop client (RDC) in its process. The COM server hosting the IKozaniManager APIs is a background process,
+ // which may not be able to launch the RDC to desktop foreground. From experiments we've found that if the caller process is a
+ // foregrounddoes process (e.g., just got activated from Start Menu) but does not display a window (process with no UIs), launching
+ // RDC from its process will show the RDC in foreground, while launching RDC in the IKozaniManager APIs COM server process will
+ // have the RDC window in background with flashing icon on the taskbar.
+ auto rdcLauncher{ winrt::make_self() };
+
winrt::check_hresult(m_kozaniManager->ActivateRemoteApplication(
static_cast(activationKind),
appUserModelId.c_str(),
connectionRdpFilePath.c_str(),
- additionalSettingsFilePath.c_str(),
- reinterpret_cast<::IInspectable*>(winrt::get_abi(args)),
- reinterpret_cast<::IKozaniStatusCallback*>(winrt::get_abi(statusCallback)),
- associatedLocalProcessId));
+ reinterpret_cast<::IKozaniRemoteDesktopClientLauncher*>(winrt::get_abi(rdcLauncher)),
+ associatedLocalProcessId,
+ args.as<::IInspectable>().get(),
+ statusCallback.as<::IKozaniStatusCallback>().get(),
+ additionalSettingsFilePath.c_str()));
}
}
diff --git a/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.h b/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.h
index eeaf2ad0e9..446301a917 100644
--- a/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.h
+++ b/dev/Kozani/KozaniManagerRuntime/M.K.MR.ManagerRuntimeManager.h
@@ -18,10 +18,10 @@ namespace winrt::Microsoft::Kozani::ManagerRuntime::implementation
Windows::ApplicationModel::Activation::ActivationKind activationKind,
winrt::hstring appUserModelId,
winrt::hstring connectionRdpFilePath,
- winrt::hstring additionalSettingsFilePath,
+ UINT32 associatedLocalProcessId,
Windows::ApplicationModel::Activation::IActivatedEventArgs args,
IInspectable statusCallback,
- UINT32 associatedLocalProcessId);
+ winrt::hstring additionalSettingsFilePath);
private:
wil::com_ptr m_kozaniManager;
diff --git a/dev/Kozani/KozaniManagerRuntime/dllmain.cpp b/dev/Kozani/KozaniManagerRuntime/dllmain.cpp
index 2da5b862d4..3cc4d89335 100644
--- a/dev/Kozani/KozaniManagerRuntime/dllmain.cpp
+++ b/dev/Kozani/KozaniManagerRuntime/dllmain.cpp
@@ -12,6 +12,8 @@ BOOL APIENTRY DllMain(HMODULE hmodule, DWORD reason, LPVOID reserved)
switch (reason)
{
case DLL_PROCESS_ATTACH:
+ // Hook up wil logging MACROs to trace provider.
+ wil::SetResultLoggingCallback(&TraceFailureFromProvider);
DisableThreadLibraryCalls(hmodule);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
diff --git a/dev/Kozani/KozaniManagerRuntime/packages.config b/dev/Kozani/KozaniManagerRuntime/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniManagerRuntime/packages.config
+++ b/dev/Kozani/KozaniManagerRuntime/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniManagerRuntime/pch.h b/dev/Kozani/KozaniManagerRuntime/pch.h
index be289b02c9..e0a5cd8dae 100644
--- a/dev/Kozani/KozaniManagerRuntime/pch.h
+++ b/dev/Kozani/KozaniManagerRuntime/pch.h
@@ -16,5 +16,6 @@
#include "framework.h"
#include "KozaniManagerRuntimeActivity.h"
#include "KozaniManagerRuntimeTraceLogging.h"
+#include "Logging.h"
#endif //PCH_H
diff --git a/dev/Kozani/KozaniPackage/packages.config b/dev/Kozani/KozaniPackage/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniPackage/packages.config
+++ b/dev/Kozani/KozaniPackage/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniProtocol/Kozani.DVC.proto b/dev/Kozani/KozaniProtocol/Kozani.DVC.proto
index 4ef02b3b46..8993e951f8 100644
--- a/dev/Kozani/KozaniProtocol/Kozani.DVC.proto
+++ b/dev/Kozani/KozaniProtocol/Kozani.DVC.proto
@@ -65,3 +65,14 @@ message LaunchActivationArgs
{
string arguments = 1;
}
+
+message FileActivationArgs
+{
+ string verb = 1;
+ repeated string file_paths = 2;
+}
+
+message ProtocolActivationArgs
+{
+ string uri = 1;
+}
\ No newline at end of file
diff --git a/dev/Kozani/KozaniRemoteManager/ConnectionManager.cpp b/dev/Kozani/KozaniRemoteManager/ConnectionManager.cpp
index 6337149279..d43b354273 100644
--- a/dev/Kozani/KozaniRemoteManager/ConnectionManager.cpp
+++ b/dev/Kozani/KozaniRemoteManager/ConnectionManager.cpp
@@ -42,7 +42,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
CATCH_LOG_RETURN()
- void ConnectionManager::Connect(PCSTR connectionId)
+ void ConnectionManager::Connect(PCSTR connectionId, IKozaniApplicationLauncher* appLauncher)
{
auto lock{ std::unique_lock(m_dvcServerLock) };
@@ -88,7 +88,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
}
- m_dvcServer->SendConnectionAck(connectionId);
+ m_dvcServer->ProcessClientConnection(connectionId, appLauncher);
}
// Report error from DVC server object. Called from the DVC server object encounting error.
diff --git a/dev/Kozani/KozaniRemoteManager/ConnectionManager.h b/dev/Kozani/KozaniRemoteManager/ConnectionManager.h
index 8c46b3d038..0b1a6355be 100644
--- a/dev/Kozani/KozaniRemoteManager/ConnectionManager.h
+++ b/dev/Kozani/KozaniRemoteManager/ConnectionManager.h
@@ -15,7 +15,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
~ConnectionManager() noexcept;
- void Connect(PCSTR connectionId);
+ void Connect(_In_ PCSTR connectionId, _In_ IKozaniApplicationLauncher* appLauncher);
void ReportDvcServerError(HRESULT hr);
private:
diff --git a/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.cpp b/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.cpp
index 7c45d3a631..36af192dac 100644
--- a/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.cpp
+++ b/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.cpp
@@ -4,7 +4,6 @@
#pragma once
#include "pch.h"
-#include
#include
#include
@@ -83,6 +82,16 @@ namespace Microsoft::Kozani::KozaniRemoteManager
return S_OK;
}
+ void KozaniDvcServer::ProcessClientConnection(_In_ PCSTR connectionId, _In_ IKozaniApplicationLauncher* appLauncher)
+ {
+ {
+ auto lock{ m_appLauncherLock.lock_exclusive() };
+ m_appLauncher = appLauncher;
+ }
+
+ SendConnectionAck(connectionId);
+ }
+
void KozaniDvcServer::OpenDvc()
{
auto lock{ std::unique_lock(m_dvcLock) };
@@ -151,13 +160,13 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
HANDLE events[]{ m_dvcThreadExit.get(), readComplete.get() };
- LOG_HR_MSG(KOZANI_S_INFO, "[DVC] Listener thread starting to wait");
+ LOG_HR_MSG(KOZANI_E_INFO, "[DVC] Listener thread starting to wait");
// When we reach this point, the DVC listener thread has passed setup phase and is running.
m_dvcThreadStarted.SetEvent();
const DWORD result{ WaitForMultipleObjects(ARRAYSIZE(events), events, FALSE, INFINITE) };
- LOG_HR_MSG(KOZANI_S_INFO, "[DVC] Listener thread wait completed (result=0x%x)", result);
+ LOG_HR_MSG(KOZANI_E_INFO, "[DVC] Listener thread wait completed (result=0x%x)", result);
if (result == WAIT_FAILED)
{
hr = HRESULT_FROM_WIN32(GetLastError());
@@ -170,7 +179,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
case WAIT_OBJECT_0:
{
// Thread exit handle signaled.
- LOG_HR_MSG(KOZANI_S_INFO, "[DVC] Thread exit event handled");
+ LOG_HR_MSG(KOZANI_E_INFO, "[DVC] Thread exit event handled");
return S_OK;
}
@@ -346,6 +355,10 @@ namespace Microsoft::Kozani::KozaniRemoteManager
connectionManager.m_activityMap.erase(pdu.activity_id());
}
+
+ wchar_t textBuffer[300]{};
+ swprintf(textBuffer, ARRAYSIZE(textBuffer), L"Error code: 0x%x, message: %hs", hr, errorMessage.c_str());
+ MessageBox(nullptr, textBuffer, L"Error", MB_ICONERROR);
}
}
CATCH_LOG_RETURN()
@@ -386,16 +399,19 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
}
- wil::com_ptr aam;
- HRESULT hrCoCreateInstance{ CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aam)) };
- if (FAILED(hrCoCreateInstance))
+ std::wstring appUserModelId{ ::Microsoft::Utf8::ToUtf16(activateAppRequest.app_user_model_id()) };
+ DWORD processId{};
+
+ wil::com_ptr appLauncher;
{
- errorMessage = "Failed to CoCreateInstance CLSID_ApplicationActivationManager.";
- RETURN_HR(hrCoCreateInstance);
+ // Lock and assign m_appLauncher to local com_ptr appLauncher, which adds ref count of the IKozaniApplicationLauncher object to
+ // keep it alive through this method. m_appLauncher can be replaced with a different object and deref in another thread when there is another
+ // client connection coming in. Do not hold the lock during app activation so if the current activation takes a long time it will not block
+ // subsequent activation requests.
+ auto lock{ m_appLauncherLock.lock_shared() };
+ appLauncher = m_appLauncher;
}
- std::wstring appUserModelId{ ::Microsoft::Utf8::ToUtf16(activateAppRequest.app_user_model_id()) };
- DWORD processId{};
switch (activateAppRequest.activation_kind())
{
case Dvc::ActivationKind::Launch:
@@ -412,8 +428,8 @@ namespace Microsoft::Kozani::KozaniRemoteManager
launchArgs = ::Microsoft::Utf8::ToUtf16(args.arguments());
}
-
- HRESULT hrActivateApp{ aam->ActivateApplication(appUserModelId.c_str(), launchArgs.c_str(), AO_NONE, &processId) };
+
+ HRESULT hrActivateApp{ appLauncher->Launch(appUserModelId.c_str(), launchArgs.c_str(), &processId) };
if (FAILED(hrActivateApp))
{
errorMessage = "Failed to Activate app.";
@@ -423,11 +439,11 @@ namespace Microsoft::Kozani::KozaniRemoteManager
break;
case Dvc::ActivationKind::File:
- // ToDo: https://task.ms/43963854 support FTA launch.
+ RETURN_IF_FAILED(ProcessFileActivationRequest(appLauncher.get(), appUserModelId, activateAppRequest, processId, errorMessage));
break;
case Dvc::ActivationKind::Protocol:
- // ToDo: https://task.ms/43963854 support protocol launch.
+ RETURN_IF_FAILED(ProcessProtocolActivationRequest(appLauncher.get(), appUserModelId, activateAppRequest, processId, errorMessage));
break;
default:
@@ -482,6 +498,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
{
const DWORD errorOpenProcess{ LOG_LAST_ERROR_MSG("ProcessId: %u", processId) };
+ //connectionManager.m_processIdMap.erase(processId);
connectionManager.m_activityMap.erase(iter);
errorMessage = "Failed to OpenProcess after the app is activated. The app may have crashed. Process Id: " + std::to_string(processId);
RETURN_WIN32(errorOpenProcess);
@@ -512,6 +529,101 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
CATCH_RETURN()
+ HRESULT KozaniDvcServer::ProcessFileActivationRequest(
+ _In_ IKozaniApplicationLauncher* appLauncher,
+ const std::wstring& appUserModelId,
+ const Dvc::ActivateAppRequest& activateAppRequest,
+ _Out_ DWORD& processId,
+ _Out_ std::string& errorMessage) noexcept try
+ {
+ if (activateAppRequest.arguments().empty())
+ {
+ errorMessage = "Arguments for File activation cannot be empty";
+ RETURN_WIN32(ERROR_INVALID_DATA);
+ }
+
+ Dvc::FileActivationArgs args;
+ if (!args.ParseFromString(activateAppRequest.arguments()))
+ {
+ errorMessage = "Failed to parse File activation arguments";
+ RETURN_WIN32(ERROR_INVALID_DATA);
+ }
+
+ int filePathsCount{ args.file_paths_size() };
+
+ // There should be at least 1 file path in the FileActivationArgs for file activation to work.
+ RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), filePathsCount <= 0);
+
+ std::vector filePathArray;
+ wistd::unique_ptr filePaths{ new PCWSTR[filePathsCount] };
+ RETURN_IF_NULL_ALLOC(filePaths);
+
+ PCWSTR* pFilePaths{ filePaths.get() };
+ ZeroMemory(pFilePaths, sizeof(PCWSTR) * filePathsCount);
+
+ for (int i = 0; i < filePathsCount; i++)
+ {
+ std::wstring clientLocalPath{ ::Microsoft::Utf8::ToUtf16(args.file_paths(i)) };
+
+ filePathArray.emplace_back(GetRedirectedClientPath(clientLocalPath));
+ pFilePaths[i] = filePathArray.back().c_str();
+ }
+
+ KozaniAppType appType{ GetAppType(appUserModelId) };
+ std::wstring verb{ ::Microsoft::Utf8::ToUtf16(args.verb()) };
+ HRESULT hrActivateApp{ appLauncher->LaunchFiles(appUserModelId.c_str(), verb.c_str(), filePathsCount, pFilePaths, &appType, &processId) };
+ if (FAILED(hrActivateApp))
+ {
+ errorMessage = "Failed to activate app for file ";
+ std::string path{ ::Microsoft::Utf8::ToUtf8(pFilePaths[0]) };
+ errorMessage += path;
+ RETURN_HR(hrActivateApp);
+ }
+
+ UpdateAppTypeIfNeeded(appUserModelId, appType);
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ HRESULT KozaniDvcServer::ProcessProtocolActivationRequest(
+ _In_ IKozaniApplicationLauncher* appLauncher,
+ const std::wstring& appUserModelId,
+ const Dvc::ActivateAppRequest& activateAppRequest,
+ _Out_ DWORD& processId,
+ _Out_ std::string& errorMessage) noexcept try
+ {
+ processId = 0;
+ errorMessage.clear();
+
+ if (activateAppRequest.arguments().empty())
+ {
+ errorMessage = "Arguments for Protocol activation cannot be empty";
+ RETURN_WIN32(ERROR_INVALID_DATA);
+ }
+
+ Dvc::ProtocolActivationArgs args;
+ if (!args.ParseFromString(activateAppRequest.arguments()))
+ {
+ errorMessage = "Failed to parse Protocol activation arguments";
+ RETURN_WIN32(ERROR_INVALID_DATA);
+ }
+
+ KozaniAppType appType{ GetAppType(appUserModelId) };
+ std::wstring uri{ ::Microsoft::Utf8::ToUtf16(args.uri()) };
+ HRESULT hrActivateApp{ appLauncher->LaunchUri(appUserModelId.c_str(), uri.c_str(), &appType, &processId) };
+ if (FAILED(hrActivateApp))
+ {
+ errorMessage = "Failed to activate app for URI: ";
+ std::string uriUtf8{ ::Microsoft::Utf8::ToUtf8(uri) };
+ errorMessage += uriUtf8;
+ RETURN_HR(hrActivateApp);
+ }
+
+ UpdateAppTypeIfNeeded(appUserModelId, appType);
+ return S_OK;
+ }
+ CATCH_RETURN()
+
HRESULT KozaniDvcServer::ProcessAppTerminationNotice(_In_ Dvc::ProtocolDataUnit& pdu) noexcept try
{
ConnectionManager& connectionManager{ KozaniRemoteManagerModule::GetConnectionManagerInstance() };
@@ -549,6 +661,23 @@ namespace Microsoft::Kozani::KozaniRemoteManager
}
CATCH_RETURN()
+ // Convert local path from the remote client to a path that can be addressed by the remote desktop server. Local drives of the client have been
+ // rediected to the server so the server can directly access them. For example, local path "C:\data\MyFile.txt" will be redirected to the server
+ // side with addressable path "\\tsclient\C\data\MyFile.txt"
+ std::wstring KozaniDvcServer::GetRedirectedClientPath(const std::wstring& localPath)
+ {
+ // UNC paths are not redirected so we return it as it is.
+ if (localPath.starts_with(L"\\\\"))
+ {
+ return localPath;
+ }
+
+ std::wstring redirectedPath{ L"\\\\tsclient\\" };
+ redirectedPath += localPath[0];
+ redirectedPath += localPath.substr(2);
+ return redirectedPath;
+ }
+
bool KozaniDvcServer::IsActivationKindSupported(Dvc::ActivationKind kind)
{
switch (kind)
@@ -581,7 +710,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
m_dvcListenerThread = std::thread(&KozaniDvcServer::ProcessDvcIncomingDataThreadFunc, this);
HANDLE events[] = { m_dvcThreadStarted.get(), m_dvcThreadExit.get() };
- LOG_HR_MSG(KOZANI_S_INFO, "[StartDvcListenerThread] Waiting for listener thread starting status");
+ LOG_HR_MSG(KOZANI_E_INFO, "[StartDvcListenerThread] Waiting for listener thread starting status");
// Wait for listerner thread to start successfully. Wait no longer than 5s.
DWORD result = WaitForMultipleObjects(ARRAYSIZE(events), events, FALSE, 5000);
@@ -591,7 +720,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
{
case WAIT_OBJECT_0:
// Thread successfully started and is running.
- LOG_HR_MSG(KOZANI_S_INFO, "[StartDvcListenerThread] Listener thread successfully started");
+ LOG_HR_MSG(KOZANI_E_INFO, "[StartDvcListenerThread] Listener thread successfully started");
return;
case WAIT_OBJECT_0 + 1:
@@ -715,4 +844,38 @@ namespace Microsoft::Kozani::KozaniRemoteManager
std::string pdu{ CreateAppTerminationNoticePdu(activityId) };
SendDvcProtocolData(pdu.c_str(), static_cast(pdu.size()));
}
+
+ // Look up the type of the app from the m_appTypeMap as an optimization, as the launcher finds the type of the app (UWP or packaged desktop app)
+ // by different activation API behaviors. At first, the app type is unknown for a particular AUMID. Once it is activated for file or protocol,
+ // the appLauncher returns the app type, so we can cache in the map for faster activation next time.
+ KozaniAppType KozaniDvcServer::GetAppType(const std::wstring& appUserModelId)
+ {
+ auto lock{ m_appTypeMapLock.lock_shared() };
+
+ KozaniAppType appType{ KozaniAppType_Unknown };
+ auto iter{ m_appTypeMap.find(appUserModelId) };
+ if (iter != m_appTypeMap.end())
+ {
+ appType = iter->second;
+ }
+ return appType;
+ }
+
+ void KozaniDvcServer::UpdateAppTypeIfNeeded(const std::wstring& appUserModelId, KozaniAppType appType)
+ {
+ auto lock{ m_appTypeMapLock.lock_exclusive() };
+
+ auto iter{ m_appTypeMap.find(appUserModelId) };
+ if (iter != m_appTypeMap.end())
+ {
+ if (iter->second != appType)
+ {
+ iter->second = appType;
+ }
+ }
+ else
+ {
+ m_appTypeMap[appUserModelId] = appType;
+ }
+ }
}
diff --git a/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.h b/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.h
index 6574a56d73..d5eadbde24 100644
--- a/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.h
+++ b/dev/Kozani/KozaniRemoteManager/KozaniDvcServer.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include "KozaniDvcProtocol.h"
#include "KozaniRemoteManagerTraceLogging.h"
@@ -43,7 +44,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
// Enable error reporting to ConnectionManager. Called only after ConnectionManager has successfully created this object.
HRESULT EnableConnectionManagerReporting();
- void SendConnectionAck(PCSTR connectionId);
+ void ProcessClientConnection(_In_ PCSTR connectionId, _In_ IKozaniApplicationLauncher* appLauncher);
void SendAppTerminationNotice(uint64_t activityId);
private:
@@ -70,8 +71,24 @@ namespace Microsoft::Kozani::KozaniRemoteManager
_Out_ bool& appActivatedAndTracked,
_Out_ std::string& errorMessage) noexcept;
+ HRESULT ProcessFileActivationRequest(
+ _In_ IKozaniApplicationLauncher* appLauncher,
+ const std::wstring& appUserModelId,
+ const Dvc::ActivateAppRequest& activateAppRequest,
+ _Out_ DWORD& processId,
+ _Out_ std::string& errorMessage) noexcept;
+
+ HRESULT ProcessProtocolActivationRequest(
+ _In_ IKozaniApplicationLauncher* appLauncher,
+ const std::wstring& appUserModelId,
+ const Dvc::ActivateAppRequest& activateAppRequest,
+ _Out_ DWORD& processId,
+ _Out_ std::string& errorMessage) noexcept;
+
HRESULT ProcessAppTerminationNotice(_In_ Dvc::ProtocolDataUnit& pdu) noexcept;
+ std::wstring GetRedirectedClientPath(const std::wstring& localPath);
+
bool IsActivationKindSupported(Dvc::ActivationKind kind);
void OpenDvc();
@@ -80,6 +97,7 @@ namespace Microsoft::Kozani::KozaniRemoteManager
void ReportDvcWriterError(HRESULT errorCode);
void SendDvcProtocolData(const char* data, UINT32 size);
+ void SendConnectionAck(PCSTR connectionId);
void SendActivateAppResult(
uint64_t activityId,
HRESULT hr,
@@ -87,6 +105,9 @@ namespace Microsoft::Kozani::KozaniRemoteManager
bool isNewInstance,
_In_ const std::string& errorMessage = std::string());
+ KozaniAppType GetAppType(const std::wstring& appUserModelId);
+ void UpdateAppTypeIfNeeded(const std::wstring& appUserModelId, KozaniAppType appType);
+
private:
wil::srwlock m_errorReportingLock;
std::recursive_mutex m_dvcLock;
@@ -97,5 +118,11 @@ namespace Microsoft::Kozani::KozaniRemoteManager
bool m_errorReportingEnabled{};
HRESULT m_errorFromDvcListener{};
HRESULT m_errorFromDvcWriter{};
+
+ wil::srwlock m_appLauncherLock;
+ wil::com_ptr m_appLauncher;
+
+ wil::srwlock m_appTypeMapLock;
+ std::map m_appTypeMap;
};
}
diff --git a/dev/Kozani/KozaniRemoteManager/KozaniRemoteManager.vcxproj b/dev/Kozani/KozaniRemoteManager/KozaniRemoteManager.vcxproj
index abb4e0f26a..9dc988e14a 100644
--- a/dev/Kozani/KozaniRemoteManager/KozaniRemoteManager.vcxproj
+++ b/dev/Kozani/KozaniRemoteManager/KozaniRemoteManager.vcxproj
@@ -166,6 +166,9 @@
+
+ {3f28c3ed-2548-4530-8b6c-832fae0e993d}
+
{B9933E40-5A7C-482E-9FF3-FC06C1A7B37E}
diff --git a/dev/Kozani/KozaniRemoteManager/main.cpp b/dev/Kozani/KozaniRemoteManager/main.cpp
index 724226ae1b..20320908c2 100644
--- a/dev/Kozani/KozaniRemoteManager/main.cpp
+++ b/dev/Kozani/KozaniRemoteManager/main.cpp
@@ -5,8 +5,6 @@
#include "..\KozaniRemoteManager\KozaniRemoteManager-Constants.h"
-#include
-
// Including this file once per binary will automatically opt WIL error handling macros into calling RoOriginateError when they
// begin logging a new error. This greatly improves the debuggability of errors that propagate before a failfast.
#include
@@ -44,13 +42,11 @@ namespace KozaniRemoteManagerModule
}
};
-
-
struct __declspec(uuid(PR_KOZANIREMOTEMANAGER_CLSID_STRING)) KozaniRemoteManagerImpl WrlFinal : RuntimeClass, IKozaniRemoteManager>
{
- STDMETHODIMP Connect(_In_ PCSTR connectionId) noexcept try
+ STDMETHODIMP Connect(_In_ PCSTR connectionId, IKozaniApplicationLauncher* appLauncher) noexcept try
{
- g_connectionManager.Connect(connectionId);
+ g_connectionManager.Connect(connectionId, appLauncher);
return S_OK;
}
CATCH_RETURN()
@@ -66,6 +62,9 @@ void EndOfTheLine()
int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PSTR /*lpCmdLine*/, int /*nCmdShow*/)
{
+ // Hook up wil logging MACROs to trace provider.
+ wil::SetResultLoggingCallback(&TraceFailureFromProvider);
+
RETURN_IF_FAILED(::CoInitializeEx(nullptr, COINITBASE_MULTITHREADED));
wil::unique_event endOfTheLine(::CreateEventW(nullptr, TRUE, FALSE, nullptr));
diff --git a/dev/Kozani/KozaniRemoteManager/packages.config b/dev/Kozani/KozaniRemoteManager/packages.config
index ba003992c7..8d63d7f888 100644
--- a/dev/Kozani/KozaniRemoteManager/packages.config
+++ b/dev/Kozani/KozaniRemoteManager/packages.config
@@ -3,7 +3,7 @@
-
+
diff --git a/dev/Kozani/KozaniRemoteManager/pch.h b/dev/Kozani/KozaniRemoteManager/pch.h
index 9d937e645c..daa9b1ea95 100644
--- a/dev/Kozani/KozaniRemoteManager/pch.h
+++ b/dev/Kozani/KozaniRemoteManager/pch.h
@@ -31,4 +31,5 @@
#include
-#include "Logging.h"
\ No newline at end of file
+#include
+#include "Logging.h"
diff --git a/dev/Kozani/KozaniRemoteManagerInterface/KozaniRemoteManagerInterface.idl b/dev/Kozani/KozaniRemoteManagerInterface/KozaniRemoteManagerInterface.idl
index 3df36ddf69..ca3ca92391 100644
--- a/dev/Kozani/KozaniRemoteManagerInterface/KozaniRemoteManagerInterface.idl
+++ b/dev/Kozani/KozaniRemoteManagerInterface/KozaniRemoteManagerInterface.idl
@@ -4,6 +4,38 @@
import "oaidl.idl";
import "ocidl.idl";
+typedef [v1_enum] enum KozaniAppType
+{
+ KozaniAppType_Unknown = 0,
+ KozaniAppType_PackagedDesktopApp = 1,
+ KozaniAppType_UWP = 2
+} KozaniAppType;
+
+[object]
+[uuid(0b86ddd1-faba-40dc-b92b-9f29654a97b2)]
+[pointer_default(unique)]
+interface IKozaniApplicationLauncher : IUnknown
+{
+ HRESULT Launch(
+ [in, string] LPCWSTR appUserModelId,
+ [in, string, unique] LPCWSTR arguments,
+ [out] DWORD* processId);
+
+ HRESULT LaunchFiles(
+ [in, string] LPCWSTR appUserModelId,
+ [in, string] LPCWSTR verb,
+ UINT32 fileCount,
+ [in, string, size_is(fileCount)] LPCWSTR* filePaths,
+ [in, out] KozaniAppType* appType,
+ [out] DWORD* processId);
+
+ HRESULT LaunchUri(
+ [in, string] LPCWSTR appUserModelId,
+ [in, string] LPCWSTR uri,
+ [in, out] KozaniAppType* appType,
+ [out] DWORD* processId);
+};
+
[object]
[uuid(30599ceb-631f-468f-bdd6-febc5bb12b81)]
[pointer_default(unique)]
@@ -11,5 +43,5 @@ interface IKozaniRemoteManager : IUnknown
{
// Connects to client DVC by opening a DVC channel with Kozani_DVC name and sends back an ACK message with connectionId
// to link the connection to the client request.
- HRESULT Connect([in, string] LPCSTR connectionId);
+ HRESULT Connect([in, string] LPCSTR connectionId, [in] IKozaniApplicationLauncher* appLauncher);
};
diff --git a/dev/Kozani/KozaniRemoteManagerLauncher/main.cpp b/dev/Kozani/KozaniRemoteManagerLauncher/main.cpp
index 288a2db9a9..ff28a929e6 100644
--- a/dev/Kozani/KozaniRemoteManagerLauncher/main.cpp
+++ b/dev/Kozani/KozaniRemoteManagerLauncher/main.cpp
@@ -2,19 +2,434 @@
// Licensed under the MIT License.
#include "pch.h"
+#include
// Including this file once per binary will automatically opt WIL error handling macros into calling RoOriginateError when they
// begin logging a new error. This greatly improves the debuggability of errors that propagate before a failfast.
#include
+#include
+#include
+#include
#include
#include "KozaniDvc-Constants.h"
+using namespace Microsoft::WRL;
using namespace winrt::Windows::Foundation;
using namespace Microsoft::Kozani::DVC;
+wil::unique_event g_exitProcess;
+
+struct KozaniApplicationLauncher : winrt::implements
+{
+private:
+ enum AssociationType
+ {
+ File = 0,
+ Protocol
+ };
+
+ const PCWSTR c_registeredPackagedApplicationsPath{ L"SOFTWARE\\RegisteredApplications\\PackagedApps" };
+ const PCWSTR c_fileAssociationsKeyName{ L"FileAssociations" };
+ const PCWSTR c_protocolAssociationsKeyName{ L"URLAssociations" };
+
+public:
+ STDMETHODIMP Launch(_In_ PCWSTR appUserModelId, _In_opt_ PCWSTR arguments, _Out_ DWORD* processId) noexcept try
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, appUserModelId);
+ RETURN_HR_IF_NULL(E_INVALIDARG, processId);
+
+ *processId = 0;
+
+#ifdef MEASURE_PERF
+ DWORD startTime = GetTickCount();
+#endif
+
+ wil::com_ptr aam;
+ RETURN_IF_FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aam)));
+ RETURN_IF_FAILED(aam->ActivateApplication(appUserModelId, arguments, AO_NONE, processId));
+
+#ifdef MEASURE_PERF
+ MessageBox(nullptr, std::format(L"Activation costs - aam: {}ms", GetTickCount() - startTime).c_str(), L"Perf", MB_OK);
+#endif
+
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP LaunchFiles(
+ _In_ PCWSTR appUserModelId,
+ _In_ PCWSTR verb,
+ UINT32 fileCount,
+ _In_count_(fileCount) PCWSTR* filePaths,
+ _Inout_ KozaniAppType* appType,
+ _Out_ DWORD* processId) noexcept try
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, appUserModelId);
+ RETURN_HR_IF_NULL(E_INVALIDARG, processId);
+ RETURN_HR_IF_NULL(E_INVALIDARG, filePaths);
+ RETURN_HR_IF(E_INVALIDARG, fileCount == 0);
+
+ *processId = 0;
+
+#ifdef MEASURE_PERF
+ DWORD aamCost{};
+ DWORD shellExeCost{};
+ DWORD findProcessCost{};
+ DWORD startTime = GetTickCount();
+#endif
+
+ // If appType is KozaniAppType_Unknown, we try to activate it as KozaniAppType_PackagedDesktopApp. If we activate a PackagedDesktopApp
+ // using IApplicationActivationManager, it will fail and try to repair the registration of the app unnecessarily, also causing forced
+ // shutdown of the app if it is already running.
+ if (*appType == KozaniAppType_Unknown || *appType == KozaniAppType_PackagedDesktopApp)
+ {
+ RETURN_IF_FAILED(ShellExecuteAssociationHandler(appUserModelId, AssociationType::File, filePaths[0], verb, processId));
+
+#ifdef MEASURE_PERF
+ shellExeCost = GetTickCount() - startTime;
+#endif
+
+ if (*processId == 0)
+ {
+ // If the app is UWP, ShellExecute will not return its process handle and pid will be 0. Correct the appType so the next time
+ // it is launched, we will use the IApplicationActivationManager API, which will return pid for UWPs.
+ *appType = KozaniAppType_UWP;
+
+#ifdef MEASURE_PERF
+ DWORD findProcessStartTime = GetTickCount();
+#endif
+
+ // Try to find the process Id of the process that has the same AUMID as the app we just launched, from all running processes.
+ // Best effort only and will not fail the call if we fail to find the pid.
+ LOG_IF_FAILED(FindProcessIdFromSnapshot(appUserModelId, processId));
+
+#ifdef MEASURE_PERF
+ findProcessCost = GetTickCount() - findProcessStartTime;
+#endif
+ }
+ else if (*appType == KozaniAppType_Unknown)
+ {
+ *appType = KozaniAppType_PackagedDesktopApp;
+ }
+ }
+ else if (*appType == KozaniAppType_UWP)
+ {
+ // IApplicationActivationManager file activation only works for UWP apps.
+ if (FAILED_LOG(LaunchFilesByActivationManager(appUserModelId, verb, fileCount, filePaths, processId)))
+ {
+#ifdef MEASURE_PERF
+ DWORD aamTime = GetTickCount();
+ aamCost = aamTime - startTime;
+#endif
+
+ // The incoming appType may not be correct. Fall back to using ShellExecute if LaunchFilesByActivationManager fails.
+ // ShellExecute can only launch one file a time.
+ RETURN_IF_FAILED(ShellExecuteAssociationHandler(appUserModelId, AssociationType::File, filePaths[0], verb, processId));
+ if (*processId != 0)
+ {
+ *appType = KozaniAppType_PackagedDesktopApp;
+ }
+ else
+ {
+ LOG_IF_FAILED(FindProcessIdFromSnapshot(appUserModelId, processId));
+ }
+
+#ifdef MEASURE_PERF
+ shellExeCost = GetTickCount() - aamTime;
+#endif
+ }
+ else
+ {
+#ifdef MEASURE_PERF
+ aamCost = GetTickCount() - startTime;
+#endif
+ }
+ }
+ else
+ {
+ // Invalid KozaniAppType enum value.
+ RETURN_HR(E_INVALIDARG);
+ }
+
+#ifdef MEASURE_PERF
+ MessageBox(nullptr, std::format(L"Activation costs - aam: {}ms, shellexec: {}ms, FindProcess: {}ms, pid: {}",
+ aamCost, shellExeCost, findProcessCost, *processId).c_str(), L"Perf", MB_OK);
+#endif
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP LaunchUri(_In_ PCWSTR appUserModelId, _In_ PCWSTR uri, _Inout_ KozaniAppType* appType, _Out_ DWORD* processId) noexcept try
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, appUserModelId);
+ RETURN_HR_IF_NULL(E_INVALIDARG, uri);
+ RETURN_HR_IF_NULL(E_INVALIDARG, processId);
+
+ *processId = 0;
+
+#ifdef MEASURE_PERF
+ DWORD aamCost{};
+ DWORD shellExeCost{};
+ DWORD startTime = GetTickCount();
+#endif
+
+ // If appType is KozaniAppType_Unknown, we try to activate it as KozaniAppType_PackagedDesktopApp. If we activate a PackagedDesktopApp
+ // using IApplicationActivationManager, it will fail and try to repair the registration of the app unnecessarily, also causing forced
+ // shutdown of the app if it is already running.
+ if (*appType == KozaniAppType_Unknown || *appType == KozaniAppType_PackagedDesktopApp)
+ {
+ RETURN_IF_FAILED(ShellExecuteAssociationHandler(appUserModelId, AssociationType::Protocol, uri, nullptr /* verb */, processId));
+
+#ifdef MEASURE_PERF
+ shellExeCost = GetTickCount() - startTime;
+#endif
+
+ if (*processId == 0)
+ {
+ // If the app is UWP, ShellExecute will not return its process handle and pid will be 0. Correct the appType so the next time
+ // it is launched, we will use the IApplicationActivationManager API, which will return pid for UWPs.
+ *appType = KozaniAppType_UWP;
+
+ // Try to find the process Id of the process that has the same AUMID as the app we just launched, from all running processes.
+ // Best effort only and will not fail the call if we fail to find the pid.
+ LOG_IF_FAILED(FindProcessIdFromSnapshot(appUserModelId, processId));
+ }
+ }
+ else if (*appType == KozaniAppType_UWP)
+ {
+ // IApplicationActivationManager protocol activation only works for UWP apps. The reason we don't try IApplicationActivationManager first
+ // when the app type is unknown is it will crash the existing running app process if it is not UWP.
+ if (FAILED_LOG(LaunchUriByActivationManager(appUserModelId, uri, processId)))
+ {
+#ifdef MEASURE_PERF
+ DWORD aamTime = GetTickCount();
+ aamCost = aamTime - startTime;
+#endif
+
+ // The incoming appType may not be correct. Fall back to using ShellExecute if LaunchFilesByActivationManager fails.
+ RETURN_IF_FAILED(ShellExecuteAssociationHandler(appUserModelId, AssociationType::Protocol, uri, nullptr /* verb */, processId));
+ if (*processId != 0)
+ {
+ *appType = KozaniAppType_PackagedDesktopApp;
+ }
+ else
+ {
+ LOG_IF_FAILED(FindProcessIdFromSnapshot(appUserModelId, processId));
+ }
+
+#ifdef MEASURE_PERF
+ shellExeCost = GetTickCount() - aamTime;
+#endif
+ }
+ else
+ {
+#ifdef MEASURE_PERF
+ aamCost = GetTickCount() - startTime;
+#endif
+ }
+ }
+ else
+ {
+ // Invalid KozaniAppType enum value.
+ RETURN_HR(E_INVALIDARG);
+ }
+
+#ifdef MEASURE_PERF
+ MessageBox(nullptr, std::format(L"Activation costs - aam: {}ms, shellexec: {}ms, pid: {}", aamCost, shellExeCost, *processId).c_str(), L"Perf", MB_OK);
+#endif
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ ULONG __stdcall Release() noexcept override
+ {
+ ULONG refCount{ winrt::implements::Release() };
+ if (refCount == 0)
+ {
+ g_exitProcess.SetEvent();
+ }
+ return refCount;
+ }
+
+private:
+ HRESULT LaunchFilesByActivationManager(
+ _In_ PCWSTR appUserModelId,
+ _In_ PCWSTR verb,
+ UINT32 fileCount,
+ _In_count_(fileCount) PCWSTR* filePaths,
+ _Out_ DWORD* processId) noexcept try
+ {
+ wil::com_ptr aam;
+ RETURN_IF_FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aam)));
+
+ wistd::unique_ptr filePathList(new PIDLIST_ABSOLUTE[fileCount]);
+ RETURN_IF_NULL_ALLOC(filePathList);
+
+ PIDLIST_ABSOLUTE* pidlistFilePaths{ filePathList.get() };
+ ZeroMemory(pidlistFilePaths, sizeof(PIDLIST_ABSOLUTE)* fileCount);
+
+ auto freeFilePathList{ wil::scope_exit([&]()
+ {
+ for (UINT32 i = 0; i < fileCount; i++)
+ {
+ if (pidlistFilePaths[i])
+ {
+ CoTaskMemFree(pidlistFilePaths[i]);
+ }
+ }
+ }) };
+
+ for (UINT32 i = 0; i < fileCount; i++)
+ {
+ RETURN_IF_FAILED(SHParseDisplayName(filePaths[i], nullptr, &pidlistFilePaths[i], 0, nullptr));
+ }
+
+ wil::com_ptr filePathArray;
+ RETURN_IF_FAILED(SHCreateShellItemArrayFromIDLists(fileCount, const_cast(pidlistFilePaths), &filePathArray));
+
+ RETURN_IF_FAILED(aam->ActivateForFile(appUserModelId, filePathArray.get(), verb, processId));
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ HRESULT LaunchUriByActivationManager(_In_ PCWSTR appUserModelId, _In_ PCWSTR uri, _Out_ DWORD* processId) noexcept try
+ {
+ wil::com_ptr aam;
+ RETURN_IF_FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aam)));
+
+ wil::com_ptr shellItem;
+ RETURN_IF_FAILED(SHCreateItemFromParsingName(uri, nullptr, IID_PPV_ARGS(&shellItem)));
+
+ wil::com_ptr shellItemArray;
+ RETURN_IF_FAILED(SHCreateShellItemArrayFromShellItem(shellItem.get(), IID_PPV_ARGS(&shellItemArray)));
+
+ RETURN_IF_FAILED(aam->ActivateForProtocol(appUserModelId, shellItemArray.get(), processId));
+
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ std::wstring GetAppAssociationProgId(
+ _In_ PCWSTR appUserModelId,
+ AssociationType associationType,
+ _In_ PCWSTR associationKeyword)
+ {
+ wil::unique_hkey appsKey;
+ THROW_IF_WIN32_ERROR(RegOpenKeyEx(HKEY_CURRENT_USER, c_registeredPackagedApplicationsPath, 0, KEY_READ, wil::out_param(appsKey)));
+
+ std::wstring stringValue;
+ stringValue.resize(MAX_PATH);
+
+ // The PackagedApps key contains AUMID -> AssociaitonInfoRegPath key/value pairs. We can look up the path to the registry key storing the
+ // app's association info by its AUMID. For example:
+ // Microsoft.SkypeApp_kzf8qxf38zg5c!App = Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\Microsoft.SkypeApp_15.99.3202.0_x64__kzf8qxf38zg5c\App\Capabilities
+ DWORD bufferSize{ static_cast(stringValue.size() * sizeof(wchar_t)) };
+ THROW_IF_WIN32_ERROR(RegGetValue(appsKey.get(), nullptr, appUserModelId, RRF_RT_REG_SZ, nullptr, stringValue.data(), &bufferSize));
+
+ // Under the association info key, there are subkeys based on association types. Each assocation type subkey contains AssociationKeyword -> ProgId key/value pairs.
+ // For example:
+ // ...\Capabilities
+ // \FileAssociations
+ // .txt = AppX4ztfk9wxr86nxmzzq47px0nh0e58b8fw
+ // \URLAssociations
+ // tel = AppX5mseefwz6s981bhyy79d4wwmcper2jyg
+ wil::unique_hkey associationInfoKey;
+ THROW_IF_WIN32_ERROR(RegOpenKeyEx(HKEY_CURRENT_USER, stringValue.c_str(), 0, KEY_READ, wil::out_param(associationInfoKey)));
+
+ stringValue.clear();
+ stringValue.resize(MAX_PATH);
+ PCWSTR associationTypeKeyName{ (associationType == AssociationType::File) ? c_fileAssociationsKeyName : c_protocolAssociationsKeyName };
+ THROW_IF_WIN32_ERROR(RegGetValue(associationInfoKey.get(), associationTypeKeyName, associationKeyword, RRF_RT_REG_SZ, nullptr, stringValue.data(), &bufferSize));
+
+ return stringValue;
+ }
+
+ HRESULT ShellExecuteAssociationHandler(
+ _In_ PCWSTR appUserModelId,
+ AssociationType associationType,
+ _In_ PCWSTR launchTarget,
+ _In_opt_ PCWSTR verb,
+ _Out_ DWORD* processId) noexcept try
+ {
+ std::wstring associationKeyword;
+ if (associationType == AssociationType::File)
+ {
+ associationKeyword = std::filesystem::path(launchTarget).extension();
+ }
+ else
+ {
+ PCWSTR schemeEnd{ wcschr(launchTarget, L':') };
+ RETURN_HR_IF_NULL_MSG(E_INVALIDARG, schemeEnd, "Invalid URI: %ls", launchTarget);
+
+ associationKeyword.assign(launchTarget, schemeEnd - launchTarget);
+ }
+
+ std::wstring progId{ GetAppAssociationProgId(appUserModelId, associationType, associationKeyword.c_str()) };
+
+ SHELLEXECUTEINFO shellExecuteInfo{};
+ shellExecuteInfo.cbSize = sizeof(shellExecuteInfo);
+ shellExecuteInfo.fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_CLASSNAME;
+ shellExecuteInfo.lpVerb = verb;
+ shellExecuteInfo.lpFile = launchTarget;
+ shellExecuteInfo.lpClass = progId.c_str();
+
+ shellExecuteInfo.nShow = SW_SHOWNORMAL;
+
+ RETURN_IF_WIN32_BOOL_FALSE(ShellExecuteEx(&shellExecuteInfo));
+ if (shellExecuteInfo.hProcess != nullptr)
+ {
+ *processId = GetProcessId(shellExecuteInfo.hProcess);
+ RETURN_LAST_ERROR_IF(*processId == 0);
+ }
+
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ HRESULT FindProcessIdFromSnapshot(_In_ PCWSTR appUserModelId, _Out_ DWORD* processId) noexcept try
+ {
+ PROCESSENTRY32 entry;
+ entry.dwSize = sizeof(PROCESSENTRY32);
+
+ wil::unique_handle snapshot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
+ RETURN_LAST_ERROR_IF(!snapshot);
+
+ RETURN_IF_WIN32_BOOL_FALSE(Process32First(snapshot.get(), &entry));
+
+ wchar_t aumidBuffer[APPLICATION_USER_MODEL_ID_MAX_LENGTH]{};
+ do
+ {
+ wil::unique_handle process{ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.th32ProcessID) };
+ if (process)
+ {
+ wil::unique_handle token;
+ if (OpenProcessToken(process.get(), TOKEN_QUERY, &token))
+ {
+ UINT32 aumidBufferLength = ARRAYSIZE(aumidBuffer);
+ if (ERROR_SUCCESS == GetApplicationUserModelIdFromToken(token.get(), &aumidBufferLength, aumidBuffer))
+ {
+ if (_wcsicmp(appUserModelId, aumidBuffer) == 0)
+ {
+ *processId = entry.th32ProcessID;
+ return S_OK;
+ }
+ }
+ }
+ }
+ }
+ while (Process32Next(snapshot.get(), &entry));
+
+ RETURN_WIN32(ERROR_NOT_FOUND);
+ }
+ CATCH_RETURN()
+};
+
int main(int argc, char* argv[]) try
{
+ // Hook up wil logging MACROs to trace provider.
+ wil::SetResultLoggingCallback(&TraceFailureFromProvider);
+
if (argc < 3)
{
return E_INVALIDARG;
@@ -27,8 +442,26 @@ int main(int argc, char* argv[]) try
auto uninitOnExit = wil::CoInitializeEx();
+ g_exitProcess.create();
+
+ auto appLauncher{ winrt::make_self() };
+
PCSTR connectionId = argv[2];
auto remoteManager = wil::CoCreateInstance(CLSCTX_LOCAL_SERVER);
- return remoteManager->Connect(connectionId);
+ RETURN_IF_FAILED(remoteManager->Connect(connectionId, appLauncher.get()));
+
+ appLauncher = nullptr;
+
+ // Wait up to 30s for KozaniRemoteManager to call back to activate app before exiting the process.
+ // If the KozaniApplicationLauncher object this process handed out is released earlier than that it will exit sooner.
+ g_exitProcess.wait(30000);
+
+ // If a debugger is attached to this process, wait forever so it does not terminate the process during debugging.
+ if (IsDebuggerPresent())
+ {
+ g_exitProcess.wait(INFINITE);
+ }
+
+ return S_OK;
}
CATCH_RETURN()
diff --git a/dev/Kozani/KozaniRemoteManagerLauncher/packages.config b/dev/Kozani/KozaniRemoteManagerLauncher/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniRemoteManagerLauncher/packages.config
+++ b/dev/Kozani/KozaniRemoteManagerLauncher/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniRemoteManagerLauncher/pch.h b/dev/Kozani/KozaniRemoteManagerLauncher/pch.h
index f06e603567..5a5a4f09fb 100644
--- a/dev/Kozani/KozaniRemoteManagerLauncher/pch.h
+++ b/dev/Kozani/KozaniRemoteManagerLauncher/pch.h
@@ -16,5 +16,6 @@
#include "framework.h"
#include "KozaniRemoteManagerLauncherActivity.h"
#include "KozaniRemoteManagerLauncherTraceLogging.h"
+#include "Logging.h"
#endif //PCH_H
diff --git a/dev/Kozani/KozaniSendToLocal/packages.config b/dev/Kozani/KozaniSendToLocal/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniSendToLocal/packages.config
+++ b/dev/Kozani/KozaniSendToLocal/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniSendToRemote/packages.config b/dev/Kozani/KozaniSendToRemote/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniSendToRemote/packages.config
+++ b/dev/Kozani/KozaniSendToRemote/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/KozaniSettings/packages.config b/dev/Kozani/KozaniSettings/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/KozaniSettings/packages.config
+++ b/dev/Kozani/KozaniSettings/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/Kozani/MakeMSIX/packages.config b/dev/Kozani/MakeMSIX/packages.config
index 14efb7baf5..cd05427e9c 100644
--- a/dev/Kozani/MakeMSIX/packages.config
+++ b/dev/Kozani/MakeMSIX/packages.config
@@ -3,6 +3,6 @@
-
+
diff --git a/dev/MRTCore/mrt/Core/unittests/packages.config b/dev/MRTCore/mrt/Core/unittests/packages.config
index f11cc64c3e..1861ca894b 100644
--- a/dev/MRTCore/mrt/Core/unittests/packages.config
+++ b/dev/MRTCore/mrt/Core/unittests/packages.config
@@ -1,4 +1,4 @@
-
+
diff --git a/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/UnpackagedTests/packages.config b/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/UnpackagedTests/packages.config
index e827484f00..11a9dacfc8 100644
--- a/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/UnpackagedTests/packages.config
+++ b/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/UnpackagedTests/packages.config
@@ -1,4 +1,4 @@
-
+
diff --git a/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/packages.config b/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/packages.config
index 11a32940bf..9b45da6a85 100644
--- a/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/packages.config
+++ b/dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/packages.config
@@ -3,5 +3,5 @@
-
+
diff --git a/dev/MRTCore/mrt/mrm/UnitTests/packages.config b/dev/MRTCore/mrt/mrm/UnitTests/packages.config
index ef4201b12e..3a3c1cd7e9 100644
--- a/dev/MRTCore/mrt/mrm/UnitTests/packages.config
+++ b/dev/MRTCore/mrt/mrm/UnitTests/packages.config
@@ -1,5 +1,5 @@
-
+
diff --git a/dev/PackageManager/API/M.W.M.D.AddPackageOptions.cpp b/dev/PackageManager/API/M.W.M.D.AddPackageOptions.cpp
new file mode 100644
index 0000000000..42566d9061
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.AddPackageOptions.cpp
@@ -0,0 +1,171 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+
+#include "M.W.M.D.AddPackageOptions.h"
+#include "Microsoft.Windows.Management.Deployment.AddPackageOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume AddPackageOptions::TargetVolume()
+ {
+ return m_targetVolume;
+ }
+ void AddPackageOptions::TargetVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value)
+ {
+ m_targetVolume = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector AddPackageOptions::DependencyPackageUris()
+ {
+ if (!m_dependencyPackageUris)
+ {
+ m_dependencyPackageUris = winrt::single_threaded_vector();
+ }
+ return m_dependencyPackageUris;
+ }
+ winrt::Windows::Foundation::Collections::IVector AddPackageOptions::OptionalPackageFamilyNames()
+ {
+ if (!m_optionalPackageFamilyNames)
+ {
+ m_optionalPackageFamilyNames = winrt::single_threaded_vector();
+ }
+ return m_optionalPackageFamilyNames;
+ }
+ winrt::Windows::Foundation::Collections::IVector AddPackageOptions::OptionalPackageUris()
+ {
+ if (!m_optionalPackageUris)
+ {
+ m_optionalPackageUris = winrt::single_threaded_vector();
+ }
+ return m_optionalPackageUris;
+ }
+ winrt::Windows::Foundation::Collections::IVector AddPackageOptions::RelatedPackageUris()
+ {
+ if (!m_relatedPackageUris)
+ {
+ m_relatedPackageUris = winrt::single_threaded_vector();
+ }
+ return m_relatedPackageUris;
+ }
+ winrt::Windows::Foundation::Uri AddPackageOptions::ExternalLocationUri()
+ {
+ return m_externalLocationUri;
+ }
+ void AddPackageOptions::ExternalLocationUri(winrt::Windows::Foundation::Uri const& value)
+ {
+ m_externalLocationUri = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::StubPackageOption AddPackageOptions::StubPackageOption()
+ {
+ return m_stubPackageOption;
+ }
+ void AddPackageOptions::StubPackageOption(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption const& value)
+ {
+ m_stubPackageOption = value;
+ }
+ bool AddPackageOptions::AllowUnsigned()
+ {
+ return m_allowUnsigned;
+ }
+ void AddPackageOptions::AllowUnsigned(bool value)
+ {
+ m_allowUnsigned = value;
+ }
+ bool AddPackageOptions::DeveloperMode()
+ {
+ return m_developerMode;
+ }
+ void AddPackageOptions::DeveloperMode(bool value)
+ {
+ m_developerMode = value;
+ }
+ bool AddPackageOptions::ForceAppShutdown()
+ {
+ return m_forceAppShutdown;
+ }
+ void AddPackageOptions::ForceAppShutdown(bool value)
+ {
+ m_forceAppShutdown = value;
+ }
+ bool AddPackageOptions::ForceTargetAppShutdown()
+ {
+ return m_forceTargetAppShutdown;
+ }
+ void AddPackageOptions::ForceTargetAppShutdown(bool value)
+ {
+ m_forceTargetAppShutdown = value;
+ }
+ bool AddPackageOptions::ForceUpdateFromAnyVersion()
+ {
+ return m_forceUpdateFromAnyVersion;
+ }
+ void AddPackageOptions::ForceUpdateFromAnyVersion(bool value)
+ {
+ m_forceUpdateFromAnyVersion = value;
+ }
+ bool AddPackageOptions::InstallAllResources()
+ {
+ return m_installAllResources;
+ }
+ void AddPackageOptions::InstallAllResources(bool value)
+ {
+ m_installAllResources = value;
+ }
+ bool AddPackageOptions::RequiredContentGroupOnly()
+ {
+ return m_requiredContentGroupOnly;
+ }
+ void AddPackageOptions::RequiredContentGroupOnly(bool value)
+ {
+ m_requiredContentGroupOnly = value;
+ }
+ bool AddPackageOptions::RetainFilesOnFailure()
+ {
+ return m_retainFilesOnFailure;
+ }
+ void AddPackageOptions::RetainFilesOnFailure(bool value)
+ {
+ m_retainFilesOnFailure = value;
+ }
+ bool AddPackageOptions::StageInPlace()
+ {
+ return m_stageInPlace;
+ }
+ void AddPackageOptions::StageInPlace(bool value)
+ {
+ m_stageInPlace = value;
+ }
+ bool AddPackageOptions::DeferRegistrationWhenPackagesAreInUse()
+ {
+ return m_deferRegistrationWhenPackagesAreInUse;
+ }
+ void AddPackageOptions::DeferRegistrationWhenPackagesAreInUse(bool value)
+ {
+ m_deferRegistrationWhenPackagesAreInUse = value;
+ }
+ bool AddPackageOptions::IsExpectedDigestsSupported()
+ {
+ // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
+ return WindowsVersion::IsWindows11_22H2OrGreater();
+ }
+ winrt::Windows::Foundation::Collections::IMap AddPackageOptions::ExpectedDigests()
+ {
+ return m_expectedDigests;
+ }
+ bool AddPackageOptions::IsLimitToExistingPackagesSupported()
+ {
+ // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
+ return WindowsVersion::IsWindows11_22H2OrGreater();
+ }
+ bool AddPackageOptions::LimitToExistingPackages()
+ {
+ return m_limitToExistingPackages;
+ }
+ void AddPackageOptions::LimitToExistingPackages(bool value)
+ {
+ m_limitToExistingPackages = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.AddPackageOptions.h b/dev/PackageManager/API/M.W.M.D.AddPackageOptions.h
new file mode 100644
index 0000000000..a0a438473e
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.AddPackageOptions.h
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.AddPackageOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct AddPackageOptions : AddPackageOptionsT
+ {
+ AddPackageOptions() = default;
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume TargetVolume();
+ void TargetVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value);
+ winrt::Windows::Foundation::Collections::IVector DependencyPackageUris();
+ winrt::Windows::Foundation::Collections::IVector OptionalPackageFamilyNames();
+ winrt::Windows::Foundation::Collections::IVector OptionalPackageUris();
+ winrt::Windows::Foundation::Collections::IVector RelatedPackageUris();
+ winrt::Windows::Foundation::Uri ExternalLocationUri();
+ void ExternalLocationUri(winrt::Windows::Foundation::Uri const& value);
+ winrt::Microsoft::Windows::Management::Deployment::StubPackageOption StubPackageOption();
+ void StubPackageOption(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption const& value);
+ bool AllowUnsigned();
+ void AllowUnsigned(bool value);
+ bool DeveloperMode();
+ void DeveloperMode(bool value);
+ bool ForceAppShutdown();
+ void ForceAppShutdown(bool value);
+ bool ForceTargetAppShutdown();
+ void ForceTargetAppShutdown(bool value);
+ bool ForceUpdateFromAnyVersion();
+ void ForceUpdateFromAnyVersion(bool value);
+ bool InstallAllResources();
+ void InstallAllResources(bool value);
+ bool RequiredContentGroupOnly();
+ void RequiredContentGroupOnly(bool value);
+ bool RetainFilesOnFailure();
+ void RetainFilesOnFailure(bool value);
+ bool StageInPlace();
+ void StageInPlace(bool value);
+ bool IsDeferRegistrationWhenPackagesAreInUseSupported();
+ bool DeferRegistrationWhenPackagesAreInUse();
+ void DeferRegistrationWhenPackagesAreInUse(bool value);
+ bool IsExpectedDigestsSupported();
+ winrt::Windows::Foundation::Collections::IMap ExpectedDigests();
+ bool IsLimitToExistingPackagesSupported();
+ bool LimitToExistingPackages();
+ void LimitToExistingPackages(bool value);
+
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume m_targetVolume{};
+ winrt::Windows::Foundation::Collections::IVector m_dependencyPackageUris{};
+ winrt::Windows::Foundation::Collections::IVector m_optionalPackageFamilyNames{};
+ winrt::Windows::Foundation::Collections::IVector m_optionalPackageUris{};
+ winrt::Windows::Foundation::Collections::IVector m_relatedPackageUris{};
+ winrt::Windows::Foundation::Uri m_externalLocationUri{ nullptr };
+ winrt::Microsoft::Windows::Management::Deployment::StubPackageOption m_stubPackageOption{};
+ bool m_allowUnsigned{};
+ bool m_developerMode{};
+ bool m_forceAppShutdown{};
+ bool m_forceTargetAppShutdown{};
+ bool m_forceUpdateFromAnyVersion{};
+ bool m_installAllResources{};
+ bool m_requiredContentGroupOnly{};
+ bool m_retainFilesOnFailure{};
+ bool m_stageInPlace{};
+ bool m_deferRegistrationWhenPackagesAreInUse{};
+ winrt::Windows::Foundation::Collections::IMap m_expectedDigests;
+ bool m_limitToExistingPackages{};
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct AddPackageOptions : AddPackageOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.cpp b/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.cpp
new file mode 100644
index 0000000000..6b6927aa37
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "M.W.M.D.AddPackageSetOptions.h"
+#include "Microsoft.Windows.Management.Deployment.AddPackageSetOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel AddPackageSetOptions::DeploymentProcessingModel()
+ {
+ return m_deploymentProcessingModel;
+ }
+ void AddPackageSetOptions::DeploymentProcessingModel(winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel const& value)
+ {
+ m_deploymentProcessingModel = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority AddPackageSetOptions::DeploymentPriority()
+ {
+ return m_deploymentPriority;
+ }
+ void AddPackageSetOptions::DeploymentPriority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value)
+ {
+ m_deploymentPriority = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions AddPackageSetOptions::AddPackageOptions()
+ {
+ return m_addPackageOptions;
+ }
+ void AddPackageSetOptions::AddPackageOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions const& value)
+ {
+ m_addPackageOptions = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.h b/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.h
new file mode 100644
index 0000000000..86b8fea9b8
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.AddPackageSetOptions.h
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.AddPackageSetOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct AddPackageSetOptions : AddPackageSetOptionsT
+ {
+ AddPackageSetOptions() = default;
+
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel DeploymentProcessingModel();
+ void DeploymentProcessingModel(winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel const& value);
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority DeploymentPriority();
+ void DeploymentPriority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value);
+ winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions AddPackageOptions();
+ void AddPackageOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions const& value);
+
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel m_deploymentProcessingModel{};
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority m_deploymentPriority{ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority::Normal };
+ winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions m_addPackageOptions{};
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct AddPackageSetOptions : AddPackageSetOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.cpp b/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.cpp
new file mode 100644
index 0000000000..4b44c8b2c5
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.cpp
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+
+#include "M.W.M.D.EnsureIsReadyOptions.h"
+#include "Microsoft.Windows.Management.Deployment.EnsureIsReadyOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel EnsureIsReadyOptions::DeploymentProcessingModel()
+ {
+ return m_deploymentProcessingModel;
+ }
+ void EnsureIsReadyOptions::DeploymentProcessingModel(winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel const& value)
+ {
+ m_deploymentProcessingModel = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority EnsureIsReadyOptions::DeploymentPriority()
+ {
+ return m_deploymentPriority;
+ }
+ void EnsureIsReadyOptions::DeploymentPriority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value)
+ {
+ m_deploymentPriority = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.h b/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.h
new file mode 100644
index 0000000000..9b0fe6c04c
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.EnsureIsReadyOptions.h
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.EnsureIsReadyOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct EnsureIsReadyOptions : EnsureIsReadyOptionsT
+ {
+ EnsureIsReadyOptions() = default;
+
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel DeploymentProcessingModel();
+ void DeploymentProcessingModel(winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel const& value);
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority DeploymentPriority();
+ void DeploymentPriority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value);
+
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentProcessingModel m_deploymentProcessingModel{};
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority m_deploymentPriority{ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority::Normal };
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct EnsureIsReadyOptions : EnsureIsReadyOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.cpp b/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.cpp
new file mode 100644
index 0000000000..d1f49eb744
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.FindPackageSetOptions.h"
+#include "Microsoft.Windows.Management.Deployment.FindPackageSetOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ bool FindPackageSetOptions::TODO_MustHaveAtLeastOneInterfaceOrStaticFactoryPlaceholder()
+ {
+ throw hresult_not_implemented();
+ }
+ void FindPackageSetOptions::TODO_MustHaveAtLeastOneInterfaceOrStaticFactoryPlaceholder(bool value)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.h b/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.h
new file mode 100644
index 0000000000..a4251fef49
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.FindPackageSetOptions.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.FindPackageSetOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct FindPackageSetOptions : FindPackageSetOptionsT
+ {
+ FindPackageSetOptions() = default;
+
+ bool TODO_MustHaveAtLeastOneInterfaceOrStaticFactoryPlaceholder();
+ void TODO_MustHaveAtLeastOneInterfaceOrStaticFactoryPlaceholder(bool value);
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct FindPackageSetOptions : FindPackageSetOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.cpp b/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.cpp
new file mode 100644
index 0000000000..73c2088b8b
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.cpp
@@ -0,0 +1,584 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageDeploymentManager.h"
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentManager.g.cpp"
+
+#include "M.W.M.D.PackageDeploymentResult.h"
+#include "M.W.M.D.PackageDeploymentProgress.h"
+#include "M.W.M.D.PackageVolumeManager.h"
+#include "MsixPackageManager.h"
+#include "PackageDeploymentResolver.h"
+
+static_assert(static_cast(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::Default) == static_cast(winrt::Windows::Management::Deployment::StubPackageOption::Default),
+ "winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::Default != winrt::Windows::Management::Deployment::StubPackageOption::Default");
+static_assert(static_cast(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::InstallFull) == static_cast(winrt::Windows::Management::Deployment::StubPackageOption::InstallFull),
+ "winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::InstallFull != winrt::Windows::Management::Deployment::StubPackageOption::InstallFull");
+static_assert(static_cast(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::InstallStub) == static_cast(winrt::Windows::Management::Deployment::StubPackageOption::InstallStub),
+ "winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::InstallStub != winrt::Windows::Management::Deployment::StubPackageOption::InstallStub");
+static_assert(static_cast(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::UsePreference) == static_cast(winrt::Windows::Management::Deployment::StubPackageOption::UsePreference),
+ "winrt::Microsoft::Windows::Management::Deployment::StubPackageOption::UsePreference != winrt::Windows::Management::Deployment::StubPackageOption::UsePreference");
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager PackageDeploymentManager::GetDefault()
+ {
+ return winrt::make();
+ }
+ bool PackageDeploymentManager::IsPackageSetReady(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet)
+ {
+ Validate(packageSet);
+
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSet.PackageSetItems())
+ {
+ if (!IsReady(packageSetItem))
+ {
+ (void)LOG_HR_MSG(MSIXPACKAGEMANAGER_E_PACKAGE_SCAN_FAILED,
+ "Id=%ls PackageFamilyName=%ls MinVersion=%hu.%hu.%hu.%hu ArchitectureFilter:0x%X",
+ packageSetItem.Id().c_str(),
+ packageSetItem.PackageFamilyName().c_str(),
+ packageSetItem.MinVersion().Major,
+ packageSetItem.MinVersion().Minor,
+ packageSetItem.MinVersion().Build,
+ packageSetItem.MinVersion().Revision,
+ packageSetItem.ProcessorArchitectureFilter());
+ return false;
+ }
+ }
+ return true;
+ }
+ bool PackageDeploymentManager::IsPackageSetReadyById(hstring const& packageSetId)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::EnsurePackageSetIsReadyAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions options)
+ {
+ //TODO auto logTelemetry{ PackageDeploymentTelemetry::CreateChannelAsync::Start(g_telemetryHelper, remoteId) };
+
+ auto strong = get_strong();
+
+ auto cancellation{ co_await winrt::get_cancellation_token() };
+ cancellation.enable_propagation(true);
+
+ //TODO logTelemetry.IgnoreCurrentThread();
+
+ // Allow to register the progress and complete handler
+ co_await resume_background();
+
+ //TODO auto logTelemetryContinuation = logTelemetry.ContinueOnCurrentThread();
+
+ auto progress{ co_await winrt::get_progress_token() };
+ auto packageDeploymentProgress{
+ winrt::make<
+ winrt::Microsoft::Windows::Management::Deployment::implementation::PackageDeploymentProgress>(
+ PackageDeploymentProgressStatus::Queued, 0) };
+ progress(packageDeploymentProgress);
+
+ // Check parameter(s)
+ Validate(packageSet);
+
+ // Is there any work to do?
+ packageDeploymentProgress.status(PackageDeploymentProgressStatus::InProgress);
+ const double c_progressPercentageStartOfIsReady{ 0.01 };
+ packageDeploymentProgress.percentage(c_progressPercentageStartOfIsReady);
+ progress(packageDeploymentProgress);
+ if (IsPackageSetReady(packageSet))
+ {
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedSuccess, S_OK, true, /*TODO*/winrt::guid{});
+ }
+
+ const double c_progressPercentageStartOfInstalls{ 0.10 };
+ packageDeploymentProgress.percentage(c_progressPercentageStartOfInstalls);
+ progress(packageDeploymentProgress);
+ auto packageSetItems{ packageSet.PackageSetItems() };
+ const double progressIncrementPerPackageSetItem{ (1.0 - c_progressPercentageStartOfInstalls) / packageSetItems.Size() };
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSetItems)
+ {
+ try
+ {
+ EnsureIsReadyAsync(packageSetItem, options);
+ packageDeploymentProgress.percentage(packageDeploymentProgress.percentage() + progressIncrementPerPackageSetItem);
+ progress(packageDeploymentProgress);
+ }
+ catch (...)
+ {
+ auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) };
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedFailure, exception.code(), false, /*TODO*/winrt::guid{});
+ }
+ }
+
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedSuccess, S_OK, true, /*TODO*/winrt::guid{});
+
+ //TODO logTelemetry.Stop();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::EnsurePackageSetIsReadyByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::AddPackageAsync(hstring package, winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options)
+ {
+ const winrt::Windows::Foundation::Uri packageUri{ package };
+ const auto packageAbsoluteUri{ packageUri.AbsoluteUri() };
+ if (!packageAbsoluteUri.empty())
+ {
+ const std::wstring packageAsString{ package.c_str() };
+ if (packageAsString.ends_with(L".appinstaller"))
+ {
+ //TODO: return AddPackageByAppInstallerFileAsync(packageUri);
+ }
+ else
+ {
+ return AddPackageByUriAsync(packageUri, options);
+ }
+ }
+ THROW_HR_MSG(E_INVALIDARG, "%ls", package.c_str());
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::AddPackageByUriAsync(winrt::Windows::Foundation::Uri packageUri, winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options)
+ {
+ //TODO auto logTelemetry{ PackageDeploymentTelemetry::CreateChannelAsync::Start(g_telemetryHelper, remoteId) };
+
+ auto strong = get_strong();
+
+ auto cancellation{ co_await winrt::get_cancellation_token() };
+ cancellation.enable_propagation(true);
+
+ //TODO logTelemetry.IgnoreCurrentThread();
+
+ // Allow to register the progress and complete handler
+ co_await resume_background();
+
+ //TODO auto logTelemetryContinuation = logTelemetry.ContinueOnCurrentThread();
+
+ auto progress{ co_await winrt::get_progress_token() };
+ auto packageDeploymentProgress{
+ winrt::make<
+ winrt::Microsoft::Windows::Management::Deployment::implementation::PackageDeploymentProgress>(
+ PackageDeploymentProgressStatus::Queued, 0) };
+ progress(packageDeploymentProgress);
+
+ // Check parameter(s)
+ //TODO Validate(packageSet);
+
+ winrt::Windows::Management::Deployment::AddPackageOptions addOptions{ ToOptions(options) };
+ try
+ {
+ AddAsync(packageUri, addOptions);
+ }
+ catch (...)
+ {
+ auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) };
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedFailure, exception.code(), false, /*TODO*/winrt::guid{});
+ }
+
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedSuccess, S_OK, true, /*TODO*/winrt::guid{});
+
+ //TODO logTelemetry.Stop();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::AddPackageSetAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions options)
+ {
+ //TODO auto logTelemetry{ PackageDeploymentTelemetry::CreateChannelAsync::Start(g_telemetryHelper, remoteId) };
+
+ auto strong = get_strong();
+
+ auto cancellation{ co_await winrt::get_cancellation_token() };
+ cancellation.enable_propagation(true);
+
+ //TODO logTelemetry.IgnoreCurrentThread();
+
+ // Allow to register the progress and complete handler
+ co_await resume_background();
+
+ //TODO auto logTelemetryContinuation = logTelemetry.ContinueOnCurrentThread();
+
+ auto progress{ co_await winrt::get_progress_token() };
+ auto packageDeploymentProgress{
+ winrt::make<
+ winrt::Microsoft::Windows::Management::Deployment::implementation::PackageDeploymentProgress>(
+ PackageDeploymentProgressStatus::Queued, 0) };
+ progress(packageDeploymentProgress);
+
+ // Check parameter(s)
+ Validate(packageSet);
+
+ packageDeploymentProgress.status(PackageDeploymentProgressStatus::InProgress);
+ const double c_progressPercentageStartOfInstalls{ 0.10 };
+ packageDeploymentProgress.percentage(c_progressPercentageStartOfInstalls);
+ progress(packageDeploymentProgress);
+ auto packageSetItems{ packageSet.PackageSetItems() };
+ const double progressIncrementPerPackageSetItem{ (1.0 - c_progressPercentageStartOfInstalls) / packageSetItems.Size() };
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSetItems)
+ {
+ try
+ {
+ AddAsync(packageSetItem, options);
+ packageDeploymentProgress.percentage(packageDeploymentProgress.percentage() + progressIncrementPerPackageSetItem);
+ progress(packageDeploymentProgress);
+ }
+ catch (...)
+ {
+ auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) };
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedFailure, exception.code(), false, /*TODO*/winrt::guid{});
+ }
+ }
+
+ co_return winrt::make(
+ PackageDeploymentStatus::CompletedSuccess, S_OK, true, /*TODO*/winrt::guid{});
+
+ //TODO logTelemetry.Stop();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::AddPackageSetByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::RemovePackageAsync(hstring package, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options)
+ {
+ if (VerifyPackageFamilyName(package.c_str()) == ERROR_SUCCESS)
+ {
+ return RemovePackageByFamilyNameAsync(package, options);
+ }
+ else if (VerifyPackageFullName(package.c_str()) == ERROR_SUCCESS)
+ {
+ return RemovePackageByFullNameAsync(package, options);
+ }
+ THROW_HR_MSG(E_INVALIDARG, "%ls", package.c_str());
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::RemovePackageByFullNameAsync(hstring packageFullName, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::RemovePackageByFamilyNameAsync(hstring packageFamilyName, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::RemovePackageSetAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ PackageDeploymentManager::RemovePackageSetByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options)
+ {
+ throw hresult_not_implemented();
+ }
+
+ bool PackageDeploymentManager::IsReady(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem)
+ {
+ const AppModel::Identity::PackageVersion minVersion{ packageSetItem.MinVersion() };
+ const auto processorArchitectureFilter{ packageSetItem.ProcessorArchitectureFilter() };
+ return ::Microsoft::Windows::ApplicationModel::PackageDeploymentResolver::FindAny(m_packageManager, packageSetItem.PackageFamilyName(), minVersion, processorArchitectureFilter);
+ }
+
+ void PackageDeploymentManager::Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet) const
+ {
+ THROW_HR_IF(E_INVALIDARG, packageSet.Id().empty());
+ const auto& packageSetItems{ packageSet.PackageSetItems() };
+ THROW_HR_IF(E_INVALIDARG, packageSetItems.Size() == 0);
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSetItems)
+ {
+ Validate(packageSetItem);
+ }
+ }
+
+ void PackageDeploymentManager::Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem) const
+ {
+ const auto packageFamilyName{ packageSetItem.PackageFamilyName() };
+ THROW_IF_WIN32_ERROR_MSG(VerifyPackageFamilyName(packageFamilyName.c_str()), "PackageFamilyName:%ls", packageFamilyName.c_str());
+
+ const auto packageUri{ packageSetItem.PackageUri() };
+ THROW_HR_IF_NULL_MSG(E_INVALIDARG, packageUri, "PackageUri:");
+ }
+
+ void PackageDeploymentManager::EnsureIsReadyAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions const& options)
+ {
+ if (IsReady(packageSetItem))
+ {
+ return;
+ }
+
+ auto packageUri{ packageSetItem.PackageUri() };
+ winrt::Windows::Management::Deployment::AddPackageOptions addOptions{ ToOptions(options) };
+ auto deploymentOperation{ m_packageManager.AddPackageByUriAsync(packageUri, addOptions) };
+ deploymentOperation.get();
+ try
+ {
+ const auto deploymentResult{ deploymentOperation.GetResults() };
+ if (deploymentOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Error)
+ {
+ const winrt::hresult hr{ static_cast(deploymentOperation.ErrorCode()) };
+ THROW_IF_FAILED_MSG(hr, "%ls", packageUri.ToString().c_str());
+ const winrt::hresult extendedHr{ deploymentResult.ExtendedErrorCode() };
+ THROW_IF_FAILED_MSG(extendedHr, "%ls", packageUri.ToString().c_str());
+ FAIL_FAST_HR_MSG(E_UNEXPECTED, "%ls", packageUri.ToString().c_str());
+ }
+ else if (deploymentOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Canceled)
+ {
+ THROW_WIN32_MSG(ERROR_CANCELLED, "%ls", packageUri.ToString().c_str());
+ }
+ FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, deploymentOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed, "%ls", packageUri.ToString().c_str());
+ }
+ catch (...)
+ {
+ auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) };
+ THROW_HR_MSG(exception.code(), "%ls", packageUri.ToString().c_str());
+ }
+ }
+
+ void PackageDeploymentManager::AddAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions const& options)
+ {
+ auto packageUri{ packageSetItem.PackageUri() };
+ winrt::Windows::Management::Deployment::AddPackageOptions addOptions{ ToOptions(options) };
+ AddAsync(packageUri, addOptions);
+ }
+
+ void PackageDeploymentManager::AddAsync(winrt::Windows::Foundation::Uri const& packageUri, winrt::Windows::Management::Deployment::AddPackageOptions const& addOptions)
+ {
+ auto deploymentOperation{ m_packageManager.AddPackageByUriAsync(packageUri, addOptions) };
+ deploymentOperation.get();
+ try
+ {
+ const auto deploymentResult{ deploymentOperation.GetResults() };
+ if (deploymentOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Error)
+ {
+ const winrt::hresult hr{ static_cast(deploymentOperation.ErrorCode()) };
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_DOWNGRADE))
+ {
+ // Newer version already installed. Success!
+ (void)LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_DOWNGRADE), "%ls", deploymentResult.ErrorText().c_str());
+ return;
+ }
+ THROW_IF_FAILED_MSG(hr, "%ls", packageUri.ToString().c_str());
+ const winrt::hresult extendedHr{ deploymentResult.ExtendedErrorCode() };
+ THROW_IF_FAILED_MSG(extendedHr, "%ls", packageUri.ToString().c_str());
+ FAIL_FAST_HR_MSG(E_UNEXPECTED, "%ls", packageUri.ToString().c_str());
+ }
+ else if (deploymentOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Canceled)
+ {
+ THROW_WIN32_MSG(ERROR_CANCELLED, "%ls", packageUri.ToString().c_str());
+ }
+ FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, deploymentOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed, "%ls", packageUri.ToString().c_str());
+ }
+ catch (...)
+ {
+ auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) };
+ THROW_HR_MSG(exception.code(), "%ls", packageUri.ToString().c_str());
+ }
+ }
+
+ winrt::Windows::Management::Deployment::PackageVolume PackageDeploymentManager::ToPackageVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& packageVolume) const
+ {
+ if (packageVolume)
+ {
+ const auto name{ packageVolume.Name() };
+ if (!name.empty())
+ {
+ auto toPackageVolume{ m_packageManager.FindPackageVolume(name) };
+ return toPackageVolume;
+ }
+ }
+ return nullptr;
+ }
+
+ winrt::Windows::Management::Deployment::AddPackageOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions const& options) const
+ {
+ if (!options)
+ {
+ return winrt::Windows::Management::Deployment::AddPackageOptions();
+ }
+
+ winrt::Windows::Management::Deployment::AddPackageOptions toOptions;
+ const auto targetVolume{ options.TargetVolume() };
+ if (targetVolume)
+ {
+ const auto toPackageVolume{ ToPackageVolume(targetVolume) };
+ if (toPackageVolume)
+ {
+ toOptions.TargetVolume(toPackageVolume);
+ }
+ }
+ for (const auto uri : options.DependencyPackageUris())
+ {
+ toOptions.DependencyPackageUris().Append(uri);
+ }
+ for (const auto packageFamilyName : options.OptionalPackageFamilyNames())
+ {
+ toOptions.OptionalPackageFamilyNames().Append(packageFamilyName);
+ }
+ for (const auto uri : options.OptionalPackageUris())
+ {
+ toOptions.OptionalPackageUris().Append(uri);
+ }
+ for (const auto uri : options.RelatedPackageUris())
+ {
+ toOptions.RelatedPackageUris().Append(uri);
+ }
+ toOptions.ExternalLocationUri(options.ExternalLocationUri());
+ toOptions.StubPackageOption(static_cast(options.StubPackageOption()));
+ toOptions.AllowUnsigned(options.AllowUnsigned());
+ toOptions.DeveloperMode(options.DeveloperMode());
+ toOptions.ForceAppShutdown(options.ForceAppShutdown());
+ toOptions.ForceTargetAppShutdown(options.ForceTargetAppShutdown());
+ toOptions.ForceUpdateFromAnyVersion(options.ForceUpdateFromAnyVersion());
+ toOptions.InstallAllResources(options.InstallAllResources());
+ toOptions.RequiredContentGroupOnly(options.RequiredContentGroupOnly());
+ toOptions.RetainFilesOnFailure(options.RetainFilesOnFailure());
+ toOptions.StageInPlace(options.StageInPlace());
+ toOptions.DeferRegistrationWhenPackagesAreInUse(options.DeferRegistrationWhenPackagesAreInUse());
+ if (options.IsExpectedDigestsSupported())
+ {
+ const auto expectedDigests{ options.ExpectedDigests() };
+ if (expectedDigests)
+ {
+ auto toExpectedDigests{ toOptions.ExpectedDigests() };
+ for (const auto expectedDigest : expectedDigests)
+ {
+ toExpectedDigests.Insert(expectedDigest.Key(), expectedDigest.Value());
+ }
+ }
+ }
+ if (options.IsLimitToExistingPackagesSupported())
+ {
+ toOptions.LimitToExistingPackages(options.LimitToExistingPackages());
+ }
+ return toOptions;
+ }
+
+ winrt::Windows::Management::Deployment::AddPackageOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions const& options) const
+ {
+ return ToOptions(options.AddPackageOptions());
+ }
+
+ winrt::Windows::Management::Deployment::StagePackageOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::StagePackageOptions const& options) const
+ {
+ winrt::Windows::Management::Deployment::StagePackageOptions toOptions;
+ const auto targetVolume{ options.TargetVolume() };
+ if (targetVolume)
+ {
+ const auto toPackageVolume{ ToPackageVolume(targetVolume) };
+ if (toPackageVolume)
+ {
+ toOptions.TargetVolume(toPackageVolume);
+ }
+ }
+ for (const auto uri : options.DependencyPackageUris())
+ {
+ toOptions.DependencyPackageUris().Append(uri);
+ }
+ for (const auto packageFamilyName : options.OptionalPackageFamilyNames())
+ {
+ toOptions.OptionalPackageFamilyNames().Append(packageFamilyName);
+ }
+ for (const auto uri : options.OptionalPackageUris())
+ {
+ toOptions.OptionalPackageUris().Append(uri);
+ }
+ for (const auto uri : options.RelatedPackageUris())
+ {
+ toOptions.RelatedPackageUris().Append(uri);
+ }
+ toOptions.ExternalLocationUri(options.ExternalLocationUri());
+ toOptions.StubPackageOption(static_cast(options.StubPackageOption()));
+ toOptions.DeveloperMode(options.DeveloperMode());
+ toOptions.ForceUpdateFromAnyVersion(options.ForceUpdateFromAnyVersion());
+ toOptions.InstallAllResources(options.InstallAllResources());
+ toOptions.RequiredContentGroupOnly(options.RequiredContentGroupOnly());
+ toOptions.StageInPlace(options.StageInPlace());
+ toOptions.AllowUnsigned(options.AllowUnsigned());
+ if (options.IsExpectedDigestsSupported())
+ {
+ const auto expectedDigests{ options.ExpectedDigests() };
+ if (expectedDigests)
+ {
+ auto toExpectedDigests{ toOptions.ExpectedDigests() };
+ for (const auto expectedDigest : expectedDigests)
+ {
+ toExpectedDigests.Insert(expectedDigest.Key(), expectedDigest.Value());
+ }
+ }
+ }
+ return toOptions;
+ }
+
+ winrt::Windows::Management::Deployment::RegisterPackageOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::RegisterPackageOptions const& options) const
+ {
+ winrt::Windows::Management::Deployment::RegisterPackageOptions toOptions;
+ const auto appDataVolume{ options.AppDataVolume() };
+ if (appDataVolume)
+ {
+ const auto toPackageVolume{ ToPackageVolume(appDataVolume) };
+ if (toPackageVolume)
+ {
+ toOptions.AppDataVolume(toPackageVolume);
+ }
+ }
+ for (const auto uri : options.DependencyPackageUris())
+ {
+ toOptions.DependencyPackageUris().Append(uri);
+ }
+ for (const auto packageFamilyName : options.OptionalPackageFamilyNames())
+ {
+ toOptions.OptionalPackageFamilyNames().Append(packageFamilyName);
+ }
+ toOptions.ExternalLocationUri(options.ExternalLocationUri());
+ toOptions.DeveloperMode(options.DeveloperMode());
+ toOptions.ForceAppShutdown(options.ForceAppShutdown());
+ toOptions.ForceTargetAppShutdown(options.ForceTargetAppShutdown());
+ toOptions.ForceUpdateFromAnyVersion(options.ForceUpdateFromAnyVersion());
+ toOptions.InstallAllResources(options.InstallAllResources());
+ toOptions.StageInPlace(options.StageInPlace());
+ toOptions.AllowUnsigned(options.AllowUnsigned());
+ toOptions.DeferRegistrationWhenPackagesAreInUse(options.DeferRegistrationWhenPackagesAreInUse());
+ if (options.IsExpectedDigestsSupported())
+ {
+ const auto expectedDigests{ options.ExpectedDigests() };
+ if (expectedDigests)
+ {
+ auto toExpectedDigests{ toOptions.ExpectedDigests() };
+ for (const auto expectedDigest : expectedDigests)
+ {
+ toExpectedDigests.Insert(expectedDigest.Key(), expectedDigest.Value());
+ }
+ }
+ }
+ return toOptions;
+ }
+
+ winrt::Windows::Management::Deployment::RemovalOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions const& options) const
+ {
+ auto toOptions{ winrt::Windows::Management::Deployment::RemovalOptions::None };
+ if (options.PreserveApplicationData())
+ {
+ toOptions |= winrt::Windows::Management::Deployment::RemovalOptions::PreserveApplicationData;
+ }
+ if (options.PreserveRoamableApplicationData())
+ {
+ toOptions |= winrt::Windows::Management::Deployment::RemovalOptions::PreserveRoamableApplicationData;
+ }
+ if (options.RemoveForAllUsers())
+ {
+ toOptions |= winrt::Windows::Management::Deployment::RemovalOptions::RemoveForAllUsers;
+ }
+ //TODO DeploymentPriority Priority;
+ return toOptions;
+ }
+
+ winrt::Windows::Management::Deployment::AddPackageOptions PackageDeploymentManager::ToOptions(winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions const& /*options*/) const
+ {
+ return winrt::Windows::Management::Deployment::AddPackageOptions();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.h b/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.h
new file mode 100644
index 0000000000..be9c8ed393
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentManager.h
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentManager.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageDeploymentManager : PackageDeploymentManagerT
+ {
+ PackageDeploymentManager() = default;
+
+ static winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager GetDefault();
+ bool IsPackageSetReady(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet);
+ bool IsPackageSetReadyById(hstring const& packageSetId);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress EnsurePackageSetIsReadyAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress EnsurePackageSetIsReadyByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress AddPackageAsync(hstring package, winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress AddPackageByUriAsync(winrt::Windows::Foundation::Uri packageUri, winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress AddPackageSetAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress AddPackageSetByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RemovePackageAsync(hstring packageFullName, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RemovePackageByFullNameAsync(hstring packageFullName, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RemovePackageByFamilyNameAsync(hstring packageFamilyName, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RemovePackageSetAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSet packageSet, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RemovePackageSetByIdAsync(hstring packageSetId, winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions options);
+
+ private:
+ bool IsReady(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSet);
+ void Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet) const;
+ void Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem) const;
+ void EnsureIsReadyAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions const& options);
+ void AddAsync(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions const& options);
+ void AddAsync(winrt::Windows::Foundation::Uri const& packageUri, winrt::Windows::Management::Deployment::AddPackageOptions const& addOptions);
+ winrt::Windows::Management::Deployment::PackageVolume ToPackageVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& packageVolume) const;
+ winrt::Windows::Management::Deployment::AddPackageOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions const& options) const;
+ winrt::Windows::Management::Deployment::AddPackageOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::AddPackageSetOptions const& options) const;
+ winrt::Windows::Management::Deployment::StagePackageOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::StagePackageOptions const& options) const;
+ winrt::Windows::Management::Deployment::RegisterPackageOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::RegisterPackageOptions const& options) const;
+ winrt::Windows::Management::Deployment::RemovalOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::RemovePackageOptions const& options) const;
+ winrt::Windows::Management::Deployment::AddPackageOptions ToOptions(winrt::Microsoft::Windows::Management::Deployment::EnsureIsReadyOptions const& options) const;
+
+ private:
+ winrt::Windows::Management::Deployment::PackageManager m_packageManager;
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageDeploymentManager : PackageDeploymentManagerT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.cpp b/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.cpp
new file mode 100644
index 0000000000..51cb33ba92
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageDeploymentProgress.h"
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentProgress.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ PackageDeploymentProgress::PackageDeploymentProgress(
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus const& status,
+ double percentage) :
+ m_status(status),
+ m_percentage(percentage)
+ {
+ }
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus PackageDeploymentProgress::status()
+ {
+ return m_status;
+ }
+ void PackageDeploymentProgress::status(winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus const& value)
+ {
+ m_status = value;
+ }
+ double PackageDeploymentProgress::percentage()
+ {
+ return m_percentage;
+ }
+ void PackageDeploymentProgress::percentage(double value)
+ {
+ m_percentage = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.h b/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.h
new file mode 100644
index 0000000000..21da166ad2
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentProgress.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentProgress.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageDeploymentProgress : PackageDeploymentProgressT
+ {
+ PackageDeploymentProgress() = default;
+
+ PackageDeploymentProgress(
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus const& status,
+ double percentage);
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus status();
+ void status(winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus const& value);
+ double percentage();
+ void percentage(double value);
+
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgressStatus m_status{};
+ double m_percentage{};
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.cpp b/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.cpp
new file mode 100644
index 0000000000..ba5bd56032
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageDeploymentResult.h"
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentResult.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ PackageDeploymentResult::PackageDeploymentResult(winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus status, winrt::hresult const& extendedError, bool isRegistered, winrt::guid const& activityId) :
+ m_status(status),
+ m_extendedError(extendedError),
+ m_isRegistered(isRegistered),
+ m_activityId(activityId)
+ {
+ }
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus PackageDeploymentResult::Status()
+ {
+ return m_status;
+ }
+ winrt::hresult PackageDeploymentResult::ExtendedError()
+ {
+ return m_extendedError;
+ }
+ bool PackageDeploymentResult::IsRegistered()
+ {
+ return m_isRegistered;
+ }
+ winrt::guid PackageDeploymentResult::ActivityId()
+ {
+ return m_activityId;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.h b/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.h
new file mode 100644
index 0000000000..ba865976d0
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageDeploymentResult.h
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageDeploymentResult.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageDeploymentResult : PackageDeploymentResultT
+ {
+ PackageDeploymentResult() = default;
+ PackageDeploymentResult(winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus status, winrt::hresult const& extendedError, bool isRegistered, winrt::guid const& activityId);
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus Status();
+ winrt::hresult ExtendedError();
+ winrt::guid ActivityId();
+ bool IsRegistered();
+
+ private:
+ PackageDeploymentStatus m_status{};
+ winrt::hresult m_extendedError;
+ bool m_isRegistered{};
+ winrt::guid m_activityId{};
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.cpp b/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.cpp
new file mode 100644
index 0000000000..cff2cbf024
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.cpp
@@ -0,0 +1,125 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageRuntimeManager.h"
+#include "Microsoft.Windows.Management.Deployment.PackageRuntimeManager.g.cpp"
+
+#include "M.W.M.D.PackageSetItemRuntimeDisposition.h"
+#include "M.W.M.D.PackageSetRuntimeDisposition.h"
+
+#include
+#include
+#include
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageRuntimeManager PackageRuntimeManager::GetDefault()
+ {
+ return winrt::make();
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition PackageRuntimeManager::AddPackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet)
+ {
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions createOptions;
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions addOptions;
+ return AddPackageSet(packageSet, createOptions, addOptions);
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition PackageRuntimeManager::AddPackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions)
+ {
+ // Check parameter(s)
+ Validate(packageSet);
+ Validate(createOptions);
+ Validate(addOptions);
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition packageSetRuntimeDisposition;
+ packageSetRuntimeDisposition.PackageSetId(packageSet.Id());
+ auto packageSetItemRuntimeDispositions{ packageSetRuntimeDisposition.PackageSetItemRuntimeDispositions() };
+
+ const auto packageSetItems{ packageSet.PackageSetItems() };
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSetItems)
+ {
+ auto packageSetItemRuntimeDisposition{ AddPackageSetItem(packageSetItem, createOptions, addOptions) };
+ packageSetItemRuntimeDispositions.Append(packageSetItemRuntimeDisposition);
+ }
+
+ return packageSetRuntimeDisposition;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition PackageRuntimeManager::AddPackageSetById(hstring const& packageSetId)
+ {
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions createOptions;
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions addOptions;
+ return AddPackageSetById(packageSetId, createOptions, addOptions);
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition PackageRuntimeManager::AddPackageSetById(hstring const& packageSetId, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions)
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageRuntimeManager::RemovePackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition const& packageSetRuntimeDisposition)
+ {
+ const auto packageSetItemRuntimeDispositions{ packageSetRuntimeDisposition.PackageSetItemRuntimeDispositions() };
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItemRuntimeDisposition& packageSetItemRuntimeDisposition : packageSetItemRuntimeDispositions)
+ {
+ RemovePackageSetItem(packageSetItemRuntimeDisposition);
+ }
+ }
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetItemRuntimeDisposition PackageRuntimeManager::AddPackageSetItem(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions)
+ {
+ auto createPackageDependencyOptions{ MddCreatePackageDependencyOptions::None };
+ WI_SetFlagIf(createPackageDependencyOptions, MddCreatePackageDependencyOptions::DoNotVerifyDependencyResolution, !createOptions.VerifyDependencyResolution());
+ wil::unique_process_heap_string packageDependencyId;
+ THROW_IF_FAILED(MddCore::Win11::TryCreatePackageDependency(nullptr, packageSetItem.PackageFamilyName(),
+ packageSetItem.MinVersion(), packageSetItem.ProcessorArchitectureFilter(),
+ createOptions, &packageDependencyId));
+
+ auto addPackageDependencyOptions{ MddAddPackageDependencyOptions::None };
+ WI_SetFlagIf(addPackageDependencyOptions, MddAddPackageDependencyOptions::PrependIfRankCollision, addOptions.PrependIfRankCollision());
+ wil::unique_mdd_package_dependency_context mddPackageDependencyContext{};
+ wil::unique_process_heap_string packageFullName;
+ THROW_IF_FAILED(MddCore::Win11::AddPackageDependency(packageDependencyId.get(), addOptions, &mddPackageDependencyContext, &packageFullName));
+
+ auto packageSetItemRuntimeDisposition{ winrt::make(
+ packageSetItem.Id(), packageFullName.get(), packageDependencyId.get(), mddPackageDependencyContext.get()) };
+ mddPackageDependencyContext.reset();
+ return packageSetItemRuntimeDisposition;
+ }
+
+ void PackageRuntimeManager::RemovePackageSetItem(winrt::Microsoft::Windows::Management::Deployment::PackageSetItemRuntimeDisposition const& packageSetItemRuntimeDisposition)
+ {
+ const auto packageDependencyContextId{ packageSetItemRuntimeDisposition.PackageDependencyContextId() };
+ MddCore::Win11::RemovePackageDependency(packageDependencyContextId);
+
+ const auto packageDependencyId{ packageSetItemRuntimeDisposition.PackageDependencyId() };
+ MddCore::Win11::DeletePackageDependency(packageDependencyId);
+ }
+
+ void PackageRuntimeManager::Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet) const
+ {
+ THROW_HR_IF(E_INVALIDARG, packageSet.Id().empty());
+ const auto& packageSetItems{ packageSet.PackageSetItems() };
+ THROW_HR_IF(E_INVALIDARG, packageSetItems.Size() == 0);
+ for (const winrt::Microsoft::Windows::Management::Deployment::PackageSetItem& packageSetItem : packageSetItems)
+ {
+ Validate(packageSetItem);
+ }
+ }
+
+ void PackageRuntimeManager::Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem) const
+ {
+ const auto packageFamilyName{ packageSetItem.PackageFamilyName() };
+ THROW_IF_WIN32_ERROR_MSG(VerifyPackageFamilyName(packageFamilyName.c_str()), "PackageFamilyName:%ls", packageFamilyName.c_str());
+
+ const auto packageUri{ packageSetItem.PackageUri() };
+ THROW_HR_IF_NULL_MSG(E_INVALIDARG, packageUri, "PackageUri:");
+ }
+
+ void PackageRuntimeManager::Validate(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& options) const
+ {
+ // Nothing to do!
+ }
+
+ void PackageRuntimeManager::Validate(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& options) const
+ {
+ // Nothing to do!
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.h b/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.h
new file mode 100644
index 0000000000..18e65ad647
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageRuntimeManager.h
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageRuntimeManager.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageRuntimeManager : PackageRuntimeManagerT
+ {
+ PackageRuntimeManager() = default;
+
+ static winrt::Microsoft::Windows::Management::Deployment::PackageRuntimeManager GetDefault();
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition AddPackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet);
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition AddPackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions);
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition AddPackageSetById(hstring const& packageSetId);
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition AddPackageSetById(hstring const& packageSetId, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions);
+ void RemovePackageSet(winrt::Microsoft::Windows::Management::Deployment::PackageSetRuntimeDisposition const& packageSetRuntimeDisposition);
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetItemRuntimeDisposition AddPackageSetItem(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& createOptions, winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& addOptions);
+ void RemovePackageSetItem(winrt::Microsoft::Windows::Management::Deployment::PackageSetItemRuntimeDisposition const& packageSetItemRuntimeDisposition);
+ void Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet) const;
+ void Validate(winrt::Microsoft::Windows::Management::Deployment::PackageSetItem const& packageSetItem) const;
+ void Validate(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::CreatePackageDependencyOptions const& options) const;
+ void Validate(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::AddPackageDependencyOptions const& options) const;
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageRuntimeManager : PackageRuntimeManagerT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSet.cpp b/dev/PackageManager/API/M.W.M.D.PackageSet.cpp
new file mode 100644
index 0000000000..9382a7c428
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSet.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageSet.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSet.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ hstring PackageSet::Id()
+ {
+ return m_id;
+ }
+ void PackageSet::Id(hstring const& value)
+ {
+ m_id = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector PackageSet::PackageSetItems()
+ {
+ if (!m_packageSetItems)
+ {
+ m_packageSetItems = winrt::single_threaded_vector();
+ }
+ return m_packageSetItems;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSet.h b/dev/PackageManager/API/M.W.M.D.PackageSet.h
new file mode 100644
index 0000000000..f38581041e
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSet.h
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageSet.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageSet : PackageSetT
+ {
+ PackageSet() = default;
+
+ hstring Id();
+ void Id(hstring const& value);
+ winrt::Windows::Foundation::Collections::IVector PackageSetItems();
+
+ private:
+ hstring m_id;
+ winrt::Windows::Foundation::Collections::IVector m_packageSetItems;
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageSet : PackageSetT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetItem.cpp b/dev/PackageManager/API/M.W.M.D.PackageSetItem.cpp
new file mode 100644
index 0000000000..ab8623dbfe
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetItem.cpp
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageSetItem.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSetItem.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ hstring PackageSetItem::Id()
+ {
+ return m_id;
+ }
+ void PackageSetItem::Id(hstring const& value)
+ {
+ m_id = value;
+ }
+ hstring PackageSetItem::PackageFamilyName()
+ {
+ return m_packageFamilyName;
+ }
+ void PackageSetItem::PackageFamilyName(hstring const& value)
+ {
+ m_packageFamilyName = value;
+ }
+ winrt::Windows::ApplicationModel::PackageVersion PackageSetItem::MinVersion()
+ {
+ return m_minVersion;
+ }
+ void PackageSetItem::MinVersion(winrt::Windows::ApplicationModel::PackageVersion const& value)
+ {
+ m_minVersion = value;
+ }
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures PackageSetItem::ProcessorArchitectureFilter()
+ {
+ return m_processorArchitectureFilter;
+ }
+ void PackageSetItem::ProcessorArchitectureFilter(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures const& value)
+ {
+ m_processorArchitectureFilter = value;
+ }
+ winrt::Windows::Foundation::Uri PackageSetItem::PackageUri()
+ {
+ return m_packageUri;
+ }
+ void PackageSetItem::PackageUri(winrt::Windows::Foundation::Uri const& value)
+ {
+ m_packageUri = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetItem.h b/dev/PackageManager/API/M.W.M.D.PackageSetItem.h
new file mode 100644
index 0000000000..00e98e04cc
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetItem.h
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageSetItem.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageSetItem : PackageSetItemT
+ {
+ PackageSetItem() = default;
+
+ hstring Id();
+ void Id(hstring const& value);
+
+ hstring PackageFamilyName();
+ void PackageFamilyName(hstring const& value);
+ winrt::Windows::ApplicationModel::PackageVersion MinVersion();
+ void MinVersion(winrt::Windows::ApplicationModel::PackageVersion const& value);
+
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures ProcessorArchitectureFilter();
+ void ProcessorArchitectureFilter(winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures const& value);
+ winrt::Windows::Foundation::Uri PackageUri();
+ void PackageUri(winrt::Windows::Foundation::Uri const& value);
+
+ private:
+ hstring m_id;
+ hstring m_packageFamilyName;
+ winrt::Windows::ApplicationModel::PackageVersion m_minVersion{};
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyProcessorArchitectures m_processorArchitectureFilter{};
+ winrt::Windows::Foundation::Uri m_packageUri{ nullptr };
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageSetItem : PackageSetItemT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.cpp b/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.cpp
new file mode 100644
index 0000000000..21fe846d79
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "M.W.M.D.PackageSetItemRuntimeDisposition.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSetItemRuntimeDisposition.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ hstring PackageSetItemRuntimeDisposition::PackageSetItemId()
+ {
+ return m_packageSetItemId;
+ }
+ hstring PackageSetItemRuntimeDisposition::PackageFullName()
+ {
+ return m_packageFullName;
+ }
+ hstring PackageSetItemRuntimeDisposition::PackageDependencyId()
+ {
+ return m_packageDependencyId;
+ }
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId PackageSetItemRuntimeDisposition::PackageDependencyContextId()
+ {
+ return m_packageDependencyContextId;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.h b/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.h
new file mode 100644
index 0000000000..34fec4a95c
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetItemRuntimeDisposition.h
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageSetItemRuntimeDisposition.g.h"
+
+#include "MsixDynamicDependency.h"
+#include
+
+#include "MddWin11.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageSetItemRuntimeDisposition : PackageSetItemRuntimeDispositionT
+ {
+ PackageSetItemRuntimeDisposition() = default;
+ PackageSetItemRuntimeDisposition(winrt::hstring const& packageSetItemId,
+ winrt::hstring const& packageFullName,
+ winrt::hstring const& packageDependencyId,
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId packageDependencyContextId) :
+ m_packageSetItemId(packageSetItemId),
+ m_packageFullName(packageFullName),
+ m_packageDependencyId(packageDependencyId),
+ m_packageDependencyContextId(packageDependencyContextId)
+ {
+ }
+ PackageSetItemRuntimeDisposition(winrt::hstring const& packageSetItemId,
+ winrt::hstring const& packageFullName,
+ winrt::hstring const& packageDependencyId,
+ MDD_PACKAGEDEPENDENCY_CONTEXT mddPackageDependencyContext) :
+ m_packageSetItemId(packageSetItemId),
+ m_packageFullName(packageFullName),
+ m_packageDependencyId(packageDependencyId),
+ m_packageDependencyContextId(MddCore::Win11::ToContextId(mddPackageDependencyContext))
+ {
+ }
+
+ hstring PackageSetItemId();
+ hstring PackageFullName();
+ hstring PackageDependencyId();
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId PackageDependencyContextId();
+
+ private:
+ hstring m_packageSetItemId;
+ hstring m_packageFullName;
+ hstring m_packageDependencyId;
+ winrt::Microsoft::Windows::ApplicationModel::DynamicDependency::PackageDependencyContextId m_packageDependencyContextId;
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageSetItemRuntimeDisposition : PackageSetItemRuntimeDispositionT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetManager.cpp b/dev/PackageManager/API/M.W.M.D.PackageSetManager.cpp
new file mode 100644
index 0000000000..96006406b0
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetManager.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageSetManager.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSetManager.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageSetManager PackageSetManager::GetDefault()
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageSetManager::Add(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet)
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageSetManager::Update(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet)
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageSetManager::Remove(hstring const& packageSetId)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageSet PackageSetManager::Get(hstring const& packageSetId)
+ {
+ throw hresult_not_implemented();
+ }
+ winrt::Windows::Foundation::Collections::IVector PackageSetManager::Find(winrt::Microsoft::Windows::Management::Deployment::FindPackageSetOptions const& options)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetManager.h b/dev/PackageManager/API/M.W.M.D.PackageSetManager.h
new file mode 100644
index 0000000000..192e0f7d29
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetManager.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageSetManager.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageSetManager : PackageSetManagerT
+ {
+ PackageSetManager() = default;
+
+ static winrt::Microsoft::Windows::Management::Deployment::PackageSetManager GetDefault();
+ void Add(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet);
+ void Update(winrt::Microsoft::Windows::Management::Deployment::PackageSet const& packageSet);
+ void Remove(hstring const& packageSetId);
+ winrt::Microsoft::Windows::Management::Deployment::PackageSet Get(hstring const& packageSetId);
+ winrt::Windows::Foundation::Collections::IVector Find(winrt::Microsoft::Windows::Management::Deployment::FindPackageSetOptions const& options);
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageSetManager : PackageSetManagerT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.cpp b/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.cpp
new file mode 100644
index 0000000000..0708139845
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "M.W.M.D.PackageSetRuntimeDisposition.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSetRuntimeDisposition.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ hstring PackageSetRuntimeDisposition::PackageSetId()
+ {
+ return m_packageSetId;
+ }
+ void PackageSetRuntimeDisposition::PackageSetId(hstring const& value)
+ {
+ m_packageSetId = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector PackageSetRuntimeDisposition::PackageSetItemRuntimeDispositions()
+ {
+ if (!m_packageSetItemRuntimeDispositions)
+ {
+ m_packageSetItemRuntimeDispositions = winrt::single_threaded_vector();
+ }
+ return m_packageSetItemRuntimeDispositions;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.h b/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.h
new file mode 100644
index 0000000000..c339c6d611
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageSetRuntimeDisposition.h
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "M.W.M.D.PackageSetRuntimeDisposition.h"
+#include "Microsoft.Windows.Management.Deployment.PackageSetRuntimeDisposition.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageSetRuntimeDisposition : PackageSetRuntimeDispositionT
+ {
+ PackageSetRuntimeDisposition() = default;
+#if 0
+ PackageSetRuntimeDisposition(winrt::hstring const& packageSetId) :
+ m_packageSetId(packageSetId)
+ {
+ }
+ PackageSetRuntimeDisposition(winrt::hstring const& packageSetId, winrt::Windows::Foundation::Collections::IVector& packageSetItemRuntimeDispositions) :
+ m_packageSetId(packageSetId),
+ m_packageSetItemRuntimeDispositions(packageSetItemRuntimeDispositions)
+ {
+ }
+#endif
+
+ hstring PackageSetId();
+ void PackageSetId(hstring const& value);
+ winrt::Windows::Foundation::Collections::IVector PackageSetItemRuntimeDispositions();
+ private:
+ hstring m_packageSetId;
+ winrt::Windows::Foundation::Collections::IVector m_packageSetItemRuntimeDispositions{};
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageSetRuntimeDisposition : PackageSetRuntimeDispositionT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp
new file mode 100644
index 0000000000..835e8aa25d
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageVolume.h"
+#include "Microsoft.Windows.Management.Deployment.PackageVolume.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ PackageVolume::PackageVolume(winrt::Windows::Management::Deployment::PackageVolume const& value)
+ {
+ m_isSystemVolume = value.IsSystemVolume();
+ m_mountPoint = value.MountPoint();
+ m_name = value.Name();
+ m_packageStorePath = value.PackageStorePath();
+ m_supportsHardLinks = value.SupportsHardLinks();
+ m_isFullTrustPackageSupported = value.IsFullTrustPackageSupported();
+ m_isAppxInstallSupported = value.IsAppxInstallSupported();
+ //TODO m_packageStatus = value.Status();
+ }
+ bool PackageVolume::IsSystemVolume()
+ {
+ return m_isSystemVolume;
+ }
+ hstring PackageVolume::MountPoint()
+ {
+ return m_mountPoint;
+ }
+ hstring PackageVolume::Name()
+ {
+ return m_name;
+ }
+ hstring PackageVolume::PackageStorePath()
+ {
+ return m_packageStorePath;
+ }
+ bool PackageVolume::SupportsHardLinks()
+ {
+ return m_supportsHardLinks;
+ }
+ bool PackageVolume::IsFullTrustPackageSupported()
+ {
+ return m_isFullTrustPackageSupported;
+ }
+ bool PackageVolume::IsAppxInstallSupported()
+ {
+ return m_isAppxInstallSupported;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolumeStatus PackageVolume::Status()
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageVolume::FixMe()
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h
new file mode 100644
index 0000000000..9c09798084
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageVolume.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageVolume : PackageVolumeT
+ {
+ PackageVolume() = default;
+ PackageVolume(winrt::Windows::Management::Deployment::PackageVolume const& value);
+
+ bool IsSystemVolume();
+ hstring MountPoint();
+ hstring Name();
+ hstring PackageStorePath();
+ bool SupportsHardLinks();
+ bool IsFullTrustPackageSupported();
+ bool IsAppxInstallSupported();
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolumeStatus Status();
+ void FixMe();
+
+ private:
+ bool m_isSystemVolume{};
+ hstring m_mountPoint;
+ hstring m_name;
+ hstring m_packageStorePath;
+ bool m_supportsHardLinks{};
+ bool m_isFullTrustPackageSupported{};
+ bool m_isAppxInstallSupported{};
+ //TODO winrt::Microsoft::Windows::Management::Deployment::PackageVolumeStatus m_status{};
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageVolume : PackageVolumeT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.cpp
new file mode 100644
index 0000000000..8a74361c2a
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "pch.h"
+#include "M.W.M.D.PackageVolumeManager.h"
+#include "Microsoft.Windows.Management.Deployment.PackageVolumeManager.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Windows::Foundation::Collections::IVector PackageVolumeManager::FindPackageVolumes()
+ {
+ winrt::Windows::Foundation::Collections::IVector microsoftPackageVolumes{ winrt::single_threaded_vector() };
+
+ winrt::Windows::Management::Deployment::PackageManager packageManager;
+ winrt::Windows::Foundation::Collections::IIterable windowsPackageVolumes{ packageManager.FindPackageVolumes() };
+ for (winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume : windowsPackageVolumes)
+ {
+ auto microsoftPackageVolume{ winrt::make(windowsPackageVolume) };
+ microsoftPackageVolumes.Append(microsoftPackageVolume);
+ }
+ return microsoftPackageVolumes;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolumeManager::FindPackageVolumeByPath(hstring const& path)
+ {
+ const auto c_volumePathNameMaxLength{ MAX_PATH };
+ wchar_t volumePathName[c_volumePathNameMaxLength]{};//AKA volumeMountPoint
+ THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumePathNameW(path.c_str(), volumePathName, ARRAYSIZE(volumePathName)), "Path:%ls", path.c_str());
+ GUID mediaId{};
+ const size_t c_volumeNameMaxLength{ 50 }; // "\\?\Volume{GUID}\" == 11 + 11111111-2222-3333-4444-555555555555 + 2 + null-terminator == 11 + 36 + 3 = 50
+ wchar_t volumeName[c_volumeNameMaxLength]{};
+ THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumeNameForVolumeMountPoint(volumePathName, volumeName, ARRAYSIZE(volumeName)), "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName);
+ const auto volumeNameLength{ wcslen(volumeName) };
+ THROW_HR_IF_MSG(E_UNEXPECTED, volumeNameLength == 0, "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName);
+ const auto offset{ volumeNameLength - 1 };
+ if (volumeName[offset] == L'\\')
+ {
+ volumeName[offset] = L'\0';
+ }
+ return FindPackageVolumeByName(winrt::hstring{ volumeName });
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolumeManager::FindPackageVolumeByMediaId(hstring const& mediaId)
+ {
+ winrt::Windows::Management::Deployment::PackageManager packageManager;
+ winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.FindPackageVolume(mediaId) };
+ return winrt::make(windowsPackageVolume);
+ }
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolumeManager::FindPackageVolumeByName(hstring const& name)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.h b/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.h
new file mode 100644
index 0000000000..94e3db998a
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolumeManager.h
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageVolumeManager.g.h"
+#include "M.W.M.D.PackageVolume.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageVolumeManager
+ {
+ PackageVolumeManager() = default;
+
+ static winrt::Windows::Foundation::Collections::IVector FindPackageVolumes();
+ static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& path);
+ static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByMediaId(hstring const& mediaId);
+ static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name);
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageVolumeManager : PackageVolumeManagerT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.cpp
new file mode 100644
index 0000000000..828c54f668
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "M.W.M.D.PackageVolumeStatus.h"
+#include "Microsoft.Windows.Management.Deployment.PackageVolumeStatus.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ bool PackageVolumeStatus::IsOK()
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageVolumeStatus::IsOK(bool value)
+ {
+ throw hresult_not_implemented();
+ }
+ bool PackageVolumeStatus::IsOffline()
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageVolumeStatus::IsOffline(bool value)
+ {
+ throw hresult_not_implemented();
+ }
+ bool PackageVolumeStatus::IsBroken()
+ {
+ throw hresult_not_implemented();
+ }
+ void PackageVolumeStatus::IsBroken(bool value)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.h b/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.h
new file mode 100644
index 0000000000..faa8169a91
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.PackageVolumeStatus.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.PackageVolumeStatus.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct PackageVolumeStatus : PackageVolumeStatusT
+ {
+ PackageVolumeStatus() = default;
+
+ bool IsOK();
+ void IsOK(bool value);
+ bool IsOffline();
+ void IsOffline(bool value);
+ bool IsBroken();
+ void IsBroken(bool value);
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct PackageVolumeStatus : PackageVolumeStatusT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.cpp b/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.cpp
new file mode 100644
index 0000000000..8015a759cf
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.cpp
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+
+#include "M.W.M.D.RegisterPackageOptions.h"
+#include "Microsoft.Windows.Management.Deployment.RegisterPackageOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume RegisterPackageOptions::AppDataVolume()
+ {
+ return m_appDataVolume;
+ }
+ void RegisterPackageOptions::AppDataVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value)
+ {
+ m_appDataVolume = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector RegisterPackageOptions::DependencyPackageUris()
+ {
+ if (!m_dependencyPackageUris)
+ {
+ m_dependencyPackageUris = winrt::single_threaded_vector();
+ }
+ return m_dependencyPackageUris;
+ }
+ winrt::Windows::Foundation::Collections::IVector RegisterPackageOptions::OptionalPackageFamilyNames()
+ {
+ if (!m_optionalPackageFamilyNames)
+ {
+ m_optionalPackageFamilyNames = winrt::single_threaded_vector();
+ }
+ return m_optionalPackageFamilyNames;
+ }
+ winrt::Windows::Foundation::Uri RegisterPackageOptions::ExternalLocationUri()
+ {
+ return m_externalLocationUri;
+ }
+ void RegisterPackageOptions::ExternalLocationUri(winrt::Windows::Foundation::Uri const& value)
+ {
+ m_externalLocationUri = value;
+ }
+ bool RegisterPackageOptions::DeveloperMode()
+ {
+ return m_developerMode;
+ }
+ void RegisterPackageOptions::DeveloperMode(bool value)
+ {
+ m_developerMode = value;
+ }
+ bool RegisterPackageOptions::ForceAppShutdown()
+ {
+ return m_forceAppShutdown;
+ }
+ void RegisterPackageOptions::ForceAppShutdown(bool value)
+ {
+ m_forceAppShutdown = value;
+ }
+ bool RegisterPackageOptions::ForceTargetAppShutdown()
+ {
+ return m_forceTargetAppShutdown;
+ }
+ void RegisterPackageOptions::ForceTargetAppShutdown(bool value)
+ {
+ m_forceTargetAppShutdown = value;
+ }
+ bool RegisterPackageOptions::ForceUpdateFromAnyVersion()
+ {
+ return m_forceUpdateFromAnyVersion;
+ }
+ void RegisterPackageOptions::ForceUpdateFromAnyVersion(bool value)
+ {
+ m_forceUpdateFromAnyVersion = value;
+ }
+ bool RegisterPackageOptions::InstallAllResources()
+ {
+ return m_installAllResources;
+ }
+ void RegisterPackageOptions::InstallAllResources(bool value)
+ {
+ m_installAllResources = value;
+ }
+ bool RegisterPackageOptions::StageInPlace()
+ {
+ return m_stageInPlace;
+ }
+ void RegisterPackageOptions::StageInPlace(bool value)
+ {
+ m_stageInPlace = value;
+ }
+ bool RegisterPackageOptions::AllowUnsigned()
+ {
+ return m_allowUnsigned;
+ }
+ void RegisterPackageOptions::AllowUnsigned(bool value)
+ {
+ m_allowUnsigned = value;
+ }
+ bool RegisterPackageOptions::DeferRegistrationWhenPackagesAreInUse()
+ {
+ return m_deferRegistrationWhenPackagesAreInUse;
+ }
+ void RegisterPackageOptions::DeferRegistrationWhenPackagesAreInUse(bool value)
+ {
+ m_deferRegistrationWhenPackagesAreInUse = value;
+ }
+ bool RegisterPackageOptions::IsExpectedDigestsSupported()
+ {
+ // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
+ return WindowsVersion::IsWindows11_22H2OrGreater();
+ }
+ winrt::Windows::Foundation::Collections::IMap RegisterPackageOptions::ExpectedDigests()
+ {
+ return m_expectedDigests;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.h b/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.h
new file mode 100644
index 0000000000..27bb36d673
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.RegisterPackageOptions.h
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.RegisterPackageOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct RegisterPackageOptions : RegisterPackageOptionsT
+ {
+ RegisterPackageOptions() = default;
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume AppDataVolume();
+ void AppDataVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value);
+ winrt::Windows::Foundation::Collections::IVector DependencyPackageUris();
+ winrt::Windows::Foundation::Collections::IVector OptionalPackageFamilyNames();
+ winrt::Windows::Foundation::Uri ExternalLocationUri();
+ void ExternalLocationUri(winrt::Windows::Foundation::Uri const& value);
+ bool DeveloperMode();
+ void DeveloperMode(bool value);
+ bool ForceAppShutdown();
+ void ForceAppShutdown(bool value);
+ bool ForceTargetAppShutdown();
+ void ForceTargetAppShutdown(bool value);
+ bool ForceUpdateFromAnyVersion();
+ void ForceUpdateFromAnyVersion(bool value);
+ bool InstallAllResources();
+ void InstallAllResources(bool value);
+ bool StageInPlace();
+ void StageInPlace(bool value);
+ bool AllowUnsigned();
+ void AllowUnsigned(bool value);
+ bool IsDeferRegistrationWhenPackagesAreInUseSupported();
+ bool DeferRegistrationWhenPackagesAreInUse();
+ void DeferRegistrationWhenPackagesAreInUse(bool value);
+ bool IsExpectedDigestsSupported();
+ winrt::Windows::Foundation::Collections::IMap ExpectedDigests();
+
+ private:
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume m_appDataVolume{};
+ winrt::Windows::Foundation::Collections::IVector m_dependencyPackageUris{};
+ winrt::Windows::Foundation::Collections::IVector m_optionalPackageFamilyNames{};
+ winrt::Windows::Foundation::Uri m_externalLocationUri{ nullptr };
+ bool m_developerMode{};
+ bool m_forceAppShutdown{};
+ bool m_forceTargetAppShutdown{};
+ bool m_forceUpdateFromAnyVersion{};
+ bool m_installAllResources{};
+ bool m_stageInPlace{};
+ bool m_allowUnsigned{};
+ bool m_deferRegistrationWhenPackagesAreInUse{};
+ winrt::Windows::Foundation::Collections::IMap m_expectedDigests;
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct RegisterPackageOptions : RegisterPackageOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.cpp b/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.cpp
new file mode 100644
index 0000000000..95cf0b69f6
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "M.W.M.D.RemovePackageOptions.h"
+#include "Microsoft.Windows.Management.Deployment.RemovePackageOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ bool RemovePackageOptions::PreserveApplicationData()
+ {
+ return m_preserveApplicationData;
+ }
+ void RemovePackageOptions::PreserveApplicationData(bool value)
+ {
+ m_preserveApplicationData = value;
+ }
+ bool RemovePackageOptions::PreserveRoamableApplicationData()
+ {
+ return m_preserveRoamableApplicationData;
+ }
+ void RemovePackageOptions::PreserveRoamableApplicationData(bool value)
+ {
+ m_preserveRoamableApplicationData = value;
+ }
+ bool RemovePackageOptions::RemoveForAllUsers()
+ {
+ return m_removeForAllUsers;
+ }
+ void RemovePackageOptions::RemoveForAllUsers(bool value)
+ {
+ m_removeForAllUsers = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority RemovePackageOptions::Priority()
+ {
+ return m_priority;
+ }
+ void RemovePackageOptions::Priority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value)
+ {
+ m_priority = value;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.h b/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.h
new file mode 100644
index 0000000000..523278f5c3
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.RemovePackageOptions.h
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.RemovePackageOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct RemovePackageOptions : RemovePackageOptionsT
+ {
+ RemovePackageOptions() = default;
+
+ bool PreserveApplicationData();
+ void PreserveApplicationData(bool value);
+ bool PreserveRoamableApplicationData();
+ void PreserveRoamableApplicationData(bool value);
+ bool RemoveForAllUsers();
+ void RemoveForAllUsers(bool value);
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority Priority();
+ void Priority(winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority const& value);
+
+ private:
+ bool m_preserveApplicationData{};
+ bool m_preserveRoamableApplicationData{};
+ bool m_removeForAllUsers{};
+ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority m_priority{ winrt::Microsoft::Windows::Management::Deployment::DeploymentPriority::Normal };
+ };
+}
+namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation
+{
+ struct RemovePackageOptions : RemovePackageOptionsT
+ {
+ };
+}
diff --git a/dev/PackageManager/API/M.W.M.D.StagePackageOptions.cpp b/dev/PackageManager/API/M.W.M.D.StagePackageOptions.cpp
new file mode 100644
index 0000000000..a743fb09d7
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.StagePackageOptions.cpp
@@ -0,0 +1,126 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+
+#include "M.W.M.D.StagePackageOptions.h"
+#include "Microsoft.Windows.Management.Deployment.StagePackageOptions.g.cpp"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume StagePackageOptions::TargetVolume()
+ {
+ return m_targetVolume;
+ }
+ void StagePackageOptions::TargetVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value)
+ {
+ m_targetVolume = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector StagePackageOptions::DependencyPackageUris()
+ {
+ if (!m_dependencyPackageUris)
+ {
+ m_dependencyPackageUris = winrt::single_threaded_vector();
+ }
+ return m_dependencyPackageUris;
+ }
+ winrt::Windows::Foundation::Collections::IVector StagePackageOptions::OptionalPackageFamilyNames()
+ {
+ if (!m_optionalPackageFamilyNames)
+ {
+ m_optionalPackageFamilyNames = winrt::single_threaded_vector();
+ }
+ return m_optionalPackageFamilyNames;
+ }
+ winrt::Windows::Foundation::Collections::IVector StagePackageOptions::OptionalPackageUris()
+ {
+ if (!m_optionalPackageUris)
+ {
+ m_optionalPackageUris = winrt::single_threaded_vector();
+ }
+ return m_optionalPackageUris;
+ }
+ winrt::Windows::Foundation::Collections::IVector StagePackageOptions::RelatedPackageUris()
+ {
+ if (!m_relatedPackageUris)
+ {
+ m_relatedPackageUris = winrt::single_threaded_vector();
+ }
+ return m_relatedPackageUris;
+ }
+ winrt::Windows::Foundation::Uri StagePackageOptions::ExternalLocationUri()
+ {
+ return m_externalLocationUri;
+ }
+ void StagePackageOptions::ExternalLocationUri(winrt::Windows::Foundation::Uri const& value)
+ {
+ m_externalLocationUri = value;
+ }
+ winrt::Microsoft::Windows::Management::Deployment::StubPackageOption StagePackageOptions::StubPackageOption()
+ {
+ return m_stubPackageOption;
+ }
+ void StagePackageOptions::StubPackageOption(winrt::Microsoft::Windows::Management::Deployment::StubPackageOption const& value)
+ {
+ m_stubPackageOption = value;
+ }
+ bool StagePackageOptions::DeveloperMode()
+ {
+ return m_developerMode;
+ }
+ void StagePackageOptions::DeveloperMode(bool value)
+ {
+ m_developerMode = value;
+ }
+ bool StagePackageOptions::ForceUpdateFromAnyVersion()
+ {
+ return m_forceUpdateFromAnyVersion;
+ }
+ void StagePackageOptions::ForceUpdateFromAnyVersion(bool value)
+ {
+ m_forceUpdateFromAnyVersion = value;
+ }
+ bool StagePackageOptions::InstallAllResources()
+ {
+ return m_installAllResources;
+ }
+ void StagePackageOptions::InstallAllResources(bool value)
+ {
+ m_installAllResources = value;
+ }
+ bool StagePackageOptions::RequiredContentGroupOnly()
+ {
+ return m_requiredContentGroupOnly;
+ }
+ void StagePackageOptions::RequiredContentGroupOnly(bool value)
+ {
+ m_requiredContentGroupOnly = value;
+ }
+ bool StagePackageOptions::StageInPlace()
+ {
+ return m_stageInPlace;
+ }
+ void StagePackageOptions::StageInPlace(bool value)
+ {
+ m_stageInPlace = value;
+ }
+ bool StagePackageOptions::AllowUnsigned()
+ {
+ return m_allowUnsigned;
+ }
+ void StagePackageOptions::AllowUnsigned(bool value)
+ {
+ m_allowUnsigned = value;
+ }
+ bool StagePackageOptions::IsExpectedDigestsSupported()
+ {
+ // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
+ return WindowsVersion::IsWindows11_22H2OrGreater();
+ }
+ winrt::Windows::Foundation::Collections::IMap StagePackageOptions::ExpectedDigests()
+ {
+ return m_expectedDigests;
+ }
+}
diff --git a/dev/PackageManager/API/M.W.M.D.StagePackageOptions.h b/dev/PackageManager/API/M.W.M.D.StagePackageOptions.h
new file mode 100644
index 0000000000..5ccd499753
--- /dev/null
+++ b/dev/PackageManager/API/M.W.M.D.StagePackageOptions.h
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Microsoft.Windows.Management.Deployment.StagePackageOptions.g.h"
+
+namespace winrt::Microsoft::Windows::Management::Deployment::implementation
+{
+ struct StagePackageOptions : StagePackageOptionsT
+ {
+ StagePackageOptions() = default;
+
+ winrt::Microsoft::Windows::Management::Deployment::PackageVolume TargetVolume();
+ void TargetVolume(winrt::Microsoft::Windows::Management::Deployment::PackageVolume const& value);
+ winrt::Windows::Foundation::Collections::IVector DependencyPackageUris();
+ winrt::Windows::Foundation::Collections::IVector OptionalPackageFamilyNames();
+ winrt::Windows::Foundation::Collections::IVector