Страницы

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

понедельник, 23 декабря 2019 г.

Использование Desktop Duplication API

#cpp #cpp_cli #directx #direct3d


#include "stdafx.h"

#include "stdafx.h"
#include "iostream"

#include "D3D9.h"
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#pragma comment(lib, "D3D11.lib")
#pragma comment(lib, "D3d9.lib")
#pragma comment(lib, "dxgi.lib")

#pragma comment(lib, "gdi32.lib")

using namespace System;

#define EXIT(hr) { if (FAILED(hr)) \
                { Console::WriteLine("Error!"); \
                Console::ReadKey(); return -1; } }

HBITMAP ExtractBitmap(ID3D11Texture2D* d3dtex, ID3D11Device* pDevice) 
{
    HRESULT hr;

    HBITMAP hBitmapTexture = NULL;
    HGDIOBJ hBitmap;

    D3D11_TEXTURE2D_DESC desc;
    ID3D11Texture2D* pNewTexture = NULL;

    D3D11_TEXTURE2D_DESC description;

    d3dtex->GetDesc(&desc);
    d3dtex->GetDesc(&description);

    description.BindFlags = 0;
    description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    description.Usage = D3D11_USAGE_STAGING;

    if (FAILED(pDevice->CreateTexture2D(&description, NULL, &pNewTexture)))
    {
        Console::WriteLine("CreateTexture2D failed!");
        return NULL;
    }

    ID3D11DeviceContext* ctx = NULL;
    pDevice->GetImmediateContext(&ctx);

    ctx->CopyResource(pNewTexture, d3dtex);

    D3D11_MAPPED_SUBRESOURCE resource;
    UINT subresource = D3D11CalcSubresource(0, 0, 0);
    ctx->Map(pNewTexture, subresource, D3D11_MAP_READ_WRITE, 0, &resource);

    // Copy from texture to bitmap buffer.
    uint8_t* sptr = reinterpret_cast(resource.pData);
    uint8_t* dptr = new uint8_t[desc.Width*desc.Height * 4];

    for (size_t h = 0; h < desc.Height; ++h)
    {
        size_t msize = std::min(desc.Width * 4, resource.RowPitch);
        memcpy_s(dptr, desc.Width * 4, sptr, msize);
        sptr += resource.RowPitch;
        dptr += desc.Width * 4;
    }

    dptr -= desc.Width*desc.Height * 4;

    // Swap BGR to RGB bitmap.
    uint32_t *dPtr = reinterpret_cast(dptr);
    for (size_t count = 0; count < desc.Width*desc.Height * 4; count += 4)
    {
        uint32_t t = *dPtr;
        uint32_t t1 = (t & 0x00ff0000) >> 16;
        uint32_t t2 = (t & 0x000000ff) << 16;
        uint32_t t3 = (t & 0x0000ff00);
        uint32_t ta = (t & 0xFF000000);
        *(dPtr++) = t1 | t2 | t3 | ta;
    }

    hBitmapTexture = CreateCompatibleBitmap(GetDC(NULL), desc.Width, desc.Height);
    SetBitmapBits(hBitmapTexture, desc.Width*desc.Height * 4, dptr);

    return (HBITMAP)CopyImage(hBitmapTexture, IMAGE_BITMAP, desc.Width, desc.Height,
LR_CREATEDIBSECTION);
}


int main(array ^args)
{
    HRESULT hr;

    // Supported feature levels.
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_1
    };

    D3D_FEATURE_LEVEL d3dFeatLvl;
    ID3D11Device* pDevice = nullptr;
    ID3D11DeviceContext* pImmediateContext = nullptr;

    // Get device object.
    hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE,
        NULL, 0, featureLevels,
        ARRAYSIZE(featureLevels),
        D3D11_SDK_VERSION,
        &pDevice,
        &d3dFeatLvl,
        &pImmediateContext);
    EXIT(hr);

    // Get DXGI device.
    IDXGIDevice* DxgiDevice = nullptr;
    hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&DxgiDevice));
    EXIT(hr);

    // Get DXGI adapter.
    IDXGIAdapter* DxgiAdapter = nullptr;
    hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast(&DxgiAdapter));
    DxgiDevice->Release();
    DxgiDevice = nullptr;
    EXIT(hr);

    // Get DXGI output.
    IDXGIOutput* DxgiOutput = nullptr;
    hr = DxgiAdapter->EnumOutputs(0, &DxgiOutput);
    DxgiAdapter->Release();
    DxgiAdapter = nullptr;
    EXIT(hr);

    DXGI_OUTPUT_DESC OutputDesc;
    DxgiOutput->GetDesc(&OutputDesc);

    // Query interface for Output1.
    IDXGIOutput1* DxgiOutput1 = nullptr;
    hr = DxgiOutput->QueryInterface(__uuidof(DxgiOutput1), reinterpret_cast(&DxgiOutput1));
    DxgiOutput->Release();
    DxgiOutput = nullptr;
    EXIT(hr);

    // Create desktop duplication.
    IDXGIOutputDuplication* DeskDupl = nullptr;
    hr = DxgiOutput1->DuplicateOutput(pDevice, &DeskDupl);
    DxgiOutput1->Release();
    DxgiOutput1 = nullptr;
    EXIT(hr);

    DXGI_OUTDUPL_DESC OutputDuplDesc;
    DeskDupl->GetDesc(&OutputDuplDesc);

    ///////////////////////////////////////////////////////////////////////////

    ID3D11Texture2D* AcquiredDesktopImage = nullptr;

    IDXGIResource* DesktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo;

    // Get new frame.
    hr = DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);
    EXIT(hr);

    // If still holding old frame, destroy it.
    if (AcquiredDesktopImage)
    {
        AcquiredDesktopImage->Release();
        AcquiredDesktopImage = nullptr;
    }

    // Query interface for IDXGIResource.
    hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast(&AcquiredDesktopImage));
    DesktopResource->Release();
    DesktopResource = nullptr;
    EXIT(hr);

    HBITMAP hBmp = (HBITMAP)ExtractBitmap(AcquiredDesktopImage, pDevice);

    ///////////////////////////////////////////////////////////////////////////

    System::Drawing::Bitmap::FromHbitmap(IntPtr(hBmp))->Save("Screenshot.bmp");

    Console::WriteLine("END!");
    Console::ReadKey();
    return 0;
}


Привожу пример своего исходника по работе с Desktop Duplication API (на C++/CLI).
К сожалению, не могу добиться от него результата - картинка получается пустая.
Каким образом можно поправить этот код, чтобы он работал; +добавить цикл, чтобы можно
было получать скрины не вызывая функцию целиком.
    


Ответы

Ответ 1



Собственно, вот. #include "D3D9.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma comment(lib, "D3D11.lib") #pragma comment(lib, "D3d9.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "gdi32.lib") using namespace System; #define EXIT(hr) { if (FAILED(hr)) \ { Console::WriteLine("Error!"); \ Console::ReadKey(); return -1; } } HBITMAP ExtractBitmap(ID3D11Texture2D* d3dtex, ID3D11Device* pDevice) { HRESULT hr; HBITMAP hBitmapTexture = NULL; HGDIOBJ hBitmap; D3D11_TEXTURE2D_DESC desc; ID3D11Texture2D* pNewTexture = NULL; D3D11_TEXTURE2D_DESC description; d3dtex->GetDesc(&desc); d3dtex->GetDesc(&description); description.BindFlags = 0; description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; description.Usage = D3D11_USAGE_STAGING; description.MiscFlags = 0; if (FAILED(pDevice->CreateTexture2D(&description, NULL, &pNewTexture))) { return NULL; } ID3D11DeviceContext* ctx = NULL; pDevice->GetImmediateContext(&ctx); ctx->CopyResource(pNewTexture, d3dtex); D3D11_MAPPED_SUBRESOURCE resource; UINT subresource = D3D11CalcSubresource(0, 0, 0); ctx->Map(pNewTexture, subresource, D3D11_MAP_READ_WRITE, 0, &resource); // Copy from texture to bitmap buffer. uint8_t* sptr = reinterpret_cast(resource.pData); uint8_t* dptr = new uint8_t[desc.Width*desc.Height * 4]; for (size_t h = 0; h < desc.Height; ++h) { size_t msize = std::min(desc.Width * 4, resource.RowPitch); memcpy_s(dptr, desc.Width * 4, sptr, msize); sptr += resource.RowPitch; dptr += desc.Width * 4; } dptr -= desc.Width*desc.Height * 4; // SWAP BGR to RGB bitmap uint32_t *dPtr = reinterpret_cast(dptr); for (size_t count = 0; count < desc.Width*desc.Height * 4; count += 4) { uint32_t t = *(dPtr); uint32_t t1 = (t & 0x00ff0000) >> 16; uint32_t t2 = (t & 0x000000ff) << 16; uint32_t t3 = (t & 0x0000ff00); uint32_t ta = (t & 0xFF000000); *(dPtr++) = t1 | t2 | t3 | ta; } hBitmapTexture = CreateCompatibleBitmap(GetDC(NULL), desc.Width, desc.Height); SetBitmapBits(hBitmapTexture, desc.Width*desc.Height * 4, dptr); return (HBITMAP)CopyImage(hBitmapTexture, IMAGE_BITMAP, desc.Width, desc.Height, LR_CREATEDIBSECTION); } int main(array ^args) { HRESULT hr; // Supported feature levels. D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 }; D3D_FEATURE_LEVEL d3dFeatLvl; ID3D11Device* pDevice = nullptr; ID3D11DeviceContext* pImmediateContext = nullptr; // Get device object. hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &pDevice, &d3dFeatLvl, &pImmediateContext); EXIT(hr); // Get DXGI device. IDXGIDevice* DxgiDevice = nullptr; hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&DxgiDevice)); // Get DXGI adapter. IDXGIAdapter* DxgiAdapter = nullptr; hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast(&DxgiAdapter)); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DxgiDevice->GetParent"); Console::Read(); return -1; } DxgiDevice->Release(); DxgiDevice = nullptr; // Get DXGI output. IDXGIOutput* DxgiOutput = nullptr; hr = DxgiAdapter->EnumOutputs(0, &DxgiOutput); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DxgiAdapter->EnumOutputs"); Console::Read(); return -1; } DxgiAdapter->Release(); DxgiAdapter = nullptr; DXGI_OUTPUT_DESC OutputDesc; DxgiOutput->GetDesc(&OutputDesc); // Query interface for Output1. IDXGIOutput1* DxgiOutput1 = nullptr; hr = DxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast(&DxgiOutput1)); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DxgiOutput->QueryInterface"); Console::Read(); return -1; } DxgiOutput->Release(); DxgiOutput = nullptr; // Create desktop duplication. IDXGIOutputDuplication* DeskDupl = nullptr; hr = DxgiOutput1->DuplicateOutput(pDevice, &DeskDupl); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DxgiOutput1->DuplicateOutput"); Console::Read(); return -1; } DxgiOutput1->Release(); DxgiOutput1 = nullptr; DXGI_OUTDUPL_DESC OutputDuplDesc; DeskDupl->GetDesc(&OutputDuplDesc); /////////////////////////////////////////////////////////////////////////// ID3D11Texture2D* AcquiredDesktopImage = nullptr; IDXGIResource* DesktopResource = nullptr; DXGI_OUTDUPL_FRAME_INFO FrameInfo; // Get new frame. hr = DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DeskDupl->AcquireNextFrame"); Console::Read(); return -1; } // If still holding old frame, destroy it. //if (AcquiredDesktopImage) //{ //AcquiredDesktopImage->Release(); //AcquiredDesktopImage = nullptr; //} // Query interface for IDXGIResource. hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast(&AcquiredDesktopImage)); if (FAILED(hr)) { Console::WriteLine("ERROR: failed to DesktopResource->QueryInterface"); Console::Read(); return -1; } DesktopResource->Release(); DesktopResource = nullptr; HBITMAP hBmp = (HBITMAP)ExtractBitmap(AcquiredDesktopImage, pDevice); /////////////////////////////////////////////////////////////////////////// System::Drawing::Bitmap::FromHbitmap(IntPtr(hBmp))->Save("Screenshot.bmp"); Console::WriteLine("END!"); Console::ReadKey(); return 0; } На вопрос где же была ошибка, могу сказать одно. Копируя чужой код в свой проект, проверяйте его, а так же читайте комментарии :)

Ответ 2



Подробный ответ дан здесь Суть в двух моментах: Однократного вызова AcquireNextFrame недостаточно для получения изображения экрана, так как "Frame" - это необязательно изображение экрана, а совокупность некоторой информации о изменении состояния рабочего стола (среди которой, иногда, может быть и изображение экрана). Для получения изображения нужно циклически вызывать AcquireNextFrame и сохранять все полученные результаты. Для корректного зацикливания нужно освободить Frame: IDXGIOutputDuplication* DeskDupl; //инициализация... DeskDupl->AcquireNextFrame(5000, &FrameInfo, &DesktopResource); //работа с Frame... hr = DeskDupl->ReleaseFrame();//освобождаем Frame if (FAILED(hr)) { //произошла ошибка } else { //можно получить следующий Frame }

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

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