Dx游戏窗口后台截屏问题

Home / Article MrLee 2016-11-2 5842

游戏用的是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.");
  }

找到原因了,直接取主表面,copy一份到离屏表面,然后打印,那个结果就是遮挡的还是遮挡. 解决方法就是对主表面的blt函数hook,当主表面更新数据时,即调用blt时,此时传入的src表面是未遮挡的,就是麻烦点,那个src表面就是离屏表面,而且是多个拼凑的... 顺便还做了个小测试,在主表面的blt函数中加了个sleep(50),这个cpu占用率就降低了 哈哈哈

本文链接:https://www.it72.com/11180.htm

推荐阅读
最新回复 (0)
返回