commit bba4994c747dee8b6d558bfb3d7e5677b2188c9d
parent e8b8f31f948531a11b170fc17d270381d97c67c8
Author: KEINOS <github+fork-qiita-news@keinos.com>
Date: Fri, 13 Jun 2025 02:16:37 +0000
Merge remote-tracking branch 'upstream/master'
Diffstat:
5 files changed, 115 insertions(+), 17 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
@@ -64,7 +64,6 @@ jobs:
buildOutDirAnyCpu: $(Build.SourcesDirectory)\src\AnyCPU\$(buildConfiguration)
artifactsDir: $(Build.ArtifactStagingDirectory)\$(buildPlatform)
appxPackageDir: $(Build.ArtifactStagingDirectory)\$(buildPlatform)\AppxPackages
- packageLayoutDir: $(Build.BinariesDirectory)\WingetPackageLayout
steps:
- task: NuGetToolInstaller@1
@@ -153,7 +152,6 @@ jobs:
displayName: 'Copy specific build artifacts'
inputs:
Contents: |
- $(buildOutDir)\WindowsPackageManager\WindowsPackageManager.pdb
$(buildOutDir)\WinGetUtil\WinGetUtil.dll
$(buildOutDir)\WinGetUtil\WinGetUtil.pdb
TargetFolder: '$(artifactsDir)'
@@ -162,22 +160,10 @@ jobs:
displayName: Create Package Layout
inputs:
filePath: 'src\AppInstallerCLIPackage\Execute-AppxRecipe.ps1'
- arguments: '-AppxRecipePath AppInstallerCLIPackage\bin\$(buildPlatform)\$(buildConfiguration)\AppInstallerCLIPackage.build.appxrecipe -LayoutPath $(packageLayoutDir) -Force -Verbose'
+ arguments: '-AppxRecipePath AppInstallerCLIPackage\bin\$(buildPlatform)\$(buildConfiguration)\AppInstallerCLIPackage.build.appxrecipe -LayoutPath $(artifactsDir)\DevPackage -Force -Verbose'
workingDirectory: 'src'
- task: CopyFiles@2
- displayName: 'Copy Dev Package (Loose Files)'
- inputs:
- SourceFolder: '$(packageLayoutDir)'
- TargetFolder: '$(artifactsDir)\DevPackage'
-
- - task: DeleteFiles@1
- displayName: Clean up Package Layout after copy
- inputs:
- SourceFolder: '$(packageLayoutDir)'
- Contents: '**/*'
-
- - task: CopyFiles@2
displayName: 'Copy native binaries for Microsoft.WinGet.Client (net8)'
inputs:
SourceFolder: $(buildOutDir)
diff --git a/src/ConfigurationRemotingServer/ConfigurationRemotingServer.csproj b/src/ConfigurationRemotingServer/ConfigurationRemotingServer.csproj
@@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows10.0.26100.0</TargetFramework>
+ <UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
diff --git a/src/ConfigurationRemotingServer/Program.cs b/src/ConfigurationRemotingServer/Program.cs
@@ -8,6 +8,8 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Management.Configuration;
using Microsoft.Management.Configuration.Processor;
+using Microsoft.Management.Configuration.Processor.Helpers;
+using Microsoft.Win32;
using WinRT;
using IConfigurationSetProcessorFactory = global::Microsoft.Management.Configuration.IConfigurationSetProcessorFactory;
@@ -79,6 +81,18 @@ namespace ConfigurationRemotingServer
string staticsCallback = args[1];
+ // Listen for setting change message and update PATH if needed.
+ HiddenForm hiddenForm = new HiddenForm();
+ var settingChangedListenerThread = new Thread(
+ () =>
+ {
+ SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged;
+ Application.Run(hiddenForm);
+ SystemEvents.UserPreferenceChanged -= OnUserPreferenceChanged;
+ });
+
+ settingChangedListenerThread.Start();
+
try
{
string completionEventName = args[2];
@@ -147,11 +161,32 @@ namespace ConfigurationRemotingServer
return WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(0, factoryInterface.ThisPtr, staticsCallback, completionEventName, parentProcessId);
}
- catch(Exception ex)
+ catch (Exception ex)
{
WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(ex.HResult, IntPtr.Zero, staticsCallback, null, 0);
return ex.HResult;
}
+ finally
+ {
+ hiddenForm.BeginInvoke(new Action(() => { hiddenForm.Close(); }));
+ settingChangedListenerThread.Join();
+ }
+ }
+
+ private class HiddenForm : Form
+ {
+ public HiddenForm()
+ {
+ this.Width = 0;
+ this.Height = 0;
+ this.Visible = false;
+ this.Load += (sender, e) => this.Hide();
+ }
+ }
+
+ private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
+ {
+ PathEnvironmentVariableHandler.UpdatePath();
}
private class LimitationSetMetadata
diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Helpers/ProcessExecution.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Helpers/ProcessExecution.cs
@@ -11,6 +11,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers
using System.Diagnostics;
using System.Text;
using System.Threading;
+ using Microsoft.Management.Configuration.Processor.Helpers;
/// <summary>
/// Wrapper for a single process execution and its output.
@@ -134,7 +135,13 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers
throw new InvalidOperationException("Process has already been started.");
}
- ProcessStartInfo startInfo = new ProcessStartInfo(this.ExecutablePath, this.SerializedArguments);
+ ProcessStartInfo startInfo;
+
+ lock (PathEnvironmentVariableHandler.Lock)
+ {
+ startInfo = new ProcessStartInfo(this.ExecutablePath, this.SerializedArguments);
+ }
+
this.Process = new Process() { StartInfo = startInfo };
startInfo.UseShellExecute = false;
diff --git a/src/Microsoft.Management.Configuration.Processor/Public/PathEnvironmentVariableHandler.cs b/src/Microsoft.Management.Configuration.Processor/Public/PathEnvironmentVariableHandler.cs
@@ -0,0 +1,69 @@
+// -----------------------------------------------------------------------------
+// <copyright file="PathEnvironmentVariableHandler.cs" company="Microsoft Corporation">
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+// </copyright>
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.Management.Configuration.Processor.Helpers
+{
+ using System;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Class for handling PATH environment variable.
+ /// </summary>
+ public static class PathEnvironmentVariableHandler
+ {
+ private const string PathEnvironmentVariable = "PATH";
+
+ private static readonly object EnvironmentVariableLock = new object();
+
+ /// <summary>
+ /// Gets the lock to read or write PATH environment variable.
+ /// </summary>
+ public static object Lock
+ {
+ get { return EnvironmentVariableLock; }
+ }
+
+ /// <summary>
+ /// Updates the process's PATH environment variable if new paths added.
+ /// Only adds new paths since we add to PATH in other code which may not be in the registry.
+ /// </summary>
+ public static void UpdatePath()
+ {
+ HashSet<string> paths = new HashSet<string>(Environment.GetEnvironmentVariable(PathEnvironmentVariable)?.Split(';') ?? Array.Empty<string>());
+ var originalPathsSize = paths.Count;
+
+ AddPathsIfNotExist(paths, Environment.GetEnvironmentVariable(PathEnvironmentVariable, EnvironmentVariableTarget.Machine)?.Split(';'));
+ AddPathsIfNotExist(paths, Environment.GetEnvironmentVariable(PathEnvironmentVariable, EnvironmentVariableTarget.User)?.Split(';'));
+
+ if (paths.Count > originalPathsSize)
+ {
+ lock (Lock)
+ {
+ Environment.SetEnvironmentVariable(PathEnvironmentVariable, string.Join(';', paths));
+ }
+ }
+ }
+
+ // TODO: Currently it always adds new paths to the end. The "proper" thing to do would probably be to calculate
+ // the full new list of paths (what one would expect to get from a new process launch) and use a line merge algorithm
+ // with a strategy that puts the ephemeral entries before the new permanent ones.
+#pragma warning disable SA1011 // Closing square brackets should be spaced correctly
+ private static void AddPathsIfNotExist(HashSet<string> currentPaths, string[]? paths)
+#pragma warning restore SA1011 // Closing square brackets should be spaced correctly
+ {
+ if (paths is not null)
+ {
+ foreach (var path in paths)
+ {
+ if (!currentPaths.Contains(path))
+ {
+ currentPaths.Add(path);
+ }
+ }
+ }
+ }
+ }
+}