首页 > 系统相关 >【UWP】在 UWP 中使用 Windows App SDK

【UWP】在 UWP 中使用 Windows App SDK

时间:2024-10-18 15:43:58浏览次数:1  
标签:Windows App UWP WIN32 static Detours ERROR result

众所周知,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
// ----------------------------------------------------------------------
//                               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);
    }
}
Window_Partial.cpp#L80-L114
{ L"EnableUWPWindow", RuntimeEnabledFeature::EnableUWPWindow, false, 0, 0 }

所以我们只需要修改注册表就行了。

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WinUI\Xaml]
"EnableUWPWindow"=dword:00000001

但是到处修改注册表并不是一个好主意,于是初生之鸟便提出利用Detours来劫持读取注册表的方法:HookCoreAppWinUI

我们将其翻译成 C#,再加一些小修改,便能得出如下内容:

#r "nuget:Detours.Win32Metadata"
#r "nuget:Microsoft.Windows.CsWin32"

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Registry;
using Detours = Microsoft.Detours.PInvoke;

/// <summary>
/// Represents a hook for getting the value of the <c>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WinUI\Xaml\EnableUWPWindow</c> registry key always returning <see langword="00000001"/>.
/// </summary>
public partial class HookRegistry : IDisposable
{
    /// <summary>
    /// The value that indicates whether the class has been disposed.
    /// </summary>
    private bool disposed;

    /// <summary>
    /// The reference count for the hook.
    /// </summary>
    private static int refCount;

    /// <summary>
    /// The dictionary that maps the <see cref="HKEY"/> to a value that indicates whether the key is a real key.
    /// </summary>
    private static readonly Dictionary<HKEY, bool> xamlKeyMap = [];

    /// <summary>
    /// The object used to synchronize access to the <see cref="xamlKeyMap"/> dictionary.
    /// </summary>
    private static readonly object locker = new();

    /// <remarks>The original <see cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/>
    private static unsafe delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> RegOpenKeyExW;

    /// <remarks>The original <see cref="PInvoke.RegCloseKey(HKEY)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegCloseKey(HKEY)"/>
    private static unsafe delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> RegCloseKey;

    /// <remarks>The original <see cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/>
    private static unsafe delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> RegQueryValueExW;

    /// <summary>
    /// Initializes a new instance of the <see cref="HookRegistry"/> class.
    /// </summary>
    public HookRegistry()
    {
        refCount++;
        StartHook();
    }

    /// <summary>
    /// Finalizes this instance of the <see cref="HookRegistry"/> class.
    /// </summary>
    ~HookRegistry()
    {
        Dispose();
    }

    /// <summary>
    /// Gets the value that indicates whether the hook is active.
    /// </summary>
    public static bool IsHooked { get; private set; }

    /// <summary>
    /// Starts the hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.
    /// </summary>
    private static unsafe void StartHook()
    {
        if (!IsHooked)
        {
            using FreeLibrarySafeHandle library = PInvoke.GetModuleHandle("ADVAPI32.dll");
            if (!library.IsInvalid
                && NativeLibrary.TryGetExport(library.DangerousGetHandle(), "RegOpenKeyExW", out nint regOpenKeyExW)
                && NativeLibrary.TryGetExport(library.DangerousGetHandle(), nameof(PInvoke.RegCloseKey), out nint regCloseKey)
                && NativeLibrary.TryGetExport(library.DangerousGetHandle(), "RegQueryValueExW", out nint regQueryValueExW))
            {
                void* regOpenKeyExWPtr = (void*)regOpenKeyExW;
                void* regCloseKeyPtr = (void*)regCloseKey;
                void* regQueryValueExWPtr = (void*)regQueryValueExW;

                delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> overrideRegOpenKeyExW = &OverrideRegOpenKeyExW;
                delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> overrideRegCloseKey = &OverrideRegCloseKey;
                delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> overrideRegQueryValueExW = &OverrideRegQueryValueExW;

                _ = Detours.DetourRestoreAfterWith();

                _ = Detours.DetourTransactionBegin();
                _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
                _ = Detours.DetourAttach(ref regOpenKeyExWPtr, overrideRegOpenKeyExW);
                _ = Detours.DetourAttach(ref regCloseKeyPtr, overrideRegCloseKey);
                _ = Detours.DetourAttach(ref regQueryValueExWPtr, overrideRegQueryValueExW);
                _ = Detours.DetourTransactionCommit();

                RegOpenKeyExW = (delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR>)regOpenKeyExWPtr;
                RegCloseKey = (delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR>)regCloseKeyPtr;
                RegQueryValueExW = (delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR>)regQueryValueExWPtr;

                IsHooked = true;
            }
        }
    }

    /// <summary>
    /// Ends the hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.
    /// </summary>
    public static unsafe void EndHook()
    {
        if (--refCount == 0 && IsHooked)
        {
            void* regOpenKeyExWPtr = RegOpenKeyExW;
            void* regCloseKeyPtr = RegCloseKey;
            void* regQueryValueExWPtr = RegQueryValueExW;

            delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> overrideRegOpenKeyExW = &OverrideRegOpenKeyExW;
            delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> overrideRegCloseKey = &OverrideRegCloseKey;
            delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> overrideRegQueryValueExW = &OverrideRegQueryValueExW;

            _ = Detours.DetourTransactionBegin();
            _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
            _ = Detours.DetourDetach(&regOpenKeyExWPtr, overrideRegOpenKeyExW);
            _ = Detours.DetourDetach(&regCloseKeyPtr, overrideRegCloseKey);
            _ = Detours.DetourDetach(&regQueryValueExWPtr, overrideRegQueryValueExW);
            _ = Detours.DetourTransactionCommit();

            RegOpenKeyExW = null;
            RegCloseKey = null;
            RegQueryValueExW = null;

            IsHooked = false;
        }
    }

    /// <remarks>The overridden <see cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/>
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
    private static unsafe WIN32_ERROR OverrideRegOpenKeyExW(HKEY hKey, PCWSTR lpSubKey, uint ulOptions, REG_SAM_FLAGS samDesired, HKEY* phkResult)
    {
        WIN32_ERROR result = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
        if (hKey == HKEY.HKEY_LOCAL_MACHINE && lpSubKey.ToString().Equals(@"Software\Microsoft\WinUI\Xaml", StringComparison.OrdinalIgnoreCase))
        {
            if (result == WIN32_ERROR.ERROR_FILE_NOT_FOUND)
            {
                HKEY key = new(HANDLE.INVALID_HANDLE_VALUE);
                xamlKeyMap[key] = false;
                *phkResult = key;
                result = WIN32_ERROR.ERROR_SUCCESS;
            }
            else if (result == WIN32_ERROR.ERROR_SUCCESS)
            {
                xamlKeyMap[*phkResult] = true;
            }
        }
        return result;
    }

    /// <remarks>The overridden <see cref="PInvoke.RegCloseKey(HKEY)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegCloseKey(HKEY)"/>
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
    private static unsafe WIN32_ERROR OverrideRegCloseKey(HKEY hKey)
    {
        bool isXamlKey;
        lock (locker)
        {
            if (isXamlKey = xamlKeyMap.TryGetValue(hKey, out bool isRealKey))
            {
                xamlKeyMap.Remove(hKey);
            }
            return isXamlKey
                ? isRealKey
                    ? RegCloseKey(hKey) // real key
                    : WIN32_ERROR.ERROR_SUCCESS // simulated key
                : hKey == HANDLE.INVALID_HANDLE_VALUE
                    ? WIN32_ERROR.ERROR_INVALID_HANDLE
                    : RegCloseKey(hKey);
        }
    }

    /// <remarks>The overridden <see cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/> function.</remarks>
    /// <inheritdoc cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/>
    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
    private static unsafe WIN32_ERROR OverrideRegQueryValueExW(HKEY hKey, PCWSTR lpValueName, [Optional] uint* lpReserved, [Optional] REG_VALUE_TYPE* lpType, [Optional] byte* lpData, [Optional] uint* lpcbData)
    {
        if (lpValueName.Value != default && lpValueName.ToString().Equals("EnableUWPWindow", StringComparison.OrdinalIgnoreCase))
        {
            lock (locker)
            {
                if (xamlKeyMap.TryGetValue(hKey, out bool isRealKey))
                {
                    WIN32_ERROR result;
                    if (isRealKey)
                    {
                        // real key
                        result = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
                        if (result == WIN32_ERROR.ERROR_SUCCESS && lpData != default)
                        {
                            *lpData = 1;
                        }
                        else if (result == WIN32_ERROR.ERROR_FILE_NOT_FOUND)
                        {
                            if (lpData == default && lpcbData != default)
                            {
                                *lpcbData = sizeof(int);
                                result = WIN32_ERROR.ERROR_SUCCESS;
                            }
                            else if (lpData != default && lpcbData != default)
                            {
                                if (*lpcbData >= sizeof(int))
                                {
                                    *lpData = 1;
                                    result = WIN32_ERROR.ERROR_SUCCESS;
                                }
                                else
                                {
                                    result = WIN32_ERROR.ERROR_MORE_DATA;
                                }
                            }
                        }
                    }
                    else
                    {
                        // simulated key
                        result = WIN32_ERROR.ERROR_FILE_NOT_FOUND;
                        if (lpData == default && lpcbData != default)
                        {
                            *lpcbData = sizeof(int);
                            result = WIN32_ERROR.ERROR_SUCCESS;
                        }
                        else if (lpData != default && lpcbData != default)
                        {
                            if (*lpcbData >= sizeof(int))
                            {
                                *lpData = 1;
                                result = WIN32_ERROR.ERROR_SUCCESS;
                            }
                            else
                            {
                                result = WIN32_ERROR.ERROR_MORE_DATA;
                            }
                        }
                    }
                    return result;
                }
            }
        }
        return RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
    }

    /// <inheritdoc/>
    public void Dispose()
    {
        if (!disposed && IsHooked)
        {
            EndHook();
        }
        GC.SuppressFinalize(this);
        disposed = true;
    }
}

随后我们只需要在入口点创建App时进行劫持就行了。

private static bool IsSupportCoreWindow
{
    get
    {
        try
        {
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\WinUI\Xaml");
            return registryKey?.GetValue("EnableUWPWindow") is > 0;
        }
        catch
        {
            return false;
        }
    }
}

private static void Main()
{
    ComWrappersSupport.InitializeComWrappers();
    HookRegistry hookRegistry = null;
    try
    {
        if (!IsSupportCoreWindow)
        {
            hookRegistry = new HookRegistry();
        }
        XamlCheckProcessRequirements();
        Application.Start(p =>
        {
            DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread());
            SynchronizationContext.SetSynchronizationContext(context);
            _ = new App();
        });
    }
    finally
    {
        hookRegistry?.Dispose();
    }
}

当然想要自定义入口函数,我们需要在csproj加上定义。

<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>

同时还要记得在清单中明确入口点。

<?xml version="1.0" encoding="utf-8"?>
<Package ...>
  ...
  <Applications>
    <Application ...
      EntryPoint="明确的入口点">
      ...
    </Application>
  </Applications>
  ...
</Package>

随后我们就可以正常的使用 UWP/WAS 了。

最后附上示例应用:https://github.com/wherewhere/CoreAppUWP/tree/muxc

标签:Windows,App,UWP,WIN32,static,Detours,ERROR,result
From: https://www.cnblogs.com/wherewhere/p/18447226

相关文章

  • Create-react-app创建的项目打包后页面空白的解决方法
    当我们使用create-react-app脚手架创建一个react项目之后,等到项目开发完成想要打包部署时会发现,通过npmrunbuild命令打包后的项目在浏览器端访问时会出现页面空白的情况。解决方法:此类问题一般有两种解决方法,其中第一种也是最常见的,当我们打开浏览器控制台时会发现,当首页空白......
  • 博客-django--路由分发--找不到app的views--解决办法
    博客-django--路由分发--找不到app的views--解决办法bash先给出我的项目文件目录结构主要是主目录project与app01省略了migrations问题问题出现在路由分发中以下是主urls以下是app的urls解决方式需要使用相对路径.思考其实正常的话使用绝对路径也可以,如参考代码mysite2项目---目......
  • Windows自带的录屏神器,你竟然还不知道?
    咱们现在可是活在数字时代,录屏工具简直就是工作和娱乐的得力助手。不管是教别人怎么做事,展示你的PPT,还是录下你玩游戏的高光时刻,都离不开录屏。你可能没注意到,Windows系统自己就有好几个超实用的录屏功能,不用额外下载别的软件,就能搞定大部分录屏需求。这篇文章就给你聊聊window......
  • Nuxt.js 应用中的 app:templates 事件钩子详解
    title:Nuxt.js应用中的app:templates事件钩子详解date:2024/10/18updated:2024/10/18author:cmdragonexcerpt:app:templates是Nuxt.js中一个强大的生命周期钩子,它在NuxtApp生成过程中调用。这一钩子允许开发者自定义、修改或添加新文件到构建目录,提供了极大的......
  • 苹果(ios)应用ipa文件上传到苹果商店app store步骤
    这篇文章的前提是你已经用苹果打包证书打包好ipa文件,准备将ipa文件上传到appstore。假如你还没有苹果证书,还没有打包好ipa文件,你还不知道证书怎么创建,可以参考这篇文章先生成证书和证书profile文件:https://www.cnblogs.com/handsome0916/p/18329211然后你到iosdevcenter,也......
  • WhatsApp收不到验证码?试试这些方法
    WhatsApp可以说是跨境外贸的万能工具之一,但是WhatsApp验证码问题比被封问题更难解决,甚至有小伙伴两三个月都收不到验证码,导致一直无法使用WhatsApp,包括但不限于以下情况:1、短信验证码收不到2、“致电给我”选项来获取验证码,收不到验证码语音电话。3、“致电给我”按钮变......
  • Unity Apple Vision Pro 保姆级开发教程-环境配置、导入 PolySpatial 案例、程序发布
    视频教程Unity环境配置、导入PolySpatial案例、程序发布到设备教程说明这期教程我将介绍使用Unity开发AppleVisionPro应用所需要的Unity环境配置,以及如何导入PolySpatial样例场景、将Unity程序打包到头显中运行。开发前期准备(软硬件要求,开启visionpro......
  • Unity Apple Vision Pro 保姆级开发教程-准备阶段
    视频教程:UnityPolySpatial开发AppleVisionPro教程,三十分钟快速了解开发AppleVisionPro使用原生开发和unity开发有什么区别如果你的项目需要充分利用AppleVisionPro的独特功能、追求最佳的性能表现,或者针对特定于VisionOS的开发场景,原生开发可能是更好的......
  • uniapp开发微信小程序之搜索联想、高亮显示(附demo)
    小程序比较常见的功能就是搜索,搜索的一个体验点就联想、高亮显示,惯例还是先看效果。实现效果实现思路1)uni-search-bar搜索框,监听input事件,触发搜索联想2)调用后台接口,根据分词查询数据(TopN),返回前端数据3)前端利用正则表达式,匹配数据中的分词,添加高亮样式4)v-html标......
  • 统信uos v20国产信创系统运行Windows的exe程序-后续
    本次尝试使用wine软件来进行exe程序的安装,因为第一次使用迁移助手来做,发现每次都要重新安装组件,要等待很长时间,不适合实时调试,所以采用了当前这种方式。1、通过应用商店安装wine软件,我这边版本是:4.1.0.02、执行命令开启串口权限给指定用户sudousermod-a-Gdialoutlenov......