任意程式上的蒙版畫筆實現

猝不及防發表於2021-04-26

任意程式上的蒙版畫筆實現

根據

SetWindowPos function (winuser.h) - Win32 apps | Microsoft Docs

SetWindowDisplayAffinity function (winuser.h) - Win32 apps | Microsoft Docs

總效果:

上面是一個透明畫的筆應用和一個閱讀的應用,我們可以控制畫筆在上層或者下層達到一個蒙版的效果。

核心:

1 一個視窗蓋住另一個效果
        public static void Active(IntPtr handleToActive, IntPtr handleToPutToSecondFloor)
        {
            SetWindowPos(handleToActive, new IntPtr(HWND_TOPMOST), 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
            SetWindowPos(handleToPutToSecondFloor, new IntPtr(HWND_NOTOPMOST), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
            SetForegroundWindow(handleToActive);
        }

2 去除窗體辯題邊框等
  public static void RemoveWindowBorder(IntPtr handle)
        {
            SetWindowLongA(handle, GWL_STYLE, WS_VISIBLE);
        }
3 移動窗體改變大小
  public static void MoveAndResizeWindow(IntPtr handle, int x, int y, int cx, int cy, bool repaint)
        {
            MoveWindow(handle, x, y, cx, cy, repaint);
        }

一 透明的IncCavans畫板

對於蒙版畫筆程式的窗體,我們需要設定透明

WindowState="Maximized" WindowStyle="None"  Background="Transparent" AllowsTransparency="True" Topmost="True" IsHitTestVisible="True"

對於IncCavans,我們需要設定其背景透明,但是純透明的話就無法顯示畫筆了,所以要留一點透明度

 <InkCanvas Name="inkCanvas" >
            <InkCanvas.Background>
                <SolidColorBrush Color="Gray" Opacity="0.05" ></SolidColorBrush>
            </InkCanvas.Background>
        </InkCanvas>

二 在啟動被蒙版的應用

我們通過Process啟動該程式,需要注意的是,AppProcess.WaitForInputIdle();並不能判斷窗體已經載入完成,可以通過判斷AppProcess.MainWindowHandle == IntPtr.Zero來判斷窗體是否建立完成

  try
            {

                AppProcess = new System.Diagnostics.Process();
                var procInfo = new System.Diagnostics.ProcessStartInfo(AppPath);
                procInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(AppPath);
                //procInfo.UseShellExecute = false;
                //procInfo.CreateNoWindow = true;
                //procInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                AppProcess.StartInfo = procInfo;
                AppProcess.Start();
                AppProcess.WaitForInputIdle();
                while (AppProcess.MainWindowHandle == IntPtr.Zero)
                {
                    Thread.Sleep(10);
                }
                AppWindowHandle = AppProcess.MainWindowHandle;
            }
            catch (Exception ex)
            {
                //Debug.Print(ex.Message + "Error");
                MessageBox.Show(ex.Message + "Error");
            }

三 將被蒙版的應用放在合適的位置

   var window = Window.GetWindow(this);
            var helper = new WindowInteropHelper(Window.GetWindow(window));
            MaskToolModel = new MaskToolModel(AppPath, helper.Handle);
            var loacation = this.TransformToAncestor(window).Transform(new Point(0, 0));
            MaskToolModel.LoadApplicationWindow((int)loacation.X, (int)loacation.Y, (int)this.ActualWidth, (int)this.ActualHeight);

四 關於透射的一些注意事項

比如

因為上層窗體透明,所以當滑鼠劃過,下層的Button.MouseOver事件也會觸發,此時,我們需要給他一個Contaniner,並設定IsHitTestVisible="False"

  <Grid Grid.Row="0" Name="Container" IsHitTestVisible="False">
            <mask:MaskTool x:Name="maskControl" AppPath="{Binding U3DAppPath}" IsAppWindowActive="{Binding IsU3DWindowActive}" ></mask:MaskTool>
        </Grid>

五 個人封裝了一個自定義控制元件來簡單實現此效果

<Grid Grid.Row="0" Name="Container" IsHitTestVisible="True">
            <mask:MaskTool x:Name="maskControl" AppPath="{Binding U3DAppPath}" IsAppWindowActive="{Binding IsU3DWindowActive}" ></mask:MaskTool>
        </Grid>

AppPath:被蒙版層應用路徑

IsAppWindowActive:True蒙版層應用顯示在上層

核心程式碼:

在Userload時載入應用,也不用擔心Dispose下層應用,在window.closed時自動Dispose:

   private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            var window = Window.GetWindow(this);
            window.Closed += Window_Closed;
            var helper = new WindowInteropHelper(Window.GetWindow(window));
            MaskToolModel = new MaskToolModel(AppPath, helper.Handle);
            var loacation = this.TransformToAncestor(window).Transform(new Point(0, 0));
            MaskToolModel.LoadApplicationWindow((int)loacation.X, (int)loacation.Y, (int)this.ActualWidth, (int)this.ActualHeight);
        }

Github:tiancai4652/MaskTool: Two ppp.window Show like in one (github.com)

相關文章