该代码来源于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

win32 - 使用Desktop Duplication API复制桌面图像的更多相关文章

  1. Win32++:可替代MFC的Windows桌面应用开发框架

    写在前面 有过Win32编程经验的朋友都知道,使用Windows提供的API开发桌面应用是相当繁琐的,创建一个功能简单能接收并处理消息的窗口至少也得几百行代码.创建一个可视化的窗口一般要以下几个步骤: ...

  2. C#使用Windows API实现桌面上的遮罩层(鼠标穿透)

    C#使用Windows API实现桌面上的遮罩层(鼠标穿透) C#实现实现桌面上的遮罩层(鼠标穿透)主要通过一下几个API函数来实现:GetWindowLong,SetWindowLong,SetLa ...

  3. [转]OpenGL 使用 PBO 高速复制屏幕图像到内存或者纹理中

    如果你想给游戏做个截图功能,或者想把屏幕图像弄成一个纹理,你就非常需要 PBO 了 通常情况下,你想把屏幕图像的像素数据读到内存需要用 glReadPixels 然后 pixels 参数传进去一块内存 ...

  4. VC Windows API获得桌面所有窗口句柄的方法

    VC Windows API应用之GetDesktopWindow ——获得桌面所有窗口句柄的方法 Windows API Windows 这个多作业系统除了协调应用程序的执行.分配内存.管理资源…之 ...

  5. OpenGL 使用 PBO 高速复制屏幕图像到内存或者纹理中

    如果你想给游戏做个截图功能,或者想把屏幕图像弄成一个纹理,你就非常需要 PBO 了 通常情况下,你想把屏幕图像的像素数据读到内存需要用 glReadPixels 然后 pixels 参数传进去一块内存 ...

  6. 利用API设置桌面背景

    实现效果: 知识运用: API函数SystemParametersInfo 实现代码: [DllImport("user32.dll", EntryPoint = "Sy ...

  7. 使用Desktop App Converter打包桌面应用程序

    打包具有安装程序 (.msi) 的应用程序 DesktopAppConverter.exe -Installer C:\Installer\MyAppSetup.msi -Destination C: ...

  8. 【Ubuntu Desktop】安装主流桌面

    ubuntu的桌面环境实在多,在这里选了几款主流的桌面环境,大家可以按需安装使用. 1.GNOME 2 Classic 经典老界面 gnome2   after reboot,choose GNOME ...

  9. 通过微信公众号API复制公众号自定义菜单同时增加子菜单方法

    主要的原因是再不破坏公众号以前的菜单的基础上增加自定义菜单,主要步骤如下: 1.通过微信提供的微信公众平台接口调试工具获取公众号的所有自定义菜单 网址:https://mp.weixin.qq.com ...

  10. Windows api实现桌面任务栏隐藏\显示

    //隐藏任务栏 HWND hWnd = ::FindWindow(TEXT("Shell_traywnd"),TEXT("")); ::SetWindowPos ...

随机推荐

  1. [转帖]手摸手搭建简单的jmeter+influxdb+grafana性能监控平台

    我安装的机器是阿里云的centos8机器,其他的系统暂未验证 1.安装influxdb influxdb 下载地址https://portal.influxdata.com/downloads/,也可 ...

  2. [转帖]java获取到heapdump文件后,如何快速分析?

    https://www.jianshu.com/p/aaf56385766d   简介 在之前的OOM问题复盘之后,本周,又一Java服务出现了内存问题,这次问题不严重,只会触发堆内存占用高报警,没有 ...

  3. [转帖]创建lvm

    https://www.jianshu.com/p/bf6b92d73b9b 一.环境介绍 服务器中有sda,sdb,sdc,sdd,sde,sdf六块硬盘,其中sda作为系统盘已经安装了系统,需要将 ...

  4. [转帖]021系统状态检测命令sosreport

    https://www.cnblogs.com/anyoneofus/p/16467677.html   sosreport命令用于收集系统配置及架构信息并输出诊断文档.

  5. 【转帖】route命令详解大全(route命令使用实例)

    https://www.cxdtop.cn/n/225987.html 在实际的网络应用中,我们可能会遇到这样的网络环境,上外网我们使用的无线网络,内网我们使用的是有限网卡.在设置完成后会出现外网和内 ...

  6. [转帖]Linux系统硬链接和软链接具体实例讲解(超详细)

    简介 在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名.文件名仅是为了方便人们的记忆和使用, ...

  7. Oracle 提示 用户在线,无法删除的清理方法

    查找删除策略. select username,sid,serial# from v$session where username='FSSCDEC004'; alter system kill se ...

  8. zabbix 6.0 官方文档

    Choose your platform   ZABBIX VERSION 6.0 LTS 5.4 5.0 LTS 4.0 LTS OS DISTRIBUTION Red Hat Enterprise ...

  9. Vue.use和install之间的关系

    创建一个plugins.js文件 跟main.js同级下,创建一个plugins.js文件 export default { // install是vue给我们提供的.它会自动去执行install. ...

  10. STM32CubeMX教程26 FatFs 文件系统 - W25Q128读写

    1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 ...