可以截取layered窗口(包括透明窗口)的代码:
procedure CaptureScreen(AFileName: string); const CAPTUREBLT = $40000000; var hdcScreen: HDC; hdcCompatible: HDC; bmp: TBitmap; hbmScreen: HBITMAP; begin hdcScreen := CreateDC('DISPLAY', nil, nil, nil); hdcCompatible := CreateCompatibleDC(hdcScreen); hbmScreen := CreateCompatibleBitmap(hdcScreen, GetDeviceCaps(hdcScreen, HORZRES), GetDeviceCaps(hdcScreen, VERTRES)); SelectObject(hdcCompatible, hbmScreen); bmp := TBitmap.Create; bmp.Handle := hbmScreen; BitBlt(hdcCompatible, 0, 0, bmp.Width, bmp.Height, hdcScreen, 0, 0, SRCCOPY or CAPTUREBLT); bmp.SaveToFile(AFileName); bmp.Free; DeleteDC(hdcScreen); DeleteDC(hdcCompatible); end;
DX Primary Surface截图代码!包含DX8与DX9两个版本 ... interface {$DEFINE D3D9} uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, {$IFDEF D3D9} // D3DX9, // use D3D to save surface Direct3D9 {$ELSE} // D3DX8, // use D3D to save surface Direct3D8 {$ENDIF}; ... procedure TForm1.BitBtn1Click(Sender: TObject); // Capture screen through D3D. var BitsPerPixel: Byte; {$IFDEF D3D9} pD3D: IDirect3D9; pSurface: IDirect3DSurface9; g_pD3DDevice: IDirect3DDevice9; {$ELSE} pD3D: IDirect3D8; pSurface: IDirect3DSurface8; g_pD3DDevice: IDirect3DDevice8; {$ENDIF} D3DPP: TD3DPresentParameters; ARect: TRect; LockedRect: TD3DLockedRect; BMP: TBitmap; i, p: Integer; begin BitsPerPixel := GetDeviceCaps(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; {$IFDEF D3D9} 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); {$ELSE} pD3D := Direct3DCreate8(D3D_SDK_VERSION); pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetDesktopWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DPP, g_pD3DDevice); g_pD3DDevice.CreateImageSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, pSurface); g_pD3DDevice.GetFrontBuffer(pSurface); {$ENDIF} // 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('Desktop.bmp'); BMP.Free; pSurface.UnlockRect; end; |
以上DX截图代码,不需要额外的DLL支持,有DirectX 9.0即可 采用上面的2个方案以外,还有些视频播放器的图像不能截取吧,呵呵 怎么解决呢? 它们使用的,是称为"覆盖表面"的技术,截取覆盖表面,需要Hook的手段才行 思路是: 通过Hook DDraw的DirectDrawCreate(RealOne用)同DirectDrawCreateEx(WMP用) 获得IDirectDraw(7) 再COM Hook CreateSurface,注意RealOne使用的是通过QueryInterface获得IDirectDraw2 WMP则是IDirectDraw7 Hook了CreateSurface后,就能获得OverlaySurface 所以必须在软件使用前,启动全局Hook,才有效 在需要截图的时候 Lock Overlay Surface,读取数据,马上Unlock,以免损失性能 解码读出来的数据,即可,但是由于获得的数据是显卡硬件VRAM的数据,一般是YUY2,YV12等格式,需要转换为RGB格式 例如,在我的GF6600上,RealOne(RMVB)用的是YUY2,而WMP(AVI)用的是YV12,还与当前播放的文件格式有关提供主表面截图源码和覆盖表面截图的测试程序http://lysoft.lz169.com/projects/DXCapture.rar 现在支持YV12,NV12,YUY2,UUVY 4个格式 |