该代码来源于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. [转帖]TiDB 中的各种超时

    https://docs.pingcap.com/zh/tidb/stable/dev-guide-timeouts-in-tidb 本章将介绍 TiDB 中的各种超时,为排查错误提供依据. GC 超 ...

  2. [转帖]鲲鹏性能优化十板斧——鲲鹏处理器NUMA简介与性能调优五步法

    https://www.cnblogs.com/huaweicloud/p/12166354.html 1.1 鲲鹏处理器NUMA简介 随着现代社会信息化.智能化的飞速发展,越来越多的设备接入互联网. ...

  3. [转帖]调优"四剑客"的实战演练,福尔摩斯•K带你轻松优化性能

     前言 天下武功,唯快不破.在侦探的世界中,破案效率永远是衡量一名侦探能力的不二法门.作为推理界冉冉升起的新星,大侦探福尔摩斯·K凭借着冷静的头脑.严谨的思维,为我们展现了一场场华丽而热血的推理盛宴. ...

  4. [转帖]Day63_Kafka(一)

    第一讲 Kafka基础操作 课程大纲 课程内容 学习效果 掌握目标 Kafka简介 消息队列 掌握 Kafka简介 Kafka分布式环境 Kafka操作 Kafka shell 掌握 Kafka ap ...

  5. [转帖]Redis中的Lua脚本

    最近琢磨分布式锁时接触到的知识点,简单记一下. 文章目录 1. Redis中的Lua 2. 利用Lua操作Redis 3. Lua脚本的原子性 4. 关于 EVALSHA 5. 常用`SCRIPT` ...

  6. [转帖]超线程 Smt 究竟可以快多少?

    https://www.51cto.com/article/686171.html 刚才我们关闭SMT是把CPU10-CPU19全关了,只留下每对里面的1个CPU,也就是留下了CPU0-CPU9. 默 ...

  7. JVM启动参数脚本的再学习与研究

    JVM启动参数脚本的再学习与研究 摘要 学无止境 前段时间一直再研究JVM参数调优. 但是最近也在想不应该仅研究如何调优. 因为不管怎么设置, 总有猪队友会把环境搞崩. 所以应该想办法在无人值守的情况 ...

  8. JVM启动速度大页内存验证

    大页内存设置 先查看 cat /proc/meminfo |grep -i huge 获取大页内存的大小信息. AnonHugePages: 42022912 kB HugePages_Total: ...

  9. 测试环境Nginx反向代理负载均衡模板说明

    公司里面为了验证 https 以及域名特点进行了相关的测试工作.  为了简单起见 将 安装文件执行了导出. 这样的话就比较简单了. 注意说明一点的是 我这边导出的工具都是 放到根目录下面 目录最简单. ...

  10. 一条sql了解MYSQL的架构设计

    1 前言 对于一个服务端开发来说 MYSQL 可能是他使用最熟悉的数据库工具,然而,大部分的Java工程师对MySQL的了解和掌握程度,大致就停留在这么一个阶段:它可以建库.建表.建索引,然后就是对里 ...