win32 - 使用Desktop Duplication API复制桌面图像
该代码来源于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复制桌面图像的更多相关文章
- Win32++:可替代MFC的Windows桌面应用开发框架
写在前面 有过Win32编程经验的朋友都知道,使用Windows提供的API开发桌面应用是相当繁琐的,创建一个功能简单能接收并处理消息的窗口至少也得几百行代码.创建一个可视化的窗口一般要以下几个步骤: ...
- C#使用Windows API实现桌面上的遮罩层(鼠标穿透)
C#使用Windows API实现桌面上的遮罩层(鼠标穿透) C#实现实现桌面上的遮罩层(鼠标穿透)主要通过一下几个API函数来实现:GetWindowLong,SetWindowLong,SetLa ...
- [转]OpenGL 使用 PBO 高速复制屏幕图像到内存或者纹理中
如果你想给游戏做个截图功能,或者想把屏幕图像弄成一个纹理,你就非常需要 PBO 了 通常情况下,你想把屏幕图像的像素数据读到内存需要用 glReadPixels 然后 pixels 参数传进去一块内存 ...
- VC Windows API获得桌面所有窗口句柄的方法
VC Windows API应用之GetDesktopWindow ——获得桌面所有窗口句柄的方法 Windows API Windows 这个多作业系统除了协调应用程序的执行.分配内存.管理资源…之 ...
- OpenGL 使用 PBO 高速复制屏幕图像到内存或者纹理中
如果你想给游戏做个截图功能,或者想把屏幕图像弄成一个纹理,你就非常需要 PBO 了 通常情况下,你想把屏幕图像的像素数据读到内存需要用 glReadPixels 然后 pixels 参数传进去一块内存 ...
- 利用API设置桌面背景
实现效果: 知识运用: API函数SystemParametersInfo 实现代码: [DllImport("user32.dll", EntryPoint = "Sy ...
- 使用Desktop App Converter打包桌面应用程序
打包具有安装程序 (.msi) 的应用程序 DesktopAppConverter.exe -Installer C:\Installer\MyAppSetup.msi -Destination C: ...
- 【Ubuntu Desktop】安装主流桌面
ubuntu的桌面环境实在多,在这里选了几款主流的桌面环境,大家可以按需安装使用. 1.GNOME 2 Classic 经典老界面 gnome2 after reboot,choose GNOME ...
- 通过微信公众号API复制公众号自定义菜单同时增加子菜单方法
主要的原因是再不破坏公众号以前的菜单的基础上增加自定义菜单,主要步骤如下: 1.通过微信提供的微信公众平台接口调试工具获取公众号的所有自定义菜单 网址:https://mp.weixin.qq.com ...
- Windows api实现桌面任务栏隐藏\显示
//隐藏任务栏 HWND hWnd = ::FindWindow(TEXT("Shell_traywnd"),TEXT("")); ::SetWindowPos ...
随机推荐
- [转帖]Linux内核参数 rp_filter
https://www.cnblogs.com/chenmh/p/6001977.html 简介 rp_filter (Reverse Path Filtering)参数定义了网卡对接收到的数据包进行 ...
- [转帖]TIDB - 使用BR工具进行数据热备份与恢复
一.BR工具 BR 全称为 Backup & Restore,是 TiDB 分布式备份恢复的命令行工具,用于对 TiDB 集群进行数据备份和恢复.BR 只支持在 TiDB v3.1 及以上版本 ...
- [转帖]一个小操作,SQL 查询速度翻了 1000 倍
https://tidb.net/book/tidb-monthly/2022/2022-04/usercase/sql-1000 背景介绍 某一天早上来到公司,接到业务同学反馈,线上某个SQL之前 ...
- [转帖]Linux—vi/vim全局替换
https://www.jianshu.com/p/4daa5dbc7dd5 vim全局替换 在linux系统中编辑文件或者配置时,常常会用到全局替换功能. 语法格式 :%s/oldWords/n ...
- [转帖]Redis压力测试——redis-benchmark
liunx 安装 redis & redis benchmark 1.下载安装包 点击官网,下载stable版本 wget http://download.redis.io/releases/ ...
- [转帖]服务器稳定性测试-LTP压力测试方法及工具下载
简介 LTP(LinuxTest Project)是SGI.IBM.OSDL和Bull合作的项目,目的是为开源社区提供一个测试套件,用来验证Linux系统可靠性.健壮性和稳定性.LTP测试套件是测试L ...
- 系统Hosts文件原理和应用
Hosts的概念 Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联"数据库",当用户在浏览器中输入一个需要 ...
- 从零开始配置vim(25)——关于 c++ python 的配置
从9月份到国庆这段时间,因为得了女儿,于是回老家帮忙料理家事以及陪伴老婆和女儿.一时之间无暇顾及该系列教程的更新.等我回来的时候发现很多小伙伴私信我催更.在这里向支持本人这一拙劣教程的各位小伙伴表示真 ...
- Linux和Windows系统下安装深度学习框架所需支持:Anaconda、Paddlepaddle、Paddlenlp、pytorch,含GPU、CPU版本详细安装过程
Linux和Windows系统下安装深度学习框架所需支持:Anaconda.Paddlepaddle.Paddlenlp.pytorch,含GPU.CPU版本详细安装过程 1.下载 Anaconda ...
- 7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中LyShark一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以监控进程线程创建为例,在Win10系统中监控进程与线程可以使用微软提供给我们的两个新函数来 ...