|
众所周知,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(®OpenKeyExWPtr, overrideRegOpenKeyExW);
- _ = Detours.DetourDetach(®CloseKeyPtr, overrideRegCloseKey);
- _ = Detours.DetourDetach(®QueryValueExWPtr, 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
来源:https://www.cnblogs.com/wherewhere/p/18447226
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|