using System; namespace ScreenConnect; public class NativeBitmap : RootBitmap { public IntPtr DibBits { get; } public IntPtr BitmapHandle { get; } public IntPtr OldBitmapHandle { get; } public IntPtr DeviceContextHandle { get; } public NativeBitmap(PixelModel pixelModel, int width, int height, int stride, IntPtr scan0, IntPtr dibBits, IntPtr bitmapHandle, IntPtr oldBitmapHandle, IntPtr deviceContextHandle) : base(pixelModel, width, height, stride, scan0) { DibBits = dibBits; BitmapHandle = bitmapHandle; OldBitmapHandle = oldBitmapHandle; DeviceContextHandle = deviceContextHandle; } protected override void Dispose(bool disposing) { NativeCleanup(DeviceContextHandle, BitmapHandle, OldBitmapHandle); } private static void NativeCleanup(IntPtr deviceContextHandle, IntPtr dibHandle, IntPtr oldDibHandle) { if (oldDibHandle != (IntPtr)0) { WindowsNative.SelectObject(deviceContextHandle, oldDibHandle); } if (dibHandle != (IntPtr)0) { WindowsNative.DeleteObject(dibHandle); } if (deviceContextHandle != (IntPtr)0) { WindowsNative.DeleteDC(deviceContextHandle); } } public static WindowsNative.BITMAPINFO GetBitmapInfo(int width, int height, int bitsPerPixel = 32, bool topDownOrBottomUp = true) { WindowsNative.BITMAPINFO result = new WindowsNative.BITMAPINFO { bmiHeader = { biSize = WindowsNative.BitmapInfoHeaderStructureSize, biWidth = width, biHeight = height, biPlanes = 1, biBitCount = (short)bitsPerPixel } }; if (topDownOrBottomUp) { result.bmiHeader.biHeight *= -1; } return result; } public static NativeBitmap CreateBitmap(int width, int height, int bitsPerPixel = 32, bool topDownOrBottomUp = true) { return CreateBitmap(GetBitmapInfo(width, height, bitsPerPixel, topDownOrBottomUp)); } public static NativeBitmap CreateBitmap(WindowsNative.BITMAPINFO bitmapInfo) { PixelModel pixelModel = null; if (bitmapInfo.bmiHeader.biBitCount == 32) { pixelModel = new BgrPixelModel24(32); } else { if (bitmapInfo.bmiHeader.biBitCount != 24) { throw new InvalidOperationException("Bit depth not supported: " + bitmapInfo.bmiHeader.biBitCount); } pixelModel = new BgrPixelModel24(24); } IntPtr intPtr = default(IntPtr); IntPtr intPtr2 = default(IntPtr); IntPtr intPtr3 = default(IntPtr); IntPtr ppvBits = default(IntPtr); WindowsNative.BITMAP lpObject = default(WindowsNative.BITMAP); try { if ((intPtr = WindowsNative.CreateCompatibleDC((IntPtr)0)) == (IntPtr)0) { WindowsExtensions.ThrowLastError(); } if ((intPtr2 = WindowsNative.CreateDIBSection(intPtr, ref bitmapInfo, 0u, out ppvBits, IntPtr.Zero, 0u)) == (IntPtr)0) { WindowsExtensions.ThrowLastError(); } intPtr3 = WindowsNative.SelectObject(intPtr, intPtr2); if (WindowsNative.GetObjectBitmap(intPtr2, WindowsNative.BitmapStructureSize, ref lpObject) == 0) { WindowsExtensions.ThrowLastError(); } return new NativeBitmap(pixelModel, bitmapInfo.bmiHeader.biWidth, Math.Abs(bitmapInfo.bmiHeader.biHeight), lpObject.bmWidthBytes * ((bitmapInfo.bmiHeader.biHeight < 0) ? 1 : (-1)), new IntPtr(ppvBits.ToInt64() + ((bitmapInfo.bmiHeader.biHeight >= 0) ? (lpObject.bmWidthBytes * (bitmapInfo.bmiHeader.biHeight - 1)) : 0)), ppvBits, intPtr2, intPtr3, intPtr); } catch { NativeCleanup(intPtr, intPtr2, intPtr3); throw; } } }