Delphi 2010:使用DirectX进行快速ScreenShot

时间:2015-12-17 00:53:46

标签: delphi

大家。 我正在使用截图开发一个应用程序。 使用Bitblt(StretchBlt)函数有时会给我黑屏图像

procedure CaptureScreen_4(const FileName: string);overload;
var
  nScreenWidth,nScreenHeight: integer;
  ScreenDc,hCaptureDC: HDC;
  bmp: TBitmap;
begin
  nScreenWidth := GetSystemMetrics(SM_CXSCREEN);
  nScreenHeight := GetSystemMetrics(SM_CYSCREEN);
  ScreenDc := GetDC(GetDesktopWindow);
  hCaptureDC := CreateCompatibleDC(ScreenDc);
  bmp := TBitmap.Create;
  bmp.Handle :=CreateCompatibleBitmap(ScreenDc,nScreenWidth, nScreenHeight);
  SelectObject(hCaptureDC,bmp.Handle);
  BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,ScreenDc,0,0,SRCCOPY);
  bmp.SaveToFile(fileName);
  ReleaseDC(GetDesktopWindow,ScreenDc);
  DeleteDC(hCaptureDC);
  bmp.Free;
end;

所以我使用了另一种使用directx的方法

procedure CaptureScreen_1(Const FileName: string);
var
  BitsPerPixel: Byte;
  pD3D: IDirect3D9;
  pSurface: IDirect3DSurface9;
  g_pD3DDevice: IDirect3DDevice9;
  D3DPP: TD3DPresentParameters;
  ARect: TRect;
  LockedRect: TD3DLockedRect;
  BMP: TBitmap;
  i, p: Integer;
begin
  BitsPerPixel := GetDeviceCaps(Form3.Canvas.Handle, BITSPIXEL);
  FillChar(d3dpp, SizeOf(d3dpp), 0);
  D3DPP.Windowed := True;
  D3DPP.Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  D3DPP.SwapEffect := D3DSWAPEFFECT_DISCARD;
  D3DPP.BackBufferWidth := Screen.Width;
  D3DPP.BackBufferHeight := Screen.Height;
  D3DPP.BackBufferFormat := D3DFMT_X8R8G8B8;
  pD3D := Direct3DCreate9(D3D_SDK_VERSION);
  pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING, @D3DPP, g_pD3DDevice);
  g_pD3DDevice.CreateOffscreenPlainSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);
  g_pD3DDevice.GetFrontBufferData(0, pSurface);
  // use D3D to save surface. Notes: D3DX%ab.dll is required!
//  D3DXSaveSurfaceToFile('Desktop.bmp', D3DXIFF_BMP, pSurface, nil,  nil);
  // use Bitmap to save surface
  ARect := Screen.DesktopRect;
  pSurface.LockRect(LockedRect, @ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
  BMP := TBitmap.Create;
  BMP.Width := Screen.Width;
  BMP.Height := Screen.Height;
  case BitsPerPixel of
    8:  BMP.PixelFormat := pf8bit;
    16: BMP.PixelFormat := pf16bit;
    24: BMP.PixelFormat := pf24bit;
    32: BMP.PixelFormat := pf32bit;
  end;
  p := Cardinal(LockedRect.pBits);
  for i := 0 to Screen.Height - 1 do
    begin
      CopyMemory(BMP.ScanLine[i], Ptr(p), Screen.Width * BitsPerPixel div 8);
      p := p + LockedRect.Pitch;
    end;
  BMP.SaveToFile(FileName);
  BMP.Free;
  pSurface.UnlockRect;
end;

此方法总是给我正确的截图图像。 但这比使用Bitblt方法慢得多。 还有另一个快速完美的捕获屏幕吗?

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。 事实上,我想帮助的原因是阻止特殊应用的捕获。 所以我将capture dll注入dest应用程序。 注入捕获DLL后,应用程序不再阻止捕获。 当然,我已经使用线程在inject dll中捕获图像。 注入程序就像我的问题[procedure CaptureScreen_4(const FileName: string);overload;] 我想让每个人都参考我的经历。