看流星社区

 找回密码
 注册账号
查看: 1937|回复: 2

【求助】Dx游戏窗口后台截屏问题

[复制链接]

该用户从未签到

发表于 2013-4-5 08:34:24 | 显示全部楼层 |阅读模式
游戏用的是DirectDraw, 我的截屏是这样做的:
1.hook了DirectDrawCreate获取了LPDIRECTDRAW
2.hook了CreateSurface, 将主表面地址保存起来
3.创建一个离屏surface,将主表面copy到这个离屏表面上,然后输出到文件

现在问题是这个截屏后,若游戏窗口被遮挡,则被遮挡部分无法获取.
这个是什么原因呢? 是这种截图方式不支持遮挡部分截屏呢?
还是说跟游戏主表面的创建有关,有点诡异,游戏窗口大小是800*600,却创建了一个1400*900(显示器大小)的主表面.
还请高手指点下:)


代码:
  //创建后台表面
  if (g_lpDirectDrawCopySurface == NULL)
  {
    LPDIRECTDRAW lpDD = NULL;

    //创建DirectDraw
    if (FAILED( DirectDrawCreate(NULL,&lpDD,NULL)))
    {
      MyTrace(L_ERROR, "Couldn't create DirectDraw object.");
      return E_FAIL;
    }

    if (FAILED(lpDD->SetCooperativeLevel(hwnd/*NULL*/, DDSCL_NORMAL)))
    {
      MyTrace(L_ERROR, "SetCooperativeLevel failed.");
      lpDD->Release();
      return E_FAIL;
    }

    //创建后台表面
    RECT rc;
    GetClientRect(hwnd, &rc);
  
    DDSURFACEDESC desc;
    ZeroMemory(&desc,sizeof(desc));
    desc.dwSize=sizeof(desc);
    desc.dwFlags= DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
    desc.dwWidth=/*::GetSystemMetrics(SM_CXSCREEN); */ /*primedesc.dwWidth*/ /*800*/ rc.right - rc.left;
    desc.dwHeight=/*::GetSystemMetrics(SM_CYSCREEN); */ /*primedesc.dwHeight*/ /*600*/ rc.bottom - rc.top;
    desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;

    if (FAILED(hr = lpDD->CreateSurface(&desc, &g_lpDirectDrawCopySurface, NULL)))
    {
      MyTrace(L_ERROR, "CreateSurface copysurface failed.err=0x%x", hr);
      lpDD->Release();
      return E_FAIL;
    }
  }
   

  RECT rc;
  //GetWindowRect(hwnd, &rc);
  GetClientRect(hwnd, &rc);
  MyTrace(L_DEBUG, "GetClientRect: %d,%d,%d,%d", rc.left, rc.right, rc.top, rc.bottom);

  DDSURFACEDESC desc;
  ZeroMemory(&desc,sizeof(desc));
  desc.dwSize = sizeof(desc);
  if (FAILED(hr = g_lpDirectDrawCopySurface->GetSurfaceDesc(&desc)))
  {
    MyTrace(L_ERROR, "copysurface GetSurfaceDesc failed.err=0x%x", hr);
    return E_FAIL;
  }
  else
  {
    MyTrace(L_DEBUG, "copysurface GetSurfaceDesc successfully, nWidth=%d, nHeight=%d", desc.dwWidth, desc.dwHeight);
  }

  if (FAILED(hr = g_lpDirectDrawCopySurface->BltFast(0,0,g_lpDirectDrawPrimeSurface,&rc,DDBLTFAST_NOCOLORKEY| DDBLTFAST_WAIT)))
  {
    MyTrace(L_ERROR, "BltFast failed.err=0x%x", hr);
    return E_FAIL;
  }

  if (FAILED(hr = g_lpDirectDrawCopySurface->Lock(NULL, &desc, DDLOCK_WAIT|DDLOCK_NOSYSLOCK,NULL)))
  {
    MyTrace(L_ERROR, "Lock failed.err=0x%x", hr);
    return E_FAIL;
  }

  //save to bmp
  if(SaveToBitmapFile(&desc, pszFilePath) != S_OK)
  {
    g_lpDirectDrawCopySurface->Unlock(NULL);
    MyTrace(L_ERROR, "SaveToBitmapFile failed.");
    return E_FAIL;
  }
  else
  {
    g_lpDirectDrawCopySurface->Unlock(NULL);
    MyTrace(L_DEBUG, "SaveToBitmapFile successfully.");
  }

该用户从未签到

发表于 2013-4-5 08:35:21 | 显示全部楼层
现在的DX游戏都是在前台才绘图,当游戏窗口最小化后,就不会再绘制了,因为这时候停止了DX调用,想要截图的话得先把窗口置前台,然后2个调用就搞定,只要没有最小化,窗口被挡住也可以截取,没有LZ那么麻烦
this->GetBackBuffer  //获取图形缓冲区
D3D9SaveSurfaceToFile  //保存到文件

该用户从未签到

发表于 2013-4-5 08:35:34 | 显示全部楼层
恩,最小化肯定不能这么简单就截取.
你的这个不是DirectDraw画图,是D3D9的, 虽然都是属于directx,但不一样啊

该用户从未签到

发表于 2013-4-5 08:35:56 | 显示全部楼层
据说游戏引擎在最小化或者窗体XX的时候,直接停止重绘节约gpu和cpu成本了~~

该用户从未签到

 楼主| 发表于 2013-4-5 08:36:21 | 显示全部楼层
找到原因了,直接取主表面,copy一份到离屏表面,然后打印,那个结果就是遮挡的还是遮挡.
解决方法就是对主表面的blt函数hook,当主表面更新数据时,即调用blt时,此时传入的src表面是未遮挡的,就是麻烦点,那个src表面就是离屏表面,而且是多个拼凑的...
顺便还做了个小测试,在主表面的blt函数中加了个sleep(50),这个cpu占用率就降低了 哈哈哈
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2022-8-14 13:43

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表