Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this C# method not produce the right screenshot?

I want to save the snapshot of a window with the title ending in - Scrivener in a PNG file. To do this, I wrote following method (based on this answer):

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Process[] processes  = Process.GetProcesses();
            Process scrivenerProcess = null;
            foreach (Process curProcess in processes)
            {
                Console.WriteLine("Name: " + curProcess.ProcessName + ", title: " + curProcess.MainWindowTitle);
                if (curProcess.MainWindowTitle.EndsWith("- Scrivener"))
                {
                    scrivenerProcess = curProcess;
                    break;
                }
            }
            if (scrivenerProcess == null)
            {
                Console.WriteLine("Scrivener not found");
                return;
            }

            var rect = new RECT();

            GetWindowRect(new HandleRef(this, scrivenerProcess.MainWindowHandle), out rect);

            int width = rect.Right - rect.Left;
            int height = rect.Bottom - rect.Top;
            var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            Graphics graphics = Graphics.FromImage(bmp);
            graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);

            bmp.Save("C:\\usr\\dp\\ref\\marcomm\\2020_04_22_wordCounter\\2020-04-24-TestScreenshot.png", ImageFormat.Png);

            Console.WriteLine("Heyo!");
        }

There are several problems with this code:

First, if the application I want to capture (Scrivener) is not in the foreground while I'm calling that code, the resulting screenshot is empty.

Second, if the Scrivener window is in the foreground, I get the screenshot of the parent window (see below).

Screenshot of parent and child window

How do I need to change my code in order for it to

a. work even when the window is not in foreground and

b. only capture the word count window (not its parent)?

Here is the code.

like image 997
Dmitrii Pisarenko Avatar asked Jan 26 '23 03:01

Dmitrii Pisarenko


1 Answers

Here's your problem:

scrivenerProcess.MainWindowHandle

From the documentation:

The main window is the window opened by the process that currently has the focus

In your screenshot, the window you're after does not have Focus (it has a white background with grey text, indicating it's inactive).

Unfortunately, to enumerate a process' other windows you need to use P/Invoke as they aren't exposed via the Process class. Use EnumWindows or EnumChildWindows.

like image 91
Dai Avatar answered Jan 27 '23 16:01

Dai