diff --git a/ScreenCapture.NET.GDI/GDIScreenCapture.cs b/ScreenCapture.NET.GDI/GDIScreenCapture.cs
new file mode 100644
index 0000000..0cf8e78
--- /dev/null
+++ b/ScreenCapture.NET.GDI/GDIScreenCapture.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+using HPPH;
+using HPPH.System.Drawing;
+
+namespace ScreenCapture.NET;
+
+///
+/// Represents a ScreenCapture using GDI
+///
+// ReSharper disable once InconsistentNaming
+public sealed partial class GDIScreenCapture : AbstractScreenCapture
+{
+ #region DLL-Import
+
+ private const int SRCCOPY = 0x00CC0020;
+
+ [LibraryImport("gdi32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static partial bool BitBlt(nint hdcDest, int xDest, int yDest, int w, int h, nint hdcSrc, int xSrc, int ySrc, int rop);
+
+ [LibraryImport("user32.dll")]
+ private static partial nint GetDC(nint hwnd);
+
+ [LibraryImport("user32.dll")]
+ private static partial int ReleaseDC(nint hwnd, nint hdc);
+
+ #endregion
+
+ #region Properties & Fields
+
+ private readonly Lock _captureLock = new();
+
+ private Bitmap? _bitmap;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to duplicate.
+ internal GDIScreenCapture(Display display)
+ : base(display)
+ {
+ Restart();
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ protected override unsafe bool PerformScreenCapture()
+ {
+ lock (_captureLock)
+ {
+ if (_bitmap == null) return false;
+
+ using Graphics gDest = Graphics.FromImage(_bitmap);
+ nint dc = 0;
+ nint dest = 0;
+
+ try
+ {
+ //dc = GetDC(nint.Zero);
+ //dest = gDest.GetHdc();
+ Stopwatch sw = Stopwatch.StartNew();
+ gDest.CopyFromScreen(0, 0, 0, 0, new Size(Display.Width, 2));
+ //BitBlt(dest, 0, 0, Display.Width, Display.Height, dc, 0, 0, SRCCOPY);
+ Console.WriteLine(sw.Elapsed.TotalMilliseconds);
+ }
+ catch
+ {
+ return false;
+ }
+ finally
+ {
+ gDest.ReleaseHdc(dest);
+
+ if (dc != nint.Zero)
+ ReleaseDC(nint.Zero, dc);
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ protected override void PerformCaptureZoneUpdate(CaptureZone captureZone, Span buffer)
+ {
+ if (_bitmap == null) return;
+
+ using IDisposable @lock = captureZone.Lock();
+
+ if (captureZone.DownscaleLevel == 0)
+ CopyZone(captureZone, buffer);
+ else
+ DownscaleZone(captureZone, buffer);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void CopyZone(CaptureZone captureZone, Span buffer)
+ {
+ if (_bitmap == null) return;
+
+ BitmapData data = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadOnly, _bitmap.PixelFormat);
+ ReadOnlySpan bitmapBuffer = new(data.Scan0.ToPointer(), data.Stride * data.Height);
+
+ RefImage.Wrap(bitmapBuffer, Display.Width, Display.Height, data.Stride)[captureZone.X, captureZone.Y, captureZone.Width, captureZone.Height]
+ .CopyTo(MemoryMarshal.Cast(buffer));
+
+ _bitmap.UnlockBits(data);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void DownscaleZone(CaptureZone captureZone, Span buffer)
+ {
+ BitmapData data = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadOnly, _bitmap.PixelFormat);
+ ReadOnlySpan bitmapBuffer = new(data.Scan0.ToPointer(), data.Stride * data.Height);
+
+ RefImage source = RefImage.Wrap(bitmapBuffer, Display.Width, Display.Height, data.Stride)[captureZone.X, captureZone.Y, captureZone.UnscaledWidth, captureZone.UnscaledHeight];
+ Span target = MemoryMarshal.Cast(buffer);
+
+ int blockSize = 1 << captureZone.DownscaleLevel;
+
+ int width = captureZone.Width;
+ int height = captureZone.Height;
+
+ for (int y = 0; y < height; y++)
+ for (int x = 0; x < width; x++)
+ target[(y * width) + x] = source[x * blockSize, y * blockSize, blockSize, blockSize].Average();
+
+ _bitmap.UnlockBits(data);
+ }
+
+ ///
+ public override void Restart()
+ {
+ base.Restart();
+
+ lock (_captureLock)
+ {
+ _bitmap?.Dispose();
+ _bitmap = new Bitmap(Display.Width, Display.Height, PixelFormat.Format32bppArgb);
+ }
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ lock (_captureLock)
+ DisposeDX();
+ }
+
+ private void DisposeDX()
+ {
+ try
+ {
+ _bitmap?.Dispose();
+ _bitmap = null;
+ }
+ catch { /**/ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/ScreenCapture.NET.GDI/GDIScreenCaptureService.cs b/ScreenCapture.NET.GDI/GDIScreenCaptureService.cs
new file mode 100644
index 0000000..8a04978
--- /dev/null
+++ b/ScreenCapture.NET.GDI/GDIScreenCaptureService.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ScreenCapture.NET;
+
+///
+/// Represents a using the .
+///
+public class GDIScreenCaptureService : IScreenCaptureService
+{
+ #region Properties & Fields
+
+ private readonly Dictionary _screenCaptures = new();
+
+ private bool _isDisposed;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public GDIScreenCaptureService()
+ {
+ }
+
+ ~GDIScreenCaptureService() => Dispose();
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public IEnumerable GetGraphicsCards()
+ {
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
+ return [new GraphicsCard(0, "Default", 0, 0)];
+ }
+
+ ///
+ public IEnumerable GetDisplays(GraphicsCard graphicsCard)
+ {
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
+ Screen screen = Screen.PrimaryScreen!;
+ return [new Display(0, screen.DeviceName, screen.Bounds.Width, screen.Bounds.Height, Rotation.None, graphicsCard)];
+ }
+
+ ///
+ IScreenCapture IScreenCaptureService.GetScreenCapture(Display display) => GetScreenCapture(display);
+ public GDIScreenCapture GetScreenCapture(Display display)
+ {
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
+ if (!_screenCaptures.TryGetValue(display, out GDIScreenCapture? screenCapture))
+ _screenCaptures.Add(display, screenCapture = new GDIScreenCapture(display));
+ return screenCapture;
+ }
+
+ ///
+ public void Dispose()
+ {
+ if (_isDisposed) return;
+
+ foreach (GDIScreenCapture screenCapture in _screenCaptures.Values)
+ screenCapture.Dispose();
+ _screenCaptures.Clear();
+
+ GC.SuppressFinalize(this);
+
+ _isDisposed = true;
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/ScreenCapture.NET.GDI/Resources/icon.png b/ScreenCapture.NET.GDI/Resources/icon.png
new file mode 100644
index 0000000..46c5033
Binary files /dev/null and b/ScreenCapture.NET.GDI/Resources/icon.png differ
diff --git a/ScreenCapture.NET.GDI/ScreenCapture.NET.GDI.csproj b/ScreenCapture.NET.GDI/ScreenCapture.NET.GDI.csproj
new file mode 100644
index 0000000..e03b131
--- /dev/null
+++ b/ScreenCapture.NET.GDI/ScreenCapture.NET.GDI.csproj
@@ -0,0 +1,77 @@
+
+
+ net8.0-windows;net9.0-windows
+ win-x64
+ latest
+ enable
+ true
+ true
+
+ Darth Affe
+ Wyrez
+ en-US
+ en-US
+ ScreenCapture.NET.GDI
+ ScreenCapture.NET.GDI
+ ScreenCapture.NET.GDI
+ ScreenCapture.NET.GDI
+ ScreenCapture.NET
+ GDI based Screen-Capturing
+ GDI based Screen-Capturing
+ Copyright © Darth Affe 2025
+ Copyright © Darth Affe 2025
+ icon.png
+ https://github.com/DarthAffe/ScreenCapture.NET
+ LGPL-2.1-only
+ Github
+ https://github.com/DarthAffe/ScreenCapture.NET
+ True
+
+
+
+
+ 3.0.0
+ 3.0.0
+ 3.0.0
+
+ ..\bin\
+ true
+ True
+ True
+ snupkg
+
+
+
+ $(DefineConstants);TRACE;DEBUG
+ true
+ full
+ false
+
+
+
+ portable
+ true
+ $(NoWarn);CS1591;CS1572;CS1573
+ $(DefineConstants);RELEASE
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ScreenCapture.NET.sln b/ScreenCapture.NET.sln
index b91b878..6065a9c 100644
--- a/ScreenCapture.NET.sln
+++ b/ScreenCapture.NET.sln
@@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCapture.NET.DX9", "Sc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCapture.NET.X11", "ScreenCapture.NET.X11\ScreenCapture.NET.X11.csproj", "{F81562C8-2035-4FB9-9547-C51F9D343BDF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenCapture.NET.GDI", "ScreenCapture.NET.GDI\ScreenCapture.NET.GDI.csproj", "{53FEEA34-B9F0-4A02-9408-BCC3AD0EC1E3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +43,10 @@ Global
{F81562C8-2035-4FB9-9547-C51F9D343BDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F81562C8-2035-4FB9-9547-C51F9D343BDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F81562C8-2035-4FB9-9547-C51F9D343BDF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {53FEEA34-B9F0-4A02-9408-BCC3AD0EC1E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53FEEA34-B9F0-4A02-9408-BCC3AD0EC1E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53FEEA34-B9F0-4A02-9408-BCC3AD0EC1E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53FEEA34-B9F0-4A02-9408-BCC3AD0EC1E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE