从桌面运行 Windows 应用商店应用






4.92/5 (9投票s)
如何从桌面应用程序使用 Windows Store 应用 - 运行、获取应用状态、停止等等。
引言
当客户问我如何从桌面运行 Windows Store 应用时,通常的答案是 – 你不能, 但如果你真的想这样做,有一种方法可以做到。
我通常回答“你不能”的原因是 – 为了从桌面运行 Windows Store 应用,你需要安装 Windows App Certification Kit,这个包包含“microsoft.windows.softwarelogo.appxlauncher.exe”文件,该文件可以通过此应用程序模型 ID 运行 Windows Store 应用。
因此,如果你计划发布你的应用,你不能假设客户端机器上安装了 ACK。
再说一遍,如果你真的想……让我给你演示一下。
步骤 1:入门
首先创建一个 WPF 项目并添加以下引用:“C:\Program Files (x86)\Windows Kits\8.0\App Certification Kit\microsoft.windows.softwarelogo.shared.dll”。
步骤 2:获取 Windows 应用列表
你需要添加对“Microsoft.Windows.Softwarelogo.Shared.dll”的引用的原因是我们可以接收程序清单 XML 文件。该文件包含所有已安装的 Windows Store 应用的完整列表。
在我的电脑上,这是文件位置
"C:\\Users\\Shai\\AppData\\Local\\Microsoft\\AppCertKit\\programinventory_e25bb752-e7cf-4fb2-8194-874ba9b91c7b.xml"
正如我所说,此文件包含您的机器上安装的所有 Windows Store 应用,该文件下的每个 Program
元素都将显示有关该特定应用的所有信息。
那么,你如何获得文件位置呢?
这很简单;使用来自 softwarelogo.shared.dll 的 GlobaldataAccessor
方法,你可以获取程序清单位置字符串。
string itemValue = GlobalDataAccessor.GetItemValue("ProgramInventoryLocation", "PRE_PROCESS");
一旦你获得了这个文件,你需要做的就是解析 XML 并创建一个应用集合。
我创建了一个 ProductInfo
类,它将表示文件中的每个程序。正如你从下面的代码中看到的那样,我只是从 Program
元素中获取属性和元素。
public class ProductInfo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _Status;
public string Status
{
get { return _Status; }
set
{
if (value != this._Status)
{
this._Status = value;
NotifyPropertyChanged("Status");
}
}
}
public string LogoUrl { get; set; }
public string ProductName { get; set; }
public string ProductVendor { get; set; }
public string ProductLanguage { get; set; }
public string ProductVersion { get; set; }
public string RootDirPath { get; set; }
public string Id { get; set; }
public string PackageFullName { get; set; }
public ProductInfo(XmlNode xNode)
{
var attrib = xNode.Attributes["Name"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) ProductName = attrib.Value;
attrib = xNode.Attributes["Version"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) ProductVersion = attrib.Value;
attrib = xNode.Attributes["Language"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) ProductLanguage = attrib.Value;
attrib = xNode.Attributes["Publisher"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) ProductVendor = attrib.Value;
attrib = xNode.Attributes["RootDirPath"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) RootDirPath = attrib.Value;
attrib = xNode.Attributes["Id"];
if (attrib != null && !string.IsNullOrEmpty(attrib.Value)) Id = attrib.Value;
var node = xNode.SelectSingleNode("/Log/ProgramList/Program[@Id='" + this.Id +
"']/Indicators/PackageManifestIndicator/Properties/Logo");
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
var imgUrl = System.IO.Path.Combine(RootDirPath, node.InnerText);
if (File.Exists(imgUrl))
LogoUrl = imgUrl;
}
node = xNode.SelectSingleNode("/Log/ProgramList/Program[@Id='" + this.Id +
"']/Indicators/PackageManifestIndicator/PackageManifest");
if (node != null && !string.IsNullOrEmpty(node.Attributes["PackageFullName"].InnerText))
{
PackageFullName = node.Attributes["PackageFullName"].InnerText;
}
}
}
现在,让我们将这两个部分连接在一起。首先是获取 ProgramInventorylocation
,然后只需加载该 XML 文件并将其解析为包含你所需信息的对象。
private void BuildAppsList()
{
string itemValue = GlobalDataAccessor.GetItemValue("ProgramInventoryLocation", "PRE_PROCESS");
XmlNodeList list = null;
var reportDoc = new XmlDocument();
reportDoc.Load(itemValue);
ProductList = new ObservableCollection<ProductInfo>();
list = reportDoc.GetElementsByTagName("Program");
if (list.Count < 1)
{
throw new XmlException();
}
foreach (XmlNode node in list)
{
ProductInfo item = new ProductInfo(node);
ProductList.Add(item);
}
dbTable.ItemsSource = ProductList;
}
步骤 3:获取应用用户模型 ID
现在,在你获取了所有已安装在你的机器上的 Windows Store 应用之后,是时候运行它们了。为了运行 Windows Store 应用,你需要获取 AppUserModelId
,你需要 AppUserModelId
的原因是 appxlauncher.exe 需要这个值才能启动应用程序(包名称是不够的)。
在完成步骤 2 后,我们获得了应用包全名,我们需要使用此值从注册表中查找 AppUserModelId
。
HKEY_CURRENT_USER\Software\Classes\ActivatableClasses\Package\**PackageFullName**\Server
所以让我们添加以下方法。此方法接收一个 packageFullName
字符串,并在注册表中搜索 AppUserModelId
。
public static string GetAppUserModelId(string packageFullName)
{
string str = string.Empty;
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(string.Format(
@"SOFTWARE\Classes\ActivatableClasses\Package\{0}\Server\",
packageFullName)))
{
if (key == null) return str;
var appKeys = from k in key.GetSubKeyNames()
where !k.StartsWith("BackgroundTransferHost")
select k;
foreach (var appKey in appKeys)
{
using (RegistryKey serverKey = key.OpenSubKey(appKey))
{
if (serverKey.GetValue("AppUserModelId") != null)
{
str = serverKey.GetValue("AppUserModelId").ToString();
serverKey.Close();
break;
}
}
}
}
return str;
}
步骤 4:运行 Windows Store 应用
在我们拥有特定 Windows Store 应用的 AppUserModelId
字符串之后,我们就可以运行它了。
你可以通过打开命令行并编写以下内容来测试它
C:\Program Files (x86)\Windows Kits\8.0\App Certification Kit\
Microsoft.Windows.SoftwareLogo.AppxLauncher.exe “AppUserModelId”
开始按钮代码
private void StartApp_Click(object sender, RoutedEventArgs e)
{
var product = ((System.Windows.Controls.Button)sender).Tag as ProductInfo;
var appUserModelId = Helpers.GetAppUserModelId(product.PackageFullName);
var exec = @"C:\Program Files (x86)\Windows Kits\8.0\App Certification Kit\Microsoft.Windows.SoftwareLogo.AppxLauncher.exe";
if (!File.Exists(exec))
{
System.Windows.MessageBox.Show("Please install Windows App Certification Kit for Windows RT");
}
var processInfo = new ProcessStartInfo()
{
Arguments = appUserModelId,
UseShellExecute = false,
CreateNoWindow = true,
FileName = exec
};
Process.Start(processInfo);
}
步骤 5:获取应用程序状态
你可能想要的最后一件事是知道应用的执行状态。为此,你需要使用 IPackageDebugSettings
- 允许调试器开发人员控制 Windows Store 应用的生命周期,例如何时挂起或恢复 (http://msdn.microsoft.com/en-us/library/hh438393(v=vs.85).aspx)。
为此,创建一个具有以下代码的 PackageStatushelper
类
public class PackageStatusHelper
{
[ComImport, Guid("B1AEC16F-2383-4852-B0E9-8F0B1DC66B4D")]
public class PackageDebugSettings
{
}
public enum PACKAGE_EXECUTION_STATE
{
PES_UNKNOWN,
PES_RUNNING,
PES_SUSPENDING,
PES_SUSPENDED,
PES_TERMINATED
}
[ComImport, Guid("F27C3930-8029-4AD1-94E3-3DBA417810C1"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPackageDebugSettings
{
int EnableDebugging([MarshalAs(UnmanagedType.LPWStr)] string packageFullName, [MarshalAs(UnmanagedType.LPWStr)]
string debuggerCommandLine, IntPtr environment);
int DisableDebugging([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int Suspend([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int Resume([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int TerminateAllProcesses([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int SetTargetSessionId(int sessionId);
int EnumerageBackgroundTasks([MarshalAs(UnmanagedType.LPWStr)] string packageFullName,
out uint taskCount, out int intPtr, [Out] string[] array);
int ActivateBackgroundTask(IntPtr something);
int StartServicing([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int StopServicing([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int StartSessionRedirection([MarshalAs(UnmanagedType.LPWStr)] string packageFullName, uint sessionId);
int StopSessionRedirection([MarshalAs(UnmanagedType.LPWStr)] string packageFullName);
int GetPackageExecutionState([MarshalAs(UnmanagedType.LPWStr)] string packageFullName,
out PACKAGE_EXECUTION_STATE packageExecutionState);
int RegisterForPackageStateChanges([MarshalAs(UnmanagedType.LPWStr)] string packageFullName,
IntPtr pPackageExecutionStateChangeNotification, out uint pdwCookie);
int UnregisterForPackageStateChanges(uint dwCookie);
}
public static PACKAGE_EXECUTION_STATE GetPackageExecutionState(string packageFullName)
{
PACKAGE_EXECUTION_STATE packageExecutionState = PACKAGE_EXECUTION_STATE.PES_UNKNOWN;
PackageDebugSettings settings = new PackageDebugSettings();
IPackageDebugSettings settings2 = (IPackageDebugSettings)settings;
try
{
if (settings2.GetPackageExecutionState(packageFullName, out packageExecutionState) != 0)
{
System.Windows.MessageBox.Show("Failed to get package execution state.", "GetPackageExecutionState");
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message, "GetPackageExecutionState");
}
return packageExecutionState;
}
}
并且从应用程序中,你只需调用 GetPackageExecutionState
并传递包全名
private void GetAppStatus_Click(object sender, RoutedEventArgs e)
{
var btn = (System.Windows.Controls.Button)sender;
var product = btn.Tag as ProductInfo;
var status = PackageStatusHelper.GetPackageExecutionState(product.PackageFullName);
switch (status)
{
case PackageStatusHelper.PACKAGE_EXECUTION_STATE.PES_RUNNING:
btn.Foreground = new SolidColorBrush(Colors.Green);
btn.Content = "Running";
break;
case PackageStatusHelper.PACKAGE_EXECUTION_STATE.PES_SUSPENDED:
btn.Foreground = new SolidColorBrush(Colors.Orange);
btn.Content = "Suspended";
break;
case PackageStatusHelper.PACKAGE_EXECUTION_STATE.PES_TERMINATED:
btn.Foreground = new SolidColorBrush(Colors.Red);
btn.Content = "Terminated";
break;
default:
btn.Foreground = new SolidColorBrush(Colors.Gray);
btn.Content = "Unkown";
break;
}
}
兴趣点
- Windows App Certification Kit - http://msdn.microsoft.com/en-US/windows/apps/jj572486。