delphi2007 教程

delphi2007 教程

首页 新随笔 联系 聚合 管理
  1013 Posts :: 0 Stories :: 28 Comments :: 0 Trackbacks
求最快的截屏函数!最好是 50ms 之内! Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiMultimedia/html/delphi_20061024164940207.html
用   GetDC   的方法截屏大概耗时   180ms   左右。这对于远程控制来说显然是太慢了,  
  有没有更快的截屏方法。  
  听说设置系统重画钩子可以只截取屏幕变化的部分,从而可以提高速度。  
  这种使用钩子的方法,怎么作呢?  
  有另外的办法也行,只要够快就行!

procedure   TForm1.Cjt_GetScreen(var   Mybmp:   TBitmap;   DrawCur:   Boolean);  
  var  
  Cursorx,   Cursory:   integer;  
  dc:   hdc;  
  Mycan:   Tcanvas;  
  R:   TRect;  
  DrawPos:   TPoint;  
  MyCursor:   TIcon;  
  hld:   hwnd;  
  Threadld:   dword;  
  mp:   tpoint;  
  pIconInfo:   TIconInfo;  
  begin  
  Mybmp   :=   Tbitmap.Create;   {建立BMPMAP   }  
  Mycan   :=   TCanvas.Create;   {屏幕截取}  
  dc   :=   GetWindowDC(0);  
  try  
  Mycan.Handle   :=   dc;  
  R   :=   Rect(0,   0,   screen.Width,   screen.Height);  
  Mybmp.Width   :=   R.Right;  
  Mybmp.Height   :=   R.Bottom;  
  Mybmp.Canvas.CopyRect(R,   Mycan,   R);  
  finally  
  releaseDC(0,   DC);  
  end;  
  Mycan.Handle   :=   0;  
  Mycan.Free;  
  if   DrawCur   then   {画上鼠标图象}  
  begin  
  GetCursorPos(DrawPos);  
  MyCursor   :=   TIcon.Create;  
  getcursorpos(mp);  
  hld   :=   WindowFromPoint(mp);  
  Threadld   :=   GetWindowThreadProcessId(hld,   nil);  
  AttachThreadInput(GetCurrentThreadId,   Threadld,   True);  
  MyCursor.Handle   :=   Getcursor();  
  AttachThreadInput(GetCurrentThreadId,   threadld,   False);  
  GetIconInfo(Mycursor.Handle,   pIconInfo);  
  cursorx   :=   DrawPos.x   -   round(pIconInfo.xHotspot);  
  cursory   :=   DrawPos.y   -   round(pIconInfo.yHotspot);  
  Mybmp.Canvas.Draw(cursorx,   cursory,   MyCursor);   {画上鼠标}  
  DeleteObject(pIconInfo.hbmColor);{GetIconInfo   使用时创建了两个bitmap对象.   需要手工释放这两个对象}  
  DeleteObject(pIconInfo.hbmMask);{否则,调用他后,他会创建一个bitmap,多次调用会产生多个,直至资源耗尽}  
  Mycursor.ReleaseHandle;   {释放数组内存}  
  MyCursor.Free;   {释放鼠标指针}  
  end;  
  end;

这个函数应该不错

这个函数就是用的   GetDC   ,在线程中执行,在我的电脑上还是用了   172ms

能发送一个printscreen键消息吗?  
  相当于按一下printscreen那个拷屏键,  
  然后用使用剪贴板的数据就可以了

blog.joycode.com/jiangsheng/posts/10410.aspx

to   jiangsheng(蒋晟.Net[MVP])   :  
  你在文章中提到用系统钩子拦截重画消息,VNC   的源代码我看不懂,用   Delphi   如何拦截,拦截后如何截屏变化的部分?  
   
  另外听说用   DirectX   可以直接访问显存,但是用   DirecxX   如何截屏呢?  
  用   DelphiX(封装   DirecxX   的   Delphi   组件)   如何截屏呢?

up

mark

Benchmarks   shows   that   DirecxX   is   much   slower   then   GDI  
  I   don't   know   Delphi.   If   you   don't   know   C++   you   can   rewrite   all   Windows   API   calls   in   Delphi.

如果楼主愿意给分的话,我可以帮你编写一个速度超快的载图函数,而且带压缩功能。  
   
  如果想从剪切板读出图片数据,保存为一张BMP文件,也非常简单:  
   
  先发送一个PrintScreen键,再通过Image控件的SaveToFile()方法保存即可!

VNC没有完全的Delphi   Source,但是却有Delphi的组件,只是核心层仍然是使用的C++的DLL.

另外楼主最好搞清楚,你说的那个50ms是针对你的机器配置来说的,也许在别人机器上能达到50ms以内,但是放到你的机器上就不是那么回事了.  
  一个程序员,自己提出来的需求都如此,那么如果是你的客户提出类似的需求你会如何?

想快,估计只能用驱动层面上的

to   mwy654321(无条件为你):  
  你要多少分,我再开个帖子,你把代码给我!

学习中,关注~~~~~

//mwy654321的方法如下:  
  uses   Clipbrd;  
   
  procedure   TForm1.Timer1Timer(Sender:   TObject);  
  begin  
      keybd_event(VK_SNAPSHOT,   0,   0,   0);  
      keybd_event(VK_SNAPSHOT,   0,   KEYEVENTF_KEYUP,   0);  
      if   not   ClipBoard.HasFormat(CF_BITMAP)   then   Exit;  
      Image1.Picture.Bitmap.LoadFromClipboardFormat(CF_BITMAP,  
          ClipBoard.GetAsHandle(CF_BITMAP),   0);  
  end;  
 

首先,   此种应用不必设置系统钩子,   那种方法只会更慢  
  其次,   不要使用CopyRect,   因为CopyRect调用的StretchBlt,   直接使用BitBlt更快  
  对于BitBlt,

首先,   此种应用不必设置系统钩子,   那种方法只会更慢  
  其次,   不要使用CopyRect,   因为CopyRect调用的StretchBlt,   直接使用BitBlt更快  
  对于BitBlt,   我的笔记本电脑测试结果为   1024   x   768   只需要   3   ms  
  如果楼主的机器需要的时间超过50ms,那只能说明楼主的机器的显卡太烂,   应当立马更换  
  BitBlt的性能一般与CPU性能无关,   主要与显卡性能相关  
  示例如下:  
  注意,   对于性能测试,   我的例子中  
          Caption   :=   Caption   +   'OK';  
  这句看似废话,   其实必不可少;   因为   BitBlt会立即返回,   其交给显卡上的GPU完成相关操作  
  这句Caption   :=   Caption   +   'OK';是确保所有BitBlt   GPU操作完成,   否则,   如果没有此句,  
  时间之差接近于0  
   
  procedure   TForm1.Button1Click(Sender:   TObject);  
  var  
      oldTick,   NewTick:   DWord;  
      aBit:   TBitmap;  
      i:   Integer;  
      dc:   HDC;  
  begin  
      aBit   :=   TBitmap.Create;  
      try  
          aBit.Width   :=   Screen.Width;  
          aBit.Height   :=   Screen.Height;  
          OldTick   :=   GetTickCount;  
          for   i   :=   0   to   999   do  
          begin  
              dc   :=   GetDc(HWND_DESKTOP);  
              Win32Check(bitblt(aBit.Canvas.Handle,   i   mod   10,   i   mod   10,   aBit.Width,   aBit.Height,   dc,   0,   0,   SRCCOPY));  
              ReleaseDC(HWND_DESKTOP,   dc);  
          end;  
          Caption   :=   Caption   +   'OK';  
          NewTick   :=   GetTickCount;  
      finally  
          aBit.Free;  
      end;  
      Beep();  
      ShowMessage(Format('%u   -   %u   =   %d',   [NewTick,   OldTick,   NewTick   -   OldTick]));  
  end;  
   
   
 

请教楼上的,为什么要弄个循环在这里?一次bitblt不就ok了吗  
          for   i   :=   0   to   999   do  
          begin  
              dc   :=   GetDc(HWND_DESKTOP);  
              Win32Check(bitblt(aBit.Canvas.Handle,   i   mod   10,   i   mod   10,   aBit.Width,   aBit.Height,   dc,   0,   0,   SRCCOPY));  
              ReleaseDC(HWND_DESKTOP,   dc);  
          end;

回楼上:   我弄一个循环是为了测试bitblt的性能  
  因为   GetTickCount的精度只有10ms,   而一次bitblt会小于10ms  
  这样,   可以使用   总时间/次数   计算每次的时间消耗

对于楼上许多人提供的Print   Screen加Paste   From   Clipboard的方法,   我只能说这种方法太弱  
   
  其一性能很差  
  其二破坏了Clipboard   (此乃大忌)  
   
  但别对于楼主这种应用来说,   远程控制被控制的机器的Clipboard就不能用了  
 

to   spirit_sheng(老盛)   :  
  我用你的方法在我的机器上测试,怎么于其它方法相差无几,耗时还是   170~180   ms。  
  另外你说设置系统钩子会更慢,为什么?我听说   Radmin   就是用的这种办法!  
  这是我把你的代码稍加修改后的代码,没什么问题吧?  
  procedure   BitBlt_CapScreen(AStream:   TMemoryStream;   Left,   Top,   Width,   Height:   Integer);  
  var  
      aBit:   TBitmap;  
      dc:   HDC;  
  begin  
      aBit   :=   TBitmap.Create;  
      try  
          aBit.Width   :=   Screen.Width;  
          aBit.Height   :=   Screen.Height;  
          dc   :=   GetDc(HWND_DESKTOP);  
          Win32Check(BitBlt(aBit.Canvas.Handle,   0,   0,   aBit.Width,   aBit.Height,   dc,   0,   0,   SRCCOPY));  
          ReleaseDC(HWND_DESKTOP,   dc);  
  //         Caption   :=   Caption   +   'OK';  
          aBit.SaveToStream(AStream);  
      finally  
          aBit.Free;  
      end;  
  end;  
  我去掉   Caption   :=   Caption   +   'OK';   也很正常啊!

楼主把你的机器环境帖出来的吧  
  我的是   Dell   Latitude   D600  
  CPU   Intel(R)   Pentium(R)   M   Processor   725   (1.6   GHz)    
  显卡   ATI   Mobility   RADEONTM   9000   图形卡,带有   32MB   DDR   内存  
  操作系统   Windows   XP   Profressional   SP2   (简体中文)  
  在我的机器上1024x768只要3ms,   你说要170~180   ms,   相差也太大了  
 

TO:   楼主,   我那   Caption   :=   Caption   +   'OK';   主要是基于计时考虑的  
  因为   BitBlt   是立即返回的

我的机器是集成显卡。听说集成显卡已经没有显存了,所用内存是在主内存中叩!  
  我的机器是   CPU   2.6   GHz,   内存是   512   MB,   操作系统是   Windows2000   Server

请教下spirit_sheng(老盛)  
  我用你的代码,  
  明明很快就听见    
  Beep();  
  但showmessage却等了几秒才跳出来,这是为啥  
      ShowMessage(Format('%u   -   %u   =   %d',   [NewTick,   OldTick,   NewTick   -   OldTick]));

To:   楼上  
  这也就是我帖子里的说的,   你加上那句Caption   :=   Caption   +   'OK';   后,   Beep   就不会很快了出现了  
  bitblt   函数会很快返回,   其具体会交由显卡完成  
  ShowMessage   操作也要请求显卡完成,   所以,   其会等待GPU可用才能继续执行  
   
 

TO:   楼主,   你的集成显卡太差了,   更换显卡是王道

不能叫客户也去换把       :)

用循环测试Bitblt的方法有问题,GetDC可能耗费的时间更多。  
 

楼主,你可以看看这个http://www.delphibox.com/article.asp?articleid=3710远程屏幕传输   差异截图

posted on 2008-12-19 10:02 delphi2007 阅读(783) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。