Add capture test

This commit is contained in:
huiyadanli
2023-10-07 11:26:26 +08:00
parent 088360fe8d
commit 9d8c07a2a9
12 changed files with 348 additions and 0 deletions

View File

@@ -21,6 +21,10 @@ GetWindowThreadProcessId
mouse_event
PostMessage
ReleaseDC
EnumWindows
GetWindowText
IsWindowVisible
GetWindowTextLength
// COM & WinRT
D3D11CreateDevice

View File

@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterGenshinImpact.Win32",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.WindowCapture", "Fischless.WindowCapture\Fischless.WindowCapture.csproj", "{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vision.WindowCapture.Test", "Vision.WindowCapture.Test\Vision.WindowCapture.Test.csproj", "{D35CB953-C666-4E57-9A9A-3AAE5BF78402}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -51,6 +53,14 @@ Global
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|Any CPU.Build.0 = Release|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.ActiveCfg = Release|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.Build.0 = Release|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.ActiveCfg = Debug|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.Build.0 = Debug|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.Build.0 = Release|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.ActiveCfg = Release|Any CPU
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,9 @@
<Application x:Class="Vision.WindowCapture.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -0,0 +1,12 @@
<Window x:Class="Vision.WindowCapture.Test.CaptureTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="CaptureTestWindow" Height="450" Width="800">
<Grid>
<Image x:Name="DisplayCaptureResultImage" Height="Auto" Width="Auto" />
</Grid>
</Window>

View File

@@ -0,0 +1,69 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Windows.Win32.Foundation;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// CaptureTestWindow.xaml 的交互逻辑
/// </summary>
public partial class CaptureTestWindow : Window
{
private IWindowCapture? _capture;
public CaptureTestWindow()
{
InitializeComponent();
}
public void StartCapture(IntPtr hWnd, CaptureModeEnum captureMode)
{
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("请选择窗口");
return;
}
_capture = WindowCaptureFactory.Create(captureMode);
_capture.Start((HWND)hWnd);
CompositionTarget.Rendering += Loop;
}
private void Loop(object? sender, EventArgs e)
{
var sw = new Stopwatch();
sw.Start();
var bitmap = _capture?.Capture();
sw.Stop();
Debug.WriteLine("截图耗时:" + sw.ElapsedMilliseconds);
if (bitmap != null)
{
sw.Reset();
sw.Start();
DisplayCaptureResultImage.Source = ToBitmapImage(bitmap);
sw.Stop();
Debug.WriteLine("转换耗时:" + sw.ElapsedMilliseconds);
}
}
public static BitmapImage ToBitmapImage( Bitmap bitmap)
{
var ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
var image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
}
}

View File

@@ -0,0 +1,12 @@
<Window x:Class="Vision.WindowCapture.Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="400">
<Canvas>
<Button x:Name="CaptureBtn" Content="Capture" Canvas.Left="30" Canvas.Top="98" Width="75" Click="CaptureBtn_OnClick"/>
</Canvas>
</Window>

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CaptureBtn_OnClick(object sender, RoutedEventArgs e)
{
var picker = new PickerWindow();
var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(this).Handle);
if (hWnd != IntPtr.Zero)
{
var captureWindow = new CaptureTestWindow();
captureWindow.StartCapture(hWnd, CaptureModeEnum.WindowsGraphicsCapture);
captureWindow.Show();
}
}
}
}

View File

@@ -0,0 +1,36 @@
<Window x:Class="Vision.WindowCapture.Test.PickerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
mc:Ignorable="d"
Title="选择捕获窗口" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="5,0"
Orientation="Horizontal">
<TextBlock FontSize="20" Text="双击选中要捕获的窗口" />
</StackPanel>
<ListBox
x:Name="WindowList"
Grid.Row="1"
Padding="0,10"
BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl MouseDoubleClick="WindowsOnMouseDoubleClick">
<TextBlock FontSize="14" Text="{Binding Name}" />
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

View File

@@ -0,0 +1,107 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using Windows.Win32;
using Windows.Win32.Foundation;
using static Windows.Win32.PInvoke;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// PickerWindow.xaml 的交互逻辑
/// </summary>
public partial class PickerWindow : Window
{
private readonly string[] _ignoreProcesses = { "applicationframehost", "shellexperiencehost", "systemsettings", "winstore.app", "searchui" };
public PickerWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
FindWindows();
}
public IntPtr PickCaptureTarget(IntPtr hWnd)
{
new WindowInteropHelper(this).Owner = hWnd;
ShowDialog();
return ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero;
}
private unsafe void FindWindows()
{
var wih = new WindowInteropHelper(this);
EnumWindows((hWnd, lParam) =>
{
// ignore invisible windows
if (!IsWindowVisible(hWnd))
return true;
// ignore untitled windows
string title;
int bufferSize = GetWindowTextLength(hWnd) + 1;
fixed (char* windowNameChars = new char[bufferSize])
{
if (GetWindowText(hWnd, windowNameChars, bufferSize) == 0)
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode != 0)
{
throw new Win32Exception(errorCode);
}
return true;
}
title = new string(windowNameChars);
if (string.IsNullOrWhiteSpace(title))
return true;
}
// ignore me
if (wih.Handle == hWnd)
return true;
uint processId;
GetWindowThreadProcessId(hWnd, &processId);
// ignore by process name
var process = Process.GetProcessById((int)processId);
if (_ignoreProcesses.Contains(process.ProcessName.ToLower()))
return true;
WindowList.Items.Add(new CapturableWindow
{
Handle = hWnd,
Name = $"{title} ({process.ProcessName}.exe)"
});
return true;
}, IntPtr.Zero);
}
private void WindowsOnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Close();
}
}
public struct CapturableWindow
{
public string Name { get; set; }
public IntPtr Handle { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.22000.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Vision.WindowCapture\Vision.WindowCapture.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="CaptureTestWindow.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>