Я работаю над программой для создания снимков экрана окон из дескриптора окна. Я начинаю с создания снимка экрана с помощью BitBlt, и если это не удается, когда в окне используется ускоренная графика, я переключаюсь на использование Direct3D.
Для справки, вот код BitBlt:
private Bitmap BitBltWindow(Rectangle rect, IntPtr window)
{
const uint srcCopy = 0x00CC0020;
IntPtr hWndDc = GetDC(window);
IntPtr hMemDc = CreateCompatibleDC(hWndDc);
IntPtr hBitmap = CreateCompatibleBitmap(hWndDc, rect.Width, rect.Height);
SelectObject(hMemDc, hBitmap);
BitBlt(hMemDc, 0, 0, rect.Width, rect.Height, hWndDc, 0, 0, srcCopy);
Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
ReleaseDC(window, hWndDc);
ReleaseDC(IntPtr.Zero, hMemDc);
DeleteDC(hWndDc);
return bitmap;
}
И вот мой метод определить, пуст ли он:
private bool IsBitmapBlack(Bitmap bmp)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int rowSize = bmpData.Stride < 0 ? -bmpData.Stride : bmpData.Stride;
// Scanning for non-zero bytes
bool allBlack = true;
for (int y = 0; y < bmp.Height; y++)
{
byte[] pixels = new byte[rowSize];
Marshal.Copy(IntPtr.Add(ptr, y * bmpData.Stride), pixels, 0, rowSize);
if (pixels.Max() > 0)
{
allBlack = false;
break;
}
}
bmp.UnlockBits(bmpData);
return allBlack;
}
Мой вопрос заключается в том, как определить, произошел ли сбой BitBlt или нет. В таких окнах, как Chrome, вызов BitBlt просто возвращает пустое растровое изображение, это легко обнаружить, и я переключаюсь на Direct3D. Но в таких окнах, как Visual Studio 2022, похоже, используется смесь графики, поэтому возвращаемое растровое изображение не пустое, но в нем отсутствуют биты, например:
Тогда как та же запись с поверхности Direct3D выглядит так:
Кто-нибудь знает вызов Windows API, который я могу использовать, чтобы определить, использует ли окно какое-либо количество ускоренной графики?
BitBlt работает только с неускоренной графикой, т.е. просто считывает изображение из памяти устройства. Поэтому он не работает в Chrome. Direct3D может считывать память из графического процессора и памяти устройства, поэтому работает в любом окне, которое я тестировал до сих пор. Указатель на контекст устройства ненулевой во всех случаях, просто нет изображения для захвата из памяти при наличии ускоренной графики. Я хочу знать, смогу ли я определить, использует ли окно ускоренную графику.





После публикации вопроса я решил продолжить изучение процесса, чтобы посмотреть, смогу ли я определить, содержат ли загруженные модули какие-либо известные как Direct3D. Я списал это на неудачный эксперимент: получить список модулей было достаточно легко, и это работало на некоторых окнах, но не на всех окнах, на которых я это пробовал. например Хром.
Я решил преобразовать свой метод IsBitmapBlack в метод, который определяет, является ли окно частично черным. Это позволяет обойти проблему Visual Studio, в которой отсутствуют некоторые биты.
Новый метод теперь выглядит так:
private bool IsBitmapPartBlack(Bitmap bmp)
{
int height = bmp.Height;
int width = bmp.Width;
Rectangle rect = new Rectangle(0, 0, bmp.Width, height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int rowSize = bmpData.Stride < 0 ? -bmpData.Stride : bmpData.Stride;
// Scanning for non-zero bytes
bool partBlack = false;
int blackRowCount = 0;
for (int y = 0; y < height; y++)
{
byte[] pixels = new byte[rowSize];
Marshal.Copy(IntPtr.Add(ptr, y * bmpData.Stride), pixels, 0, rowSize);
if (pixels.FirstOrDefault(pixel => pixel > 0) == 0)
{
blackRowCount++;
if (blackRowCount >= height * .01) // If 1% of the bitmap rows are black then treat the image as part black
{
partBlack = true;
break;
}
}
}
bmp.UnlockBits(bmpData);
return partBlack;
}
Возможно, проблема в Chrome и/или на что указывает «указатель Windows» в каждом случае. VS — это приложение WPF, о котором я слышал в последний раз. Какой метод поддерживает или не поддерживает WPF; и/или так ли это должно быть.