mirror of
https://gitee.com/csharpui/CPF.git
synced 2025-12-27 06:35:53 +08:00
156 lines
5.8 KiB
C#
156 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.InteropServices.ComTypes;
|
|
using System.Text;
|
|
using CPF.Drawing;
|
|
using CPF.Platform;
|
|
using static CPF.Windows.UnmanagedMethods;
|
|
|
|
namespace CPF.Windows
|
|
{
|
|
public class ScreenImpl : Screen
|
|
{
|
|
private readonly IntPtr _hMonitor;
|
|
public ScreenImpl(Rect bounds, Rect workingArea, bool primary, IntPtr hMonitor) : base(bounds, workingArea, primary)
|
|
{
|
|
this._hMonitor = hMonitor;
|
|
}
|
|
|
|
//public IReadOnlyList<Screen> GetAllScreens()
|
|
//{
|
|
// var ScreenCount = GetSystemMetrics(SystemMetric.SM_CMONITORS);
|
|
// List<Screen> screens = new List<Screen>();
|
|
// EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
|
|
// (IntPtr monitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr data) =>
|
|
// {
|
|
// screens.Add(FromMonitor(monitor, hdcMonitor));
|
|
// return true;
|
|
// }, IntPtr.Zero);
|
|
// return screens;
|
|
//}
|
|
|
|
public static Screen FromMonitor(IntPtr monitor, IntPtr hdc)
|
|
{
|
|
MONITORINFO monitorInfo = MONITORINFO.Create();
|
|
if (GetMonitorInfo(monitor, ref monitorInfo))
|
|
{
|
|
RECT bounds = monitorInfo.rcMonitor;
|
|
RECT workingArea = monitorInfo.rcWork;
|
|
Rect cBounds = new Rect(bounds.left, bounds.top, bounds.right - bounds.left,
|
|
bounds.bottom - bounds.top);
|
|
Rect cWorkArea =
|
|
new Rect(workingArea.left, workingArea.top, workingArea.right - workingArea.left,
|
|
workingArea.bottom - workingArea.top);
|
|
|
|
return new ScreenImpl(cBounds, cWorkArea, monitorInfo.dwFlags == 1,
|
|
monitor);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return (int)_hMonitor;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return (obj is ScreenImpl screen) ? this._hMonitor == screen._hMonitor : base.Equals(obj);
|
|
}
|
|
|
|
public override Bitmap Screenshot()
|
|
{
|
|
IntPtr desktopHwnd = GetDesktopWindow();
|
|
IntPtr desktopDc = GetWindowDC(desktopHwnd);
|
|
IntPtr memDc = CreateCompatibleDC(desktopDc);
|
|
|
|
try
|
|
{
|
|
// 3. 创建DIBSection (24位真彩色位图)
|
|
BITMAPINFOHEADER bmi = new BITMAPINFOHEADER
|
|
{
|
|
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)),
|
|
biWidth = (int)Bounds.Width,
|
|
biHeight = -(int)Bounds.Height, // 负值表示自顶向下DIB
|
|
biPlanes = 1,
|
|
biBitCount = 24,
|
|
biCompression = 0, // BI_RGB
|
|
biSizeImage = (uint)(((int)Bounds.Width * 3 + 3) & ~3) * (uint)Bounds.Height // 行对齐到4字节
|
|
}
|
|
;
|
|
|
|
IntPtr hBitmap = CreateDIBSection(desktopDc, ref bmi, 0, out var bitsPtr, IntPtr.Zero, 0);
|
|
|
|
// 4. 将屏幕内容复制到位图
|
|
IntPtr oldBitmap = SelectObject(memDc, hBitmap);
|
|
BitBlt(memDc, 0, 0, (int)Bounds.Width, (int)Bounds.Height, desktopDc, 0, 0, TernaryRasterOperations.SRCCOPY | TernaryRasterOperations.CAPTUREBLT);
|
|
SelectObject(memDc, oldBitmap);
|
|
|
|
// 5. 构造BMP文件
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
// 5.1 计算文件大小
|
|
uint pixelDataSize = bmi.biSizeImage;
|
|
uint fileSize = (uint)(Marshal.SizeOf(typeof(BITMAPFILEHEADER)) +
|
|
(Marshal.SizeOf(typeof(BITMAPINFOHEADER))) +
|
|
pixelDataSize);
|
|
|
|
// 5.2 创建文件头
|
|
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER
|
|
{
|
|
bfType = 0x4D42, // "BM"
|
|
bfSize = fileSize,
|
|
bfOffBits = (uint)(Marshal.SizeOf(typeof(BITMAPFILEHEADER)) +
|
|
(Marshal.SizeOf(typeof(BITMAPINFOHEADER))))
|
|
}
|
|
;
|
|
|
|
// 5.3 写入文件头
|
|
byte[] fileHeaderBytes = StructureToBytes(fileHeader);
|
|
ms.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
|
|
|
|
// 5.4 写入信息头
|
|
byte[] infoHeaderBytes = StructureToBytes(bmi);
|
|
ms.Write(infoHeaderBytes, 0, infoHeaderBytes.Length);
|
|
|
|
// 5.5 写入像素数据 (直接从DIBSection内存复制)
|
|
byte[] pixelData = new byte[pixelDataSize];
|
|
Marshal.Copy(bitsPtr, pixelData, 0, (int)pixelDataSize);
|
|
ms.Write(pixelData, 0, pixelData.Length);
|
|
|
|
ms.Position = 0;
|
|
|
|
Bitmap bitmap = new Bitmap(ms);
|
|
return bitmap;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
// 6. 清理资源
|
|
ReleaseDC(desktopHwnd, desktopDc);
|
|
DeleteDC(memDc);
|
|
}
|
|
}
|
|
|
|
// 辅助方法:结构体转字节数组
|
|
private static byte[] StructureToBytes<T>(T structure) where T : struct
|
|
{
|
|
int size = Marshal.SizeOf(typeof(T));
|
|
byte[] bytes = new byte[size];
|
|
IntPtr ptr = Marshal.AllocHGlobal(size);
|
|
try
|
|
{
|
|
Marshal.StructureToPtr(structure, ptr, false);
|
|
Marshal.Copy(ptr, bytes, 0, size);
|
|
return bytes;
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|