Сделайте снимок экрана в полноэкранном приложении DirectX
Это меня поражает. DirectX обходит все и разговаривает напрямую с драйвером устройства, поэтому GDI и другие обычные методы не будут работать - если Aero не отключен (или недоступен), все, что появляется, это черный прямоугольник в левом верхнем углу экрана. Я попробовал то, что другие предложили на нескольких форумах, используя DirectX, чтобы получить задний буфер и сохранить его, но я получаю тот же результат:
device- > GetFrontBufferData (0, поверхность);
D3DXSaveSurfaceToFile ( "имя_файла", D3DXIFF_BMP, поверхность, NULL, NULL);
Есть ли способ получить снимок экрана другого полноэкранного приложения DirectX, когда включен Aero?
Ответы
Ответ 1
Посмотрите Detours.
Используя Detours, вы можете выполнять такие вызовы, как Direct3DCreate9
, IDirect3D9::CreateDevice
и IDirect3D9::Present
, в которых вы выполняете операции, необходимые для настройки, а затем выполняете захват кадров.
Ответ 2
Вот пример С#, связанный с подключением объектов IDirect3DDevice9 через DLL-инъекцию и запуск функции с помощью EasyHook (например, Microsoft Detours). Это похоже на то, как работает FRAPS.
Это позволяет вам захватить экран в оконном/полноэкранном режиме и использовать задний буфер, который намного быстрее, чем попытка извлечь данные из переднего буфера.
Небольшая DLL-помощник С++ используется для определения методов объекта IDirect3DDevice9 для привязки во время выполнения.
Обновление: для DirectX 10/11 см. Захват экрана и наложения для D3D 9, 10 и 11
Ответ 3
Это фрагмент кода, который я использовал в качестве теста только сейчас, кажется, работает.
ширина и высота - это размер экрана в оконном режиме, а не в окнах. Поэтому для меня они установлены на 1280 x 1024, а не на окно, которое я обрабатываю по размеру.
Вам нужно будет заменить mEngine- > getDevice() каким-то образом получить ваш IDirect3DDevice9. Я просто вставлял этот код в случайное приложение d3d, которое мне пришлось упростить для тестирования. Но я могу подтвердить, что он захватывает как выход из этого приложения, так и другое приложение d3d, работающее одновременно.
О, я предположил, что это D3D9, как вы не сказали, я не уверен в d3d10 или 11
IDirect3DSurface9* surface;
mEngine->getDevice()->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
mEngine->getDevice()->GetFrontBufferData(0, surface);
D3DXSaveSurfaceToFile("c:\\tmp\\output.jpg", D3DXIFF_JPG, surface, NULL, NULL);
surface->Release();
Ответ 4
Существует программа с открытым исходным кодом, например, fraps: taksi, но выглядит устаревшей
Ответ 5
Вот несколько обсуждений того, как работает Fraps. Это не просто.
http://www.woodmann.com/forum/archive/index.php/t-11023.html
Любой трюк, который пытается прочитать передний буфер с другого устройства DirectX, я подозреваю, что он может изредка работать из-за удачи неинициализированной памяти.
Ответ 6
После ответа J99 я сделал работу кода как для оконных, так и для полноэкранных режимов. Это также делается в D3D9.
IDirect3DSurface9* surface;
D3DDISPLAYMODE mode;
pDev->GetDisplayMode(0, &mode); // pDev is my *IDirect3DDevice
// we can capture only the entire screen,
// so width and height must match current display mode
pDev->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
if(pDev->GetFrontBufferData(0, surface)==D3D_OK)
{
if(bWindowed) // a global config variable
{
// get client area in desktop coordinates
// this might need to be changed to support multiple screens
RECT r;
GetClientRect(hWnd, &r); // hWnd is our window handle
POINT p = {0, 0};
ClientToScreen(hWnd, &p);
SetRect(&r, p.x, p.y, p.x+r.right, p.y+r.bottom);
D3DXSaveSurfaceToFile(szFilename, D3DXIFF_JPG, surface, NULL, &r);
}
else
D3DXSaveSurfaceToFile(szFilename, D3DXIFF_JPG, surface, NULL, NULL);
}
surface->Release();
Похоже, что параметры формата и пула CreateOffscreenPlainSurface должны быть точно такими же.
Ответ 7
Возможно, вы захотите взглянуть на мой проект Investigo.
Он использует прокси DLL DirectX для перехвата функций DirectX API.
Здесь есть код, чтобы делать снимки экрана во время вызова Present. Хотя он еще не доступен из пользовательского интерфейса. Вы должны иметь возможность легко включить код.
http://www.codeproject.com/Articles/448756/Introducing-Investigo-Using-a-Proxy-DLL-and-embedd