可以截取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个格式

用delphi实现完美屏幕截图的更多相关文章

  1. delphi之完美Splash方案(在TfrmMain.FormCreate里不断调用TfrmSplash显示加载进度文字,并且及时Update显示)

    前言:网上有很多介绍delphi创建闪屏的代码,大多只是在程序开启前显示一个闪屏,但是却没有说如何在闪屏上显示程序加载的进度,于是笔者有意思介绍一下这种闪屏方式. 1.创建一个窗体(TfrmSplas ...

  2. delphi xe10 获取屏幕截图

    //截取屏幕图片 function MakeScaleScreenshot(Sender: TControl): TBitmap; function GetScreenScale: Single; v ...

  3. 【个人吐槽】C、Delphi、C#、java 摘抄

    作为个人的一个感受就是,在win平台上开发软件,别再他妈的用MFC了,不适合新手,上手太难.你妹,实现一个半透明的功能,一堆代码,而C#就他妈的几行话.靠. 似乎很多人都觉得Delphi已经没落了.过 ...

  4. Delphi 2010下载+完美破解

    点击链接进入http://altd.embarcadero.com/download/RADStudio2010/delphicbuilder_2010_3615_win.isoRAD Studio/ ...

  5. Delphi String 与wideString 的完美转换

    一般来说,String与widestring 的转换是系统自动进行的,但是,考虑如下字符串 s:=#2+#3+#0+#10+#0+#1+#164+#59;,显然S的长度为8,然后执行如下代码 var ...

  6. delphi 数组复制利用CopyMemory 最为完美

    在各网站的文章里面,见复制数据的方法中,有move的,有system.copy的,而要实际应用中,这两种方法,并不是很完美,会遇到一些问题,比如copy在记录里面的复制时,编译都过不去,而CopyMe ...

  7. delphi完美经典-第16章 Delphi数据库程序设计----使用BDE组件

    第16章 Delphi数据库程序设计----使用BDE组件 Delphi访问数据库的方式有:ADO.BDE.dbExpress.InterBase Express. 一.TDataSet组件 虽然De ...

  8. delphi完美经典--第十八章

    第18章数据感知组件 一.TDBText组件 用来以只读.一次一条记录的方式,显示DataSet中的某一字段值.因同样继承自TCustomLabel,TDBText组件除了数据感知功能外,与标准组件T ...

  9. Delphi开发 Android 程序启动画面简单完美解决方案

    原文在这里 还是这个方法好用,简单!加上牧马人做的自动生成工具,更是简单. 以下为原文,向波哥敬礼! 前面和音儿一起研究 Android 下启动画面的问题,虽然问题得到了解决,但是,总是感觉太麻烦,主 ...

随机推荐

  1. linux下常用FTP命令 上传下载文件【转】

    1. 连接ftp服务器 格式:ftp [hostname| ip-address]a)在linux命令行下输入: ftp 192.168.1.1 b)服务器询问你用户名和密码,分别输入用户名和相应密码 ...

  2. eclipse中 EAR Libraries 是什么?

    eclipse中 EAR Libraries 是 开发EJB工程所需的库包. 由于新建web工程时,eclipse并不能智能化的判断是否该项目以后会用到ejb, 所以为了全面考虑 就已经帮用户导入了E ...

  3. 解决cef中title不现实tooltip的问题

    本文转自:https://blog.csdn.net/hu1340748/article/details/79030569 感谢感谢 最近在使用chromiumFX做项目,突然发现页面标签中的titl ...

  4. PHP获取客户端的IP地址

    首先我们来了解相关变量的含义: $_SERVER['REMOTE_ADDR']:浏览当前页面的用户计算机的ip地址 $_SERVER['HTTP_CLIENT_IP']:客户端的ip $_SERVER ...

  5. python爬虫-基础

    所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地. 类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源. 1.浏 ...

  6. 《Java多线程编程核心技术》学习笔记

    第2章 对象及变量的并发访问 2.1 synchronized同步方法 方法内的变量为线程安全: 方法内部的变量是线程私有的 方法中有一个变量num,后面对它赋值 两个线程同时调用这个方法,对其赋不同 ...

  7. 【BZOJ】2120: 数颜色

    题解 练习一下带修改莫队 先按照左端点的块排序,再按照右端点的块排序,然后按照时间排序 每个修改操作存一下修改前这个位置的值就可以逆序操作了 代码 #include <bits/stdc++.h ...

  8. 【LOJ】#2536. 「CQOI2018」解锁屏幕

    题解 什么破题,看一眼就能想出来\(n^2 2^n\)看了一眼数据范围有点虚,结果跑得飞快= = 处理出\(a[i][j]\)表示从\(i\)到\(j\)经过的点的点集 然后\(f[i][S]\)表示 ...

  9. 【LOJ】#2527. 「HAOI2018」染色

    题解 简单容斥题 至少选了\(k\)个颜色恰好出现\(S\)次方案数是 \(F[k] = \binom{M}{k} \frac{N!}{(S!)^{k}(N - i * S)!}(M - k)^{N ...

  10. bzoj 1151: [CTSC2007]动物园zoo

    思路:因为每个人最多只能看到五个动物,我们考虑将其状压,f[ i ][ s ] 表示到了第 i 个位置, i, i + 1, i + 2, i + 3, i + 4这四个动物的状态为s, 此时的最大值 ...