大多数“现代应用程序”(或Windows商店应用程序,或AppX应用程序模型中的应用程序)的信息可以从官方API中查询。
您可以从GetPackageFullName函数 开始(它获取指定进程的包全名)。一旦您获得一个包全名,您就可以使用Package Query API获取更多信息。
这些API是本机的,所以据我所知,在.NET Framework中它们没有相应的等效物。但是,它们在某种程度上可以从WinRT应用程序中访问(并且您确实可以从标准的.NET Framework应用程序中访问其中的一些WinRT API,但这有点像黑客行为)。
因此,我构建了一个实用类,允许您从这些应用程序中获取信息。这里有一个示例应用程序,可以转储所有当前加载的Windows商店包和应用程序。
这些应用程序中包含的图像是特殊的,因为它们被定义为资源(资产)键,可以使用限定符进行调整以形成最终路径。例如,这在如何使用限定符为资源命名(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
{
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;
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))
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);
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();
IAppxManifestReader CreateManifestReader(IStream inputStream);
}
[Guid("4E1BD148-55A0-4480-A3D1-15544710637C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAppxManifestReader
{
void _VtblGap0_1();
IAppxManifestProperties GetProperties();
void _VtblGap1_5();
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);
}
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
}