获取“现代”图标;Windows应用程序从桌面应用程序

本文关键字:应用程序 Windows 桌面 图标 现代 获取 | 更新日期: 2023-09-27 18:09:01

我开发了一个函数,它返回给定窗口句柄的窗口图标。它是这样的。

private static BitmapSource GetWindowIcon(IntPtr windowHandle)
{
    var hIcon = default(IntPtr);
    hIcon = SendMessage(windowHandle, WM_GETICON, ICON_BIG, IntPtr.Zero);
    if (hIcon == IntPtr.Zero)
        hIcon = GetClassLongPtr(windowHandle, GCL_HICON);
    if (hIcon == IntPtr.Zero)
    {
        hIcon = LoadIcon(IntPtr.Zero, (IntPtr)0x7F00/*IDI_APPLICATION*/);
    }
    if (hIcon != IntPtr.Zero)
    {
        return Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
    } else {
        throw new InvalidOperationException("Could not load window icon.");
    }
}

我将此函数与GetForegroundWindow结合使用以获得活动窗口的图标。

然而,它似乎为通用应用程序产生了同样沉闷的图标。

是否有可能以某种方式从正在运行的通用应用程序中获取平铺图像或图标?

获取“现代”图标;Windows应用程序从桌面应用程序

下面是一些示例代码,演示如何做到这一点。注意:

  1. 你应该运行这个升级,否则你将无法访问文件夹与应用程序资源(我想,没有真正检查自己,因为调查的事情,我授予自己访问该文件夹)。
  2. 现代应用程序在ApplicationFrameHost主机进程下运行。您将需要一些技巧来获得实际的可执行文件(如Calculator.exe),这些技巧在代码中被注释。
  3. 现代应用程序清单包含路径的标志,但可能有几个标志(黑色,白色,白色结构为例)。你需要一些逻辑来选择一个。我自己没有详细调查过。
  4. 我在Windows 10的计算器应用程序上测试了这个,它工作得很好。但是,当然需要更多的应用程序进行更多的测试,以确保一切正常。

代码如下:

public static class IconHelper {
    public static BitmapSource GetForegroundWindowIcon() {
        var hwnd = GetForegroundWindow();
        uint pid;
        GetWindowThreadProcessId(hwnd, out pid);
        Process proc = Process.GetProcessById((int) pid);
        // modern apps run under ApplicationFrameHost host process in windows 10
        // don't forget to check if that is true for windows 8 - maybe they use another host there
        if (proc.MainModule.ModuleName == "ApplicationFrameHost.exe") {
            // this should be modern app
            return GetModernAppLogo(hwnd);
        }
        return GetWindowIcon(hwnd);
    }
    public static BitmapSource GetModernAppLogo(IntPtr hwnd) {
        // get folder where actual app resides
        var exePath = GetModernAppProcessPath(hwnd); 
        var dir = System.IO.Path.GetDirectoryName(exePath);
        var manifestPath = System.IO.Path.Combine(dir, "AppxManifest.xml");            
        if (File.Exists(manifestPath)) {
            // this is manifest file
            string pathToLogo;
            using (var fs = File.OpenRead(manifestPath)) {
                var manifest = XDocument.Load(fs);
                const string ns = "http://schemas.microsoft.com/appx/manifest/foundation/windows10";
                // rude parsing - take more care here
                pathToLogo = manifest.Root.Element(XName.Get("Properties", ns)).Element(XName.Get("Logo", ns)).Value;
            }
            // now here it is tricky again - there are several files that match logo, for example
            // black, white, contrast white. Here we choose first, but you might do differently
            string finalLogo = null;
            // serach for all files that match file name in Logo element but with any suffix (like "Logo.black.png, Logo.white.png etc)
            foreach (var logoFile in Directory.GetFiles(System.IO.Path.Combine(dir, System.IO.Path.GetDirectoryName(pathToLogo)),
                System.IO.Path.GetFileNameWithoutExtension(pathToLogo) + "*" + System.IO.Path.GetExtension(pathToLogo))) {
                finalLogo = logoFile;
                break;
            }
            if (System.IO.File.Exists(finalLogo)) {
                using (var fs = File.OpenRead(finalLogo)) {
                    var img = new BitmapImage() {
                    };
                    img.BeginInit();
                    img.StreamSource = fs;
                    img.CacheOption = BitmapCacheOption.OnLoad;
                    img.EndInit();
                    return img;
                }
            }
        }
        return null;
    }
    private static string GetModernAppProcessPath(IntPtr hwnd) {
        uint pid = 0;
        GetWindowThreadProcessId(hwnd, out pid);            
        // now this is a bit tricky. Modern apps are hosted inside ApplicationFrameHost process, so we need to find
        // child window which does NOT belong to this process. This should be the process we need
        var children = GetChildWindows(hwnd);
        foreach (var childHwnd in children) {
            uint childPid = 0;
            GetWindowThreadProcessId(childHwnd, out childPid);
            if (childPid != pid) {
                // here we are
                Process childProc = Process.GetProcessById((int) childPid);
                return childProc.MainModule.FileName;
            }
        }
        throw new Exception("Cannot find a path to Modern App executable file");
    }
    public static BitmapSource GetWindowIcon(IntPtr windowHandle) {
        var hIcon = default(IntPtr);
        hIcon = SendMessage(windowHandle, WM_GETICON, (IntPtr) ICON_BIG, IntPtr.Zero);
        if (hIcon == IntPtr.Zero)
            hIcon = GetClassLongPtr(windowHandle, GCL_HICON);
        if (hIcon == IntPtr.Zero) {
            hIcon = LoadIcon(IntPtr.Zero, (IntPtr) 0x7F00 /*IDI_APPLICATION*/);
        }
        if (hIcon != IntPtr.Zero) {
            return Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        else {
            throw new InvalidOperationException("Could not load window icon.");
        }
    }
    #region Helper methods
    const UInt32 WM_GETICON = 0x007F;
    const int ICON_BIG = 1;
    const int GCL_HICON = -14;
    private static List<IntPtr> GetChildWindows(IntPtr parent)
    {
        List<IntPtr> result = new List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc(result);
        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            if (listHandle.IsAllocated)
                listHandle.Free();
        }
        return result;
    }
    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        GCHandle gch = GCHandle.FromIntPtr(pointer);
        List<IntPtr> list = gch.Target as List<IntPtr>;
        if (list == null)
        {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        }
        list.Add(handle);
        //  You can modify this to check to see if you want to cancel the operation, then return a null here
        return true;
    }
    public delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
    [DllImport("user32.Dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumChildWindows(IntPtr parentHandle, EnumWindowProc callback, IntPtr lParam);
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId);
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    private static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex)
    {
        if (IntPtr.Size > 4)
            return GetClassLongPtr64(hWnd, nIndex);
        else
            return new IntPtr(GetClassLongPtr32(hWnd, nIndex));
    }
    [DllImport("user32.dll", EntryPoint = "GetClassLong")]
    public static extern uint GetClassLongPtr32(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")]
    public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex);
    #endregion
}

用法:

var icon = IconHelper.GetForegroundWindowIcon();

大多数"modern app"(或Windows Store应用程序,或AppX应用程序模型中的应用程序)信息可以从官方api查询。

您可以从GetPackageFullName函数开始(它获取指定进程的包全名)。一旦你得到了包的全名,你就可以使用包查询API来获取更多的信息。

这些API是原生的,所以据我所知,它们在。net框架中没有等同的。然而,它们可以通过某种方式从WinRT应用程序访问(你确实可以从标准的。net框架应用程序访问一些WinRT api,但这是一种hack)。

因此,我已经构建了一个实用程序类,它将允许您从这些应用程序中获取信息。下面是一个示例应用程序,它转储所有当前加载的Windows Store包&应用。

这些应用程序中包含的图像是特殊的,因为它们被定义为资源(资产)键,可以使用限定符进行调整以形成最终路径。如何使用限定符(HTML)命名资源,以及如何使用文件或图像资源(HTML)。

问题是你能找到的在很大程度上取决于应用程序本身,所以它不是超级容易确定什么图像你可以使用,我没有找到任何API为此,所以我已经编码了一个样本,获得最高规模的图像为一个给定的资源名称为例(FindHighestScaleQualifiedImagePath)。您可以从此路径加载WPF BitmapSource(或任何其他成像平台资源)。

    static void Main(string[] args)
    {
        foreach (var p in Process.GetProcesses())
        {
            var package = AppxPackage.FromProcess(p);
            if (package != null)
            {
                Show(0, package);
                Console.WriteLine();
                Console.WriteLine();
            }
        }
    }
    private static void Show(int indent, AppxPackage package)
    {
        string sindent = new string(' ', indent);
        Console.WriteLine(sindent + "FullName               : " + package.FullName);
        Console.WriteLine(sindent + "FamilyName             : " + package.FamilyName);
        Console.WriteLine(sindent + "IsFramework            : " + package.IsFramework);
        Console.WriteLine(sindent + "ApplicationUserModelId : " + package.ApplicationUserModelId);
        Console.WriteLine(sindent + "Path                   : " + package.Path);
        Console.WriteLine(sindent + "Publisher              : " + package.Publisher);
        Console.WriteLine(sindent + "PublisherId            : " + package.PublisherId);
        Console.WriteLine(sindent + "Logo                   : " + package.Logo);
        Console.WriteLine(sindent + "Best Logo Path         : " + package.FindHighestScaleQualifiedImagePath(package.Logo));
        Console.WriteLine(sindent + "ProcessorArchitecture  : " + package.ProcessorArchitecture);
        Console.WriteLine(sindent + "Version                : " + package.Version);
        Console.WriteLine(sindent + "PublisherDisplayName   : " + package.PublisherDisplayName);
        Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(package.PublisherDisplayName));
        Console.WriteLine(sindent + "DisplayName            : " + package.DisplayName);
        Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(package.DisplayName));
        Console.WriteLine(sindent + "Description            : " + package.Description);
        Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(package.Description));
        Console.WriteLine(sindent + "Apps                   :");
        int i = 0;
        foreach (var app in package.Apps)
        {
            Console.WriteLine(sindent + " App [" + i + "] Description       : " + app.Description);
            Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(app.Description));
            Console.WriteLine(sindent + " App [" + i + "] DisplayName       : " + app.DisplayName);
            Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(app.DisplayName));
            Console.WriteLine(sindent + " App [" + i + "] ShortName         : " + app.ShortName);
            Console.WriteLine(sindent + "   Localized           : " + package.LoadResourceString(app.ShortName));
            Console.WriteLine(sindent + " App [" + i + "] EntryPoint        : " + app.EntryPoint);
            Console.WriteLine(sindent + " App [" + i + "] Executable        : " + app.Executable);
            Console.WriteLine(sindent + " App [" + i + "] Id                : " + app.Id);
            Console.WriteLine(sindent + " App [" + i + "] Logo              : " + app.Logo);
            Console.WriteLine(sindent + " App [" + i + "] SmallLogo         : " + app.SmallLogo);
            Console.WriteLine(sindent + " App [" + i + "] StartPage         : " + app.StartPage);
            Console.WriteLine(sindent + " App [" + i + "] Square150x150Logo : " + app.Square150x150Logo);
            Console.WriteLine(sindent + " App [" + i + "] Square30x30Logo   : " + app.Square30x30Logo);
            Console.WriteLine(sindent + " App [" + i + "] BackgroundColor   : " + app.BackgroundColor);
            Console.WriteLine(sindent + " App [" + i + "] ForegroundText    : " + app.ForegroundText);
            Console.WriteLine(sindent + " App [" + i + "] WideLogo          : " + app.WideLogo);
            Console.WriteLine(sindent + " App [" + i + "] Wide310x310Logo   : " + app.Wide310x310Logo);
            Console.WriteLine(sindent + " App [" + i + "] Square310x310Logo : " + app.Square310x310Logo);
            Console.WriteLine(sindent + " App [" + i + "] Square70x70Logo   : " + app.Square70x70Logo);
            Console.WriteLine(sindent + " App [" + i + "] MinWidth          : " + app.MinWidth);
            Console.WriteLine(sindent + " App [" + i + "] Square71x71Logo   : " + app.GetStringValue("Square71x71Logzo"));
            i++;
        }
        Console.WriteLine(sindent + "Deps                   :");
        foreach (var dep in package.DependencyGraph)
        {
            Show(indent + 1, dep);
        }
    }
public sealed class AppxPackage
{
    private List<AppxApp> _apps = new List<AppxApp>();
    private IAppxManifestProperties _properties;
    private AppxPackage()
    {
    }
    public string FullName { get; private set; }
    public string Path { get; private set; }
    public string Publisher { get; private set; }
    public string PublisherId { get; private set; }
    public string ResourceId { get; private set; }
    public string FamilyName { get; private set; }
    public string ApplicationUserModelId { get; private set; }
    public string Logo { get; private set; }
    public string PublisherDisplayName { get; private set; }
    public string Description { get; private set; }
    public string DisplayName { get; private set; }
    public bool IsFramework { get; private set; }
    public Version Version { get; private set; }
    public AppxPackageArchitecture ProcessorArchitecture { get; private set; }
    public IReadOnlyList<AppxApp> Apps
    {
        get
        {
            return _apps;
        }
    }
    public IEnumerable<AppxPackage> DependencyGraph
    {
        get
        {
            return QueryPackageInfo(FullName, PackageConstants.PACKAGE_FILTER_ALL_LOADED).Where(p => p.FullName != FullName);
        }
    }
    public string FindHighestScaleQualifiedImagePath(string resourceName)
    {
        if (resourceName == null)
            throw new ArgumentNullException("resourceName");
        const string scaleToken = ".scale-";
        var sizes = new List<int>();
        string name = System.IO.Path.GetFileNameWithoutExtension(resourceName);
        string ext = System.IO.Path.GetExtension(resourceName);
        foreach (var file in Directory.EnumerateFiles(System.IO.Path.Combine(Path, System.IO.Path.GetDirectoryName(resourceName)), name + scaleToken + "*" + ext))
        {
            string fileName = System.IO.Path.GetFileNameWithoutExtension(file);
            int pos = fileName.IndexOf(scaleToken) + scaleToken.Length;
            string sizeText = fileName.Substring(pos);
            int size;
            if (int.TryParse(sizeText, out size))
            {
                sizes.Add(size);
            }
        }
        if (sizes.Count == 0)
            return null;
        sizes.Sort();
        return System.IO.Path.Combine(Path, System.IO.Path.GetDirectoryName(resourceName), name + scaleToken + sizes.Last() + ext);
    }
    public override string ToString()
    {
        return FullName;
    }
    public static AppxPackage FromWindow(IntPtr handle)
    {
        int processId;
        GetWindowThreadProcessId(handle, out processId);
        if (processId == 0)
            return null;
        return FromProcess(processId);
    }
    public static AppxPackage FromProcess(Process process)
    {
        if (process == null)
        {
            process = Process.GetCurrentProcess();
        }
        try
        {
            return FromProcess(process.Handle);
        }
        catch
        {
            // probably access denied on .Handle
            return null;
        }
    }
    public static AppxPackage FromProcess(int processId)
    {
        const int QueryLimitedInformation = 0x1000;
        IntPtr hProcess = OpenProcess(QueryLimitedInformation, false, processId);
        try
        {
            return FromProcess(hProcess);
        }
        finally
        {
            if (hProcess != IntPtr.Zero)
            {
                CloseHandle(hProcess);
            }
        }
    }
    public static AppxPackage FromProcess(IntPtr hProcess)
    {
        if (hProcess == IntPtr.Zero)
            return null;
        // hprocess must have been opened with QueryLimitedInformation
        int len = 0;
        GetPackageFullName(hProcess, ref len, null);
        if (len == 0)
            return null;
        var sb = new StringBuilder(len);
        string fullName = GetPackageFullName(hProcess, ref len, sb) == 0 ? sb.ToString() : null;
        if (string.IsNullOrEmpty(fullName)) // not an AppX
            return null;
        var package = QueryPackageInfo(fullName, PackageConstants.PACKAGE_FILTER_HEAD).First();
        len = 0;
        GetApplicationUserModelId(hProcess, ref len, null);
        sb = new StringBuilder(len);
        package.ApplicationUserModelId = GetApplicationUserModelId(hProcess, ref len, sb) == 0 ? sb.ToString() : null;
        return package;
    }
    public string GetPropertyStringValue(string name)
    {
        if (name == null)
            throw new ArgumentNullException("name");
        return GetStringValue(_properties, name);
    }
    public bool GetPropertyBoolValue(string name)
    {
        if (name == null)
            throw new ArgumentNullException("name");
        return GetBoolValue(_properties, name);
    }
    public string LoadResourceString(string resource)
    {
        return LoadResourceString(FullName, resource);
    }
    private static IEnumerable<AppxPackage> QueryPackageInfo(string fullName, PackageConstants flags)
    {
        IntPtr infoRef;
        OpenPackageInfoByFullName(fullName, 0, out infoRef);
        if (infoRef != IntPtr.Zero)
        {
            IntPtr infoBuffer = IntPtr.Zero;
            try
            {
                int len = 0;
                int count;
                GetPackageInfo(infoRef, flags, ref len, IntPtr.Zero, out count);
                if (len > 0)
                {
                    var factory = (IAppxFactory)new AppxFactory();
                    infoBuffer = Marshal.AllocHGlobal(len);
                    int res = GetPackageInfo(infoRef, flags, ref len, infoBuffer, out count);
                    for (int i = 0; i < count; i++)
                    {
                        var info = (PACKAGE_INFO)Marshal.PtrToStructure(infoBuffer + i * Marshal.SizeOf(typeof(PACKAGE_INFO)), typeof(PACKAGE_INFO));
                        var package = new AppxPackage();
                        package.FamilyName = Marshal.PtrToStringUni(info.packageFamilyName);
                        package.FullName = Marshal.PtrToStringUni(info.packageFullName);
                        package.Path = Marshal.PtrToStringUni(info.path);
                        package.Publisher = Marshal.PtrToStringUni(info.packageId.publisher);
                        package.PublisherId = Marshal.PtrToStringUni(info.packageId.publisherId);
                        package.ResourceId = Marshal.PtrToStringUni(info.packageId.resourceId);
                        package.ProcessorArchitecture = info.packageId.processorArchitecture;
                        package.Version = new Version(info.packageId.VersionMajor, info.packageId.VersionMinor, info.packageId.VersionBuild, info.packageId.VersionRevision);
                        // read manifest
                        string manifestPath = System.IO.Path.Combine(package.Path, "AppXManifest.xml");
                        const int STGM_SHARE_DENY_NONE = 0x40;
                        IStream strm;
                        SHCreateStreamOnFileEx(manifestPath, STGM_SHARE_DENY_NONE, 0, false, IntPtr.Zero, out strm);
                        if (strm != null)
                        {
                            var reader = factory.CreateManifestReader(strm);
                            package._properties = reader.GetProperties();
                            package.Description = package.GetPropertyStringValue("Description");
                            package.DisplayName = package.GetPropertyStringValue("DisplayName");
                            package.Logo = package.GetPropertyStringValue("Logo");
                            package.PublisherDisplayName = package.GetPropertyStringValue("PublisherDisplayName");
                            package.IsFramework = package.GetPropertyBoolValue("Framework");
                            var apps = reader.GetApplications();
                            while (apps.GetHasCurrent())
                            {
                                var app = apps.GetCurrent();
                                var appx = new AppxApp(app);
                                appx.Description = GetStringValue(app, "Description");
                                appx.DisplayName = GetStringValue(app, "DisplayName");
                                appx.EntryPoint = GetStringValue(app, "EntryPoint");
                                appx.Executable = GetStringValue(app, "Executable");
                                appx.Id = GetStringValue(app, "Id");
                                appx.Logo = GetStringValue(app, "Logo");
                                appx.SmallLogo = GetStringValue(app, "SmallLogo");
                                appx.StartPage = GetStringValue(app, "StartPage");
                                appx.Square150x150Logo = GetStringValue(app, "Square150x150Logo");
                                appx.Square30x30Logo = GetStringValue(app, "Square30x30Logo");
                                appx.BackgroundColor = GetStringValue(app, "BackgroundColor");
                                appx.ForegroundText = GetStringValue(app, "ForegroundText");
                                appx.WideLogo = GetStringValue(app, "WideLogo");
                                appx.Wide310x310Logo = GetStringValue(app, "Wide310x310Logo");
                                appx.ShortName = GetStringValue(app, "ShortName");
                                appx.Square310x310Logo = GetStringValue(app, "Square310x310Logo");
                                appx.Square70x70Logo = GetStringValue(app, "Square70x70Logo");
                                appx.MinWidth = GetStringValue(app, "MinWidth");
                                package._apps.Add(appx);
                                apps.MoveNext();
                            }
                            Marshal.ReleaseComObject(strm);
                        }
                        yield return package;
                    }
                    Marshal.ReleaseComObject(factory);
                }
            }
            finally
            {
                if (infoBuffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(infoBuffer);
                }
                ClosePackageInfo(infoRef);
            }
        }
    }
    public static string LoadResourceString(string packageFullName, string resource)
    {
        if (packageFullName == null)
            throw new ArgumentNullException("packageFullName");
        if (string.IsNullOrWhiteSpace(resource))
            return null;
        const string resourceScheme = "ms-resource:";
        if (!resource.StartsWith(resourceScheme))
            return null;
        string part = resource.Substring(resourceScheme.Length);
        string url;
        if (part.StartsWith("/"))
        {
            url = resourceScheme + "//" + part;
        }
        else
        {
            url = resourceScheme + "///resources/" + part;
        }
        string source = string.Format("@{{{0}? {1}}}", packageFullName, url);
        var sb = new StringBuilder(1024);
        int i = SHLoadIndirectString(source, sb, sb.Capacity, IntPtr.Zero);
        if (i != 0)
            return null;
        return sb.ToString();
    }
    private static string GetStringValue(IAppxManifestProperties props, string name)
    {
        if (props == null)
            return null;
        string value;
        props.GetStringValue(name, out value);
        return value;
    }
    private static bool GetBoolValue(IAppxManifestProperties props, string name)
    {
        bool value;
        props.GetBoolValue(name, out value);
        return value;
    }
    internal static string GetStringValue(IAppxManifestApplication app, string name)
    {
        string value;
        app.GetStringValue(name, out value);
        return value;
    }
    [Guid("5842a140-ff9f-4166-8f5c-62f5b7b0c781"), ComImport]
    private class AppxFactory
    {
    }
    [Guid("BEB94909-E451-438B-B5A7-D79E767B75D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IAppxFactory
    {
        void _VtblGap0_2(); // skip 2 methods
        IAppxManifestReader CreateManifestReader(IStream inputStream);
    }
    [Guid("4E1BD148-55A0-4480-A3D1-15544710637C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IAppxManifestReader
    {
        void _VtblGap0_1(); // skip 1 method
        IAppxManifestProperties GetProperties();
        void _VtblGap1_5(); // skip 5 methods
        IAppxManifestApplicationsEnumerator GetApplications();
    }
    [Guid("9EB8A55A-F04B-4D0D-808D-686185D4847A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IAppxManifestApplicationsEnumerator
    {
        IAppxManifestApplication GetCurrent();
        bool GetHasCurrent();
        bool MoveNext();
    }
    [Guid("5DA89BF4-3773-46BE-B650-7E744863B7E8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAppxManifestApplication
    {
        [PreserveSig]
        int GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string vaue);
    }
    [Guid("03FAF64D-F26F-4B2C-AAF7-8FE7789B8BCA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IAppxManifestProperties
    {
        [PreserveSig]
        int GetBoolValue([MarshalAs(UnmanagedType.LPWStr)]string name, out bool value);
        [PreserveSig]
        int GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string vaue);
    }
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    private static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    private static extern int SHCreateStreamOnFileEx(string fileName, int grfMode, int attributes, bool create, IntPtr reserved, out IStream stream);
    [DllImport("user32.dll")]
    private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
    [DllImport("kernel32.dll")]
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hObject);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern int OpenPackageInfoByFullName(string packageFullName, int reserved, out IntPtr packageInfoReference);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetPackageInfo(IntPtr packageInfoReference, PackageConstants flags, ref int bufferLength, IntPtr buffer, out int count);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern int ClosePackageInfo(IntPtr packageInfoReference);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetPackageFullName(IntPtr hProcess, ref int packageFullNameLength, StringBuilder packageFullName);
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetApplicationUserModelId(IntPtr hProcess, ref int applicationUserModelIdLength, StringBuilder applicationUserModelId);
    [Flags]
    private enum PackageConstants
    {
        PACKAGE_FILTER_ALL_LOADED = 0x00000000,
        PACKAGE_PROPERTY_FRAMEWORK = 0x00000001,
        PACKAGE_PROPERTY_RESOURCE = 0x00000002,
        PACKAGE_PROPERTY_BUNDLE = 0x00000004,
        PACKAGE_FILTER_HEAD = 0x00000010,
        PACKAGE_FILTER_DIRECT = 0x00000020,
        PACKAGE_FILTER_RESOURCE = 0x00000040,
        PACKAGE_FILTER_BUNDLE = 0x00000080,
        PACKAGE_INFORMATION_BASIC = 0x00000000,
        PACKAGE_INFORMATION_FULL = 0x00000100,
        PACKAGE_PROPERTY_DEVELOPMENT_MODE = 0x00010000,
    }
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    private struct PACKAGE_INFO
    {
        public int reserved;
        public int flags;
        public IntPtr path;
        public IntPtr packageFullName;
        public IntPtr packageFamilyName;
        public PACKAGE_ID packageId;
    }
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    private struct PACKAGE_ID
    {
        public int reserved;
        public AppxPackageArchitecture processorArchitecture;
        public ushort VersionRevision;
        public ushort VersionBuild;
        public ushort VersionMinor;
        public ushort VersionMajor;
        public IntPtr name;
        public IntPtr publisher;
        public IntPtr resourceId;
        public IntPtr publisherId;
    }
}
public sealed class AppxApp
{
    private AppxPackage.IAppxManifestApplication _app;
    internal AppxApp(AppxPackage.IAppxManifestApplication app)
    {
        _app = app;
    }
    public string GetStringValue(string name)
    {
        if (name == null)
            throw new ArgumentNullException("name");
        return AppxPackage.GetStringValue(_app, name);
    }
    // we code well-known but there are others (like Square71x71Logo, Square44x44Logo, whatever ...)
    // https://msdn.microsoft.com/en-us/library/windows/desktop/hh446703.aspx
    public string Description { get; internal set; }
    public string DisplayName { get; internal set; }
    public string EntryPoint { get; internal set; }
    public string Executable { get; internal set; }
    public string Id { get; internal set; }
    public string Logo { get; internal set; }
    public string SmallLogo { get; internal set; }
    public string StartPage { get; internal set; }
    public string Square150x150Logo { get; internal set; }
    public string Square30x30Logo { get; internal set; }
    public string BackgroundColor { get; internal set; }
    public string ForegroundText { get; internal set; }
    public string WideLogo { get; internal set; }
    public string Wide310x310Logo { get; internal set; }
    public string ShortName { get; internal set; }
    public string Square310x310Logo { get; internal set; }
    public string Square70x70Logo { get; internal set; }
    public string MinWidth { get; internal set; }
}
public enum AppxPackageArchitecture
{
    x86 = 0,
    Arm = 5,
    x64 = 9,
    Neutral = 11,
    Arm64 = 12
}