利用 Win32 启动和检测 UWP App 的方法

简介: 原文:利用 Win32 启动和检测 UWP App 的方法一种启动和检测 UWP 应用的方法 背景 我们发布过多款 UWP 平台的同类型 App ,最近有一个需求:用传统 Win32 程序启动我们的 UWP 程序。
原文: 利用 Win32 启动和检测 UWP App 的方法

一种启动和检测 UWP 应用的方法

背景

我们发布过多款 UWP 平台的同类型 App ,最近有一个需求:用传统 Win32 程序启动我们的 UWP 程序。因为我们的每一个UWP App在客户机器上都是互斥的,也就是同时只能存在一个,并且我们的win32程序也只有一个版本,所以启动 UWP App 时,需要先检测,再启动。

我们大概有4个办法,前3个比较扯,第4个目前可行,也是我们采用的。这4个方法的主要关注点是:如何检测客户机器上是否有我们的 UWP App。至于调用,方法比较简单。

Solution 1

Win32 和 UWP 交互,首先想到的就是微软的 Desktop Bridge 相关的内容,找了一圈,倒是发现了 Win32 调用 UWP Api 的方法,不过可以调用的 Api 有限,而且文档比较残缺,最麻烦的就是要对 Win32 Project 配置修改,引入一堆 WinRT 的东西。尝试了半天,终于不报错了,但是运行时会奔溃,原因未知,有待继续探索。而且比较存疑的是官方文档有矛盾,我们用到的 Windows.System.Launcher Api 是否被这种调用方式支持不明确,因为报错我们也无法验证。

有兴趣的小伙伴可以参考以下链接:

Desktop Bridge

Detect UWP App

Solution 2

简单粗暴,直接检测 UWP 的安装目录。一般 UWP 的默认安装路径就是 "C:\Program Files\WindowsApps"。这种方法真的很简单粗暴,但是有几个缺点:

  1. 可能有强迫症用户修改了 UWP 的安装路径。这种情况下,需要自行去查注册表,当然注册表键值是什么就需要baidu了;
  2. 如果直接枚举 "C:\Program Files\WindowsApps"的子目录,会有权限问题(System),普通用户权限只能访问类似 "C:\Program Files\WindowsApps\microsoft.windowscommunicationsapps_17.9126.21695.0_x64__8wekyb3d8bbwe"的特定 UWP App 目录,这就需要我们提前确定要查找的 UWP App的 pfn (package family name,UWP App 的特定标识,全球唯一)和版本,但是版本因为经常变化,比较不好确定。

Solution 3 (Solution 1和这个差不多)

微软为我们提供了许多启动 UWP 的方式,比如什么协议启动,命令行启动等,但是这些方法的使用前提是:我们的UWP app需要修改现有的 App Manifest,这对于已经发布出去的UWP App,显然是不可能的。(在我们的场景下,因为我们的 UWP App 和驱动绑定,一般随驱动升级,比较稳定,所以此方法不可用)

Solution 4 (Best solution)

隐约记得以前使用 Fiddler 的时候,有一个 WinConfig 功能,可以列出当前电脑上所有的 UWP 程序(实际上是 沙箱类程序,从 Windows 8 开始, UWP 也包含其中),然后可以进行 web 调试。所以就想能不能借鉴 Fiddler 的做法。然后理所应当的发现 Fiddler 安装目录下面有一个名为 EnableLoopback.exe 的程序,没有为什么,我就把它丢到了ILSpy里面,完美的反编译出了C#代码,然后经过一番探索,发现了AppContainer类,无论看类名还是类的定义,都很明确,这就是我们要找的东西,然后顺着这个类看下去,找到了它获取所有 UWP 程序的方法:通过 FirewallAPI.dll 里面的接口 NetworkIsolationEnumAppContainers 来枚举。

AppContainer

有了了解,开始Coding!

BTW,如果想省事儿的话,直接把这个类相关的内容导出,是可以直接用的。不过我们的 Win32 是用C++写的,所以要稍稍转换一下。

C++代码如下:

#include <Netfw.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
namespace Launcher
{
    typedef DWORD(*pNetworkIsolationEnumAppContainers)(
        _In_  DWORD                        Flags,
        _Out_ DWORD                        *pdwNumPublicAppCs,
        _Out_ PINET_FIREWALL_APP_CONTAINER *ppPublicAppCs
        );
    typedef DWORD(*pNetworkIsolationFreeAppContainers)(
        _In_ PINET_FIREWALL_APP_CONTAINER pPublicAppCs
        );
    void LaunchSpecifcApp(wstring *pfn)
    {
        TCHAR szCommandLine[1024];
        wsprintf(szCommandLine, L"explorer.exe shell:AppsFolder\\%ws!App", (*pfn).c_str());
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));

        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = TRUE;

        BOOL bRet = ::CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

    }

    void LaunchUWPApp()
    {
        vector<wstring> uwpApps;
        uwpApps.push_back(L"microsoft.windowscommunicationsapps_8wekyb3d8bbwe");

        HMODULE FirewallAPIModule;
        FirewallAPIModule = (LoadLibrary(L"FirewallAPI.dll"));

        auto EnumAppContainersProc = pNetworkIsolationEnumAppContainers(GetProcAddress(FirewallAPIModule, "NetworkIsolationEnumAppContainers"));
        auto FreeAppContainersProc = pNetworkIsolationFreeAppContainers(GetProcAddress(FirewallAPIModule, "NetworkIsolationFreeAppContainers"));

        DWORD pdwNumPublicAppCs = 0;
        PINET_FIREWALL_APP_CONTAINER ppPublicAppCs = NULL;
        HRESULT re = EnumAppContainersProc(0, &pdwNumPublicAppCs, &ppPublicAppCs);

        for (int i = 0; i < pdwNumPublicAppCs; i++)
        {
            auto appContainer = ppPublicAppCs[i];
            for (int j = 0; j < uwpApps.size(); j++)
            {
                auto app = uwpApps.at(j);
                transform(app.begin(), app.end(), app.begin(), tolower);
                if (app == appContainer.appContainerName)
                {
                    //launch it;
                    auto temp = uwpApps.at(j);
                    LaunchSpecifcApp(&temp);
                }
            }
        }
        FreeAppContainersProc(ppPublicAppCs);
        FreeLibrary(FirewallAPIModule);
        vector<wstring>().swap(uwpApps);
    }
}

代码很直白,里里面就两个函数,一个用来查找,一个用来启动,额外用到的就是 Win32 Dll 调用相关的内容了。

最后

可以看到,我们查找 UWP 比较麻烦,但是调用却很简单,核心就是:

"explorer.exe shell:AppsFolder\\{pfn}!App"

很直白,赤裸裸的一个快捷方式呀!但是有坑,如果传递的参数有任何问题(要么拼错了,要么不存在),explorer 会直接忽略参数,把自己启动。这种行为,对于不明真相的用户,会很莫名其妙,垃圾软件。所以我们在启动我们的 UWP App 时,要确保这个我们的 App 一定存在于用户的电脑上面,所以才有了上面检测 UWP App 的逻辑。如果参数错误,explorer 啥也不敢的话,我们就不这么麻烦了,可以直接把我们所有的 UWP app 挨个启动一遍,简单粗暴!

最后的最后

我们用到了 Fillder 里面所使用的方法,但对于 Fiddler 版权的各种问题,个人不了解。好在我们直接用 C++ 实现,没有任何影响。 权当学习学习!

之前网上有 Fiddler 2.x版本的源码,但不清楚这软件是不是开源。

致敬 Fiddler !

目录
相关文章
|
3月前
|
存储 移动开发 安全
如何实现APP安全加固?加固技术、方法和方案
通过前面的文章我们知道了app安全检测要去检测哪些内容,发现问题后我们如何去修复?如何避免安全问题?首先我们先来讲一下APP安全加固技术。
|
4月前
|
iOS开发 开发者
📝 App备案与iOS云管理式证书 ,公钥及证书SHA-1指纹的获取方法
在iOS应用程序开发过程中,进行App备案并获取公钥及证书SHA-1指纹是至关重要的步骤。本文将介绍如何通过appuploader工具获取iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹,帮助开发者更好地理解和应用该过程。
|
2月前
|
开发者 iOS开发
处理开发者账号到期导致 APP 下架的方处理开发者账号到期导致 APP 下架的方法
处理开发者账号到期导致 APP 下架的方处理开发者账号到期导致 APP 下架的方法
|
4月前
|
编解码 Java 测试技术
『App自动化测试之Appium应用篇』| uiautomator + accessibility_id定位方法完全使用攻略
『App自动化测试之Appium应用篇』| uiautomator + accessibility_id定位方法完全使用攻略
123 0
|
27天前
|
Android开发 iOS开发 开发者
App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
79 0
|
4月前
|
Android开发 开发者
 一键在线获取APP公钥、包名、签名及备案信息方法介绍
本文介绍了一款在线APP解析工具,可以一键获取APP的公钥、包名、签名等基础信息,同时提供了详细的操作步骤和使用示例,帮助开发者更便捷地进行APP备案信息的获取。
|
4月前
|
移动开发 安全 测试技术
『App自动化测试之Appium应用篇』| 继承于selenium常用的元素定位方法有哪些?如何使用?
『App自动化测试之Appium应用篇』| 继承于selenium常用的元素定位方法有哪些?如何使用?
84 0
|
5月前
|
Android开发 iOS开发 开发者
App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
,在appuploder直接复制IOS信息;如果还没有创建证书,请上传正确的P12苹果证书后,系统会自动解析出对应的签名和公钥信息; ——APP备案的原理是基于原有的工信部域名备案系统,如果已经有了域名备案,无需新增备案主体;只需要在之前的域名备案系统里面,新增APP信息,收集的APP信息主要包括APP包名和签名及公钥这3项;——APP备案是属于行政常规主体信息预存,和域名一样,自行决定是否备案。目前国内安卓应用商店是全面要求APP备案的,如果没有APP备案是不能通过审核发布到各大应用商店。——如看了教程,还不清楚怎么获取APP包名、安卓签名、苹果sha1签名、公钥等信息,请联系我们在线客服,
|
3月前
|
开发框架 编解码 移动开发
从网页到应用:探索在线生成App的方法
本文介绍了如何在线生成App,将网页封装成App的技术方法和步骤。通过使用特定的工具和框架,开发者可以将现有的网页转化为功能完善的移动应用程序,提供更好的用户体验和便捷的访问方式。
21 0
|
3月前
|
移动开发 搜索推荐 UED
从网页到应用:探索在线生成App的技术方法
本文将介绍如何利用在线工具将网页封装成App的技术方法。通过简单易行的步骤,开发者可以将自己的网页转化为功能完备的应用程序,提供更好的用户体验和更广阔的市场覆盖。

热门文章

最新文章