3
\$\begingroup\$

I've got a function which takes a screenshot of a particular window. It's important that the screenshot works whether the window is focused/covered by other windows or not, hence why I've used PrintWindow.

This function takes 45ms to complete, and I was hoping to decrease that. The end goal is to:

  • Take a screenshot of a window based on a handle, which works even if the window is covered by a different window
  • Finally return a byte[] to be exported as a PNG using NodeJS.

screenshot.cs

using System.Runtime.InteropServices;
using System;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows;
using System.Windows.Forms;

public class main
{
   [StructLayout(LayoutKind.Sequential)]
   private struct Rect
   {
      public int Left;
      public int Top;
      public int Right;
      public int Bottom;
   }

   [DllImport("user32.dll")]
   private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

   [DllImport("user32.dll")]
   private static extern IntPtr GetClientRect(IntPtr hWnd, ref Rect rect);

   [DllImport("user32.dll")]
   private static extern IntPtr ClientToScreen(IntPtr hWnd, ref Point point);

   [DllImport("User32.dll", SetLastError = true)]
   [return: MarshalAs(UnmanagedType.Bool)]
   static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);

   public static Bitmap CaptureWindow(IntPtr handle)
   {
      var rect = new Rect();
      GetClientRect(handle, ref rect);

      var point = new Point(0,0);
      ClientToScreen(handle, ref point);

      var bounds = new Rectangle(point.X, point.Y, rect.Right, rect.Bottom);
      var result = new Bitmap(bounds.Width, bounds.Height);

      using (var graphics = Graphics.FromImage(result))
      {
         IntPtr dc = graphics.GetHdc();
         bool success = PrintWindow(handle, dc, 0);
         graphics.ReleaseHdc(dc);
      }

      return result;
   }

   public static byte[] ImageToByte(Image img)
   {
      ImageConverter converter = new ImageConverter();
      return (byte[])converter.ConvertTo(img, typeof(byte[]));
   }
}

NodeJS code

const {K, U} = require('win32-api');
const user32 = U.load();
const edge = require('edge-js');
const ss = edge.func(path.join(__dirname, 'screenshot.cs'));

var hWnd = user32.FindWindowExW(0, 0, null, Buffer.from('application\0', 'ucs2'))
ss(hWnd, function (err, r) { fs.writeFileSync("screenshot.png", r); });
\$\endgroup\$
  • 3
    \$\begingroup\$ What is ImageToByte for? It doesn't seem to be used. \$\endgroup\$ – tinstaafl Mar 24 at 14:58
  • 4
    \$\begingroup\$ What is the expected formatting for byte[]? The .NET docs are woefully inadequate in describing how it does that particular conversion. A simple LockBits and then a buffer copy takes a fraction of the time that converter.ConvertTo takes, but the resulting byte array is not formatted at all the same as what's there now. \$\endgroup\$ – Jeff E Mar 24 at 16:28
  • \$\begingroup\$ ImageToByte( CaptureWindow(hWnd) ) is returned to a nodejs application and exported as a png file using fs.writeFileSync \$\endgroup\$ – Edge Mar 24 at 21:06
  • 1
    \$\begingroup\$ Obligatory "have you used a profiler?" comment. This will give you various metrics so you can target optimizations.. \$\endgroup\$ – Zer0 Mar 25 at 1:36
  • \$\begingroup\$ Please include all relevant parts of the code. It looks like some of the core essentials are missing, which makes optimizing for performance unnecessarily hard on the reviewers. \$\endgroup\$ – Mast Mar 25 at 8:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.