翼度科技»论坛 编程开发 .net 查看内容

【UWP】在 UWP 中使用 Windows App SDK

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
众所周知,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. //                               IWindow
  3. // ----------------------------------------------------------------------
  4. Window::Window()
  5. {
  6.     // The first window created internally by DXamlCore _must_ be a UWP Window.  DXamlCore
  7.     // requires and controls the lifetime of a hidden UWP Microsoft.UI.Xaml.Window.
  8.     // note that this Window instance will be the 'real' window for UWP instances, but
  9.     // serves as a dummy for all other instances. dummy behavior is deprecated and being removed.
  10.     auto dxamlCore = DXamlCore::GetCurrent();
  11.     Window* window = dxamlCore->GetDummyWindowNoRef();
  12.     if (!window)
  13.     {
  14.         // Do a runtime check to see if UWP should be enabled
  15.         static auto runtimeEnabledFeatureDetector = RuntimeFeatureBehavior::GetRuntimeEnabledFeatureDetector();
  16.         auto UWPWindowEnabled = runtimeEnabledFeatureDetector->IsFeatureEnabled(RuntimeEnabledFeature::EnableUWPWindow);
  17.         // WinUI UWP
  18.         if (!UWPWindowEnabled && DXamlCore::GetCurrent()->GetHandle()->GetInitializationType() != InitializationType::IslandsOnly)
  19.         {
  20.             ::RoOriginateError(
  21.                 E_NOT_SUPPORTED,
  22.                 wrl_wrappers::HStringReference(
  23.                 L"WinUI: Error creating an UWP Window. Creating an UWP window is not allowed."
  24.                 ).Get());
  25.             XAML_FAIL_FAST();
  26.         }
  27.         m_spWindowImpl = std::make_shared<UWPWindowImpl>(this);
  28.     }
  29.     else
  30.     {
  31.         m_spWindowImpl = std::make_shared<DesktopWindowImpl>(this);
  32.     }
  33. }
复制代码
Window_Partial.cpp#L80-L114
  1. { L"EnableUWPWindow", RuntimeEnabledFeature::EnableUWPWindow, false, 0, 0 }
复制代码
所以我们只需要修改注册表就行了。
  1. Windows Registry Editor Version 5.00
  2. [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WinUI\Xaml]
  3. "EnableUWPWindow"=dword:00000001
复制代码
但是到处修改注册表并不是一个好主意,于是初生之鸟便提出利用Detours来劫持读取注册表的方法:HookCoreAppWinUI
我们将其翻译成 C#,再加一些小修改,便能得出如下内容:
  1. #r "nuget:Detours.Win32Metadata"
  2. #r "nuget:Microsoft.Windows.CsWin32"
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Runtime.CompilerServices;
  6. using System.Runtime.InteropServices;
  7. using Windows.Win32;
  8. using Windows.Win32.Foundation;
  9. using Windows.Win32.System.Registry;
  10. using Detours = Microsoft.Detours.PInvoke;
  11. /// <summary>
  12. /// 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"/>.
  13. /// </summary>
  14. public partial class HookRegistry : IDisposable
  15. {
  16.     /// <summary>
  17.     /// The value that indicates whether the class has been disposed.
  18.     /// </summary>
  19.     private bool disposed;
  20.     /// <summary>
  21.     /// The reference count for the hook.
  22.     /// </summary>
  23.     private static int refCount;
  24.     /// <summary>
  25.     /// The dictionary that maps the <see cref="HKEY"/> to a value that indicates whether the key is a real key.
  26.     /// </summary>
  27.     private static readonly Dictionary<HKEY, bool> xamlKeyMap = [];
  28.     /// <summary>
  29.     /// The object used to synchronize access to the <see cref="xamlKeyMap"/> dictionary.
  30.     /// </summary>
  31.     private static readonly object locker = new();
  32.     /// <remarks>The original <see cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/> function.</remarks>
  33.     /// <inheritdoc cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/>
  34.     private static unsafe delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> RegOpenKeyExW;
  35.     /// <remarks>The original <see cref="PInvoke.RegCloseKey(HKEY)"/> function.</remarks>
  36.     /// <inheritdoc cref="PInvoke.RegCloseKey(HKEY)"/>
  37.     private static unsafe delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> RegCloseKey;
  38.     /// <remarks>The original <see cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/> function.</remarks>
  39.     /// <inheritdoc cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/>
  40.     private static unsafe delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> RegQueryValueExW;
  41.     /// <summary>
  42.     /// Initializes a new instance of the <see cref="HookRegistry"/> class.
  43.     /// </summary>
  44.     public HookRegistry()
  45.     {
  46.         refCount++;
  47.         StartHook();
  48.     }
  49.     /// <summary>
  50.     /// Finalizes this instance of the <see cref="HookRegistry"/> class.
  51.     /// </summary>
  52.     ~HookRegistry()
  53.     {
  54.         Dispose();
  55.     }
  56.     /// <summary>
  57.     /// Gets the value that indicates whether the hook is active.
  58.     /// </summary>
  59.     public static bool IsHooked { get; private set; }
  60.     /// <summary>
  61.     /// Starts the hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.
  62.     /// </summary>
  63.     private static unsafe void StartHook()
  64.     {
  65.         if (!IsHooked)
  66.         {
  67.             using FreeLibrarySafeHandle library = PInvoke.GetModuleHandle("ADVAPI32.dll");
  68.             if (!library.IsInvalid
  69.                 && NativeLibrary.TryGetExport(library.DangerousGetHandle(), "RegOpenKeyExW", out nint regOpenKeyExW)
  70.                 && NativeLibrary.TryGetExport(library.DangerousGetHandle(), nameof(PInvoke.RegCloseKey), out nint regCloseKey)
  71.                 && NativeLibrary.TryGetExport(library.DangerousGetHandle(), "RegQueryValueExW", out nint regQueryValueExW))
  72.             {
  73.                 void* regOpenKeyExWPtr = (void*)regOpenKeyExW;
  74.                 void* regCloseKeyPtr = (void*)regCloseKey;
  75.                 void* regQueryValueExWPtr = (void*)regQueryValueExW;
  76.                 delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> overrideRegOpenKeyExW = &OverrideRegOpenKeyExW;
  77.                 delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> overrideRegCloseKey = &OverrideRegCloseKey;
  78.                 delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> overrideRegQueryValueExW = &OverrideRegQueryValueExW;
  79.                 _ = Detours.DetourRestoreAfterWith();
  80.                 _ = Detours.DetourTransactionBegin();
  81.                 _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
  82.                 _ = Detours.DetourAttach(ref regOpenKeyExWPtr, overrideRegOpenKeyExW);
  83.                 _ = Detours.DetourAttach(ref regCloseKeyPtr, overrideRegCloseKey);
  84.                 _ = Detours.DetourAttach(ref regQueryValueExWPtr, overrideRegQueryValueExW);
  85.                 _ = Detours.DetourTransactionCommit();
  86.                 RegOpenKeyExW = (delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR>)regOpenKeyExWPtr;
  87.                 RegCloseKey = (delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR>)regCloseKeyPtr;
  88.                 RegQueryValueExW = (delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR>)regQueryValueExWPtr;
  89.                 IsHooked = true;
  90.             }
  91.         }
  92.     }
  93.     /// <summary>
  94.     /// Ends the hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.
  95.     /// </summary>
  96.     public static unsafe void EndHook()
  97.     {
  98.         if (--refCount == 0 && IsHooked)
  99.         {
  100.             void* regOpenKeyExWPtr = RegOpenKeyExW;
  101.             void* regCloseKeyPtr = RegCloseKey;
  102.             void* regQueryValueExWPtr = RegQueryValueExW;
  103.             delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*, WIN32_ERROR> overrideRegOpenKeyExW = &OverrideRegOpenKeyExW;
  104.             delegate* unmanaged[Stdcall]<HKEY, WIN32_ERROR> overrideRegCloseKey = &OverrideRegCloseKey;
  105.             delegate* unmanaged[Stdcall]<HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*, WIN32_ERROR> overrideRegQueryValueExW = &OverrideRegQueryValueExW;
  106.             _ = Detours.DetourTransactionBegin();
  107.             _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
  108.             _ = Detours.DetourDetach(&regOpenKeyExWPtr, overrideRegOpenKeyExW);
  109.             _ = Detours.DetourDetach(&regCloseKeyPtr, overrideRegCloseKey);
  110.             _ = Detours.DetourDetach(&regQueryValueExWPtr, overrideRegQueryValueExW);
  111.             _ = Detours.DetourTransactionCommit();
  112.             RegOpenKeyExW = null;
  113.             RegCloseKey = null;
  114.             RegQueryValueExW = null;
  115.             IsHooked = false;
  116.         }
  117.     }
  118.     /// <remarks>The overridden <see cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/> function.</remarks>
  119.     /// <inheritdoc cref="PInvoke.RegOpenKeyEx(HKEY, PCWSTR, uint, REG_SAM_FLAGS, HKEY*)"/>
  120.     [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
  121.     private static unsafe WIN32_ERROR OverrideRegOpenKeyExW(HKEY hKey, PCWSTR lpSubKey, uint ulOptions, REG_SAM_FLAGS samDesired, HKEY* phkResult)
  122.     {
  123.         WIN32_ERROR result = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
  124.         if (hKey == HKEY.HKEY_LOCAL_MACHINE && lpSubKey.ToString().Equals(@"Software\Microsoft\WinUI\Xaml", StringComparison.OrdinalIgnoreCase))
  125.         {
  126.             if (result == WIN32_ERROR.ERROR_FILE_NOT_FOUND)
  127.             {
  128.                 HKEY key = new(HANDLE.INVALID_HANDLE_VALUE);
  129.                 xamlKeyMap[key] = false;
  130.                 *phkResult = key;
  131.                 result = WIN32_ERROR.ERROR_SUCCESS;
  132.             }
  133.             else if (result == WIN32_ERROR.ERROR_SUCCESS)
  134.             {
  135.                 xamlKeyMap[*phkResult] = true;
  136.             }
  137.         }
  138.         return result;
  139.     }
  140.     /// <remarks>The overridden <see cref="PInvoke.RegCloseKey(HKEY)"/> function.</remarks>
  141.     /// <inheritdoc cref="PInvoke.RegCloseKey(HKEY)"/>
  142.     [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
  143.     private static unsafe WIN32_ERROR OverrideRegCloseKey(HKEY hKey)
  144.     {
  145.         bool isXamlKey;
  146.         lock (locker)
  147.         {
  148.             if (isXamlKey = xamlKeyMap.TryGetValue(hKey, out bool isRealKey))
  149.             {
  150.                 xamlKeyMap.Remove(hKey);
  151.             }
  152.             return isXamlKey
  153.                 ? isRealKey
  154.                     ? RegCloseKey(hKey) // real key
  155.                     : WIN32_ERROR.ERROR_SUCCESS // simulated key
  156.                 : hKey == HANDLE.INVALID_HANDLE_VALUE
  157.                     ? WIN32_ERROR.ERROR_INVALID_HANDLE
  158.                     : RegCloseKey(hKey);
  159.         }
  160.     }
  161.     /// <remarks>The overridden <see cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/> function.</remarks>
  162.     /// <inheritdoc cref="PInvoke.RegQueryValueEx(HKEY, PCWSTR, uint*, REG_VALUE_TYPE*, byte*, uint*)"/>
  163.     [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
  164.     private static unsafe WIN32_ERROR OverrideRegQueryValueExW(HKEY hKey, PCWSTR lpValueName, [Optional] uint* lpReserved, [Optional] REG_VALUE_TYPE* lpType, [Optional] byte* lpData, [Optional] uint* lpcbData)
  165.     {
  166.         if (lpValueName.Value != default && lpValueName.ToString().Equals("EnableUWPWindow", StringComparison.OrdinalIgnoreCase))
  167.         {
  168.             lock (locker)
  169.             {
  170.                 if (xamlKeyMap.TryGetValue(hKey, out bool isRealKey))
  171.                 {
  172.                     WIN32_ERROR result;
  173.                     if (isRealKey)
  174.                     {
  175.                         // real key
  176.                         result = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
  177.                         if (result == WIN32_ERROR.ERROR_SUCCESS && lpData != default)
  178.                         {
  179.                             *lpData = 1;
  180.                         }
  181.                         else if (result == WIN32_ERROR.ERROR_FILE_NOT_FOUND)
  182.                         {
  183.                             if (lpData == default && lpcbData != default)
  184.                             {
  185.                                 *lpcbData = sizeof(int);
  186.                                 result = WIN32_ERROR.ERROR_SUCCESS;
  187.                             }
  188.                             else if (lpData != default && lpcbData != default)
  189.                             {
  190.                                 if (*lpcbData >= sizeof(int))
  191.                                 {
  192.                                     *lpData = 1;
  193.                                     result = WIN32_ERROR.ERROR_SUCCESS;
  194.                                 }
  195.                                 else
  196.                                 {
  197.                                     result = WIN32_ERROR.ERROR_MORE_DATA;
  198.                                 }
  199.                             }
  200.                         }
  201.                     }
  202.                     else
  203.                     {
  204.                         // simulated key
  205.                         result = WIN32_ERROR.ERROR_FILE_NOT_FOUND;
  206.                         if (lpData == default && lpcbData != default)
  207.                         {
  208.                             *lpcbData = sizeof(int);
  209.                             result = WIN32_ERROR.ERROR_SUCCESS;
  210.                         }
  211.                         else if (lpData != default && lpcbData != default)
  212.                         {
  213.                             if (*lpcbData >= sizeof(int))
  214.                             {
  215.                                 *lpData = 1;
  216.                                 result = WIN32_ERROR.ERROR_SUCCESS;
  217.                             }
  218.                             else
  219.                             {
  220.                                 result = WIN32_ERROR.ERROR_MORE_DATA;
  221.                             }
  222.                         }
  223.                     }
  224.                     return result;
  225.                 }
  226.             }
  227.         }
  228.         return RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
  229.     }
  230.     /// <inheritdoc/>
  231.     public void Dispose()
  232.     {
  233.         if (!disposed && IsHooked)
  234.         {
  235.             EndHook();
  236.         }
  237.         GC.SuppressFinalize(this);
  238.         disposed = true;
  239.     }
  240. }
复制代码
随后我们只需要在入口点创建App时进行劫持就行了。
  1. private static bool IsSupportCoreWindow
  2. {
  3.     get
  4.     {
  5.         try
  6.         {
  7.             RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\WinUI\Xaml");
  8.             return registryKey?.GetValue("EnableUWPWindow") is > 0;
  9.         }
  10.         catch
  11.         {
  12.             return false;
  13.         }
  14.     }
  15. }
  16. private static void Main()
  17. {
  18.     ComWrappersSupport.InitializeComWrappers();
  19.     HookRegistry hookRegistry = null;
  20.     try
  21.     {
  22.         if (!IsSupportCoreWindow)
  23.         {
  24.             hookRegistry = new HookRegistry();
  25.         }
  26.         XamlCheckProcessRequirements();
  27.         Application.Start(p =>
  28.         {
  29.             DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread());
  30.             SynchronizationContext.SetSynchronizationContext(context);
  31.             _ = new App();
  32.         });
  33.     }
  34.     finally
  35.     {
  36.         hookRegistry?.Dispose();
  37.     }
  38. }
复制代码
当然想要自定义入口函数,我们需要在csproj加上定义。
  1. <DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
复制代码
同时还要记得在清单中明确入口点。
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Package ...>
  3.   ...
  4.   <Applications>
  5.     <Application ...
  6.       EntryPoint="明确的入口点">
  7.       ...
  8.     </Application>
  9.   </Applications>
  10.   ...
  11. </Package>
复制代码
随后我们就可以正常的使用 UWP/WAS 了。
最后附上示例应用:https://github.com/wherewhere/CoreAppUWP/tree/muxc

来源:https://www.cnblogs.com/wherewhere/p/18447226
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
来自手机

举报 回复 使用道具