原文https://msdn.microsoft.com/en-us/library/windows/desktop/hh404487(v=vs.85).aspx

win8放弃了标准的win2k显示驱动模块(XDDM),也就是镜像驱动,并提供桌面拷贝API来替代它。The desktop duplication API 提供远程接口操作一组桌面截图的协作方案。应用可以使用the desktop duplication API 来一帧一帧更新桌面。因为应用收到更新的桌面截图来自与DXGI接口,所以该应用可以完全使用GPU来完成图片的更新。

更新桌面图片数据
旋转桌面图片
更新桌面指针
相关话题

1)更新桌面图片数据

DXGL提供一种包含当前桌面图片的接口,通过新的 IDXGIOutputDuplication::AcquireNextFrame 方法。格式化桌面图片永远是DXGI_FORMAT_B8G8R8A8_UNORM,不管当前显示模式是什么。通过这个接口,那些IDXGIOutputDuplication 方法返回指定类型的信息来帮助你决定哪些像素你需要去处理。
• IDXGIOutputDuplication::GetFrameDirtyRects 返回的是“脏”的区域,没有重叠的一组组矩形区域就是自从你要求提供桌面图片后操作系统更新过的区域,
IDXGIOutputDuplication::GetFrameMoveRects  返回的是移动的区域, 操作系统将有着一组一模一样的矩形区域的像素的桌面截图移动到到另一个位置。每个移动的区域包含一个目标矩形和一个源点。源点指定从操作系统复制该区域的位置和目标矩形指定操作系统移动该区域的位置。移动区域不能被拉伸,所以源和目标的尺寸一直都是相同的。

支持桌面图片通过低速的连接传到你远程客户端中。一定数量的数据被传输到指定连接对象用来接收仅仅是图片数据,指定你的客户端程序移动区域,而不是实际像素数据。为了实现这个移动,你的客户程序必须存储上一张完成好的桌面图片。
当操作系统积累了许多未处理的桌面图片,它就会用光用来准确移动区域的存储空间,在这种情况下,操作系统开始将积累已存在更新覆盖掉刚刚更新的图片。结果导致操作系统实际不是按帧更新的而是按像素点。但是这种情况不会导致客户端的显示问题,因为你收到的是一整张的桌面图片而不仅仅是更新的像素点。
为了重建正确的桌面图片,你的客户端第一次必须处理所有的移动区域,然后再处理所有的脏的区域。两种区域的列表应该完全的清空。这个示例取自 Desktop Duplication Sample 展示了怎么样处理两种区域在同一帧中。

//
// Get next frame and write it into Data
//
HRESULT DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data)
{HRESULT hr = S_OK;IDXGIResource* DesktopResource = NULL;DXGI_OUTDUPL_FRAME_INFO FrameInfo;//Get new framehr = DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);if (FAILED(hr)){if ((hr != DXGI_ERROR_ACCESS_LOST) && (hr != DXGI_ERROR_WAIT_TIMEOUT)){DisplayErr(L"Failed to acquire next frame in DUPLICATIONMANAGER", L"Error", hr);}return hr;}// If still holding old frame, destroy itif (AcquiredDesktopImage){AcquiredDesktopImage->Release();AcquiredDesktopImage = NULL;}// QI for IDXGIResourcehr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&AcquiredDesktopImage));DesktopResource->Release();DesktopResource = NULL;if (FAILED(hr)){DisplayErr(L"Failed to QI for ID3D11Texture2D from acquired IDXGIResource in DUPLICATIONMANAGER", L"Error", hr);return hr;}// Get metadataif (FrameInfo.TotalMetadataBufferSize){// Old buffer too smallif (FrameInfo.TotalMetadataBufferSize > MetaDataSize){if (MetaDataBuffer){delete [] MetaDataBuffer;MetaDataBuffer = NULL;}MetaDataBuffer = new (std::nothrow) BYTE[FrameInfo.TotalMetadataBufferSize];if (!MetaDataBuffer){DisplayErr(L"Failed to allocate memory for metadata in DUPLICATIONMANAGER", L"Error", E_OUTOFMEMORY);MetaDataSize = 0;Data->MoveCount = 0;Data->DirtyCount = 0;return E_OUTOFMEMORY;}MetaDataSize = FrameInfo.TotalMetadataBufferSize;}UINT BufSize = FrameInfo.TotalMetadataBufferSize;// Get move rectangleshr = DeskDupl->GetFrameMoveRects(BufSize, reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(MetaDataBuffer), &BufSize);if (FAILED(hr)){if (hr != DXGI_ERROR_ACCESS_LOST){DisplayErr(L"Failed to get frame move rects in DUPLICATIONMANAGER", L"Error", hr);}Data->MoveCount = 0;Data->DirtyCount = 0;return hr;}Data->MoveCount = BufSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);BYTE* DirtyRects = MetaDataBuffer + BufSize;BufSize = FrameInfo.TotalMetadataBufferSize - BufSize;// Get dirty rectangleshr = DeskDupl->GetFrameDirtyRects(BufSize, reinterpret_cast<RECT*>(DirtyRects), &BufSize);if (FAILED(hr)){if (hr != DXGI_ERROR_ACCESS_LOST){DisplayErr(L"Failed to get frame dirty rects in DUPLICATIONMANAGER", L"Error", hr);}Data->MoveCount = 0;Data->DirtyCount = 0;return hr;}Data->DirtyCount = BufSize / sizeof(RECT);Data->MetaData = MetaDataBuffer;}Data->Frame = AcquiredDesktopImage;Data->FrameInfo = FrameInfo;return hr;
}//
// Release frame
//
HRESULT DUPLICATIONMANAGER::DoneWithFrame()
{HRESULT hr = S_OK;hr = DeskDupl->ReleaseFrame();if (FAILED(hr)){DisplayErr(L"Failed to release frame in DUPLICATIONMANAGER", L"Error", hr);return hr;}if (AcquiredDesktopImage){AcquiredDesktopImage->Release();AcquiredDesktopImage = NULL;}return hr;
}

2)旋转桌面图片
您必须向桌面复制客户端应用程序添加显式代码以支持旋转模式。在旋转模式下,从IDXGIOutputDuplication :: AcquireNextFrame接收的表面始终处于未旋转方向,桌面图像在这个表面内旋转。 例如,如果桌面在90度旋转时设置为768x1024,则AcquireNextFrame返回一个1024x768表面,桌面图像在其中旋转。 这里有一些旋转示例。
桌面复制客户端应用程序中的代码必须在显示桌面映像之前正确旋转桌面映像。
注意在多监视器方案中,您可以单独旋转每个监视器的桌面图像。
3)更新桌面光标
你需要用 desktop duplication API 来指定你是否需要把鼠标指定加到桌面图片。IDXGIOutputDuplication::AcquireNextFrame 可以提供有或者无鼠标光标的桌面图片。如果桌面被画上鼠标光标,那么光标的位置数据要被指派到AcquireNextFrame(在PointerPosition成员中DXGI_OUTDUPL_FRAME_INFO 的pFrameInfo 参数)报告分离的光标使其不可见。如果图形适配器将鼠标指针叠加在桌面图像的顶部,AcquireNextFrame报告单独的指针是可见的。因此,您的客户端应用程序必须将鼠标指针形状绘制到桌面图像上,以准确表示当前用户在其显示器上将看到的内容。

要绘制桌面的鼠标指针,请使用AcquireNextFrame的pFrameInfo参数中的DXGI_OUTDUPL_FRAME_INFO的PointerPosition成员来确定在桌面图像上的鼠标指针左上角的位置。 绘制第一帧时,必须使用IDXGIOutputDuplication :: GetFramePointerShape方法来获取有关鼠标指针形状的信息。 每次调用AcquireNextFrame以获得下一帧也提供该帧的当前指针位置。 另一方面,只有当形状改变时,您才需要再次使用GetFramePointerShape。 所以,保留最后一个指针图像的副本,并使用它来绘制桌面上,除非鼠标指针的形状更改。
注意:与指针形状图像一起,GetFramePointerShape提供热点位置的大小。 热点仅供参考。 指针图像的绘制位置与热点无关。

//
// Retrieves mouse info and write it into PtrInfo
//
HRESULT DUPLICATIONMANAGER::GetMouse(_Out_ PTR_INFO* PtrInfo, _In_ DXGI_OUTDUPL_FRAME_INFO* FrameInfo, INT OffsetX, INT OffsetY)
{HRESULT hr = S_OK;// A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape changeif (FrameInfo->LastMouseUpdateTime.QuadPart == 0){return hr;}bool UpdatePosition = true;// Make sure we don't update pointer position wrongly// If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer// was visible, if so, don't set it to invisible or update.if (!FrameInfo->PointerPosition.Visible && (PtrInfo->WhoUpdatedPositionLast != OutputNumber)){UpdatePosition = false;}// If two outputs both say they have a visible, only update if new update has newer timestampif (FrameInfo->PointerPosition.Visible && PtrInfo->Visible && (PtrInfo->WhoUpdatedPositionLast != OutputNumber) && (PtrInfo->LastTimeStamp.QuadPart > FrameInfo->LastMouseUpdateTime.QuadPart)){UpdatePosition = false;}// Update positionif (UpdatePosition){PtrInfo->Position.x = FrameInfo->PointerPosition.Position.x + OutputDesc.DesktopCoordinates.left - OffsetX;PtrInfo->Position.y = FrameInfo->PointerPosition.Position.y + OutputDesc.DesktopCoordinates.top - OffsetY;PtrInfo->WhoUpdatedPositionLast = OutputNumber;PtrInfo->LastTimeStamp = FrameInfo->LastMouseUpdateTime;PtrInfo->Visible = FrameInfo->PointerPosition.Visible != 0;}// No new shapeif (FrameInfo->PointerShapeBufferSize == 0){return hr;}// Old buffer too smallif (FrameInfo->PointerShapeBufferSize > PtrInfo->BufferSize){if (PtrInfo->PtrShapeBuffer){delete [] PtrInfo->PtrShapeBuffer;PtrInfo->PtrShapeBuffer = NULL;}PtrInfo->PtrShapeBuffer = new (std::nothrow) BYTE[FrameInfo->PointerShapeBufferSize];if (!PtrInfo->PtrShapeBuffer){DisplayErr(L"Failed to allocate memory for pointer shape in DUPLICATIONMANAGER", L"Error", E_OUTOFMEMORY);PtrInfo->BufferSize = 0;return E_OUTOFMEMORY;}// Update buffer sizePtrInfo->BufferSize = FrameInfo->PointerShapeBufferSize;}UINT BufferSizeRequired;// Get shapehr = DeskDupl->GetFramePointerShape(FrameInfo->PointerShapeBufferSize, reinterpret_cast<VOID*>(PtrInfo->PtrShapeBuffer), &BufferSizeRequired, &(PtrInfo->ShapeInfo));if (FAILED(hr)){if (hr != DXGI_ERROR_ACCESS_LOST){DisplayErr(L"Failed to get frame pointer shape in DUPLICATIONMANAGER", L"Error", hr);}delete [] PtrInfo->PtrShapeBuffer;PtrInfo->PtrShapeBuffer = NULL;PtrInfo->BufferSize = 0;return hr;}return hr;
}

4)相关话题
DXGI 1.2 Improvements

Desktop Duplication API(桌面拷贝API)相关推荐

  1. 使用ASP.NET Web API构建Restful API

    目录 介绍 这种方法有什么好处? Restful约定 构建API 测试API 一点困惑: 最佳实践: 数据传输对象(DTO) Automapper IHttpActionResult 使用Web AP ...

  2. API汇总;API大全(转载)

    API是获取网络服务最便捷的方式,合理地使用API开发项目可以大大提高开发效率,把精力都集中在程序的业务逻辑之上,避免重复造轮子.推荐给大家个人觉得很赞的第三方API(资源整合自网络).文章分为天气查 ...

  3. 十三、BIRT报表引擎API及报表API

    13.1报表引擎详解,API结构 BIRT包含几个引擎.一个引擎是一个提供一个特定领域的功能的一套Java API.例如,数据引擎包含管理数据的API,图表引擎包含生成一个图表的API.一般而言,BI ...

  4. Python API vs C++ API of TensorRT

    Python API vs C++ API of TensorRT 本质上,C++ API和Python API应该在支持您的需求方面接近相同.pythonapi的主要优点是数据预处理和后处理都很容易 ...

  5. java api 设计_Java API设计实践

    使你的API在模块化和非模块化Java环境中都可用 在优锐课的java学习分享中,对微服务有了更深层次的新概念.关于API设计实践一点就通了. 介绍 了解设计Java API时应应用的一些API设计实 ...

  6. 关于Android 隐藏 API 和内部 API的查看与使用

    前言 Android 有两种类型的 API 不能通过 SDK 访问.一种是在 com.android.internal 包中的 API,称之为 internal API.另一种是被标记为 @hide ...

  7. 揭示Win32 API拦截细节/API hooking revealed (1)

    原文出处:http://www.codeproject.com/system/hooksys.asp 简要介绍 拦截win32 API 调用对于多数windows开发人员来说都一直是很有挑战性的课题, ...

  8. Tungsten Fabric SDN — VNC API — API Server 的 API Specification

    目录 文章目录 目录 API Specification List API Resources API 调用示例 Create virtual network Create network polic ...

  9. html5在线api,HTML5 历史记录API

    HTML5 历史记录API HTML5历史记录API的使用方法,在线实例演示HTML5历史记录API如何使用.浏览器的兼容性.语法定义及它的属性值详细资料等. HTML5历史记录API使您可以通过Ja ...

最新文章

  1. ChannelFactory.Endpoint 上的地址属性为空。ChannelFactory 的终结点必须指定一个有效的地址。...
  2. 我的电脑不联网,很安全,黑客:你还有风扇呢。。。
  3. InsightFace及其mxnet、tensorflow代码实现
  4. php-5.6.26源代码 - opcode处理器,“函数调用opcode”处理器,如何调用扩展模块的函数...
  5. python堆排序算法_python 排序 堆排序
  6. httpModules 与 httpHandlers
  7. 渗透测试神器CS(4.0)的使用
  8. latex中report目录_在 LaTeX 中将不编号的章节列入目录
  9. PHY芯片88EE1111 MDIO接口调试
  10. SpringCloud工作笔记040--- XMLHTTP中setRequestHeader()方法解析
  11. Windbg分析高内存占用问题
  12. 量子计算机慕课,计算机组成原理-中国大学mooc-题库零氪
  13. 【OpenCV实战】简洁易懂的车牌号识别Python+OpenCV实现“超详解”(含代码)
  14. 【转载】教你怎么将centos7打造成桌面系统
  15. 苹果换原装电池_苹果手机换电池客户必看!苹果原装电池科普鉴别!
  16. 几种投影的特点及分带方法
  17. win7计算机高级设置在哪,windows7投屏设置在哪里
  18. Star CCM+如何修改默认单位
  19. Autoleaders-可视化pyecharts
  20. 段错误需要使用的工具 nm objdump readelf

热门文章

  1. 蓝牙 4.0 ATT属性协议
  2. xilinx官网下载vivado速度慢的解决方法(适用于所有版本)
  3. 蓝叠模拟器查看Android版本,BlueStacks蓝叠版本信息在哪看蓝叠模拟器版本信息查看方法...
  4. M资源,每个进程最多N个资源,最多几个进程不会发生死锁
  5. “年薪百万”的视频剪辑师?Adobe专家让这一切都成为可能
  6. 电子设计竞赛(6)-逆变电路
  7. 端点科技春招笔试回忆(Java方向)
  8. C语言案例之走迷宫(Ubuntu)
  9. 特斯拉充电电流设置多大_特斯拉再次升级Model S 充电状况不稳时自动降低电流...
  10. 关于virtualbox虚拟电脑控制台严重错误解决方法。。。