PrintScreen только активное окно - PullRequest
1 голос
/ 14 января 2011

Я пишу простую утилиту Windows Forms, чтобы сделать скриншот всего экрана или активного окна и сохранить файл.У winform есть кнопка Capture, которая при нажатии делает снимок экрана.

У меня полностью работает код для всего экрана, но я не могу понять его для активного окна.

По моему текущему коду, если я выбираю «Активное окно», оно заканчивается Print Screening самого приложения, что не то, что я хочу.

Вот мой код (в методе Capture_Click):

try
        {
            this.Hide();

            bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
            //bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);

            gfxScreenshot = Graphics.FromImage(bmpScreenshot);

            if (AltPrint.Checked)
            {
                gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
            }
            else
            {
                gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            }

            bmpScreenshot.Save(SaveLocation, ImageFormat.Png);

            number++;
        }

Ответы [ 6 ]

2 голосов
/ 14 января 2011

В вашем методе button_Click для захвата окна, отличного от того, которое выполняет захват, единственный возможный способ, который я вижу, - использовать user32 Windows API.

Сначала вам потребуется вызвать на платформе некоторые методы, подобные этому:

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, GetWindowLongNIndex nIndex);

Я рекомендую www.pinvoke.net / для получения дополнительной информации об этом.

Вот мой собственный класс Window (в процессе разработки, но пригодный для использования), который вы можете использовать в качестве примера: http://pastebin.com/fj2tEaPY

Некоторые полезные свойства для вас:

  • получить AllWindows
  • получить TaskbarWindows
  • набор ForegroundWindow

Вам понадобится получить дескриптор текущего окна (используйте get ForegroundWindow, затем свойство Handle), затем найдите окно, для которого вы хотите захватить изображение, возможно, используя код, подобный тому, что в TaskbarWindows. Как только у вас появится окно, вам нужно будет отправить нажатия клавиш Alt + PrtScn (снова, возможно, с использованием user32 API, но я не буду вдаваться в это.) Затем используйте свойство static ForegroundWindow, чтобы установить оригинальное окно в качестве переднего плана с использованием дескриптора, который вы сохранили в начале.

Удачи!

1 голос
/ 14 января 2011

В итоге я выбрал другой маршрут.

Я разрешаю пользователю изменять размер моего окна формы, чтобы он в точности покрывал область, необходимую ему для скриншота, а затем, когда он нажимает кнопку, форма скрывается, принимаетскриншот области, которую он покрывал и появляется снова.Вопреки моему первоначальному плану, я считаю, что это будет более выгодно, поскольку мои целевые пользователи (друзья на форуме по разгону, в котором я участвую) редко делают снимки экрана только из одного окна.В основном им требуется пара окон (мониторинг температуры, контроль скорости, тест стабильности и т. Д.).

Спасибо за ответы, ребята.Они определенно заставили меня задуматься и заставили меня осознать, какие у меня были варианты.

Если кому-то еще это понадобится, то этот код я использую для кнопки, которая захватывает только часть экрана:

        try
        {
            this.Hide();
            Thread.Sleep(250);

            bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);

            gfxScreenshot = Graphics.FromImage(bmpScreenshot);

            gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);

            bmpScreenshot.Save(SaveLocation, ImageFormat.Png);

            tbxStatus.AppendText(Environment.NewLine);
            tbxStatus.AppendText(Environment.NewLine);
            tbxStatus.AppendText("Screenshot saved at " + SaveLocation);

            numSuffix++;
        }
        catch (Exception ex)
        {
            tbxStatus.AppendText(Environment.NewLine);
            tbxStatus.AppendText(Environment.NewLine);
            tbxStatus.AppendText("Unable to take screenshot. Exception: " + ex.ToString());
        }
        finally
        {
            this.Show();
        }
1 голос
/ 14 января 2011

Ваши комментарии, кажется, понимают, что как только ваше приложение получает фокус (когда вы нажимаете на него), другое приложение теряет его и перестает быть «активным».

Возможная альтернатива: ваше приложение получает WM_SETFOCUS сообщение, когда оно получает фокус.WParam этого сообщения является дескриптором того, какое окно только что отказалось от фокуса - и это окно принадлежит приложению, которое вы хотите захватить.

Конечно, это окно будет только подокном или элементом управления,но вы можете выяснить, какому приложению принадлежит эта кнопка.

1 голос
/ 14 января 2011

Насколько я вижу, ваш код использует границы своей формы для захвата "активного" окна.Вероятно, это не то, что вы намереваетесь.

Если вы хотите использовать мышь для «печати» окна (а не горячей клавиши, которую, вероятно, проще реализовать), вы должны иметь возможность из своей собственной формы позволитьпользователь указывает на другое окно для захвата.Вот идея, описывающая, как это сделать:

  1. Когда пользователь нажимает кнопку «Захват», захватываете мышь и запускаете операцию перетаскивания.
  2. Дайте пользователю перетащить мышь (возможно, теперь имеется курсор «яблочко» или «камера») к окну для захвата.
  3. Когда пользователь отпускает мышь, определите окно, которое было сверху, и используйте местоположение и размер этого окна для захватаправильные пиксели.

Возможно, вам понадобится P / Invoke для получения информации обо всех окнах верхнего уровня на рабочем столе.

Обратите внимание, что «захват мыши» очень отличаетсяиз "захвата экрана".Когда приложение "захватывает мышь", оно становится владельцем курсора мыши и не может отслеживать мышь, даже если она перемещается за пределы окна приложения.

0 голосов
/ 14 января 2011

А как насчет SendKeys?

Windows.Forms.SendKeys.Send("%{PRTSC}");

Он скопирует текущее выбранное окно в объект буфера обмена.

Чем вызов

BitmapSource image = Clipboard.GetImage();

, вы можете вернуть изображение

0 голосов
/ 14 января 2011

Вам нужно позаимствовать дизайн коммерчески доступных приложений для захвата экрана, таких как Psp.Я думаю, что вам нужно использовать «горячую» клавишу для запуска захвата активного окна.Вместо того, чтобы делать это на событии Capture_Click.Таким образом, вы можете скрыть окно вашего приложения, чтобы оно не стало активным окном.Затем, когда пользователь нажимает «горячую» клавишу, вы можете захватить ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...