Files
PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/ProcessPackagingInspector.cs
Jiří Polášek 07b8915e19 CmdPal: Remove dead code from Window Walker and cleanup (#45570)
## Summary of the Pull Request

This PR is a light cleanup on Window Walker built-in extension:

- Removes unused types
- Removes redundant code
- Fixes inconsistent naming conventions
- De-LINQ-ify
- Fixes XML doc
- Updates language constructs to the latest (use of
System.Threading.Lock, Collection expressions)
- Updates types and members visibility and makes static classes static

⚠️ Trickiest part are 44ac1c1 and 26c946c that removes redundant null
checks.
2026-02-24 06:29:58 -06:00

122 lines
3.8 KiB
C#

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
internal static class ProcessPackagingInspector
{
#pragma warning disable SA1310 // Field names should not contain underscore
private const int ERROR_INSUFFICIENT_BUFFER = 122;
private const int APPMODEL_ERROR_NO_PACKAGE = 15700;
#pragma warning restore SA1310 // Field names should not contain underscore
/// <summary>
/// Inspect a process by PID and classify its packaging.
/// </summary>
public static ProcessPackagingInfo Inspect(int pid)
{
var hProcess = NativeMethods.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, pid);
using var process = new SafeProcessHandle(hProcess, true);
if (process.IsInvalid)
{
return new ProcessPackagingInfo(
pid,
ProcessPackagingKind.Unknown,
HasPackageIdentity: false,
IsAppContainer: false,
PackageFullName: null,
LastError: Marshal.GetLastPInvokeError());
}
// 1) Check package identity
var hasPackage = TryGetPackageFullName(process, out var packageFullName, out _);
// 2) If packaged, check AppContainer -> strict UWP
var isAppContainer = false;
int? tokenErr = null;
if (hasPackage)
{
isAppContainer = TryIsAppContainer(process, out tokenErr);
}
var kind =
!hasPackage ? ProcessPackagingKind.UnpackagedWin32 :
isAppContainer ? ProcessPackagingKind.UwpApp :
ProcessPackagingKind.PackagedWin32;
return new ProcessPackagingInfo(
pid,
kind,
HasPackageIdentity: hasPackage,
IsAppContainer: isAppContainer,
PackageFullName: packageFullName,
LastError: null);
}
private static bool TryGetPackageFullName(SafeProcessHandle hProcess, out string? packageFullName, out int? lastError)
{
packageFullName = null;
lastError = null;
uint len = 0;
var rc = NativeMethods.GetPackageFullName(hProcess, ref len, null);
if (rc == APPMODEL_ERROR_NO_PACKAGE)
{
return false; // no package identity
}
if (rc != ERROR_INSUFFICIENT_BUFFER && rc != 0)
{
lastError = rc;
return false; // unexpected error
}
if (len == 0)
{
return false;
}
var sb = new StringBuilder((int)len);
rc = NativeMethods.GetPackageFullName(hProcess, ref len, sb);
if (rc == 0)
{
packageFullName = sb.ToString();
return true;
}
lastError = rc;
return false;
}
private static bool TryIsAppContainer(SafeProcessHandle hProcess, out int? lastError)
{
lastError = null;
if (!NativeMethods.OpenProcessToken(hProcess, TokenAccess.TOKEN_QUERY, out var token))
{
lastError = Marshal.GetLastPInvokeError();
return false; // can't decide; treat as not-UWP for classification
}
using (token)
{
if (!NativeMethods.GetTokenInformation(
token,
TOKEN_INFORMATION_CLASS.TokenIsAppContainer,
out var val,
sizeof(int),
out _))
{
lastError = Marshal.GetLastPInvokeError();
return false;
}
return val != 0; // true => AppContainer (UWP)
}
}
}