Страницы

Поиск по вопросам

вторник, 11 июня 2019 г.

Как сделать скриншот окна?

Надо сделать скриншот отдельного окна на экране. Допустим калькулятора. c#


Ответ

К сожалению, я не смог найти решение совсем без P/Invoke. Вы должны найти нужный процесс (обычно он у вас и так есть, раз вы за ним следите), его окно (например, у класса Process можно опросить MainWindowHandle), и у этого окна взять его координаты на экране. Для этого придётся вызывать WinAPI-функцию GetWindowRect
using System.Drawing;

[DllImport("user32.dll", SetLastError = true)] static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
Скопировать кусок экрана можно при помощи функции Graphics.CopyFromScreen, которая доступна в WinForms. Если у вас не WinForms-приложение, придётся подключить System.Drawing.dll
Получаем такой вот код:
var process = Process.GetProcessesByName(тут имя процесса).FirstOrDefault(); // не забудьте поверку ошибок: вдруг у вас не нашлось ни одного процесса? GetWindowRect(process.MainWindowHandle, out var rect); using (var image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top)) { using (var graphics = Graphics.FromImage(image)) graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, image.Size);
// тут у вас есть картинка, вы можете, например, сохранить её image.Save(imagePath, System.Drawing.Imaging.ImageFormat.Png); }
У меня получился вот такой скриншот окна Visual Studio:

Недостатки метода:
окно должно быть на переднем плане, иначе вы получите перекрытые части могут быть проблемы с Aero-интерфейсом (вот тут решение, которое умеет бороться с этой проблемой, но я не проверял)

Обновление:
Я нашёл вот тут решение, которое обходит первую проблему, то есть, умеет делать снимок окна, не находящегося на переднем плане. Для этого мы должны использовать ещё одну WinAPI-функцию PrintWindow. Вот улучшенный код:
using System.Drawing; using System.Drawing.Imaging;

[DllImport("user32.dll", SetLastError = true)] static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")] static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }

var process = Process.GetProcessesByName(тут имя процесса).FirstOrDefault(); // не забудьте поверку ошибок: вдруг у вас не нашлось ни одного процесса? var hwnd = process.MainWindowHandle; GetWindowRect(hwnd, out var rect); using (var image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top)) { using (var graphics = Graphics.FromImage(image)) { var hdcBitmap = graphics.GetHdc(); PrintWindow(hwnd, hdcBitmap, 0); graphics.ReleaseHdc(hdcBitmap); }
// тут у вас есть картинка, вы можете, например, сохранить её image.Save(imagePath, ImageFormat.Png); }

Комментариев нет:

Отправить комментарий