using System;
using System.Runtime.InteropServices;
public class Worker {
  public Worker() {
    InitializeComponent();
  }
  public void Dispose() {
    m_bitmap?.Dispose();
    m_bitmap = null;
    m_bitmapInfo?.Dispose();
    m_bitmapInfo = null;
    m_buffer?.Dispose();
    m_buffer = null;
  }
  public void InitializeComponent() {
    var width = 3840;
    var height = 2160;
    var stride = 4 * width;
    var buffer = new byte[height * stride];
    var bmInfo = new Bitmapinfo();
    bmInfo.biSize = 40;
    bmInfo.biWidth = width;
    bmInfo.biHeight = height;
    bmInfo.biPlanes = 1;
    bmInfo.biBitCount = 32;
    bmInfo.biCompression = 0;
    bmInfo.biSizeImage = (uint)(stride * height);
    bmInfo.biXPelsPerMeter = 10;
    bmInfo.biYPelsPerMeter = 10;
    bmInfo.biClrUsed = 0;
    bmInfo.biClrImportant = 0;
    m_buffer = GCRoot.AddMemoryPressure(buffer);
    m_bufferPtr = Marshal.UnsafeAddrOfPinnedArrayElement(m_buffer, 0);
    m_bitmap = GCHandle.Alloc(bmInfo, GCHandleType.Pinned);
    m_bitmapPtr = m_bitmap.AddrOfPinnedObject();
    m_bitmapInfo = m_bitmap;
  }
  public void CopyAdditionalBuffer(byte[] buffer) {
    var width = 3840;
    var height = 2160;
    if (!(buffer?.Length == 4 * 3840 * 2160)) throw new Exception("Bad resolution");
    var stride = 4 * width;
    var additionalBufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    var additionalBufferPtr = additionalBufferHandle.AddrOfPinnedObject();
    for (var i = 50; i >= 0; i += -1) {
      User32.GetDIBits(m_screenHandle, m_screenBitmap, 0, height, m_bufferPtr + height * stride, m_bitmapPtr, 0);
      User32.GetDIBits(m_screenHandle, m_screenBitmap, 0, height, additionalBufferPtr + height * stride, m_bitmapPtr, 0);
    }
    additionalBufferHandle.Free();
  }
  public void Capture() {
    var width = 3840;
    var height = 2160;
    var stride = 4 * width;
    var handle = GCHandle.Alloc(this);
    var address = handle.AddrOfPinnedObject();
    var handleMemoryHandle = GCHandle.Alloc(address, GCHandleType.Pinned);
    var handleMemoryPtr = handleMemoryHandle.AddrOfPinnedObject();
    m_windowHandle = User32.FindWindow(null, "HGR view");
    if (m_windowHandle == IntPtr.Zero) {
      Console.WriteLine("Can not find Can not find window");
      return;
    }
    m_windowPlacement = new WindowPlacement();
    m_windowPlacement.length = Marshal.SizeOf(m_windowPlacement);
    User32.GetWindowPlacement(m_windowHandle, out m_windowPlacement);
    m_screenHandle = User32.GetDC(IntPtr.Zero);
    m_screenBitmap = User32.CreateCompatibleBitmap(m_screenHandle, width, height);
    m_realScreenBitmap = User32.SelectObject(m_screenHandle, m_screenBitmap);
    User32.BitBlt(m_screenHandle, 0, 0, width, height, User32.GetWindowDC(m_windowHandle), 0, 0, User32.SRCCOPY);
    if (m_fileName != "") {
      User32.GetSaveFileName(m_openFileName);
      if (!(string.IsNullOrEmpty(m_openFileName.lpstrFile))) {
        var bitmap = new NotImplementedException();
        for (var _loopIndex2 = 49; _loopIndex2 <= 50; _loopIndex2++) {
          if (!(File.Exists(m_fileName + _loopIndex2.ToString() + ".bmp"))) {
            bitmap.Save(m_fileName + _loopIndex2.ToString() + ".bmp");
          }
        }
      }
    }
    User32.SetWindowPlacement(m_windowHandle, in m_windowPlacement);
    User32.ReleaseDC(IntPtr.Zero, m_screenHandle);
    User32.SelectObject(m_screenHandle, m_realScreenBitmap);
    handleMemoryHandle.Free();
    handle.Free();
  }
  protected byte[] m_buffer;
  protected IntPtr m_bufferPtr;
  protected GCHandle m_bitmap;
  protected OpenFileName m_openFileName;
  protected IntPtr m_bitmapPtr;
  protected string m_fileName;
  protected WindowPlacement m_windowPlacement;
  protected IntPtr m_realScreenBitmap;
  protected IntPtr m_windowHandle;
  protected IntPtr m_screenHandle;
  protected IntPtr m_screenBitmap;
  protected GCHandle m_bitmapInfo = new GCHandle();
  protected static DateTime m_startDate;
}
internal static class User32 {
  internal
  const Int32 SRCCOPY = 13369376;
  [DllImport("user32.dll")] internal static extern bool ScreenToClient(IntPtr hWnd, ref WinPoint lpPoint);
  [DllImport("user32.dll")] internal static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
  [DllImport("user32.dll")] internal static extern bool GetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpvBits, IntPtr lpbmi, uint usage);
  [DllImport("user32.dll")] internal static extern bool GetWindowPlacement(IntPtr hWnd, out WindowPlacement lpwndpl);
  [DllImport("user32.dll")] internal static extern void SetWindowPlacement(IntPtr hWnd, in WindowPlacement lpwndpl);
  [DllImport("user32.dll")] internal static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, Int32 nWidth, Int32 nHeight);
  [DllImport("user32.dll")] internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
  [DllImport("user32.dll")] internal static extern IntPtr GetDC(IntPtr hwnd);
  [DllImport("user32.dll")] internal static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
  [DllImport("user32.dll")] internal static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, Int32 dwRop);
  [DllImport("user32.dll")] internal static extern IntPtr GetForegroundWindow();
  [DllImport("user32.dll")] internal static extern bool GetSaveFileName(OpenFileName ofn);
  [DllImport("user32.dll")] internal static extern IntPtr FindWindow([MarshalAs(UnmanagedType.LPStr)] string lpClassName, [MarshalAs(UnmanagedType.LPStr)] string lpWindowName);
  [DllImport("user32.dll")] internal static extern IntPtr GetWindowRect(IntPtr hWnd, out Rectangle rect);
  [DllImport("user32.dll")] internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
  [DllImport("user32.dll")] internal static extern IntPtr GetWindowDC(IntPtr hWnd);
}
public static class Kernels32 {
  [DllImport("kernel32.dll")] internal static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
  [DllImport("kernel32.dll")] internal static extern bool QueryPerformanceFrequency(out long lpFrequency);
} [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct win32Point {
  internal Int32 X;
  internal Int32 Y;
} [StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Auto)] internal class OpenFileName {
  internal Int32 lStructSize = 0;
  internal IntPtr hwndOwner = IntPtr.Zero;
  internal IntPtr hInstance = IntPtr.Zero;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrFilter = null;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrCustomFilter = null;
  internal Int32 nMaxCustFilter = 0;
  internal Int32 nFilterIndex = 0;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrFile = null;
  internal Int32 nMaxFile = 0;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrFileTitle = null;
  internal Int32 nMaxFileTitle = 0;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrInitialDir = null;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrTitle = null;
  internal Int32 Flags = 0;
  internal Int16 nFileOffset = 0;
  internal Int16 nFileExtension = 0;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpstrDefExt = null;
  internal IntPtr lCustData = IntPtr.Zero;
  internal IntPtr lpfnHook = IntPtr.Zero;
  [MarshalAs(UnmanagedType.LPTStr)] internal String lpTemplateName = null;
  internal IntPtr pvReserved = IntPtr.Zero;
  internal IntPtr dwReserved = IntPtr.Zero;
  internal Int32 FlagsEx = 0;
}
internal struct WindowPlacement {
  public int length;
  public int flags;
  public int showCmd;
  public WinPoint ptMinPosition;
  public WinPoint ptMaxPosition;
  public Rectangle rcNormalPosition;
} [StructLayout(LayoutKind.Sequential)] internal struct Bitmapinfo {
  internal Int32 biSize;
  internal Int32 biWidth;
  internal Int32 biHeight;
  internal short biPlanes;
  internal short biBitCount;
  internal Int32 biCompression;
  internal Int32 biSizeImage;
  internal Int32 biXPelsPerMeter;
  internal Int32 biYPelsPerMeter;
  internal Int32 biClrUsed;
  internal Int32 biClrImportant;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] internal Byte[] cols;
} [StructLayout(LayoutKind.Sequential)] internal struct WindowPlacement {
  internal Int32 length;
  internal Int32 flags;
  internal Int32 showCmd;
  internal WinPoint ptMinPosition;
  internal WinPoint ptMaxPosition;
  internal Rectangle rcNormalPosition;
} [StructLayout(LayoutKind.Sequential)] internal struct WinPoint {
  public Int32 X;
  public Int32 Y;
} [StructLayout(LayoutKind.Sequential)] internal struct Rectangle {
  public Int32 Left;
  public Int32 Top;
  public Int32 Right;
  public Int32 Bottom;
}
}

// educational purposes only