• win32


    该代码来源于codeproject,经过测试发现,在屏幕处于旋转的情况下捕获的图像是黑色的。暂时没有找到原因。

    代码开箱即用,

    #define WIN32_LEAN_AND_MEAN    
    
    #include <windows.h>
    #include <shlobj.h>
    #include <shellapi.h>
    #include <dxgi1_2.h>
    #include <d3d11.h>
    #include <memory>
    #include <algorithm>
    #include <string>
    
    #pragma comment(lib, "D3D11.lib")
    
    template <typename T>
    class CComPtrCustom
    {
    public:
    
        CComPtrCustom(T *aPtrElement)
            :element(aPtrElement)
        {
        }
    
        CComPtrCustom()
            :element(nullptr)
        {
        }
    
        virtual ~CComPtrCustom()
        {
            Release();
        }
    
        T* Detach()
        {
            auto lOutPtr = element;
    
            element = nullptr;
    
            return lOutPtr;
        }
    
        T* detach()
        {
            return Detach();
        }
    
        void Release()
        {
            if (element == nullptr)
                return;
    
            auto k = element->Release();
    
            element = nullptr;
        }
    
        CComPtrCustom& operator = (T *pElement)
        {
            Release();
    
            if (pElement == nullptr)
                return *this;
    
            auto k = pElement->AddRef();
    
            element = pElement;
    
            return *this;
        }
    
        void Swap(CComPtrCustom& other)
        {
            T* pTemp = element;
            element = other.element;
            other.element = pTemp;
        }
    
        T* operator->()
        {
            return element;
        }
    
        operator T*()
        {
            return element;
        }
    
        operator T*() const
        {
            return element;
        }
    
    
        T* get()
        {
            return element;
        }
    
        T* get() const
        {
            return element;
        }
    
        T** operator &()
        {
            return &element;
        }
    
        bool operator !()const
        {
            return element == nullptr;
        }
    
        operator bool()const
        {
            return element != nullptr;
        }
    
        bool operator == (const T *pElement)const
        {
            return element == pElement;
        }
    
    
        CComPtrCustom(const CComPtrCustom& aCComPtrCustom)
        {
            if (aCComPtrCustom.operator!())
            {
                element = nullptr;
    
                return;
            }
    
            element = aCComPtrCustom;
    
            auto h = element->AddRef();
    
            h++;
        }
    
        CComPtrCustom& operator = (const CComPtrCustom& aCComPtrCustom)
        {
            Release();
    
            element = aCComPtrCustom;
    
            auto k = element->AddRef();
    
            return *this;
        }
    
        _Check_return_ HRESULT CopyTo(T** ppT) throw()
        {
            if (ppT == NULL)
                return E_POINTER;
    
            *ppT = element;
    
            if (element)
                element->AddRef();
    
            return S_OK;
        }
    
        HRESULT CoCreateInstance(const CLSID aCLSID)
        {
            T* lPtrTemp;
    
            auto lresult = ::CoCreateInstance(aCLSID, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&lPtrTemp));
    
            if (SUCCEEDED(lresult))
            {
                if (lPtrTemp != nullptr)
                {
                    Release();
    
                    element = lPtrTemp;
                }
    
            }
    
            return lresult;
        }
    
    protected:
    
        T* element;
    };
    
    
    // Driver types supported
    D3D_DRIVER_TYPE gDriverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE
    };
    UINT gNumDriverTypes = ARRAYSIZE(gDriverTypes);
    
    // Feature levels supported
    D3D_FEATURE_LEVEL gFeatureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_1
    };
    
    UINT gNumFeatureLevels = ARRAYSIZE(gFeatureLevels);
    
    
    int main()
    {
        CComPtrCustom<ID3D11Device> lDevice;
        CComPtrCustom<ID3D11DeviceContext> lImmediateContext;
        CComPtrCustom<IDXGIOutputDuplication> lDeskDupl;
        CComPtrCustom<ID3D11Texture2D> lAcquiredDesktopImage;
        CComPtrCustom<ID3D11Texture2D> lGDIImage;
        CComPtrCustom<ID3D11Texture2D> lDestImage;
        DXGI_OUTPUT_DESC lOutputDesc;
        DXGI_OUTDUPL_DESC lOutputDuplDesc;
    
        int lresult(-1);
    
        do
        {
    
            
    
            D3D_FEATURE_LEVEL lFeatureLevel;
    
            HRESULT hr(E_FAIL);
    
            // Create device
            for (UINT DriverTypeIndex = 0; DriverTypeIndex < gNumDriverTypes; ++DriverTypeIndex)
            {
                hr = D3D11CreateDevice(
                    nullptr,
                    gDriverTypes[DriverTypeIndex],
                    nullptr,
                    0,
                    gFeatureLevels,
                    gNumFeatureLevels,
                    D3D11_SDK_VERSION,
                    &lDevice,
                    &lFeatureLevel,
                    &lImmediateContext);
    
                if (SUCCEEDED(hr))
                {
                    // Device creation success, no need to loop anymore
                    break;
                }
    
                lDevice.Release();
    
                lImmediateContext.Release();
            }
    
            if (FAILED(hr))
                break;
    
            Sleep(100);
    
            if (lDevice == nullptr)
                break;
            
            // Get DXGI device
            CComPtrCustom<IDXGIDevice> lDxgiDevice;
    
            hr = lDevice->QueryInterface(IID_PPV_ARGS(&lDxgiDevice));
    
            if (FAILED(hr))
                break;
    
            // Get DXGI adapter
            CComPtrCustom<IDXGIAdapter> lDxgiAdapter;
            hr = lDxgiDevice->GetParent(
                __uuidof(IDXGIAdapter),
                reinterpret_cast<void**>(&lDxgiAdapter));
    
            if (FAILED(hr))
                break;
    
            lDxgiDevice.Release();
    
            UINT Output = 0;
    
            // Get output
            CComPtrCustom<IDXGIOutput> lDxgiOutput;
            hr = lDxgiAdapter->EnumOutputs(
                Output,
                &lDxgiOutput);
    
            if (FAILED(hr))
                break;
    
            lDxgiAdapter.Release();
    
            hr = lDxgiOutput->GetDesc(
                &lOutputDesc);
    
            if (FAILED(hr))
                break;
    
            // QI for Output 1
            CComPtrCustom<IDXGIOutput1> lDxgiOutput1;
    
            hr = lDxgiOutput->QueryInterface(IID_PPV_ARGS(&lDxgiOutput1));
    
            if (FAILED(hr))
                break;
    
            lDxgiOutput.Release();
    
            // Create desktop duplication
            hr = lDxgiOutput1->DuplicateOutput(
                lDevice,
                &lDeskDupl);
    
            if (FAILED(hr))
                break;
    
            lDxgiOutput1.Release();
    
            // Create GUI drawing texture
            lDeskDupl->GetDesc(&lOutputDuplDesc);
    
            D3D11_TEXTURE2D_DESC desc;
    
            desc.Width = lOutputDuplDesc.ModeDesc.Width;
    
            desc.Height = lOutputDuplDesc.ModeDesc.Height;
    
            desc.Format = lOutputDuplDesc.ModeDesc.Format;
    
            desc.ArraySize = 1;
    
            desc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET;
    
            desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
    
            desc.SampleDesc.Count = 1;
    
            desc.SampleDesc.Quality = 0;
    
            desc.MipLevels = 1;
    
            desc.CPUAccessFlags = 0;
    
            desc.Usage = D3D11_USAGE_DEFAULT;
    
            hr = lDevice->CreateTexture2D(&desc, NULL, &lGDIImage);
    
            if (FAILED(hr))
                break;
    
            if (lGDIImage == nullptr)
                break;                    
    
    
            // Create CPU access texture
    
            desc.Width = lOutputDuplDesc.ModeDesc.Width;
    
            desc.Height = lOutputDuplDesc.ModeDesc.Height;
    
            desc.Format = lOutputDuplDesc.ModeDesc.Format;
    
            desc.ArraySize = 1;
    
            desc.BindFlags = 0;
    
            desc.MiscFlags = 0;
    
            desc.SampleDesc.Count = 1;
    
            desc.SampleDesc.Quality = 0;
    
            desc.MipLevels = 1;
    
            desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
            desc.Usage = D3D11_USAGE_STAGING;
    
            hr = lDevice->CreateTexture2D(&desc, NULL, &lDestImage);
    
            if (FAILED(hr))
                break;
    
            if (lDestImage == nullptr)
                break;
    
            CComPtrCustom<IDXGIResource> lDesktopResource;
            DXGI_OUTDUPL_FRAME_INFO lFrameInfo;
    
            int lTryCount = 4;
    
            do
            {
    
                Sleep(100);
    
                // Get new frame
                hr = lDeskDupl->AcquireNextFrame(
                    250,
                    &lFrameInfo,
                    &lDesktopResource);
                
                if (SUCCEEDED(hr))
                    break;
    
                if (hr == DXGI_ERROR_WAIT_TIMEOUT)
                {
                    continue;
                }
                else if (FAILED(hr))
                    break;            
    
            } while (--lTryCount > 0);
    
            if (FAILED(hr))
                break;
    
            // QI for ID3D11Texture2D
    
            hr = lDesktopResource->QueryInterface(IID_PPV_ARGS(&lAcquiredDesktopImage));
    
            if (FAILED(hr))
                break;
    
            lDesktopResource.Release();
    
            if (lAcquiredDesktopImage == nullptr)
                break;
                    
            // Copy image into GDI drawing texture
    
            lImmediateContext->CopyResource(lGDIImage, lAcquiredDesktopImage);
            
    
            // Draw cursor image into GDI drawing texture
    
            CComPtrCustom<IDXGISurface1> lIDXGISurface1;
            
            hr = lGDIImage->QueryInterface(IID_PPV_ARGS(&lIDXGISurface1));
    
            if (FAILED(hr))
                break;
    
            CURSORINFO lCursorInfo = { 0 };
    
            lCursorInfo.cbSize = sizeof(lCursorInfo);
    
            auto lBoolres = GetCursorInfo(&lCursorInfo);
    
            if (lBoolres == TRUE)
            {
                if (lCursorInfo.flags == CURSOR_SHOWING)
                {
                    auto lCursorPosition = lCursorInfo.ptScreenPos;
    
                    auto lCursorSize = lCursorInfo.cbSize;
    
                    HDC  lHDC;
    
                    lIDXGISurface1->GetDC(FALSE, &lHDC);
    
                    DrawIconEx(
                        lHDC,
                        lCursorPosition.x,
                        lCursorPosition.y,
                        lCursorInfo.hCursor,
                        0,
                        0,
                        0,
                        0,
                        DI_NORMAL | DI_DEFAULTSIZE);
    
                    lIDXGISurface1->ReleaseDC(nullptr);
                }
    
            }
    
            // Copy image into CPU access texture
    
            lImmediateContext->CopyResource(lDestImage, lGDIImage);
            
    
            // Copy from CPU access texture to bitmap buffer
    
            D3D11_MAPPED_SUBRESOURCE resource;
            UINT subresource = D3D11CalcSubresource(0, 0, 0);
            lImmediateContext->Map(lDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
            
            BITMAPINFO    lBmpInfo;
    
            // BMP 32 bpp
    
            ZeroMemory(&lBmpInfo, sizeof(BITMAPINFO));
    
            lBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    
            lBmpInfo.bmiHeader.biBitCount = 32;
    
            lBmpInfo.bmiHeader.biCompression = BI_RGB;
    
            lBmpInfo.bmiHeader.biWidth = lOutputDuplDesc.ModeDesc.Width;
    
            lBmpInfo.bmiHeader.biHeight = lOutputDuplDesc.ModeDesc.Height;
    
            lBmpInfo.bmiHeader.biPlanes = 1;
        
            lBmpInfo.bmiHeader.biSizeImage = lOutputDuplDesc.ModeDesc.Width 
                * lOutputDuplDesc.ModeDesc.Height * 4;
    
    
            std::unique_ptr<BYTE> pBuf(new BYTE[lBmpInfo.bmiHeader.biSizeImage]);
    
    
            UINT lBmpRowPitch = lOutputDuplDesc.ModeDesc.Width * 4;
    
            BYTE* sptr = reinterpret_cast<BYTE*>(resource.pData);
            BYTE* dptr = pBuf.get() + lBmpInfo.bmiHeader.biSizeImage - lBmpRowPitch;
    
            UINT lRowPitch = std::min<UINT>(lBmpRowPitch, resource.RowPitch);
    
    
            for (size_t h = 0; h < lOutputDuplDesc.ModeDesc.Height; ++h)
            {
                
                memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
                sptr += resource.RowPitch;
                dptr -= lBmpRowPitch;
            }
    
            // Save bitmap buffer into the file ScreenShot.bmp
    
            WCHAR lMyDocPath[MAX_PATH];
    
            hr = SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, lMyDocPath);
    
            if (FAILED(hr))
                break;
    
            std::wstring lFilePath = std::wstring(lMyDocPath) + L"\ScreenShot.bmp";
    
    
    
            FILE* lfile = nullptr;
    
            auto lerr = _wfopen_s(&lfile, lFilePath.c_str(), L"wb");
    
            if (lerr != 0)
                break;
    
            if (lfile != nullptr)
            {
    
                BITMAPFILEHEADER    bmpFileHeader;
    
                bmpFileHeader.bfReserved1 = 0;
                bmpFileHeader.bfReserved2 = 0;
                bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lBmpInfo.bmiHeader.biSizeImage;
                bmpFileHeader.bfType = 'MB';
                bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    
                fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, lfile);
                fwrite(&lBmpInfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, lfile);
                fwrite(pBuf.get(), lBmpInfo.bmiHeader.biSizeImage, 1, lfile);
    
                fclose(lfile);
    
                ShellExecute(0, 0, lFilePath.c_str(), 0, 0, SW_SHOW);
    
                lresult = 0;
                
            }
            
        } while (false);
        
        return lresult;
    }

    如果需要录屏,可以参考另一个文章:screen-recorder

  • 相关阅读:
    资料网站
    HTML、CSS部分
    面试题三
    面试题二
    面试题一
    上学时的HTML+JS+CSS(小总结)
    01.策略模式-上篇
    【解决方案】HTTP could not register URL http://+:6001/
    【问题与思考】1+"1"=?
    WCF安全3-Transport与Message安全模式
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14549569.html
Copyright © 2020-2023  润新知