<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【UWP】讓 UWP 自己托管自己 —— Windows App SDK 篇

      眾所周知,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方法。具體內容如下:

      #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 bool disposed;
      
          /// <summary>
          /// The reference count for the hook.
          /// </summary>
          private static int refCount;
      
          /// <summary>
          /// The value that represents the current process token.
          /// </summary>
          private const int currentProcessToken = -6;
      
          /// <remarks>The original <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.</remarks>
          /// <inheritdoc cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/>
          private static unsafe delegate* unmanaged[Stdcall]<HANDLE, AppPolicyWindowingModel*, WIN32_ERROR> AppPolicyGetWindowingModel;
      
          /// <summary>
          /// Initializes a new instance of the <see cref="HookWindowingModel"/> class.
          /// </summary>
          public HookWindowingModel()
          {
              refCount++;
              StartHook();
          }
      
          /// <summary>
          /// Finalizes this instance of the <see cref="HookWindowingModel"/> class.
          /// </summary>
          ~HookWindowingModel()
          {
              Dispose();
          }
      
          /// <summary>
          /// Gets the value that indicates whether the hook is active.
          /// </summary>
          public static bool IsHooked { get; private set; }
      
          /// <summary>
          /// Gets or sets the windowing model to use when the hooked <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function is called.
          /// </summary>
          internal static AppPolicyWindowingModel WindowingModel { get; set; } = AppPolicyWindowingModel.AppPolicyWindowingModel_ClassicDesktop;
      
          /// <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("KERNEL32.dll");
                  if (!library.IsInvalid && NativeLibrary.TryGetExport(library.DangerousGetHandle(), nameof(PInvoke.AppPolicyGetWindowingModel), out nint appPolicyGetWindowingModel))
                  {
                      void* appPolicyGetWindowingModelPtr = (void*)appPolicyGetWindowingModel;
                      delegate* unmanaged[Stdcall]<HANDLE, AppPolicyWindowingModel*, WIN32_ERROR> overrideAppPolicyGetWindowingModel = &OverrideAppPolicyGetWindowingModel;
      
                      _ = Detours.DetourRestoreAfterWith();
      
                      _ = Detours.DetourTransactionBegin();
                      _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
                      _ = Detours.DetourAttach(ref appPolicyGetWindowingModelPtr, overrideAppPolicyGetWindowingModel);
                      _ = Detours.DetourTransactionCommit();
      
                      AppPolicyGetWindowingModel = (delegate* unmanaged[Stdcall]<HANDLE, AppPolicyWindowingModel*, WIN32_ERROR>)appPolicyGetWindowingModelPtr;
                      IsHooked = true;
                  }
              }
          }
      
          /// <summary>
          /// Ends the hook for the <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.
          /// </summary>
          private static unsafe void EndHook()
          {
              if (--refCount == 0 && IsHooked)
              {
                  void* appPolicyGetWindowingModelPtr = AppPolicyGetWindowingModel;
                  delegate* unmanaged[Stdcall]<HANDLE, AppPolicyWindowingModel*, WIN32_ERROR> overrideAppPolicyGetWindowingModel = &OverrideAppPolicyGetWindowingModel;
      
                  _ = Detours.DetourTransactionBegin();
                  _ = Detours.DetourUpdateThread(PInvoke.GetCurrentThread());
                  _ = Detours.DetourDetach(&appPolicyGetWindowingModelPtr, overrideAppPolicyGetWindowingModel);
                  _ = Detours.DetourTransactionCommit();
      
                  AppPolicyGetWindowingModel = null;
                  IsHooked = false;
              }
          }
      
          /// <param name="policy">A pointer to a variable of the <a >AppPolicyWindowingModel</a> enumerated type.
          /// When the function returns successfully, the variable contains the <see cref="WindowingModel"/> when the identified process is current; otherwise, the windowing model of the identified process.</param>
          /// <remarks>The overridden <see cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/> function.</remarks>
          /// <inheritdoc cref="PInvoke.AppPolicyGetWindowingModel(HANDLE, AppPolicyWindowingModel*)"/>
          [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
          private static unsafe WIN32_ERROR OverrideAppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel* policy)
          {
              if ((int)processToken.Value == currentProcessToken)
              {
                  *policy = WindowingModel;
                  return WIN32_ERROR.ERROR_SUCCESS;
              }
              return AppPolicyGetWindowingModel(processToken, policy);
          }
      
          /// <inheritdoc/>
          public void Dispose()
          {
              if (!disposed && IsHooked)
              {
                  EndHook();
              }
              GC.SuppressFinalize(this);
              disposed = true;
          }
      }

      準備工作完成,接下來我們就可以創建窗口了,如果順利的話我們只需要new Microsoft.UI.Xaml.Window()就行了,但是很遺憾,經過測試在 UWP 并不能正常初始化這個類,有可能是我使用的方法不太正確,或許以后可能能找到正常使用的辦法,不過現在我們只能去手動創建一個 Win32 窗口了。

      首先我們需要新創建一個線程,CoreWindow 線程無法新建 XAML 島,不過在 XAML 島線程可以,新建線程只需要用Thread就行了。

      new Thread(() => { ... });

      WAS 提供了AppWindow來管理 win32 窗口,我們只需要使用它創建一個窗口就行了。

      AppWindow window = AppWindow.Create();

      接下來我們需要創建 XAML 島,這時我們就需要利用上面劫持器來劫持獲取應用模型的方法了。

      DispatcherQueueController controller;
      DesktopWindowXamlSource source;
      
      using (HookWindowingModel hook = new())
      {
          controller = DispatcherQueueController.CreateOnCurrentThread();
          source = new DesktopWindowXamlSource();
      }

      然后我們就可以把 XAML 島糊到之前創建的 AppWindow 上了。

      source.Initialize(window.Id);
      DesktopChildSiteBridge bridge = source.SiteBridge;
      bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
      bridge.Show();
      
      DispatcherQueue dispatcherQueue = controller.DispatcherQueue;
      window.AssociateWithDispatcherQueue(dispatcherQueue);

      由于 XAML 島存在的一些特性,當窗口擴展標題欄或者全屏化的時候窗口內容并不會跟著變化,所以我們需要一些小魔法來讓它在變化時調整大小。

      window.Changed += (sender, args) =>
      {
          if (args.DidPresenterChange)
          {
              bridge.ResizePolicy = ContentSizePolicy.None;
              bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
          }
      };

      最后不要忘了保持當前線程,不然這里跑完了窗口就退出了。

      dispatcherQueue.RunEventLoop();
      await controller.ShutdownQueueAsync();

      當窗口關閉后記得執行DispatcherQueue.EnqueueEventLoopExit()來釋放保持的線程。

      最后把之前的東西組合起來,再加點東西:

      /// <summary>
      /// Create a new <see cref="DesktopWindow"/> instance.
      /// </summary>
      /// <param name="launched">Do something after <see cref="DesktopWindowXamlSource"/> created.</param>
      /// <returns>The new instance of <see cref="DesktopWindow"/>.</returns>
      public static Task<DesktopWindow> CreateAsync(Action<DesktopWindowXamlSource> launched)
      {
          TaskCompletionSource<DesktopWindow> taskCompletionSource = new();
      
          new Thread(async () =>
          {
              try
              {
                  DispatcherQueueController controller;
                  DesktopWindowXamlSource source;
                  AppWindow window = AppWindow.Create();
      
                  using (HookWindowingModel hook = new())
                  {
                      controller = DispatcherQueueController.CreateOnCurrentThread();
                      source = new DesktopWindowXamlSource();
                  }
      
                  source.Initialize(window.Id);
                  DesktopChildSiteBridge bridge = source.SiteBridge;
                  bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
                  bridge.Show();
      
                  window.Changed += (sender, args) =>
                  {
                      if (args.DidPresenterChange)
                      {
                          bridge.ResizePolicy = ContentSizePolicy.None;
                          bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
                      }
                  };
      
                  DispatcherQueue dispatcherQueue = controller.DispatcherQueue;
                  window.AssociateWithDispatcherQueue(dispatcherQueue);
                  TrackWindow(window);
      
                  launched(source);
                  DesktopWindow desktopWindow = new()
                  {
                      AppWindow = window,
                      WindowXamlSource = source
                  };
                  taskCompletionSource.SetResult(desktopWindow);
      
                  dispatcherQueue.RunEventLoop();
                  await controller.ShutdownQueueAsync();
              }
              catch (Exception e)
              {
                  taskCompletionSource.SetException(e);
              }
          })
          {
              Name = nameof(DesktopWindowXamlSource)
          }.Start();
      
          return taskCompletionSource.Task;
      }
      
      /// <summary>
      /// Create a new <see cref="DesktopWindow"/> instance.
      /// </summary>
      /// <param name="dispatcherQueue">The <see cref="DispatcherQueue"/> to provide thread.</param>
      /// <param name="launched">Do something after <see cref="DesktopWindowXamlSource"/> created.</param>
      /// <returns>The new instance of <see cref="DesktopWindow"/>.</returns>
      public static Task<DesktopWindow> CreateAsync(DispatcherQueue dispatcherQueue, Action<DesktopWindowXamlSource> launched)
      {
          TaskCompletionSource<DesktopWindow> taskCompletionSource = new();
      
          _ = dispatcherQueue.TryEnqueue(() =>
          {
              try
              {
                  DesktopWindowXamlSource source;
                  AppWindow window = AppWindow.Create();
                  window.AssociateWithDispatcherQueue(dispatcherQueue);
                  TrackWindow(window);
      
                  using (HookWindowingModel hook = new())
                  {
                      source = new DesktopWindowXamlSource();
                  }
      
                  source.Initialize(window.Id);
                  DesktopChildSiteBridge bridge = source.SiteBridge;
                  bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
                  bridge.Show();
      
                  window.Changed += (sender, args) =>
                  {
                      if (args.DidPresenterChange)
                      {
                          bridge.ResizePolicy = ContentSizePolicy.None;
                          bridge.ResizePolicy = ContentSizePolicy.ResizeContentToParentWindow;
                      }
                  };
      
                  launched(source);
                  DesktopWindow desktopWindow = new()
                  {
                      AppWindow = window,
                      WindowXamlSource = source
                  };
                  taskCompletionSource.SetResult(desktopWindow);
              }
              catch (Exception e)
              {
                  taskCompletionSource.SetException(e);
              }
          });
      
          return taskCompletionSource.Task;
      }
      
      private static void TrackWindow(AppWindow window)
      {
          if (ActiveDesktopWindows.ContainsKey(window.DispatcherQueue))
          {
              ActiveDesktopWindows[window.DispatcherQueue] += 1;
          }
          else
          {
              ActiveDesktopWindows[window.DispatcherQueue] = 1;
          }
          window.Destroying -= AppWindow_Destroying;
          window.Destroying += AppWindow_Destroying;
      }
      
      private static void AppWindow_Destroying(AppWindow sender, object args)
      {
          if (ActiveDesktopWindows.TryGetValue(sender.DispatcherQueue, out ulong num))
          {
              num--;
              if (num == 0)
              {
                  ActiveDesktopWindows.Remove(sender.DispatcherQueue);
                  sender.DispatcherQueue.EnqueueEventLoopExit();
                  return;
              }
              ActiveDesktopWindows[sender.DispatcherQueue] = num;
          }
      }
      
      private static Dictionary<DispatcherQueue, ulong> ActiveDesktopWindows { get; } = [];

      其中DesktopWindow是用來存放AppWindowDesktopWindowXamlSource的類,如果不嫌麻煩的話可以包裹成一個和Microsoft.UI.Xaml.Window一樣的東西。

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

      WUXC 篇:【UWP】讓 UWP 自己托管自己 —— Windows SDK 篇

      posted @ 2024-11-03 16:10  where-where  閱讀(413)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 久久亚洲精品国产精品尤物| 最新亚洲人成网站在线影院| 亚洲日韩精品一区二区三区无码| 九九热视频在线观看精品| 中文有无人妻VS无码人妻激烈| 仪陇县| 男女啪啪高清无遮挡免费| 国产精品一区二区传媒蜜臀| 天美传媒xxxxhd videos3| 日本午夜精品一区二区三区电影| 亚洲精品日本久久久中文字幕| 疯狂添女人下部视频免费| 精品少妇人妻av无码专区| 九九久久人妻精品一区色| 国产69精品久久久久久妇女迅雷| 日韩欧美一中文字暮专区| 日本高清一区免费中文视频| 狠狠v日韩v欧美v| 潮喷失禁大喷水无码| 肉大榛一进一出免费视频| 91人妻熟妇在线视频| 久久精品一区二区日韩av| 少妇仑乱a毛片无码| 少妇熟女久久综合网色欲| 精品亚洲精品日韩精品| 精品国产成人国产在线观看 | 综合图区亚洲另类偷窥| 亚洲国产码专区在线观看| 一区二区中文字幕视频| 池州市| 亚洲一区二区三区久久受| 最新亚洲av日韩av二区| 国内自产少妇自拍区免费| 精品无码午夜福利理论片| 日韩精品国产另类专区| 日韩乱码人妻无码中文字幕视频 | 99re6在线视频精品免费下载| 你懂的亚洲一区二区三区| 精品日韩人妻中文字幕| 东方av四虎在线观看| 成人性生交大片免费看|