feat: init

This commit is contained in:
huiyadanli 2023-08-27 09:12:37 +08:00
commit 2cf632195c
20 changed files with 1017 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
.vs/
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Mine
Tmp/
/packages/
node_modules/

31
BetterGenshinImpact.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33815.320
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterGenshinImpact", "BetterGenshinImpact\BetterGenshinImpact.csproj", "{75EC89E2-413D-4725-BCEA-AFAC57708F07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vision.WindowCapture", "Vision.WindowCapture\Vision.WindowCapture.csproj", "{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|Any CPU.Build.0 = Release|Any CPU
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {352D8B78-9DE3-4E58-985F-FADD22594DB4}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,9 @@
<Application x:Class="BetterGenshinImpact.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BetterGenshinImpact"
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 BetterGenshinImpact
{
/// <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,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.22000.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Vision.WindowCapture\Vision.WindowCapture.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace BetterGenshinImpact.Extensions
{
public static class BitmapExtension
{
public static BitmapImage ToBitmapImage(this Bitmap bitmap)
{
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
}
}

View File

@ -0,0 +1,26 @@
<Window x:Class="BetterGenshinImpact.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:BetterGenshinImpact"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
AllowsTransparency="True"
WindowStyle="None"
Topmost="True"
ShowInTaskbar="False"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Background>
<SolidColorBrush Color="#FFB0B0B0"
Opacity="0" />
</Window.Background>
<Grid>
<Image x:Name="ImageResult" HorizontalAlignment="Left" Height="172" Margin="129,10,0,0" VerticalAlignment="Top" Width="281"/>
<Button x:Name="StartBtn" Content="开始捕获" HorizontalAlignment="Left" Height="22" Margin="10,10,0,0" VerticalAlignment="Top" Width="78" Click="Button_Click"/>
<ComboBox x:Name="CboCaptureType" HorizontalAlignment="Left" Height="23" Margin="10,173,0,0" VerticalAlignment="Top" Width="78" ItemsSource="{Binding ModeNames}" SelectedItem="{Binding SelectedMode, Mode=TwoWay}"/>
<Button x:Name="StopBtn" Content="停止" HorizontalAlignment="Left" Margin="10,44,0,0" VerticalAlignment="Top" Height="28" Width="78" Click="StopBtn_Click"/>
<TextBlock HorizontalAlignment="Left" Margin="117,279,0,0" TextWrapping="Wrap" Text="INFO|XXXXXXXXXXXXXXXXXXXXXXXX/nxxxxxxxxxxxxxxxxxxxx" VerticalAlignment="Top" Height="161" Width="180"/>
</Grid>
</Window>

View File

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
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;
using System.Windows.Threading;
using BetterGenshinImpact.Extensions;
using Vanara.PInvoke;
using Vision.WindowCapture;
using Vision.WindowCapture.BitBlt;
using Vision.WindowCapture.GraphicsCapture;
namespace BetterGenshinImpact
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private IWindowCapture _capture;
public MainWindow()
{
InitializeComponent();
}
public string[] ModeNames { get; } = WindowCaptureFactory.ModeNames();
public string SelectedMode { get; set; }
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Red, 2), new Rect(20, 20, 250, 250));
base.OnRender(drawingContext);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
IntPtr hWnd = FindGenshinImpactHandle();
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("未找到原神窗口");
return;
}
_capture = WindowCaptureFactory.Create(SelectedMode.ToCaptureMode());
_capture.Start(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();
ImageResult.Source = bitmap.ToBitmapImage();
sw.Stop();
Debug.WriteLine("转换耗时:" + sw.ElapsedMilliseconds);
}
}
public IntPtr FindGenshinImpactHandle()
{
var pros = Process.GetProcessesByName("YuanShen");
if (pros.Any())
{
return pros[0].MainWindowHandle;
}
pros = Process.GetProcessesByName("GenshinImpact");
if (pros.Any())
{
return pros[0].MainWindowHandle;
}
return IntPtr.Zero;
}
private void StopBtn_Click(object sender, RoutedEventArgs e)
{
_capture.Stop();
}
}
}

35
README.md Normal file
View File

@ -0,0 +1,35 @@
更多:[🛠️账号切换](https://github.com/babalae/mihoyo-starter)
# 更好的原神
## 截图
## 下载地址
[📥Github下载1.0]()
[📥蓝奏云下载]() 密码:coco
## 使用方法
由于图像识别比较吃性能,低配置电脑可能无法正常使用。
你的系统需要满足以下条件:
* Windows 10 或更高版本的64位系统
* .Net 7
## 问题反馈
提 [Issue](https://github.com/babalae/genius-invokation-auto-toy/issues) 或 QQ群[894935931](https://qm.qq.com/cgi-bin/qm/qr?k=u9Ij0HrDVQhvcoFvaiQGv38V3R7ZNY6K&jump_from=webapi&authKey=N++f74HhGHDzFje1dDD6E8vzuf45jmSFaPiVbc3Z7x/nTUWGwZ3UdSPqYQqPfOXK)
## 投喂
觉的好用的话,可以支持作者哟ヾ(・ω・`。) 👇
* [⚡爱发电](https://afdian.net/@huiyadanli)
* [🍚微信赞赏](https://github.com/huiyadanli/huiyadanli/blob/master/DONATE.md)

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Vanara.Extensions;
using Vanara.PInvoke;
namespace Vision.WindowCapture.BitBlt
{
public class BitBltCapture : IWindowCapture
{
private IntPtr _hWnd;
public bool IsCapturing { get; private set; }
public void Start(IntPtr hWnd)
{
_hWnd = hWnd;
IsCapturing = true;
}
public Bitmap? Capture()
{
if (_hWnd == IntPtr.Zero)
{
return null;
}
User32.GetWindowRect(_hWnd, out var windowRect);
var width = windowRect.right - windowRect.left;
var height = windowRect.bottom - windowRect.top;
var hdcSrc = User32.GetWindowDC(_hWnd);
var hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
var hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);
var hOld = Gdi32.SelectObject(hdcDest, hBitmap);
Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, Gdi32.RasterOperationMode.SRCCOPY);
Gdi32.SelectObject(hdcDest, hOld);
Gdi32.DeleteDC(hdcDest);
User32.ReleaseDC(_hWnd, hdcSrc);
var bitmap = hBitmap.ToBitmap();
Gdi32.DeleteObject(hBitmap);
return bitmap;
}
public void Stop()
{
_hWnd = IntPtr.Zero;
IsCapturing = false;
}
}
}

View File

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Vision.WindowCapture.GraphicsCapture.Helpers;
using Windows.Devices.HumanInterfaceDevice;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Graphics.DirectX.Direct3D11;
using SharpDX.Direct3D11;
using WinRT.Interop;
namespace Vision.WindowCapture.GraphicsCapture
{
public class GraphicsCapture : IWindowCapture
{
private IntPtr _hWnd;
private Direct3D11CaptureFramePool _captureFramePool;
private GraphicsCaptureItem _captureItem;
private GraphicsCaptureSession _captureSession;
public bool IsCapturing { get; private set; }
public void Start(IntPtr hWnd)
{
_hWnd = hWnd;
IsCapturing = true;
/*
// if use GraphicsCapturePicker, need to set this window handle
// new WindowInteropHelper(this).Handle
var picker = new GraphicsCapturePicker();
picker.SetWindow(hWnd);
_captureItem = picker.PickSingleItemAsync().AsTask().Result;
*/
_captureItem = CaptureHelper.CreateItemForWindow(_hWnd);
if (_captureItem == null)
{
throw new InvalidOperationException("Failed to create capture item.");
}
_captureItem.Closed += CaptureItemOnClosed;
var device = Direct3D11Helper.CreateDevice();
_captureFramePool = Direct3D11CaptureFramePool.Create(device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2,
_captureItem.Size);
_captureSession = _captureFramePool.CreateCaptureSession(_captureItem);
_captureSession.StartCapture();
IsCapturing = true;
}
/// <summary>
/// How to handle window size changes?
/// </summary>
/// <returns></returns>
public Bitmap? Capture()
{
using var frame = _captureFramePool?.TryGetNextFrame();
return frame?.ToBitmap();
}
public void Stop()
{
_captureSession?.Dispose();
_captureFramePool?.Dispose();
_captureSession = null;
_captureFramePool = null;
_captureItem = null;
_hWnd = IntPtr.Zero;
IsCapturing = false;
}
private void CaptureItemOnClosed(GraphicsCaptureItem sender, object args)
{
Stop();
}
}
}

View File

@ -0,0 +1,88 @@
// ---------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ---------------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Graphics.Capture;
using WinRT;
namespace Vision.WindowCapture.GraphicsCapture.Helpers
{
public static class CaptureHelper
{
static readonly Guid GraphicsCaptureItemGuid = new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760");
[ComImport]
[Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
interface IInitializeWithWindow
{
void Initialize(
IntPtr hwnd);
}
[ComImport]
[Guid("3628E81B-3CAC-4C60-B7F4-23CE0E0C3356")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
interface IGraphicsCaptureItemInterop
{
IntPtr CreateForWindow(
[In] IntPtr window,
[In] ref Guid iid);
IntPtr CreateForMonitor(
[In] IntPtr monitor,
[In] ref Guid iid);
}
public static void SetWindow(this GraphicsCapturePicker picker, IntPtr hwnd)
{
var interop = picker.As<IInitializeWithWindow>();
interop.Initialize(hwnd);
}
public static GraphicsCaptureItem CreateItemForWindow(IntPtr hwnd)
{
var factory = WinrtModule.GetActivationFactory("Windows.Graphics.Capture.GraphicsCaptureItem");
var interop = factory.AsInterface<IGraphicsCaptureItemInterop>();
var itemPointer = interop.CreateForWindow(hwnd, GraphicsCaptureItemGuid);
return GraphicsCaptureItem.FromAbi(itemPointer);
}
//public static GraphicsCaptureItem CreateItemForMonitor(IntPtr hmon)
//{
// var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
// var interop = (IGraphicsCaptureItemInterop)factory;
// var temp = typeof(GraphicsCaptureItem);
// var itemPointer = interop.CreateForMonitor(hmon, GraphicsCaptureItemGuid);
// var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem;
// Marshal.Release(itemPointer);
// return item;
//}
}
}

View File

@ -0,0 +1,140 @@
// ---------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ---------------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Windows.Graphics.DirectX.Direct3D11;
using WinRT;
namespace Vision.WindowCapture.GraphicsCapture.Helpers
{
public static class Direct3D11Helper
{
static Guid IInspectable = new Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90");
static Guid ID3D11Resource = new Guid("dc8e63f3-d12b-4952-b47b-5e45026a862d");
static Guid IDXGIAdapter3 = new Guid("645967A4-1392-4310-A798-8053CE3E93FD");
static Guid ID3D11Device = new Guid("db6f6ddb-ac77-4e88-8253-819df9bbf140");
static Guid ID3D11Texture2D = new Guid("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
[ComImport]
[Guid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
interface IDirect3DDxgiInterfaceAccess
{
IntPtr GetInterface([In] ref Guid iid);
};
[DllImport(
"d3d11.dll",
EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice",
SetLastError = true,
CharSet = CharSet.Unicode,
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall
)]
static extern UInt32 CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);
[DllImport(
"d3d11.dll",
EntryPoint = "CreateDirect3D11SurfaceFromDXGISurface",
SetLastError = true,
CharSet = CharSet.Unicode,
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall
)]
static extern UInt32 CreateDirect3D11SurfaceFromDXGISurface(IntPtr dxgiSurface, out IntPtr graphicsSurface);
public static IDirect3DDevice CreateDevice()
{
return CreateDevice(false);
}
public static IDirect3DDevice CreateDevice(bool useWARP)
{
var d3dDevice = new SharpDX.Direct3D11.Device(
useWARP ? SharpDX.Direct3D.DriverType.Software : SharpDX.Direct3D.DriverType.Hardware,
SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
var device = CreateDirect3DDeviceFromSharpDXDevice(d3dDevice);
return device;
}
public static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device d3dDevice)
{
IDirect3DDevice device = null;
// Acquire the DXGI interface for the Direct3D device.
using (var dxgiDevice = d3dDevice.QueryInterface<SharpDX.DXGI.Device3>())
{
// Wrap the native device using a WinRT interop object.
uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown);
if (hr == 0)
{
device = MarshalInterface<IDirect3DDevice>.FromAbi(pUnknown);
Marshal.Release(pUnknown);
}
}
return device;
}
public static IDirect3DSurface CreateDirect3DSurfaceFromSharpDXTexture(SharpDX.Direct3D11.Texture2D texture)
{
IDirect3DSurface surface = null;
// Acquire the DXGI interface for the Direct3D surface.
using (var dxgiSurface = texture.QueryInterface<SharpDX.DXGI.Surface>())
{
// Wrap the native device using a WinRT interop object.
uint hr = CreateDirect3D11SurfaceFromDXGISurface(dxgiSurface.NativePointer, out IntPtr pUnknown);
if (hr == 0)
{
surface = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DSurface;
Marshal.Release(pUnknown);
}
}
return surface;
}
public static SharpDX.Direct3D11.Device CreateSharpDXDevice(IDirect3DDevice device)
{
var access = (IDirect3DDxgiInterfaceAccess)device;
var d3dPointer = access.GetInterface(ID3D11Device);
var d3dDevice = new SharpDX.Direct3D11.Device(d3dPointer);
return d3dDevice;
}
public static SharpDX.Direct3D11.Texture2D CreateSharpDXTexture2D(IDirect3DSurface surface)
{
var access = surface.As<IDirect3DDxgiInterfaceAccess>();
var d3dPointer = access.GetInterface(ID3D11Texture2D);
var d3dSurface = new SharpDX.Direct3D11.Texture2D(d3dPointer);
return d3dSurface;
}
}
}

View File

@ -0,0 +1,140 @@
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Vision.WindowCapture.GraphicsCapture.Helpers;
using WinRT;
namespace Vision.WindowCapture.GraphicsCapture.Helpers
{
public static class Texture2DExtensions
{
public static Bitmap? ToBitmap(this Direct3D11CaptureFrame frame)
{
var texture2dBitmap = Direct3D11Helper.CreateSharpDXTexture2D(frame.Surface);
var d3dDevice = texture2dBitmap.Device;
// Create texture copy
var staging = new Texture2D(d3dDevice, new Texture2DDescription
{
Width = frame.ContentSize.Width,
Height = frame.ContentSize.Height,
MipLevels = 1,
ArraySize = 1,
Format = texture2dBitmap.Description.Format,
Usage = ResourceUsage.Staging,
SampleDescription = new SampleDescription(1, 0),
BindFlags = BindFlags.None,
CpuAccessFlags = CpuAccessFlags.Read,
OptionFlags = ResourceOptionFlags.None
});
try
{
// Copy data
d3dDevice.ImmediateContext.CopyResource(texture2dBitmap, staging);
var dataBox = d3dDevice.ImmediateContext.MapSubresource(staging, 0, 0, MapMode.Read,
SharpDX.Direct3D11.MapFlags.None,
out DataStream stream);
var bitmap = new Bitmap(staging.Description.Width, staging.Description.Height, dataBox.RowPitch,
PixelFormat.Format32bppArgb, dataBox.DataPointer);
return bitmap;
}
finally
{
staging.Dispose();
}
}
//public static Stream ToBitmapStream(this Direct3D11CaptureFrame frame)
//{
// var bitmap = frame.ToBitmap();
// Stream memoryStream = new MemoryStream();
// bitmap.Save(memoryStream, ImageFormat.Png);
// return memoryStream;
//}
//public static async Task<SoftwareBitmap> ToSoftwareBitmapAsync(this Direct3D11CaptureFrame frame)
//{
// var result = await SoftwareBitmap.CreateCopyFromSurfaceAsync(frame.Surface, BitmapAlphaMode.Premultiplied);
// return result;
//}
//public static async Task<Bitmap> ToBitmapAsync(this SoftwareBitmap sbitmap)
//{
// using var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
// var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
// encoder.SetSoftwareBitmap(sbitmap);
// await encoder.FlushAsync();
// var bmp = new System.Drawing.Bitmap(stream.AsStream());
// return bmp;
//}
//public static Bitmap Resize(this Bitmap source, int newWidth, int newHeight)
//{
// float wScale = (float)newWidth / source.Width;
// float hScale = (float)newHeight / source.Height;
// float minScale = Math.Min(wScale, hScale);
// var nw = (int)(source.Width * minScale);
// var nh = (int)(source.Height * minScale);
// var padDimsW = (newWidth - nw) / 2;
// var padDimsH = (newHeight - nh) / 2;
// var newBitmap = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
// using var g = Graphics.FromImage(newBitmap);
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
// g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
// g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
// g.DrawImage(source, new Rectangle(padDimsW, padDimsH, nw, nh),
// 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
// return newBitmap;
//}
//public static Bitmap ResizeWithoutPadding(this Bitmap source, int new_width, int new_height)
//{
// var newBitmap = new Bitmap(new_width, new_height, PixelFormat.Format24bppRgb);
// using var g = Graphics.FromImage(newBitmap);
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
// g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
// g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
// g.DrawImage(source, new Rectangle(0, 0, new_width, new_height),
// 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
// return newBitmap;
//}
}
}

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using WinRT;
namespace Vision.WindowCapture.GraphicsCapture.Helpers
{
[ComImport]
[Guid( "3628E81B-3CAC-4C60-B7F4-23CE0E0C3356" )]
[InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IGraphicsCaptureItemInterop
{
int CreateForWindow( [In] IntPtr window, [In] ref Guid iid, out IntPtr result );
int CreateForMonitor( [In] IntPtr monitor, [In] ref Guid iid, out IntPtr result );
}
[Guid( "00000035-0000-0000-C000-000000000046" )]
internal unsafe struct IActivationFactoryVftbl
{
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
public readonly IInspectable.Vftbl IInspectableVftbl;
private readonly void* _ActivateInstance;
#pragma warning restore
public delegate* unmanaged[Stdcall]< IntPtr, IntPtr*, int > ActivateInstance => (delegate* unmanaged[Stdcall]< IntPtr, IntPtr*, int >)_ActivateInstance;
}
internal class Platform
{
[DllImport( "api-ms-win-core-com-l1-1-0.dll" )]
internal static extern int CoDecrementMTAUsage( IntPtr cookie );
[DllImport( "api-ms-win-core-com-l1-1-0.dll" )]
internal static extern unsafe int CoIncrementMTAUsage( IntPtr* cookie );
[DllImport( "api-ms-win-core-winrt-l1-1-0.dll" )]
internal static extern unsafe int RoGetActivationFactory( IntPtr runtimeClassId, ref Guid iid, IntPtr* factory );
}
/// <summary>
/// https://github.com/zlatanov/windows-screen-recorder
/// </summary>
internal static class WinrtModule
{
private static readonly Dictionary<string, ObjectReference<IActivationFactoryVftbl>> Cache = new Dictionary<string, ObjectReference<IActivationFactoryVftbl>>();
public static ObjectReference<IActivationFactoryVftbl> GetActivationFactory( string runtimeClassId )
{
lock ( Cache )
{
if ( Cache.TryGetValue( runtimeClassId, out var factory ) )
return factory;
var m = MarshalString.CreateMarshaler( runtimeClassId );
try
{
var instancePtr = GetActivationFactory( MarshalString.GetAbi( m ) );
factory = ObjectReference<IActivationFactoryVftbl>.Attach( ref instancePtr );
Cache.Add( runtimeClassId, factory );
return factory;
}
finally
{
m.Dispose();
}
}
}
private static unsafe IntPtr GetActivationFactory( IntPtr hstrRuntimeClassId )
{
if ( s_cookie == IntPtr.Zero )
{
lock ( s_lock )
{
if ( s_cookie == IntPtr.Zero )
{
IntPtr cookie;
Marshal.ThrowExceptionForHR( Platform.CoIncrementMTAUsage( &cookie ) );
s_cookie = cookie;
}
}
}
Guid iid = typeof( IActivationFactoryVftbl ).GUID;
IntPtr instancePtr;
int hr = Platform.RoGetActivationFactory( hstrRuntimeClassId, ref iid, &instancePtr );
if ( hr == 0 )
return instancePtr;
throw new Win32Exception( hr );
}
public static bool ResurrectObjectReference( IObjectReference objRef )
{
var disposedField = objRef.GetType().GetField( "disposed", BindingFlags.NonPublic | BindingFlags.Instance )!;
if ( !(bool)disposedField.GetValue( objRef )! )
return false;
disposedField.SetValue( objRef, false );
GC.ReRegisterForFinalize( objRef );
return true;
}
private static IntPtr s_cookie;
private static readonly object s_lock = new object();
}
}

View File

@ -0,0 +1,15 @@
using System.Drawing;
namespace Vision.WindowCapture
{
public interface IWindowCapture
{
bool IsCapturing { get; }
void Start(IntPtr hWnd);
Bitmap? Capture();
void Stop();
}
}

View File

@ -0,0 +1,9 @@
# Vision.WindowCapture
一个针对窗口截图的库。输入窗口句柄后可以进行捕获,不会捕获覆盖窗体的内容。
支持以下方案:
* BitBlt
* Windows.Graphics.Capture
* DwmSharedSurface (建设中)

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.22000.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="3.4.16" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.16" />
<PackageReference Include="Vanara.Windows.Extensions" Version="3.4.16" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Vision.WindowCapture
{
public enum CaptureMode
{
BitBlt,
WindowsGraphicsCapture
}
public static class CaptureModeExtensions
{
public static CaptureMode ToCaptureMode(this string modeName)
{
return (CaptureMode) Enum.Parse(typeof(CaptureMode), modeName);
}
}
public class WindowCaptureFactory
{
public static string[] ModeNames()
{
return Enum.GetNames(typeof(CaptureMode));
}
public static IWindowCapture Create(CaptureMode mode)
{
switch (mode)
{
case CaptureMode.BitBlt:
return new BitBlt.BitBltCapture();
case CaptureMode.WindowsGraphicsCapture:
return new GraphicsCapture.GraphicsCapture();
default:
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
}
}
}
}