Windows DXGI屏幕捕获实现

news/2024/12/15 23:38:28/文章来源:https://www.cnblogs.com/blogosphere/p/18608903

Windows DXGI 方式屏幕捕获实现

主要步骤

graph TBA[D3D11CreateDevice] --> B[ID3D11Device]A[D3D11CreateDevice] --> C[ID3D11DeviceContext]B -.QueryInterface.-> D[IDXGIDevice]B -.GetParent.-> E[IDXGIAdapter]E -.EnumOutputs.-> F[IDXGIOutput]F -.QueryInterface.-> G[IDXGIOutput1]G -.DuplicateOutput.-> H[IDXGIOutputDuplication]H -.AcquireNextFrame.-> I[IDXGIResource]H -.AcquireNextFrame.-> J[DXGI_OUTDUPL_FRAME_INFO]J --> K[Release/ReleaseFrame]H -.GetDesc.-> L[DXGI_OUTDUPL_DESC]L -.设置width/height.-> M[D3D11_TEXTURE2D_DESC]M -.CreateTexture2D.-> N[ID3D11Texture2D]B -.CreateTexture2D.-> N[ID3D11Texture2D]N -.后续包括将GPU数据拷贝到CPU,绘制鼠标等操作.-> O[Release/ReleaseFrame]

绘制鼠标

  1. 方式1:使用 GDI 绘制鼠标

IDXGISurface1 对象可通过IDXGISurface QueryInterface 获取.

void DrawMouseCursor(IDXGISurface1 *p_DXGISurface1) {CURSORINFO cursorInfo = {sizeof(CURSORINFO)};ICONINFO iconInfo;bool isDraw = true;HDC hdc;cursorInfo.cbSize = sizeof(cursorInfo);p_DXGISurface1->GetDC(FALSE, &hdc);if (!GetCursorInfo(&cursorInfo)) {std::wcout << L"GetCursorInfo failed" << std::endl;}if (!(cursorInfo.flags & CURSOR_SHOWING)) {std::wcout << L"Cursor is not showing" << std::endl;}if (!GetIconInfo(cursorInfo.hCursor, &iconInfo)) {std::wcout << L"GetIconInfo failed" << std::endl;}if (!hdc || !cursorInfo.hCursor) {std::wcout << L"Failed to get bitmap" << std::endl;}if (cursorInfo.flags == CURSOR_SHOWING) {isDraw =DrawIconEx(hdc, cursorInfo.ptScreenPos.x, cursorInfo.ptScreenPos.y,cursorInfo.hCursor, 0, 0, 0, 0, DI_NORMAL | DI_DEFAULTSIZE);if (!isDraw) {DWORD error = GetLastError();std::cerr << "DrawIconEx failed with error: " << error << std::endl;}DeleteObject(iconInfo.hbmColor);DeleteObject(iconInfo.hbmMask);}p_DXGISurface1->ReleaseDC(NULL);
}
  1. 方式2:手动绘制鼠标
    参考微软官方示例:Windows-classic-samples

主要代码如下:

DUPL_RETURN OUTPUTMANAGER::ProcessMonoMask(bool IsMono, _Inout_ PTR_INFO* PtrInfo, _Out_ INT* PtrWidth, _Out_ INT* PtrHeight, _Out_ INT* PtrLeft, _Out_ INT* PtrTop, _Outptr_result_bytebuffer_(*PtrHeight * *PtrWidth * BPP) BYTE** InitBuffer, _Out_ D3D11_BOX* Box)
{// Desktop dimensionsD3D11_TEXTURE2D_DESC FullDesc;m_SharedSurf->GetDesc(&FullDesc);INT DesktopWidth = FullDesc.Width;INT DesktopHeight = FullDesc.Height;// Pointer positionINT GivenLeft = PtrInfo->Position.x;INT GivenTop = PtrInfo->Position.y;// Figure out if any adjustment is needed for out of bound positionsif (GivenLeft < 0){*PtrWidth = GivenLeft + static_cast<INT>(PtrInfo->ShapeInfo.Width);}else if ((GivenLeft + static_cast<INT>(PtrInfo->ShapeInfo.Width)) > DesktopWidth){*PtrWidth = DesktopWidth - GivenLeft;}else{*PtrWidth = static_cast<INT>(PtrInfo->ShapeInfo.Width);}if (IsMono){PtrInfo->ShapeInfo.Height = PtrInfo->ShapeInfo.Height / 2;}if (GivenTop < 0){*PtrHeight = GivenTop + static_cast<INT>(PtrInfo->ShapeInfo.Height);}else if ((GivenTop + static_cast<INT>(PtrInfo->ShapeInfo.Height)) > DesktopHeight){*PtrHeight = DesktopHeight - GivenTop;}else{*PtrHeight = static_cast<INT>(PtrInfo->ShapeInfo.Height);}if (IsMono){PtrInfo->ShapeInfo.Height = PtrInfo->ShapeInfo.Height * 2;}*PtrLeft = (GivenLeft < 0) ? 0 : GivenLeft;*PtrTop = (GivenTop < 0) ? 0 : GivenTop;// Staging buffer/textureD3D11_TEXTURE2D_DESC CopyBufferDesc;CopyBufferDesc.Width = *PtrWidth;CopyBufferDesc.Height = *PtrHeight;CopyBufferDesc.MipLevels = 1;CopyBufferDesc.ArraySize = 1;CopyBufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;CopyBufferDesc.SampleDesc.Count = 1;CopyBufferDesc.SampleDesc.Quality = 0;CopyBufferDesc.Usage = D3D11_USAGE_STAGING;CopyBufferDesc.BindFlags = 0;CopyBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;CopyBufferDesc.MiscFlags = 0;ID3D11Texture2D* CopyBuffer = nullptr;HRESULT hr = m_Device->CreateTexture2D(&CopyBufferDesc, nullptr, &CopyBuffer);if (FAILED(hr)){return ProcessFailure(m_Device, L"Failed creating staging texture for pointer", L"Error", hr, SystemTransitionsExpectedErrors);}// Copy needed part of desktop imageBox->left = *PtrLeft;Box->top = *PtrTop;Box->right = *PtrLeft + *PtrWidth;Box->bottom = *PtrTop + *PtrHeight;m_DeviceContext->CopySubresourceRegion(CopyBuffer, 0, 0, 0, 0, m_SharedSurf, 0, Box);// QI for IDXGISurfaceIDXGISurface* CopySurface = nullptr;hr = CopyBuffer->QueryInterface(__uuidof(IDXGISurface), (void **)&CopySurface);CopyBuffer->Release();CopyBuffer = nullptr;if (FAILED(hr)){return ProcessFailure(nullptr, L"Failed to QI staging texture into IDXGISurface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);}// Map pixelsDXGI_MAPPED_RECT MappedSurface;hr = CopySurface->Map(&MappedSurface, DXGI_MAP_READ);if (FAILED(hr)){CopySurface->Release();CopySurface = nullptr;return ProcessFailure(m_Device, L"Failed to map surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);}// New mouseshape buffer*InitBuffer = new (std::nothrow) BYTE[*PtrWidth * *PtrHeight * BPP];if (!(*InitBuffer)){return ProcessFailure(nullptr, L"Failed to allocate memory for new mouse shape buffer.", L"Error", E_OUTOFMEMORY);}UINT* InitBuffer32 = reinterpret_cast<UINT*>(*InitBuffer);UINT* Desktop32 = reinterpret_cast<UINT*>(MappedSurface.pBits);UINT  DesktopPitchInPixels = MappedSurface.Pitch / sizeof(UINT);// What to skip (pixel offset)UINT SkipX = (GivenLeft < 0) ? (-1 * GivenLeft) : (0);UINT SkipY = (GivenTop < 0) ? (-1 * GivenTop) : (0);if (IsMono){for (INT Row = 0; Row < *PtrHeight; ++Row){// Set maskBYTE Mask = 0x80;Mask = Mask >> (SkipX % 8);for (INT Col = 0; Col < *PtrWidth; ++Col){// Get masks using appropriate offsetsBYTE AndMask = PtrInfo->PtrShapeBuffer[((Col + SkipX) / 8) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch))] & Mask;BYTE XorMask = PtrInfo->PtrShapeBuffer[((Col + SkipX) / 8) + ((Row + SkipY + (PtrInfo->ShapeInfo.Height / 2)) * (PtrInfo->ShapeInfo.Pitch))] & Mask;UINT AndMask32 = (AndMask) ? 0xFFFFFFFF : 0xFF000000;UINT XorMask32 = (XorMask) ? 0x00FFFFFF : 0x00000000;// Set new pixelInitBuffer32[(Row * *PtrWidth) + Col] = (Desktop32[(Row * DesktopPitchInPixels) + Col] & AndMask32) ^ XorMask32;// Adjust maskif (Mask == 0x01){Mask = 0x80;}else{Mask = Mask >> 1;}}}}else{UINT* Buffer32 = reinterpret_cast<UINT*>(PtrInfo->PtrShapeBuffer);// Iterate through pixelsfor (INT Row = 0; Row < *PtrHeight; ++Row){for (INT Col = 0; Col < *PtrWidth; ++Col){// Set up maskUINT MaskVal = 0xFF000000 & Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))];if (MaskVal){// Mask was 0xFFInitBuffer32[(Row * *PtrWidth) + Col] = (Desktop32[(Row * DesktopPitchInPixels) + Col] ^ Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))]) | 0xFF000000;}else{// Mask was 0x00InitBuffer32[(Row * *PtrWidth) + Col] = Buffer32[(Col + SkipX) + ((Row + SkipY) * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))] | 0xFF000000;}}}}// Done with resourcehr = CopySurface->Unmap();CopySurface->Release();CopySurface = nullptr;if (FAILED(hr)){return ProcessFailure(m_Device, L"Failed to unmap surface for pointer", L"Error", hr, SystemTransitionsExpectedErrors);}return DUPL_RETURN_SUCCESS;
}//
// Draw mouse provided in buffer to backbuffer
//
DUPL_RETURN OUTPUTMANAGER::DrawMouse(_In_ PTR_INFO* PtrInfo)
{// Vars to be usedID3D11Texture2D* MouseTex = nullptr;ID3D11ShaderResourceView* ShaderRes = nullptr;ID3D11Buffer* VertexBufferMouse = nullptr;D3D11_SUBRESOURCE_DATA InitData;D3D11_TEXTURE2D_DESC Desc;D3D11_SHADER_RESOURCE_VIEW_DESC SDesc;// Position will be changed based on mouse positionVERTEX Vertices[NUMVERTICES] ={{XMFLOAT3(-1.0f, -1.0f, 0), XMFLOAT2(0.0f, 1.0f)},{XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},{XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},{XMFLOAT3(1.0f, -1.0f, 0), XMFLOAT2(1.0f, 1.0f)},{XMFLOAT3(-1.0f, 1.0f, 0), XMFLOAT2(0.0f, 0.0f)},{XMFLOAT3(1.0f, 1.0f, 0), XMFLOAT2(1.0f, 0.0f)},};D3D11_TEXTURE2D_DESC FullDesc;m_SharedSurf->GetDesc(&FullDesc);INT DesktopWidth = FullDesc.Width;INT DesktopHeight = FullDesc.Height;// Center of desktop dimensionsINT CenterX = (DesktopWidth / 2);INT CenterY = (DesktopHeight / 2);// Clipping adjusted coordinates / dimensionsINT PtrWidth = 0;INT PtrHeight = 0;INT PtrLeft = 0;INT PtrTop = 0;// Buffer used if necessary (in case of monochrome or masked pointer)BYTE* InitBuffer = nullptr;// Used for copying pixelsD3D11_BOX Box;Box.front = 0;Box.back = 1;Desc.MipLevels = 1;Desc.ArraySize = 1;Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;Desc.SampleDesc.Count = 1;Desc.SampleDesc.Quality = 0;Desc.Usage = D3D11_USAGE_DEFAULT;Desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;Desc.CPUAccessFlags = 0;Desc.MiscFlags = 0;// Set shader resource propertiesSDesc.Format = Desc.Format;SDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;SDesc.Texture2D.MostDetailedMip = Desc.MipLevels - 1;SDesc.Texture2D.MipLevels = Desc.MipLevels;switch (PtrInfo->ShapeInfo.Type){case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:{PtrLeft = PtrInfo->Position.x;PtrTop = PtrInfo->Position.y;PtrWidth = static_cast<INT>(PtrInfo->ShapeInfo.Width);PtrHeight = static_cast<INT>(PtrInfo->ShapeInfo.Height);break;}case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:{ProcessMonoMask(true, PtrInfo, &PtrWidth, &PtrHeight, &PtrLeft, &PtrTop, &InitBuffer, &Box);break;}case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:{ProcessMonoMask(false, PtrInfo, &PtrWidth, &PtrHeight, &PtrLeft, &PtrTop, &InitBuffer, &Box);break;}default:break;}// VERTEX creationVertices[0].Pos.x = (PtrLeft - CenterX) / (FLOAT)CenterX;Vertices[0].Pos.y = -1 * ((PtrTop + PtrHeight) - CenterY) / (FLOAT)CenterY;Vertices[1].Pos.x = (PtrLeft - CenterX) / (FLOAT)CenterX;Vertices[1].Pos.y = -1 * (PtrTop - CenterY) / (FLOAT)CenterY;Vertices[2].Pos.x = ((PtrLeft + PtrWidth) - CenterX) / (FLOAT)CenterX;Vertices[2].Pos.y = -1 * ((PtrTop + PtrHeight) - CenterY) / (FLOAT)CenterY;Vertices[3].Pos.x = Vertices[2].Pos.x;Vertices[3].Pos.y = Vertices[2].Pos.y;Vertices[4].Pos.x = Vertices[1].Pos.x;Vertices[4].Pos.y = Vertices[1].Pos.y;Vertices[5].Pos.x = ((PtrLeft + PtrWidth) - CenterX) / (FLOAT)CenterX;Vertices[5].Pos.y = -1 * (PtrTop - CenterY) / (FLOAT)CenterY;// Set texture propertiesDesc.Width = PtrWidth;Desc.Height = PtrHeight;// Set up init dataInitData.pSysMem = (PtrInfo->ShapeInfo.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) ? PtrInfo->PtrShapeBuffer : InitBuffer;InitData.SysMemPitch = (PtrInfo->ShapeInfo.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) ? PtrInfo->ShapeInfo.Pitch : PtrWidth * BPP;InitData.SysMemSlicePitch = 0;// Create mouseshape as textureHRESULT hr = m_Device->CreateTexture2D(&Desc, &InitData, &MouseTex);if (FAILED(hr)){return ProcessFailure(m_Device, L"Failed to create mouse pointer texture", L"Error", hr, SystemTransitionsExpectedErrors);}// Create shader resource from texturehr = m_Device->CreateShaderResourceView(MouseTex, &SDesc, &ShaderRes);if (FAILED(hr)){MouseTex->Release();MouseTex = nullptr;return ProcessFailure(m_Device, L"Failed to create shader resource from mouse pointer texture", L"Error", hr, SystemTransitionsExpectedErrors);}D3D11_BUFFER_DESC BDesc;ZeroMemory(&BDesc, sizeof(D3D11_BUFFER_DESC));BDesc.Usage = D3D11_USAGE_DEFAULT;BDesc.ByteWidth = sizeof(VERTEX) * NUMVERTICES;BDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;BDesc.CPUAccessFlags = 0;ZeroMemory(&InitData, sizeof(D3D11_SUBRESOURCE_DATA));InitData.pSysMem = Vertices;// Create vertex bufferhr = m_Device->CreateBuffer(&BDesc, &InitData, &VertexBufferMouse);if (FAILED(hr)){ShaderRes->Release();ShaderRes = nullptr;MouseTex->Release();MouseTex = nullptr;return ProcessFailure(m_Device, L"Failed to create mouse pointer vertex buffer in OutputManager", L"Error", hr, SystemTransitionsExpectedErrors);}// Set resourcesFLOAT BlendFactor[4] = {0.f, 0.f, 0.f, 0.f};UINT Stride = sizeof(VERTEX);UINT Offset = 0;m_DeviceContext->IASetVertexBuffers(0, 1, &VertexBufferMouse, &Stride, &Offset);m_DeviceContext->OMSetBlendState(m_BlendState, BlendFactor, 0xFFFFFFFF);m_DeviceContext->OMSetRenderTargets(1, &m_RTV, nullptr);m_DeviceContext->VSSetShader(m_VertexShader, nullptr, 0);m_DeviceContext->PSSetShader(m_PixelShader, nullptr, 0);m_DeviceContext->PSSetShaderResources(0, 1, &ShaderRes);m_DeviceContext->PSSetSamplers(0, 1, &m_SamplerLinear);// Drawm_DeviceContext->Draw(NUMVERTICES, 0);// Cleanif (VertexBufferMouse){VertexBufferMouse->Release();VertexBufferMouse = nullptr;}if (ShaderRes){ShaderRes->Release();ShaderRes = nullptr;}if (MouseTex){MouseTex->Release();MouseTex = nullptr;}if (InitBuffer){delete [] InitBuffer;InitBuffer = nullptr;}return DUPL_RETURN_SUCCESS;
}

完整代码示例

#include <Windows.h>
#include <d3d11.h>
#include <d3d12.h>
#include <dxgi1_2.h>
#include <iostream>
#include <string>
#include <windef.h>
#include <wingdi.h>#define PRINT_ERR(msg, hr)                                                     \std::cerr << msg << " failed with error code " << hr << std::endl;#pragma comment(lib, "D3D11.lib")const D3D_DRIVER_TYPE driverTypes[] = {D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE};const D3D_FEATURE_LEVEL featureLevels[] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,D3D_FEATURE_LEVEL_9_1};bool GetMouseInfo(CURSORINFO &cursorInfo, ICONINFO &iconInfo) {cursorInfo.cbSize = sizeof(cursorInfo);if (!GetCursorInfo(&cursorInfo)) {std::wcout << L"GetCursorInfo failed" << std::endl;return false;}if (!(cursorInfo.flags & CURSOR_SHOWING)) {std::wcout << L"Cursor is not showing" << std::endl;return false;}if (!GetIconInfo(cursorInfo.hCursor, &iconInfo)) {std::wcout << L"GetIconInfo failed" << std::endl;return false;}return true;
}void DrawMouseCursor(IDXGISurface1 *p_DXGISurface1) {CURSORINFO cursorInfo = {sizeof(CURSORINFO)};ICONINFO iconInfo;bool isDraw = true;HDC hdc;cursorInfo.cbSize = sizeof(cursorInfo);p_DXGISurface1->GetDC(FALSE, &hdc);if (!GetCursorInfo(&cursorInfo)) {std::wcout << L"GetCursorInfo failed" << std::endl;}if (!(cursorInfo.flags & CURSOR_SHOWING)) {std::wcout << L"Cursor is not showing" << std::endl;}if (!GetIconInfo(cursorInfo.hCursor, &iconInfo)) {std::wcout << L"GetIconInfo failed" << std::endl;}if (!hdc || !cursorInfo.hCursor) {std::wcout << L"Failed to get bitmap" << std::endl;}if (cursorInfo.flags == CURSOR_SHOWING) {isDraw =DrawIconEx(hdc, cursorInfo.ptScreenPos.x, cursorInfo.ptScreenPos.y,cursorInfo.hCursor, 0, 0, 0, 0, DI_NORMAL | DI_DEFAULTSIZE);if (!isDraw) {DWORD error = GetLastError();std::cerr << "DrawIconEx failed with error: " << error << std::endl;}DeleteObject(iconInfo.hbmColor);DeleteObject(iconInfo.hbmMask);}p_DXGISurface1->ReleaseDC(NULL);
}void DrawMouseCursor(ID3D11DeviceContext *g_pImmediateContext,ID3D11Device *g_pd3dDevice,D3D11_MAPPED_SUBRESOURCE mappedResource) {CURSORINFO cursorInfo;ICONINFO iconInfo;HDC hdc = CreateCompatibleDC(NULL);if (!GetMouseInfo(cursorInfo, iconInfo)) {std::wcout << L"Failed to get mouse info" << std::endl;return;}HBITMAP hBitmap = iconInfo.hbmColor ? iconInfo.hbmColor : iconInfo.hbmMask;if (!hBitmap) {std::wcout << L"Failed to get bitmap" << std::endl;return;}SelectObject(hdc, hBitmap);BITMAP bitmap;GetObject(hBitmap, sizeof(BITMAP), &bitmap);BITMAPINFO bmi = {0};bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmi.bmiHeader.biWidth = bitmap.bmWidth;bmi.bmiHeader.biHeight = bitmap.bmHeight;bmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 32;bmi.bmiHeader.biCompression = BI_RGB;
}void RGBDataSaveAsBmpFile(const char *bmpFile, unsigned char *pRgbData,int width, int height, int biBitCount,bool flipVertical) {int size = 0;int bitsPerPixel = 3;if (biBitCount == 24) {bitsPerPixel = 3;size = width * height * bitsPerPixel * sizeof(char);} else if (biBitCount == 32) {bitsPerPixel = 4;size = width * height * bitsPerPixel * sizeof(char);} elsereturn;BITMAPFILEHEADER bfh;bfh.bfType = (WORD)0x4d42;bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);bfh.bfSize = size + bfh.bfOffBits;bfh.bfReserved1 = 0;bfh.bfReserved2 = 0;BITMAPINFOHEADER bih;bih.biSize = sizeof(BITMAPINFOHEADER);bih.biWidth = width;if (flipVertical)bih.biHeight = -height;elsebih.biHeight = height;bih.biPlanes = 1;bih.biBitCount = biBitCount;bih.biCompression = BI_RGB;bih.biSizeImage = size;bih.biXPelsPerMeter = 0;bih.biYPelsPerMeter = 0;bih.biClrUsed = 0;bih.biClrImportant = 0;FILE *fp = NULL;fopen_s(&fp, bmpFile, "wb");if (!fp)return;fwrite(&bfh, sizeof(bfh), 1, fp);// fwrite(&bfh, 8, 1, fp);// fwrite(&bfh.bfReserved2, sizeof(bfh.bfReserved2), 1, fp);// fwrite(&bfh.bfOffBits, sizeof(bfh.bfOffBits), 1, fp);fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fp);fwrite(pRgbData, size, 1, fp);fclose(fp);
}void PrintHResultError(HRESULT hr) {LPVOID lpMsgBuf;DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS;FormatMessage(dwFlags, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf, 0, NULL);std::wcout << L"Error: " << (LPTSTR)lpMsgBuf << std::endl;LocalFree(lpMsgBuf);
}struct ScreenCapture {ID3D11Device *p_pd3dDevice;ID3D11DeviceContext *p_pImmediateContext;D3D_FEATURE_LEVEL featureLevel;IDXGIOutputDuplication *p_dxgiOutputDuplication;IDXGISurface1 *p_DesktopSurface1;IDXGIResource *p_DesktopResource;ID3D11Texture2D *p_ID3D11Texture2D;DXGI_OUTDUPL_FRAME_INFO frameInfo;D3D11_TEXTURE2D_DESC p_D3D11TextureDesc;HRESULT InitDevice() {HRESULT hr = S_OK;for (const auto &driverType : driverTypes) {hr = D3D11CreateDevice(nullptr, driverType, nullptr, 0, featureLevels,//  ARRAYSIZE(featureLevels),static_cast<UINT>(std::size(featureLevels)),D3D11_SDK_VERSION, &p_pd3dDevice, &featureLevel,&p_pImmediateContext);if (SUCCEEDED(hr)) {return hr;}}return hr;}HRESULTGetOutputDuplication(int monitorIndex) {IDXGIDevice *p_dxgiDevice = nullptr;IDXGIAdapter *p_DxgiAdapter = nullptr;HRESULT hr = S_OK;if (!p_pd3dDevice) {std::wcout << L"Failed to create device and context" << std::endl;return hr;}hr = p_pd3dDevice->QueryInterface(IID_PPV_ARGS(&p_dxgiDevice));if (FAILED(hr)) {PRINT_ERR("p_pd3dDevice->QueryInterface", hr);return hr;}hr = p_dxgiDevice->GetParent(IID_PPV_ARGS(&p_DxgiAdapter));if (FAILED(hr)) {PRINT_ERR("p_dxgiDevice->GetParent", hr);return hr;}IDXGIOutput *p_DxgiOutput = nullptr;hr = p_DxgiAdapter->EnumOutputs(monitorIndex, &p_DxgiOutput);if (FAILED(hr)) {PRINT_ERR("p_DxgiAdapter->EnumOutputs", hr);return hr;}IDXGIOutput1 *p_DxgiOutput1 = nullptr;hr = p_DxgiOutput->QueryInterface(IID_PPV_ARGS(&p_DxgiOutput1));if (FAILED(hr)) {PRINT_ERR("p_DxgiOutput->QueryInterface", hr);return hr;}hr = p_DxgiOutput1->DuplicateOutput(p_pd3dDevice, &p_dxgiOutputDuplication);if (FAILED(hr)) {PRINT_ERR("p_DxgiOutput1->DuplicateOutput", hr);return hr;}return hr;}HRESULT AcquiredDesktopImage() {HRESULT hr = S_OK;hr = p_dxgiOutputDuplication->AcquireNextFrame(1000, &frameInfo,&p_DesktopResource);if (FAILED(hr)) {PRINT_ERR("p_dxgiOutputDuplication->AcquireNextFrame", hr);return hr;} else if (frameInfo.LastPresentTime.QuadPart == 0) {p_DesktopResource->Release();p_dxgiOutputDuplication->ReleaseFrame();}hr = p_DesktopResource->QueryInterface(IID_PPV_ARGS(&p_DesktopResource));if (FAILED(hr)) {PRINT_ERR("p_DesktopResource->QueryInterface", hr);return hr;}hr = p_DesktopResource->QueryInterface(IID_PPV_ARGS(&p_ID3D11Texture2D));if (FAILED(hr)) {PRINT_ERR("p_DesktopResource->QueryInterface", hr);return hr;}return hr;}HRESULT CaptureDesktopImage(const char *bmpFilename) {DXGI_OUTDUPL_DESC p_dxgiOutputDuplicationDesc;ID3D11Texture2D *p_DesktopTexture = nullptr;ID3D11Texture2D *p_ID3DTexture2dGDI = nullptr;ID3D11Texture2D *p_ID3DTexture2dCPU = nullptr;HRESULT hr = S_OK;p_dxgiOutputDuplication->GetDesc(&p_dxgiOutputDuplicationDesc);p_D3D11TextureDesc.Width = p_dxgiOutputDuplicationDesc.ModeDesc.Width;p_D3D11TextureDesc.Height = p_dxgiOutputDuplicationDesc.ModeDesc.Height;p_D3D11TextureDesc.Format = p_dxgiOutputDuplicationDesc.ModeDesc.Format;p_D3D11TextureDesc.ArraySize = 1;p_D3D11TextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET;p_D3D11TextureDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;p_D3D11TextureDesc.SampleDesc.Count = 1;p_D3D11TextureDesc.SampleDesc.Quality = 0;p_D3D11TextureDesc.Usage = D3D11_USAGE_DEFAULT;p_D3D11TextureDesc.CPUAccessFlags = 0;p_D3D11TextureDesc.MipLevels = 1;hr = p_pd3dDevice->CreateTexture2D(&p_D3D11TextureDesc, nullptr,&p_ID3DTexture2dGDI);if (FAILED(hr)) {PRINT_ERR("g_pd3dDevice->CreateTexture2D", hr);return hr;}p_D3D11TextureDesc.BindFlags = 0;p_D3D11TextureDesc.MiscFlags = 0;p_D3D11TextureDesc.CPUAccessFlags =D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;p_D3D11TextureDesc.Usage = D3D11_USAGE_STAGING;hr = p_pd3dDevice->CreateTexture2D(&p_D3D11TextureDesc, nullptr,&p_ID3DTexture2dCPU);if (FAILED(hr)) {PRINT_ERR("g_pd3dDevice->CreateTexture2D", hr);return hr;}p_pImmediateContext->CopyResource(p_ID3DTexture2dGDI, p_ID3D11Texture2D);IDXGISurface1 *p_DesktopSurface1 = nullptr;hr = p_ID3DTexture2dGDI->QueryInterface(IID_PPV_ARGS(&p_DesktopSurface1));if (FAILED(hr)) {PRINT_ERR("p_DesktopResource->QueryInterface", hr);return hr;}if (!frameInfo.PointerPosition.Visible) {DrawMouseCursor(p_DesktopSurface1);}p_pImmediateContext->CopyResource(p_ID3DTexture2dCPU, p_ID3DTexture2dGDI);DXGI_MAPPED_RECT dxgiMappedRect;IDXGISurface *p_IDXGISurface = nullptr;hr = p_ID3DTexture2dCPU->QueryInterface(&p_IDXGISurface);if (FAILED(hr)) {PRINT_ERR("p_ID3DTexture2dCPU->QueryInterface", hr);return hr;}hr = p_IDXGISurface->Map(&dxgiMappedRect, DXGI_MAP_READ);if (FAILED(hr)) {PRINT_ERR("p_IDXGISurface->Map", hr);return hr;}RGBDataSaveAsBmpFile(bmpFilename, (unsigned char *)dxgiMappedRect.pBits,p_D3D11TextureDesc.Width, p_D3D11TextureDesc.Height,32, true);hr = p_IDXGISurface->Unmap();if (FAILED(hr)) {PRINT_ERR("p_IDXGISurface->Unmap", hr);return hr;}p_IDXGISurface->Release();p_DesktopSurface1->Release();p_ID3DTexture2dCPU->Release();p_ID3DTexture2dGDI->Release();p_DesktopResource->Release();p_dxgiOutputDuplication->ReleaseFrame();return hr;}
};HRESULT StartCapture() {ScreenCapture screenCapture;HRESULT hr = S_OK;hr = screenCapture.InitDevice();if (FAILED(hr)) {PRINT_ERR("InitDevice", hr);return hr;}hr = screenCapture.GetOutputDuplication(0);if (FAILED(hr)) {PRINT_ERR("GetOutputDuplication", hr);return hr;}for (int i = 0; i < 3; ++i) {std::string bmpFilename = "../../";hr = screenCapture.AcquiredDesktopImage();if (FAILED(hr)) {PRINT_ERR("AcquiredDesktopImage", hr);return hr;}bmpFilename.append("screenshot");bmpFilename.append(std::to_string(i));bmpFilename.append(".bmp");hr = screenCapture.CaptureDesktopImage(bmpFilename.c_str());if (FAILED(hr)) {PRINT_ERR("CaptureDesktopImage", hr);return hr;}hr = screenCapture.AcquiredDesktopImage();if (FAILED(hr)) {PRINT_ERR("AcquiredDesktopImage", hr);return hr;}screenCapture.CaptureDesktopImage(bmpFilename.c_str());screenCapture.p_dxgiOutputDuplication->ReleaseFrame();}return hr;
}int main() { return StartCapture(); }

参考资料

  • DiscreteTom/rusty-duplication: Capture the screen on Windows using the Desktop Duplication API in Rust, with shared memory support.
  • win32 - 使用Desktop Duplication API复制桌面图像 - strive-sun - 博客园
  • 捕捉屏幕的各种方法 - Dincat - 博客园
  • screen-recorder
  • Windows-classic-samples
  • dxgi_outdupl_pointer_shape_type

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853538.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL优化之《预警事件统计》

在做一件什么事情: 在首页大屏上,可以通过各种维度展示事件统计信息。 sql如下:点击查看代码 SELECTcount( * ) count,camera_code groupName FROMalarm_event WHEREalarm_event.illegal_tag ="24"AND alarm_event.organization_code ="310000110000"AN…

树形dp专项测试1

A. Promises I Cant Keep 题目意为求以每个点为根时的期望得分的最大值,换根DP即可。 式子不太难推,半个小时就出来了。太长了不往这写了。Code#include<bits/stdc++.h> #define ll long long #define il inline #define read(x){\char ch;\int fu=1;\while(!isdigit(c…

测试使用自己编译的WPF框架(本地nuget 包引用)

上一篇博客 本地编译WPF框架源码 - wuty007 - 博客园 说到自己在本地编译WPF 框架源码,并在本地 源码 的 \wpf\artifacts\packages\Debug\NonShipping 路径下打包处了 对应的 nuget包 接下来实操测试一下如何使用这些编译出来的包 一、首先为了方便看到测试的效果,我在WPF源…

安全帽佩戴监测摄像机

安全帽是工业生产中必不可少的安全防护装备,能有效保护工人头部免受意外伤害。然而,管理人员往往难以监督工人是否正确佩戴安全帽,这可能导致一些潜在的安全隐患。为了解决这一问题,一种新型的安全帽佩戴监测摄像机应运而生。安全帽是工业生产中必不可少的安全防护装备,能…

工作服穿戴监测识别摄像机

工作服穿戴监测识别摄像机是一种现代智能监控设备,通过将摄像机集成到工作服中,实现实时监测、识别和记录员工的工作状态和环境变化,从而提高工作效率和安全性。这种技术在工业生产、建筑施工、安保巡逻等领域具有广泛应用前景。工作服穿戴监测识别摄像机是一种现代智能监控…

第2章 C# 语言基础

第2章 C# 语言基础 难点提纲 mindmap 第2章 C#语言基础数值类型数值字面量溢出检查特殊的浮点值decimal舍入误差数组简化初始化的<br/>两种方式变量和参数引用局部变量引用返回值语句模式switch命名空间命名范围名称隐藏外部别名全局命名空间 2.2 语法 2.2.1 标识符和关键…

《Django 5 By Example》阅读笔记:p551-p560

《Django 5 By Example》学习第 20 天,p551-p560 总结,总计 10 页。 一、技术总结 1.custom model field (1)示例 courses/fields.py from django.core.exceptions import ObjectDoesNotExist from django.db import modelsclass OrderField(models.PositiveIntegerField):de…

C++基础学习--随记

博客地址:https://www.cnblogs.com/zylyehuo/参考“C++基础与深度解析”一、预备知识 // c++常用工具 /usr/bin/time //查看程序用了多少时间(Linux自带) $ sleep 1 $ /usr/bin/time sleep 1valgrind //分析是否有内存泄漏(软件)cppreference.com //"百科全书"…

厨师帽佩戴识别摄像机

厨师帽佩戴识别摄像机是一种用于识别厨师是否佩戴帽子的智能设备,其作用在于强制执行食品安全卫生标准,防止头发掉落入食物中。该摄像机利用人工智能和图像识别技术,能够识别厨师是否佩戴厨师帽。当摄像机检测到厨师未佩戴帽子时,会触发警报或者发送通知给相关人员进行处理…

在PyCharm/Idea中快捷放大和缩小代码界面

【File】->【Setting】->【keymap】 在Keymap中找到Increase Font Size,双击,选择Add Mouse Shortcut 在弹出的Mouse Shortcut界面,按住 Ctrl 并同时向上滚动鼠标滚轮,实现放大代码界面的设置。 在Keymap中找到Decrease Font Size,双击,选择Add Mouse Shortcut …

Easysearch Java SDK 2.0.x 使用指南(一)

各位 Easysearch 的小伙伴们,我们前一阵刚把 easysearch-client 更新到了 2.0.2 版本!借此详细介绍下新版客户端的使用。 新版客户端和 1.0 版本相比,完全重构,抛弃了旧版客户端的一些历史包袱,从里到外都焕然一新!不管是刚入门的小白还是经验丰富的老司机,2.0.x 客户端…

综合设计 ——多源异构数据采集与融合应用综合实践

综合设计 ——多源异构数据采集与融合应用综合实践 码云地址这个项目属于哪个课程 <班级的链接>组名、项目简介 组名:黑马楼:直面爬虫 项目需求:实现宠物具体种类的识别 项目目标:根据用户上传的文本和图片识别具体的宠物种类 项目开展技术路线:html,css,js,flask团…