title: Delphi 2010 : Fast ScreenShot using DirectX
body: <p>everyone.
  I am developing a application using screenshot.
  Using Bitblt(StretchBlt) function gives me black screen image sometimes</p>
  
  <pre><code>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;
  </code></pre>
  
  <p>So I used another method using directx</p>
  
  <pre><code>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;
  </code></pre>
  
  <p>This method gives always me correct screenshot image.
  But this is very slow than using Bitblt method.
  Is there another one for fast and perfect capture screen?</p>