4
\$\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\$
9
  • 3
    \$\begingroup\$ What is ImageToByte for? It doesn't seem to be used. \$\endgroup\$
    – user33306
    Commented Mar 24, 2020 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
    Commented Mar 24, 2020 at 16:28
  • \$\begingroup\$ ImageToByte( CaptureWindow(hWnd) ) is returned to a nodejs application and exported as a png file using fs.writeFileSync \$\endgroup\$
    – Edge
    Commented Mar 24, 2020 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
    Commented Mar 25, 2020 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
    Commented Mar 25, 2020 at 8:51

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.