📄 wzjh46.htm
字号:
<html>
<head>
<meta NAME="GENERATOR" Content="Microsoft FrontPage 3.0">
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=gb2312">
<meta HTTP-EQUIV="Expires" CONTENT="0">
<title>用Delphi实现远程屏幕抓取</title>
<style type="text/css">
<!--
BODY {
BACKGROUND: white; FONT-FAMILY: 宋体; FONT-SIZE: 9pt
}
.font1 {
FONT-FAMILY: "宋体"; FONT-SIZE: 11pt
; line-height: 130%}
A {
COLOR: #000080; FONT-FAMILY: 宋体, "Arial"; FONT-SIZE: 9pt; TEXT-DECORATION: none; TEXT-TRANSFORM: none
}
A:hover {
COLOR: red; FONT-SIZE: 9pt
}
TD {
FONT-FAMILY: 宋体, "Arial", "Times New Roman"; line-height: 150%; FONT-SIZE: 9pt
}
-->
</style>
<body>
<table width=100% cellspacing='0' cellpadding='0' align='center' border='0'>
<tr bgcolor="#f7f7f7">
<td class='tt2' bgcolor="#FFFFFF" >
<table border="0" cellpadding="2" cellspacing="1" width="100%" align="center">
<tr bgcolor="#FFFFFF">
<td align="centr" valign="top" class="font1"><font color="#000000">
<br>
用Delphi实现远程屏幕抓取 <br>
   <br>
   <br>
  山东巨力股份有限公司CAD中心 <br>
  檀革勤 <br>
  ---- 在网络管理中,有时需要通过监视远程计算机屏幕来了解网上微机的使用情况。虽然,市面上有很多软件可以实现该功能,有些甚至可以进行远程控制,但在使用上缺乏灵活性,如无法指定远程计算机屏幕区域的大小和位置,进而无法在一屏上同时监视多个屏幕。其实,可以用Delphi自行编制一个灵活的远程屏幕抓取工具,简述如下。
<br>
   <br>
  ---- 一、软硬件要求。 <br>
   <br>
  ---- Windows95/98对等网,用来监视的计算机(以下简称主控机)和被监视的计算机(以下简称受控机)都必须装有TCP/IP
协议,并正确配置。如没有网络,也可以在一台计算机上进行调试。 <br>
   <br>
  ---- 二、实现方法。 <br>
   <br>
  ---- 编制两个应用程序,一个为VClient.exe,装在受控机上,另一个为VServer.exe,装在主控机上。VServer.exe指定要监视的受控机的IP地址和将要在受控机屏幕上抓取区域的大小和位置,并发出屏幕抓取指令给VClient.exe,VClient.exe得到指令后,在受控机屏幕上选取指定区域,生成数据流,将其发回主控机,并在主控机上显示出抓取区域的BMP图象。由以上过程可以看出,该方法的关键有二:一是如何在受控机上进行屏幕抓取,二是如何通过TCP/IP协议在两台计算机中传输数据。
<br>
   <br>
  ---- UDP(User Datagram Protocol,意为用户报文协议)是Internet上广泛采用的通信协议之一。与TCP协议不同,它是一种非连接的传输协议,没有确认机制,可靠性不如TCP,但它的效率却比TCP高,用于远程屏幕监视还是比较适合的。同时,UDP控件不区分服务器端和客户端,只区分发送端和接收端,编程上较为简单,故选用UDP协议,使用Delphi
4.0提供的TNMUDP控件。 <br>
   <br>
  ---- 三、创建演示程序。 <br>
   <br>
  ---- 第一步,编制VClient.exe文件。新建Delphi工程,将默认窗体的Name属性设为"Client"。加入TNMUDP控件,Name属性设为"CUDP";LocalPort属性设为"1111",让控件CUDP监视受控机的1111端口,当有数据发送到该口时,触发控件CUDP的OnDataReceived事件;RemotePort属性设为"2222",当控件CUDP发送数据时,将数据发到主控机的2222口。
<br>
   <br>
  ---- 在implementation后面加入变量定义 <br>
   <br>
  const BufSize=2048;{ 发送每一笔数据的缓冲区大小 } <br>
  var <br>
  BmpStream:TMemoryStream; <br>
  LeftSize:Longint;{ 发送每一笔数据后剩余的字节数 } <br>
   <br>
  为Client的OnCreate事件添加代码: <br>
  procedure TClient.FormCreate(Sender: TObject); <br>
  begin <br>
  BmpStream:=TMemoryStream.Create; <br>
  end; <br>
   <br>
  为Client的OnDestroy事件添加代码: <br>
  procedure TClient.FormDestroy(Sender: TObject); <br>
  begin <br>
  BmpStream.Free; <br>
  end; <br>
   <br>
  为控件CUDP的OnDataReceived事件添加代码: <br>
  procedure TClient.CUDPDataReceived(Sender: TComponent; <br>
  NumberBytes: Integer; FromIP: String); <br>
  var <br>
  CtrlCode:array[0..29] of char; <br>
  Buf:array[0..BufSize-1] of char; <br>
  TmpStr:string; <br>
  SendSize,LeftPos,TopPos,RightPos,BottomPos:integer; <br>
  begin <br>
  CUDP.ReadBuffer(CtrlCode,NumberBytes);{ 读取控制码 } <br>
  if CtrlCode[0]+CtrlCode[1]+CtrlCode[2]+CtrlCode[3]='show'
then <br>
  begin { 控制码前4位为"show"表示主控机发出了抓屏指令 } <br>
  if BmpStream.Size=0 then { 没有数据可发,必须截屏生成数据 } <br>
  begin <br>
  TmpStr:=StrPas(CtrlCode); <br>
  TmpStr:=Copy(TmpStr,5,Length(TmpStr)-4); <br>
  LeftPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); <br>
  TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr) <br>
  -Pos(':',TmpStr)); <br>
  TopPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); <br>
  TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr)- <br>
  Pos(':',TmpStr)); <br>
  RightPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); <br>
  BottomPos:=StrToInt(Copy(TmpStr,Pos(':',TmpStr <br>
  )+1,Length(TmpStr)-Pos(':',TmpStr))); <br>
  ScreenCap(LeftPos,TopPos,RightPos,BottomPos); { <br>
  截取屏幕 } <br>
  end; <br>
  if LeftSize>BufSize then SendSize:=BufSize <br>
  else SendSize:=LeftSize; <br>
  BmpStream.ReadBuffer(Buf,SendSize); <br>
  LeftSize:=LeftSize-SendSize; <br>
  if LeftSize=0 then BmpStream.Clear;{ 清空流 } <br>
  CUDP.RemoteHost:=FromIP; { FromIP为主控机IP地址 } <br>
  CUDP.SendBuffer(Buf,SendSize); { 将数据发到主控机的2222口 } <br>
  end; <br>
  end; <br>
   <br>
  其中ScreenCap是自定义函数,截取屏幕指定区域, <br>
  代码如下: <br>
  procedure TClient.ScreenCap(LeftPos,TopPos, <br>
  RightPos,BottomPos:integer); <br>
  var <br>
  RectWidth,RectHeight:integer; <br>
  SourceDC,DestDC,Bhandle:integer; <br>
  Bitmap:TBitmap; <br>
  begin <br>
  RectWidth:=RightPos-LeftPos; <br>
  RectHeight:=BottomPos-TopPos; <br>
  SourceDC:=CreateDC('DISPLAY','','',nil); <br>
  DestDC:=CreateCompatibleDC(SourceDC); <br>
  Bhandle:=CreateCompatibleBitmap(SourceDC, <br>
  RectWidth,RectHeight); <br>
  SelectObject(DestDC,Bhandle); <br>
  BitBlt(DestDC,0,0,RectWidth,RectHeight,SourceDC, <br>
  LeftPos,TopPos,SRCCOPY); <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -