简体   繁体   English

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

[英]Getting icon of “modern” Windows app from a desktop application?

I have developed a function which returns the icon of the window for a given window handle. 我开发了一个函数,它返回给定窗口句柄的窗口图标。 It looks like this. 看起来像这样。

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.");
    }
}

I use this function in combination with GetForegroundWindow to get the icon of the active window. 我将此函数与GetForegroundWindow结合使用以获取活动窗口的图标。

However, it seems to produce the same dull looking icon for universal apps. 但是,它似乎为通用应用程序产生了相同的暗淡图标。

Is it possible to somehow fetch the tile image or icon from a universal app that is running? 是否有可能以某种方式从正在运行的通用应用程序中获取平铺图像或图标?

Here is some sample code demonstrating how this could be done. 以下是一些示例代码,演示如何完成此操作。 Note that: 注意:

  1. You should run this evelated, otherwise you won't be able to access folder with application resources (I think, didn't really check myself, because to investigate things I granted myself access to that folder). 你应该运行这个平均值,否则你将无法访问具有应用程序资源的文件夹(我认为,并没有真正检查自己,因为调查我授予自己访问该文件夹的内容)。
  2. Modern apps are running under ApplicationFrameHost host process. 现代应用程序在ApplicationFrameHost主机进程下运行。 You will need some tricks to get to the actual executable (like Calculator.exe), those tricks are commented in code. 您将需要一些技巧来获取实际的可执行文件(如Calculator.exe),这些技巧在代码中被注释。
  3. Modern app manifest contains path to logo, but there might be several logos (black, white, constract white as an example). 现代应用程序清单包含徽标的路径,但可能有几个徽标(黑色,白色,constract白色为例)。 You will need some logic to choose one. 你需要一些逻辑来选择一个。 Didn't investigate this myself in details. 我没有详细调查这个。
  4. I tested this on Calculator app in Windows 10 and it worked fine. 我在Windows 10中的计算器应用程序上进行了测试,它运行良好。 However of course more tests with more apps are required to ensure all is fine. 但是,当然需要更多的应用程序以确保一切正常。

Here is the code: 这是代码:

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

}

Usage is just: 用法只是:

var icon = IconHelper.GetForegroundWindowIcon();

Most of "modern app" (or Windows Store apps, or apps in the AppX application model) information can be queried from official APIs. 可以从官方API查询大多数“现代应用程序”(或Windows应用商店应用程序或AppX应用程序模型中的应用程序)信息。

You can start with the GetPackageFullName function (it gets the package full name for the specified process). 您可以从GetPackageFullName函数开始(它获取指定进程的包全名)。 Once you get a package full name, you can use the Package Query API to get more information. 获得程序包全名后,可以使用Package Query API获取更多信息。

These API are native one, so they don't have equivalent in the .NET Framework to my knowledge. 这些API是原生的,因此根据我的知识,它们在.NET Framework中没有等价物。 However, they are accessible from WinRT application somehow (and you can indeed access some of the WinRT APIs from standard .NET Framework apps, but this is kindof hack). 但是,它们可以通过某种方式从WinRT应用程序访问(并且您确实可以从标准.NET Framework应用程序访问某些WinRT API,但这很有用)。

So, I have built a utility class that will allow you to get information from these applications. 所以,我已经构建了一个实用程序类,允许您从这些应用程序中获取信息。 Here is a sample application that dumps all current loaded Windows Store packages & apps. 下面是一个示例应用程序,它转储所有当前加载的Windows应用商店包和应用。

The images contained in these apps are special, because they are defined as resources (assets) keys that can be tweaked using qualifiers to form a final path. 这些应用程序中包含的图像是特殊的,因为它们被定义为资源(​​资产)键,可以使用限定符调整它们以形成最终路径。 This is documented for example here: How to name resources using qualifiers (HTML) and here: Quickstart: Using file or image resources (HTML) . 例如,这里记录了这一点: 如何使用限定符(HTML)命名资源 ,此处: 快速入门:使用文件或图像资源(HTML)

The problem is what you can find depends heavily on the application itself, so it's not super easy to determine what image you can use and I have not found any API for this, so I have coded a sample that gets the highest scale image for a given resource name as an exemple ( FindHighestScaleQualifiedImagePath ). 你可以找到的问题在很大程度上取决于应用程序本身,因此确定你可以使用的图像并不是很容易,我没有找到任何API,所以我编写了一个样本,可以得到最高比例的图像。给定资源名称作为FindHighestScaleQualifiedImagePathFindHighestScaleQualifiedImagePath )。 You can load a WPF BitmapSource (or any other imaging platform resource) from this path. 您可以从此路径加载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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM