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 ...
随机推荐
- [转帖]坑:jmeter代理服务器录制脚本出现target controller is configured to "use recording Controller" but no such controller exists...
配置好代理服务器后,运行代理服务器 run 报错: target controller is configured to "use recording Controller" bu ...
- [转帖]py_innodb_page_info.py工具使用
目录 一.Linux安装Python3 1. 解压包 2. 安装环境 3. 生成编译脚本 4. 检查python3.10的编译器 5. 建立Python3和pip3的软链 6. 添加到PATH 7. ...
- [转帖]docker编译speccpu2017
实验步骤: 1.下载docker和speccpu2017 2.docker下载镜像,创建容器 3.将下载的宿主机speccpu2017拷贝到docker创建的容器中(docker cp) 4.在doc ...
- JRC Flink流作业调优指南
# 作者:京东物流 康琪 本文综合Apache Flink原理与京东实时计算平台(JRC)的背景,详细讲述了大规模Flink流作业的调优方法.通过阅读本文,读者可了解Flink流作业的通用调优措施,并 ...
- git查看自己是从那个分支建的分支
可能发生的情况 很多时候,开始建分支的时候, 能够确认自己是那个分支建的,但是当写完功能之后, 再去回想,有时是忘记自己基于那个分支建的分支. 这时有一个命令的话就可以很快的定位了. 查看创建的分支来 ...
- webpack配置scss
安装依赖: cnpm i sass-loader -D cnpm i node-sass -D node-sass尽量去使用cnpm去安装 创建index2.scss文件 div { h2 { bac ...
- 【JS 逆向百例】Ether Rock 空投接口 AES256 加密分析
关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...
- 从零开始配置 vim(16)——启动界面配置
不知道各位小伙伴用过 spacevim 或者 LunarVim 又或者 doomvim 或者其他的什么 vim 配置框架,我们发现他们的启动界面都做的比较好看,而我们默认进入的启动界面则显得比较素了. ...
- go中bufio使用小结
bufio 前言 例子 bufio 源码解析 Reader对象 实例化 ReadSlice ReadString ReadLine Peek Scanner Give me more data Err ...
- ElasticSearch安装、插件介绍及Kibana的安装与使用详解
ElasticSearch安装.插件介绍及Kibana的安装与使用详解 1.安装 ElasticSearch 1.1 安装 JDK 环境 因为 ElasticSearch 是用 Java 语言编写的, ...