博文

【UWP】使用 Vue/Vite 编写 WinJS/UWP

图片
如今微软网页套壳越来越变本加厉,到处都是一人一个浏览器,套壳大小已经成百上千,但殊不知微软曾经有过对网页套壳的原生支持,打包大小只按k记,那就是 MSAppHost 了,不过更为人所知的是其控件库 WinJS,所以这里就用 WinJS 代指 JS/HTML 模式的 UWP 了。WinJS/UWP 本质就是直接让 Edge (过去为 IE) 的 WebView 直接打开打包好的网页,同时给这个环境加上 WinRT 支持,由于 MSAppHost 是系统组件,所以只用打包 Web 资源就行了。WinJS 曾作为 WSA (Windows Store App) 的主推平台,甚至 Win8 应用商店都是 JS/HTML 开发的,不过在进入 Win10 之后,有了 .NET Native 的加持,C#/UWP 逐渐变为主流,MSAppHost 基本上只剩下了作为 PWA 的用途。然而随着 Edge HTML 的停更,Windows 再也没有了原生的 HTML 渲染平台,微软也在 VS 2019 中彻底删除了对 WinJS 的支持。 不过 MSAppHost 框架作为系统组件并没有被删除,利用 electron-windows-msix 插件,我们可以轻松打包一个 NPM 项目,我们只需要将清单改为 MSAppHost 模式即可。接下来我们将演示如何新建一个 Vue/UWP 项目。 首先我们根据 Vue 官方教程 新建一个空白 Vue 项目: npm create vue@latest 进入项目文件夹后安装依赖: npm i 然后我们测试一下它是否可以正常运行: npm run dev 由于 MSAppHost 永远留在了 Edge HTML 18,所以我们需要把 JS 编译到 Edge 18 兼容的版本,安装 @vitejs/plugin-legacy : npm i --save-dev @vitejs/plugin-legacy 在  vite.config.ts  配置插件,由于  vite 使用到了新版 ESM 模块特性,所以 Edge 只能使用 Legacy 模式,注意 base 一定要设置为 ./ ,因为打包插件会把编译结果打包进 ap...

【UWP】让 UWP 自己和自己通信

图片
众所周知,UWP 一般是运行在沙盒里面的,当我们需要访问沙盒外资源的时候,就需要通过沙盒外的代理服务器来获取。一般情况下我们都是利用 WinRT API 通过 Runtime Broker 来和沙盒外互通,遇到要自定义的情况则是手动开一个 Win32 服务器来互通,但是有没有可能我们可以直接拿 UWP 本体当服务器呢? UWP 本体实际上就是一个普通的 Win32 EXE 程序,只是想要以 UWP 状态运行只能通过系统托管,但是如果我们不需要它以 UWP 状态执行的时候完全可以直接双击打开它,这时候它就是一个很普通的散装 Win32 程序了。 利用这个特性,我们可以制作一种假装双击打开的方法,只需要在发现是 Win32 状态下启动就去用 API 唤起 UWP 形态的自己就行了 private static unsafe bool IsPackagedApp { get { uint length = 0 ; PWSTR str = new (); _ = PInvoke.GetCurrentPackageFullName( ref length, str); char * ptr = stackalloc char [( int )length]; str = new (ptr); WIN32_ERROR result = PInvoke.GetCurrentPackageFullName( ref length, str); return result != WIN32_ERROR.APPMODEL_ERROR_NO_PACKAGE; } } private static void Main () { if (IsPackagedApp) { Application.Start( static p => { DispatcherQueueSynchronizationContext context = new (DispatcherQueue.GetForCurrentThread()); ...

【UAP】使用 .NET Core App 编写 UAP

图片
众所周知,2024年9月微软正式宣布了 .NET Core App 的 UWP 支持,至此我们终于可以在新版 csproj 用 .NET 8 及以上编写 UWP 了,那么我们可不可以通过修改清单的方式来让 UWP 变成 UAP 呢? UWP 和 UAP 使用的是同一套 WinRT API ,Windows 区分 UAP 和 UWP 的方式是看清单,只要是用 UAP 的清单就会仿真成 Win8.1 模式,于是我们只需要将清单变成 UAP 的样子就行了。所以首先我们新建一个 .NET 9 Native AOT 的 UWP 项目 然后我们修改清单,Win8 App 清单如下,内容按需填写,Win8.1 App 的清单可以通过在 Github 搜索 OSMaxVersionTested language:XML 找到, 6.2 是 Win8, 6.3 是 Win8.1 ( $targetentrypoint$ 需配合 ApplicationEntryPoint 使用) <?xml version= "1.0" encoding= "utf-8" ?> < Package xmlns = "http://schemas.microsoft.com/appx/2010/manifest" > < Identity Name = "wherewhere.CoreAppUAP" Publisher = "CN=where" Version = "0.0.1.0" /> < Properties > < DisplayName > CoreAppUAP </ DisplayName > < PublisherDisplayName > wherewhere </ PublisherDisplayName > < Logo > Assets\StoreLogo.png </ Logo > ...

【UWP】让 UWP 自己托管自己 —— Windows SDK 篇

图片
众所周知,UWP 使用的窗口模型是 CoreWindow,但是 UWP 本身只是一个应用模型,所以完全可以创建 win32 窗口,那么我们可以不可以创建一个 win32 窗口,然后像 XAML 岛 (XAML Islands) 一样把 XAML 托管上去呢?本篇将讲述如何在 UWP 创建一个 XAML 岛窗口。 首先,XAML 岛会判断当前的应用模型是否为 ClassicDesktop ,所以我们需要利用 Detours 劫持 AppPolicyGetWindowingModel 方法。具体内容如下: #r "nuget:Detours.Win32Metadata" #r "nuget:Microsoft.Windows.CsWin32" using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Storage.Packaging.Appx; using Detours = Microsoft.Detours.PInvoke; /// <summary> /// Represents a hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function. /// </summary> public sealed partial class HookWindowingModel : IDisposable { /// <summary> /// The value that indicates whether the class has been disposed. /// </summary> private bo...