魔法薇ㄦ的书馆

wherewhere的个人博客

如今微软网页套壳越来越变本加厉,到处都是一人一个浏览器,套壳大小已经成百上千,但殊不知微软曾经有过对网页套壳的原生支持,打包大小只按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 的支持。

屏幕截图(911)

不过 MSAppHost 框架作为系统组件并没有被删除,利用 electron-windows-msix 插件,我们可以轻松打包一个 NPM 项目,我们只需要将清单改为 MSAppHost 模式即可。接下来我们将演示如何新建一个 Vue/UWP 项目。

阅读全文 »

众所周知,UWP 一般是运行在沙盒里面的,当我们需要访问沙盒外资源的时候,就需要通过沙盒外的代理服务器来获取。一般情况下我们都是利用 WinRT API 通过 Runtime Broker 来和沙盒外互通,遇到要自定义的情况则是手动开一个 Win32 服务器来互通,但是有没有可能我们可以直接拿 UWP 本体当服务器呢?

UWP 本体实际上就是一个普通的 Win32 EXE 程序,只是想要以 UWP 状态运行只能通过系统托管,但是如果我们不需要它以 UWP 状态执行的时候完全可以直接双击打开它,这时候它就是一个很普通的散装 Win32 程序了。

利用这个特性,我们可以制作一种假装双击打开的方法,只需要在发现是 Win32 状态下启动就去用 API 唤起 UWP 形态的自己就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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());
SynchronizationContext.SetSynchronizationContext(context);
_ = new App();
});
}
else
{
StartCoreApplicationAsync().Wait();
}
}

private static async Task StartCoreApplicationAsync()
{
PackageManager manager = new();
string basePath = AppDomain.CurrentDomain.BaseDirectory;
XmlDocument manifest = await XmlDocument.LoadFromFileAsync(await StorageFile.GetFileFromPathAsync(Path.Combine(basePath, "AppxManifest.xml")));
IXmlNode identity = manifest.GetElementsByTagName("Identity")?[0];
string name = identity.Attributes.FirstOrDefault(x => x.NodeName == "Name")?.InnerText;
IXmlNode application = manifest.GetElementsByTagName("Application")?[0];
string id = application.Attributes.FirstOrDefault(x => x.NodeName == "Id")?.InnerText;
IEnumerable<Package> packages = manager.FindPackagesForUser(string.Empty).Where(x => x.Id.FamilyName.StartsWith(name));
if (packages.FirstOrDefault() is Package package)
{
IReadOnlyList<AppListEntry> entries = await package.GetAppListEntriesAsync();
if (entries?[0] is AppListEntry entry)
{
_ = await entry.LaunchAsync();
}
}
}

既然我们可以让自己唤起自己,那么自己和自己通信也不是什么难事了,我们只需要在 UWP 形态下唤起一个 Win32 的自己,就可以自己利用自己滥权(bushi)了。

阅读全文 »

众所周知,2024年9月微软正式宣布了 .NET Core App 的 UWP 支持,至此我们终于可以在新版 csproj 用 .NET 8 及以上编写 UWP 了,那么我们可不可以通过修改清单的方式来让 UWP 变成 UAP 呢?

屏幕截图(785)

UWP 和 UAP 使用的是同一套 WinRT API ,Windows 区分 UAP 和 UWP 的方式是看清单,只要是用 UAP 的清单就会仿真成 Win8.1 模式,于是我们只需要将清单变成 UAP 的样子就行了。所以首先我们新建一个 .NET 9 Native AOT 的 UWP 项目

Snipaste_2025-03-13_17-52-59

然后我们修改清单,Win8 App 清单如下,内容按需填写,Win8.1 App 的清单可以通过在 Github 搜索 OSMaxVersionTested language:XML 找到,6.2 是 Win8,6.3 是 Win8.1 ($targetentrypoint$ 需配合 ApplicationEntryPoint 使用)

阅读全文 »

众所周知,UWP 使用的窗口模型是 CoreWindow,但是 UWP 本身只是一个应用模型,所以完全可以创建 win32 窗口,那么我们可以不可以创建一个 win32 窗口,然后像 XAML 岛 (XAML Islands) 一样把 XAML 托管上去呢?本篇将讲述如何在 UWP 创建一个 XAML 岛窗口。

示例

首先,XAML 岛会判断当前的应用模型是否为ClassicDesktop,所以我们需要利用Detours劫持AppPolicyGetWindowingModel方法。具体内容如下:

阅读全文 »

众所周知,UWP 使用的窗口模型是 CoreWindow,但是 UWP 本身只是一个应用模型,所以完全可以创建 win32 窗口,那么我们可以不可以创建一个 win32 窗口,然后像 XAML 岛 (XAML Islands) 一样把 XAML 托管上去呢?本篇将讲述如何利用 WAS (Windows App SDK,俗称 WinUI3) 在 UWP 创建一个 XAML 岛窗口。

示例

演示视频:https://x.com/wherewhere7/status/1721570411388039587

由于 WAS 在 win32 应用模型下本身就是个 XAML 岛,所以 WAS 对 XAML 岛的支持要比 WUXC (Windows.UI.Xaml.Controls) 要好多了,接下来的内容大多是将 WAS 中实现窗口的方法迁移到 C#。

首先,不管是 WUXC 还是 WAS 的 XAML 岛都会判断当前的应用模型是否为ClassicDesktop,所以我们需要利用Detours劫持AppPolicyGetWindowingModel方法。具体内容如下:

阅读全文 »

众所周知,WAS (Windows App SDK,俗称 WinUI3)在刚开始是支持 UWP 的,甚至最早只支持 UWP,但是微软在正式版发布前删除了对 UWP 的支持,不过真的删除了吗?初生之鸟2023年10月发现在 VS 调试下无视报错继续运行可以正常在 UWP 加载 WAS。随着 WAS 的开源,WAS 阻止在 UWP 上运行的原因也被找到,至此大家终于找到在 UWP 上使用 WAS 的方法了。

WAS 阻止在 UWP 上运行的方法很简单,就是检查注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WinUI\Xaml\EnableUWPWindow是否为00000001,如果不是就直接报错。

Window_Partial.cpp#L80-L114
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ----------------------------------------------------------------------
// IWindow
// ----------------------------------------------------------------------
Window::Window()
{
// The first window created internally by DXamlCore _must_ be a UWP Window. DXamlCore
// requires and controls the lifetime of a hidden UWP Microsoft.UI.Xaml.Window.
// note that this Window instance will be the 'real' window for UWP instances, but
// serves as a dummy for all other instances. dummy behavior is deprecated and being removed.
auto dxamlCore = DXamlCore::GetCurrent();
Window* window = dxamlCore->GetDummyWindowNoRef();

if (!window)
{
// Do a runtime check to see if UWP should be enabled
static auto runtimeEnabledFeatureDetector = RuntimeFeatureBehavior::GetRuntimeEnabledFeatureDetector();
auto UWPWindowEnabled = runtimeEnabledFeatureDetector->IsFeatureEnabled(RuntimeEnabledFeature::EnableUWPWindow);

// WinUI UWP
if (!UWPWindowEnabled && DXamlCore::GetCurrent()->GetHandle()->GetInitializationType() != InitializationType::IslandsOnly)
{
::RoOriginateError(
E_NOT_SUPPORTED,
wrl_wrappers::HStringReference(
L"WinUI: Error creating an UWP Window. Creating an UWP window is not allowed."
).Get());
XAML_FAIL_FAST();
}
m_spWindowImpl = std::make_shared<UWPWindowImpl>(this);
}
else
{
m_spWindowImpl = std::make_shared<DesktopWindowImpl>(this);
}
}
阅读全文 »

众所周知,UWP 是运行在沙盒里面的,所有权限都有严格限制,和沙盒外交互也需要特殊的通道,所以从根本杜绝了 UWP 毒瘤的存在。但是实际上 UWP 只是一个应用模型,本身是没有什么权限管理的,权限管理全靠 App Container 沙盒控制,如果我们脱离了这个沙盒,UWP 就会放飞自我了。那么有没有这种可能呢?

我们打开设置应用,通过任务管理器查看进程,就会发现它并没有 Runtime Broker 存在,这个进程是用来在沙盒间代理的,这说明微软给 UWP 开了一个后门。

任务管理器

那么我们是不是也有办法脱离沙盒运行呢?Ahmed Walid 在 2023年2月 发表了这样一个帖子

阅读全文 »

众所周知,C# 只支持对 基类/接口/class/struct/new() 以及一些 IDE 魔法的约束,比如这样

1
2
3
4
5
6
7
8
9
public static string Test<T>(T value) where T : ITest
{
return value.Test();
}

public interface ITest
{
string Test();
}

但是如果我们想要随心所欲的约束就不行了

1
2
3
4
public static string Test<T>(T value) where T : { string Test(); }
{
return value.Test();
}

最近无聊乱折腾 MSIL,弄出来好多不能跑的魔法,虽然不能跑但是反编译出的 C# 看着很神奇,其中正好就有想看看能不能弄个神奇的泛型出来,于是我胡写了一段代码

阅读全文 »

Announcing

We have packaged this project into winrt. With the winrt version, we can use it in cpp/winrt and other projects. You can find the winrt version in winrt branch.

How to use it

There are two way to reference it.

  • Reference to the project directly

    Fork this repository and change the branch to winrt.

    • If your project is face to uwp, add this to your .vcproj

      1
      2
      3
      4
      <ProjectReference Include="\path\to\AdvancedSharpAdbClient.WinRT.csproj">
      <Project>{083cdc04-9cc2-46e4-84c2-55b645be9d50}</Project>
      <SetTargetFramework>TargetFramework=uap10.0</SetTargetFramework>
      </ProjectReference>
    • If your project is face to desktop, add this to your .vcproj

      1
      2
      3
      4
      <ProjectReference Include="\path\to\AdvancedSharpAdbClient.WinRT.csproj">
      <Project>{083cdc04-9cc2-46e4-84c2-55b645be9d50}</Project>
      <SetTargetFramework>TargetFramework=net6.0-windows10.0.17763.0</SetTargetFramework>
      </ProjectReference>
  • Reference to the nuget package

    阅读全文 »

【UWP】开发小技巧――简单的增量加载

#UWP# #爱编程# #电脑玩家#

增量加载的原理这里就不多说了,具体是干什么的可以看 CNBlogs 的讲解:查看链接

这里只讲解如何使用 CNBlogs UAP 中使用的增量加载方案(我硬是看了一天才知道怎么用。。。

首先附上代码(已经被我修改过了):查看链接

部分代码

部分代码

引用时不要忘了附上出处(不是我这,是CNBlogs

阅读全文 »
0%