热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

VC++基于Dx实现的截图程序示例代码

这篇文章主要介绍了VC++基于Dx实现的截图程序示例代码,比较实用的功能,需要的朋友可以参考下

本文所述的程序示例为VC++图象特效的截图示例,需要DirectX 3.0以上版,代码中的GetScreen函数是本截图程序的关键。运行这个程序可用Esc键结束。代码中需要ddutil.h与ddutil.cpp文件,请自行下载添加。关于InitDDraw()函数,功能是初始化DirectDraw环境,创建换页链(主页面,一个后台缓冲区),以及创建一个定时器。

具体的功能代码如下:

#include 
#include 
#include 
#include 
#include 
#include "ddutil.h"
#define TITLE "截图示例" //窗口标题
#define CLASSNAME "GetScreen" //窗口类名
#define COLORS 16
HINSTANCE hInst; //应用程序实例句柄
HWND hWndMain; //主窗口句柄
LPDIRECTDRAW      lpDD;      // DirectDraw对象
LPDIRECTDRAWSURFACE   lpDDSPrimary;  // 主页面
LPDIRECTDRAWSURFACE   lpDDSBack;   // 后台缓冲区
LPDIRECTDRAWSURFACE   lpDDSPic1;   // 离屏页面1
LPDIRECTDRAWPALETTE   lpDDPal;    // 调色板
BOOL          bActive;    // 应用程序是否活跃?
HBITMAP hbm;
RECT rect;
//函数声明
void FreeObjects( void );
BOOL InitDDraw(void);
BOOL InitSurfaces(void);
void UpdateFrame(void);
void MakeRect(RECT *rect, long left, long top, long right, long bottom);
///////////////////////////////////////////////
// 截图函数,是本程序的关键
// 函数名:GetScreen
// 参数:指向屏幕矩形的指针
// 返值:Bitmap设备
//////////////////////////////////////////////
HANDLE GetScreen(LPRECT lpRect)
{
 //定义屏幕的DC和内存DC
 HDC hScrDC,hMemDC;
 //定义Bitmap设备
 HANDLE hBitmap,hOldBitmap;
 //定义屏幕坐标变量
 unsigned int nX,nY,nX2,nY2;
 unsigned int nWidth,nHeight;
 //定义屏幕分辩率变量
 unsigned int xScrn,yScrn;
 //确保屏幕矩形不为空
 if(IsRectEmpty(lpRect))
 return NULL;
 //创建屏幕的DC
 hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);
 //创建的内存DC
 hMemDC=CreateCompatibleDC(hScrDC);
 //将屏幕矩形坐标付给坐标变量
 nX=lpRect->left;
 nY=lpRect->top ;
 nX2=lpRect->right ;
 nY2=lpRect->bottom ;
 //获得屏幕分辩率
 xScrn=GetDeviceCaps(hScrDC,HORZRES);
 yScrn=GetDeviceCaps(hScrDC,VERTRES);
 if(nX<0)
 nX=0;
 if(nY<0)
 nY=0;
 if(nX2>xScrn)
 nX2=xScrn;
 if(nY2>yScrn)
 nY2=yScrn;
 //获得屏幕宽度与长度
 nWidth=nX2-nX;
 nHeight=nY2-nY;
 //获得屏幕图像并付给一个Bitmap设备
 hBitmap=CreateCompatibleBitmap(hScrDC,nWidth,nHeight);
 hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);
 BitBlt(hMemDC,0,0,nWidth,nHeight,hScrDC,nX,nY,SRCCOPY);
 hBitmap=(HBITMAP)SelectObject(hMemDC,hOldBitmap);
 //清除设备
 DeleteDC(hScrDC);
 DeleteDC(hMemDC);
 return hBitmap;
}
//*******************************************************************
//函数:FreeObject
//功能:释放所有DirectDraw对象
//*******************************************************************
void FreeObjects( void )
{
 //释放hbm位图对象
  DeleteObject(hbm);

  if( lpDD != NULL )//释放DirectDraw对象
  {
    if( lpDDSPrimary != NULL )//释放主页面
    {
      lpDDSPrimary->Release();
      lpDDSPrimary = NULL;
    }
    if( lpDDSPic1 != NULL )//释放离屏页面1
    {
      lpDDSPic1->Release();
      lpDDSPic1 = NULL;
    }
    if( lpDDPal != NULL )//释放调色板
    {
      lpDDPal->Release();
      lpDDPal = NULL;
    }
    lpDD->Release();
    lpDD = NULL;
  }
} 
//*******************************************************************
//函数:RestoreAll
//功能:页面丢失后,恢复页面内存
//*******************************************************************
HRESULT RestoreAll( void )
{
  HRESULT   ddrval;
 //恢复主页面,这也将恢复换页链中的所有页面
  ddrval = lpDDSPrimary->Restore();
 //恢复离屏页面
  ddrval = lpDDSPic1->Restore();
 //重新绘制页面图象
 InitSurfaces();
  return ddrval;
}
//*******************************************************************
//函数:WindowProc
//功能:主窗口的消息处理过程
//*******************************************************************
LRESULT CALLBACK WinProc( HWND hWnd, UINT message, 
              WPARAM wParam, LPARAM lParam )
{
  switch( message )
  {
  case WM_SETCURSOR:
 SetCursor(LoadCursor( NULL, IDC_ARROW ));
 return TRUE;
  case WM_ACTIVATEAPP://应用程序激活消息
    bActive = wParam;
    break;
  case WM_KEYDOWN://击键消息
    switch( wParam )
    {
    case VK_ESCAPE:
      PostMessage(hWnd, WM_CLOSE, 0, 0);
      break;
 }
    break;
  case WM_DESTROY://销毁窗口消息
    FreeObjects();
    PostQuitMessage(0);
    break;
  }
 //调用缺省的过程处理过程
  return DefWindowProc(hWnd, message, wParam, lParam);
}
//******************************************************************
//函数:InitWindow()
//功能:创建主窗口。
//******************************************************************
BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
{
  WNDCLASS wc; //窗口类结构
 //填充窗口类结构
  wc.style = 0;
  wc.lpfnWndProc = WinProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );
  wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);//选择黑色刷做为窗口背景
  wc.lpszMenuName = NULL;
 wc.lpszClassName = CLASSNAME;
 //注册窗口类
  RegisterClass( &wc );
 //创建主窗口
  hWndMain= CreateWindowEx(
 0,
 CLASSNAME, //窗口的类名称,必须与上面的wc.lpszClassName一致
 TITLE, //窗口的标题名
 WS_POPUP,
 0,
 0,
 GetSystemMetrics( SM_CXSCREEN ),
 GetSystemMetrics( SM_CYSCREEN ),
 NULL,
 NULL,
 hInstance,
 NULL );
  if( !hWndMain ) 
 return FALSE;
 //显示并更新窗口
  ShowWindow( hWndMain, nCmdShow );
 return TRUE;
}

//******************************************************************
//函数:InitDDraw()
//功能:初始化DirectDraw环境,创建换页链(主页面,一个后台缓冲区)
// 以及创建一个定时器。
//******************************************************************
BOOL InitDDraw(void)
{
  DDSURFACEDESC    ddsd;
  DDSCAPS       ddscaps;
  HRESULT       ddrval;
  //创建DirectDraw对象
 ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
  if( ddrval != DD_OK )
    return FALSE;
  //取得全屏独占模式
  ddrval = lpDD->SetCooperativeLevel( hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
  if( ddrval != DD_OK )
    return FALSE;
  //设置显示器显示模式为当前屏幕的分辩率,16位增强显示模式
  ddrval = lpDD->SetDisplayMode(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), COLORS);
  if( ddrval != DD_OK )
    return FALSE;
  //填充换页链结构
  ddsd.dwSize = sizeof( ddsd );
  ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
             DDSCAPS_FLIP |
             DDSCAPS_COMPLEX;
 //后台缓冲区数量为2
  ddsd.dwBackBufferCount = 2;
 //创建换页链,包括了主页面及其后台缓冲区
  ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
  if( ddrval != DD_OK )
    return FALSE;
  //获得指向后台缓冲区的页面指针
 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
  if( ddrval != DD_OK )
    return FALSE;
 //创建离屏页面
 ZeroMemory(&ddsd, sizeof(ddsd));
  ddsd.dwSize = sizeof(ddsd);
  ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  ddsd.dwWidth =GetSystemMetrics(SM_CXSCREEN);
  ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
  if (lpDD->CreateSurface(&ddsd, &lpDDSPic1, NULL) != DD_OK)
 return FALSE;
 //调用页面初始化函数
 if( !InitSurfaces() )
    return FALSE;
  return TRUE;
}

//******************************************************************
//函数:WinMain()
//功能:应用程序入口
//******************************************************************
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
 hInst=hInstance;
 //获得屏幕分辩率
 rect.left=rect.top=0;
 rect.right=GetSystemMetrics(SM_CXSCREEN);
 rect.bottom=GetSystemMetrics(SM_CYSCREEN);
 //调用截屏函数
 hbm=(HBITMAP)GetScreen(&rect);
 //初始化主窗口
 if (!InitWindow( hInstance, nCmdShow))
  return FALSE;
 //初始化DirectDraw环境
 if (!InitDDraw())
 {
 MessageBox(hWndMain, "初始化DirectDraw过程中出错!", "Error", MB_OK);
 FreeObjects();
 DestroyWindow(hWndMain);
 return FALSE;
 }

 //进入消息循环
 while(1)
 {
 if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
 {
  if(!GetMessage(&msg, NULL, 0, 0 ))
  return msg.wParam;
  TranslateMessage(&msg); 
  DispatchMessage(&msg);
 }
 else if(bActive)
 {
  UpdateFrame();
 }
 else WaitMessage();
 }
  return msg.wParam;
} 
//******************************************************************
//函数:InitSurfaces()
//功能:初始化页面图象
//******************************************************************
BOOL InitSurfaces( void )
{
 if (hbm == NULL)
 return FALSE;
 DDCopyBitmap(lpDDSPic1, hbm, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));

  return TRUE;
}
//更新屏幕
void UpdateFrame( void )
{
 HRESULT ddrval;
 //清屏后台缓冲区
 DDBLTFX ddBltFx;
 ddBltFx.dwSize = sizeof(DDBLTFX);
 ddBltFx.dwFillColor = DDColorMatch(lpDDSBack, RGB(0,0,0));
 lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx);
 //调用灰度的实现函数
 RECT srect, drect;
 MakeRect(&srect, 0, 0, rect.right ,rect.bottom);
 MakeRect(&drect, 0, 0, rect.right , rect.bottom);
 //将背景图象Blit到后台缓冲区
 lpDDSBack->Blt(&drect, lpDDSPic1, &srect, DDBLT_WAIT, NULL);
  // 换页
  while( 1 )
  {
    ddrval = lpDDSPrimary->Flip( NULL, DDFLIP_WAIT );//调用换页函数
    if( ddrval == DD_OK )//成功则退出while循环
      break;
    else if( ddrval == DDERR_SURFACELOST )//如果页面丢失,则恢复页面,再继续while循环
      RestoreAll();
    else
  break;
 }
}
void MakeRect(RECT *rect, long left, long top, long right, long bottom)
{
 rect->left=left;
 rect->top=top;
 rect->right=right;
 rect->bottom=bottom;
}

推荐阅读
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • Win10下游戏不能全屏的解决方法及兼容游戏列表
    本文介绍了Win10下游戏不能全屏的解决方法,包括修改注册表默认值和查看兼容游戏列表。同时提供了部分已经支持Win10的热门游戏列表,帮助玩家解决游戏不能全屏的问题。 ... [详细]
  • 如何在联想win10专业版中修改账户名称
    本文介绍了在联想win10专业版中修改账户名称的方法,包括在计算机管理中找到要修改的账户,通过重命名来修改登录名和属性来修改显示名称。同时指出了windows10家庭版无法使用此方法的限制。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 电脑公司win7剪切板位置及使用方法
    本文介绍了电脑公司win7剪切板的位置和使用方法。剪切板一般位于c:\windows\system32目录,程序名为clipbrd.exe。通过在搜索栏中输入cmd打开命令提示符窗口,并输入clip /?即可调用剪贴板查看器。赶紧来试试看吧!更多精彩文章请关注本站。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
author-avatar
谷智精源
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有