使用DirectX截屏

 

网上有很多关于DirectX截屏的文章,但大都是屏幕截图,很少有窗口截图,本文则两者都涉及到,先讲如何截取整个屏幕,再讲如何截取某个窗口,其实二者的区别不大,只是某个参数的设置不同而已,最后我们还将扩展到任意区域的截图。

首先看一下截屏用到的函数,最核心的当然是D3DXSaveSurfaceToFile,先看下函数原型

 HRESULT D3DXSaveSurfaceToFile( 
  LPCTSTR pDestFile, 
  D3DXIMAGE_FILEFORMAT DestFormat, 
  LPDIRECT3DSURFACE9 pSrcSurface, 
  CONST PALETTEENTRY * pSrcPalette, 
  CONST RECT * pSrcRect 
 ); 

第一个参数是指向设备的指针,不多说啦

第二个参数是截图文件的类型,支持的类型还不少,主要有下面这些

BMP,JPG,TGA,PNG,DDS,PPM,DIB,HDR,PFM

这里我们使用BMP-即位图格式

第三个参数是指向Surface的指针,也就是保存了截图数据的表面

第四个参数是Surface的调色板,这里不使用,设置为NULL

最后一个参数是Surface的矩形区域,也就是我们可以只截取Surface上某一矩形区域的数据,其实截取全屏和截取窗口的差别也就在这个参数的设置上

其他的函数在下面会逐一讲解

现在来定义我们的截屏函数,首先我们需要一个设备指针,因为在DX中,任何操作都与设备密切相关,所以设备指针几乎是每个DX函数都要用到的参数,我们这个函数也不例外,齐次需要一个窗口句柄,当我们截取窗口时,把窗口句柄传入,当我们截取整个屏幕时,直接传入NULL。最后我们需要一个字符串参数来指定截图对应的文件名,如下
1 BOOL ScreenShot(LPDIRECT3DDEVICE9 lpDevice, HWND hWnd, TCHAR* fileName)

详细步骤:

首先我们需要获取显示模式,注意这里获取的是显卡的显示模式,而不是设备的显示模式,因为设备的显示模式既有窗口模式,也有全屏模式,所以它的分辨率是不确定的,而显卡的显示模式返回的始终是最大分辨率,我们需要创建整个屏幕区域对应的Surface,当截取真个屏幕时,直接保存即可,当截取窗口时,我们将窗口所对应的区域保存即可

获取显卡显示模式的代码如下

 HRESULT hr; 
 
 // Get adapter display mode 
 D3DDISPLAYMODE mode; 
 if (FAILED(hr = lpDevice->GetDisplayMode(0, &mode))) 
    return hr; 
 

下面开始创建表面,这个表面是对应整个屏幕的

      1.  // Create the surface to hold the screen image data 
         LPDIRECT3DSURFACE9 surf; 
         if (FAILED(hr = lpDevice->CreateOffscreenPlainSurface(mode.Width, 
            mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL))) //注意第四个参数不能是D3DPOOL_DEFAULT 
         { 
            return hr; 
         } 
        

        接下来获取屏幕对应的数据,这个函数实际上是将显存中的数据拷贝到系统内存中
      // Get the screen data 
       if (FAILED(hr = lpDevice->GetFrontBufferData(0, surf))) 
       { 
          surf->Release() ; 
          return hr ; 
       } 
      

      接下来我们判断是截取窗口还是截取屏幕,很简单,只需判断hWnd是否为NULL即可,如果是截取窗口则设置窗口对应的矩形区域即可

       // area to capture 
       RECT *rect = NULL ; 
       
       WINDOWINFO windowInfo ; 
       windowInfo.cbSize = sizeof(WINDOWINFO) ; 
       
       if(hWnd) // capture window 
       { 
          GetWindowInfo(hWnd, &windowInfo) ; 
          rect = &windowInfo.rcWindow ; 
       }  
      

      最后一部,保存截图!

       // Save the screen date to file 
       hr = D3DXSaveSurfaceToFile(fileName, D3DXIFF_BMP, surf, NULL, rect); 
       
       surf->Release() ; 
       
       return hr ; 
      

      大功告成!

      完整代码

       BOOL ScreenShot(LPDIRECT3DDEVICE9 lpDevice, HWND hWnd, TCHAR* fileName) 
       { 
          HRESULT hr; 
         
          // Get adapter display mode 
          D3DDISPLAYMODE mode; 
          if (FAILED(hr = lpDevice->GetDisplayMode(0, &mode))) 
              return hr; 
      
         // Create the surface to hold the screen image data 
          LPDIRECT3DSURFACE9 surf; 
          if (FAILED(hr = lpDevice->CreateOffscreenPlainSurface(mode.Width, 
              mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL))) //注意第四个参数不能是D3DPOOL_DEFAULT 
          { 
              return hr; 
          } 
       
          // Get the screen data 
          if (FAILED(hr = lpDevice->GetFrontBufferData(0, surf))) 
          { 
              surf->Release() ; 
              return hr ; 
          } 
       
          // area to capture 
          RECT *rect = NULL ; 
       
          WINDOWINFO windowInfo ; 
          windowInfo.cbSize = sizeof(WINDOWINFO) ; 
       
          if(hWnd) // capture window 
          { 
              GetWindowInfo(hWnd, &windowInfo) ; 
              rect = &windowInfo.rcWindow ; 
          } 
      
          // Save the screen date to file 
          hr = D3DXSaveSurfaceToFile(fileName, D3DXIFF_BMP, surf, NULL, rect); 
       
          surf->Release() ; 
       
          return hr ; 
       } 
      

       

      那么如何实现任意区域截屏呢,我想大家已经想到了,假设使用鼠标拖拽的方法截图,记下鼠标按下和抬起时的坐标,构造一个RECT,然后传递给 D3DXSaveSurfaceToFile函数就可以了,需要注意到是,由于鼠标拖拽到方向是任意的,所以在构造RECT的时候要注意right < left或者bottom < top 的情况,用下面的方法可以处理

       int left = 0 ; 
       int right = 0 ; 
       int top = 0 ; 
       int bottom = 0 ; 
       RECT rect ; 
       
       case WM_LBUTTONDOWN: 
          left = ( short )LOWORD( lParam ); 
          top = ( short )HIWORD( lParam ); 
          break ; 
       
       case WM_LBUTTONUP: 
          right = ( short )LOWORD( lParam ); 
          bottom = ( short )HIWORD( lParam ); 
       
          rect.left = min(left, right) ; 
          rect.right = max(left, right) ; 
          rect.top = min(top, bottom) ; 
          rect.bottom = max(top, bottom) ; 
          // 调用截图函数 
      


       

      (文/AutumnWinter

      来自:http://www.pin5i.com/showtopic-26129.html

      • 0
        点赞
      • 3
        收藏
        觉得还不错? 一键收藏
      • 0
        评论
      提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

      “相关推荐”对你有帮助么?

      • 非常没帮助
      • 没帮助
      • 一般
      • 有帮助
      • 非常有帮助
      提交
      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值