Почему этот C# метод не дает правильный скриншот? - PullRequest
4 голосов
/ 24 апреля 2020

Я хочу сохранить снимок окна с заголовком, оканчивающимся на - Scrivener, в файл PNG. Для этого я написал следующий метод (на основе этот ответ):

        [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!");
        }

Есть несколько проблем с этим кодом:

Во-первых, если приложение, которое я хочу захватить (Scrivener), не находится на переднем плане, пока я вызываю этот код, получающийся снимок экрана будет пустым.

Во-вторых, если окно Scrivener находится на переднем плане, я получаю снимок экрана родительского окна (см. ниже).

Screenshot of parent and child window

Как мне нужно изменить свой код, чтобы он стал

а. работать даже когда окно не на переднем плане и

b. захватить только окно подсчета слов (не его родитель)?

Здесь - код.

1 Ответ

8 голосов
/ 24 апреля 2020

Вот ваша проблема:

scrivenerProcess.MainWindowHandle

Из документации :

Главное окно - это окно, открытое процессом, который в данный момент имеет фокус

На скриншоте у окна, за которым вы работаете, нет с Фокусом (на нем белый фон с серым текстом, указывающим, что он неактивен).

К сожалению, для перечисления процесса 'other windows вам нужно использовать P / Invoke, так как он не предоставляется через класс Process. Используйте EnumWindows или EnumChildWindows.

...