65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (9投票s)

2013年2月7日

CPOL

3分钟阅读

viewsIcon

55533

downloadIcon

1035

如何从桌面应用程序使用 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;
    }
} 

兴趣点 

© . All rights reserved.