关于抓屏的例子看看吧
procedure TForm1.Button1Click(Sender: TObject);
var
SDC:HDC;
begin
SDC:=CreateDC('DISPLAY',nil,nil,nil);
Image1.Width:=800;
Image1.Height:=600; BitBlt(Image1.Canvas.Handle,strtoint(Edit1.Text),Strtoint(edit2.text),
strtoint(edit3.text),strtoint(edit4.text),SDC,0,0,SRCCOPY); Image1.Refresh;
DeleteDC(SDC);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
SDC:HDC;
begin
SDC:=CreateDC('DISPLAY',nil,nil,nil);
Image1.Width:=800;
Image1.Height:=600; BitBlt(Image1.Canvas.Handle,strtoint(Edit1.Text),Strtoint(edit2.text),
strtoint(edit3.text),strtoint(edit4.text),SDC,0,0,SRCCOPY); Image1.Refresh;
DeleteDC(SDC);
end;
将远程控制应用于教学中,已成为目前计算机化教学的重要手段。一定有很多的网虫想了解
这种网络教学方式的编程原理吧。在此我们就以一个简单的远程控制程序作为示例,说明这
种网络编程的基本原理。本程序以Delphi编程为例。
其实该程序的工作机制很简单,受控方运行一个程序,用于侦听端口并接收数据包,而
主控方通过端口给受控方的端口发送数据包。根据这个原理,我们编写两个程序,一个是控
制方的,而另一个是受控方的,把这两个程序运行在两台不同的机器上,受控机等待控制机
发送过来的数据然后执行相应的操作(如本例中的重启)。
Delphi中有两类控件可以实现上面的目的。一类是控制方使用ClientSocket,受控方
使用ServerSocket(均在Internet页),另一类是双方都使用NMUDP(在FastNet页)。我们
知道网络传输都是不可靠的,也就是说传输的数据有可能丢失,而这两类控件的区别是前者
使用TCP(Transfer Control Protocol,传输控制协议)。TCP协议是面向连接,每次双方
建立连接(或断开)时需经过三次握手,较为耗时,但数据传输可靠;而后者使用UDP(User
Datagram Protocol,用户报文协议),它是面向无连接的,发出数据不需对方确认,这样
速度比TCP快,但数据有可能丢失,因此它不可靠。由于控制所需传送的数据量不大,而且需
要较高的可靠性,因此一般使用前者,程序说明如下:
第一步,开始控制方程序,在其中加入clientsocket控件,取名control,设置host属
性为受控机ip地址,port属性为1234(端口可以随便设置,但不要与一些默认端口重复,如80等)。
第二步,在FormCreate事件中加入代码control.open; //打开与受控机的通信
第三步,加入个Button,设置caption为“重新启动”,并在ButtonClick事件中加入
代码control.Socket.SendText('reboot');//通知受控机重新启动。这样就完成了控制
方的工作了。
第四步,开始受控方的程序,在其中加入serversocket控件,取名undercontrol,设置
port属性为1234(与控制方的端口一致),active属性为true;
第五步,在undercontrol的OnclientRead事件中加入代码if Socket.ReceiveText=
'reboot' then
ExitWindowsEx(EWX_REBOOT,2); //重启的API函数
这样就完成了代码的工作,然后编译这两个程序生成两个.exe文件分别放在两台机器上运行
(记得先运行Win98下的受控机程序),在控制机按下“重新启动”的Button(按钮),受控机就重
新启动了。远程控制机器重启成功实现。
由于篇幅的限制,以上忽略了很多细节的东西(如出错处理),而且只能完成远程控制的一种
功能,有兴趣者可在此基础上完善,可实现网络软件管理中的其它功能,如鼠标、键盘锁定、关
机、抓取屏幕、文件操作、视频传输等,在此就不多介绍了,有兴趣者可以上网多查看些这方面
的资料。 远程控制篇:测试IP地址使用 i:=1 to 254 do begin...end即可自动搜索地址
要知道这个IP地址是否中镖,可向它发一个字符串。如果接收到这个IP返回来的预定的字符串,
如发出"我是长江",返回"我是黄河",就可以控制这个IP地址了{uses winsock}
function testip(IP:string):string;
var
WSAData:TWSADATA;
Addr:DWORD;
begin
WSAStartup(2, WSAData);
Addr:=inet_addr(PChar(IP));
if gethostbyaddr(@Addr,sizeof(Addr),PF_INET)=nil then
result:=''
else result:=ip;
WSACleanup();
end;
远程控制篇:模拟按键模拟鼠标
鼠标移动(移动量dx,dy)
mouse_event(MOUSEEVENTF_MOVE,dx,dy,0, 0 );
鼠标在(x,y)处按下或释放
setcursorpos(x,y);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0 );
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
鼠标双击由两次按下与释放来模拟键盘模拟
一般虚拟键值(VK_)由KeyDown或keyup事件得到
特殊键值
Tab--9
Shift--16
Ctrl--17
Alt--18
CapsLock--20
Esc--27
Win--91,92
NumLock--144
ScrollLock--145按下键
keybd_event(key, MapVirtualKey(key, 0 ), KEYEVENTF_KEYUP , 0 );
释放键
keybd_event(key, MapVirtualKey(key, 0 ), 0 , 0 );
以上做法对大多数键有效,少数键要用到不同的值远程控制篇:抓取远程屏幕图像{抓屏幕图像,保存为内存流--BMP流,压缩BMP流,JPG流,以及使用流}
{在网络中传送BMP流和JPG流的速度没测试过}
{BMP流的压缩是无损压缩}
{
全局变量
memoryStream:TMemoryStream;
memoryStream:=TMemoryStream.create;
}var
image:Timage;
jpgstream:TJPEGImage;
ss:tcanvas;begin
ss:=tcanvas.Create;
ss.Handle:=getdc(0);
image:=timage.Create(self);
image.width:=Screen.width;
image.Height:=screen.Height ;
image.picture.bitmap.PixelFormat:= pf16bit;
bitblt(image.canvas.handle,0,0,image.width,image.height,ss.handle,0,0,srccopy);{大大的原始BMP流
image.picture.bitmap.SaveToStream(memoryStream);
}{无损压缩BMP流 uses Zlib.pas
{先定义变量count,DestStream,SourceStream}
image.picture.bitmap.SaveToStream(memoryStream);
Count:=memoryStream.Size;
DestStream:=TMemoryStream.Create;
{压缩方式:clnone,clfastest,cldefault,clmax}
SourceStream:=TCompressionStream.Create(cldefault, DestStream);
try
memoryStream.SaveToStream(SourceStream);
SourceStream.Free;
memoryStream.Clear;
memoryStream.WriteBuffer(Count, SizeOf(Count));
memoryStream.CopyFrom(DestStream, 0);
finally
DestStream.Free;
end;
}{JPG流 uses jpeg
jpgstream:= TJPEGImage.Create;
jpgstream.Assign(image.picture.bitmap);
jpgstream.CompressionQuality:=50; {压缩质量}
jpgstream.Compress;
jpgstream.SaveToStream(memoryStream);{保存为JPG流}
jpgstream.free;
}ReleaseDC(0,ss.Handle);
image.free;{发送内存流...}-----------------------------------------------------
{接收内存流...}{使用BMP流
image.Picture.Bitmap.LoadFromStream(bmpStream);}{还原压缩的BMP流 uses:Zlib.pas
先定义变量count,buffer,DestStream,SourceStream
memoryStream是压缩的BMP流
memoryStream.ReadBuffer(Count, SizeOf(Count));
GetMem(Buffer, Count);
DestStream:=TMemoryStream.Create;
SourceStream:=TDecompressionStream.Create(memoryStream);
Try
SourceStream.ReadBuffer(Buffer^, Count);
DestStream.WriteBuffer(Buffer^, Count);
DestStream.Position:=0;
image.Picture.Bitmap.LoadFromStream(DestStream);
finally
FreeMem(Buffer);
DestStream.Free;
end;
}使用JPG流 image.Picture.Assign(jpgstream);远程控制篇:获得网络邻居所有机器名procedure TForm1.Button1Click(Sender: TObject);
VAR
command:string ;
comline: pchar ;
begin
command:='COMMAND.COM /C net view>c:\~~~.txt';
comline:=pchar(command);
WinExec(comline, sw_hide);
timer1.Enabled:=true;
end;每秒试一次
procedure TForm1.Timer1Timer(Sender: TObject);
var f:tstringlist;
ll,ii:integer;
s1,s:string;
b:bool;
begin
f:=tstringlist.Create;
try
f.LoadFromFile('c:\~~~.txt');
except
end;
if f.Count>10 then begin
memo1.Clear;
memo1.lines.add(f.text);
timer1.Enabled:=false;
f.Free;
{去掉多余的行和'\\'}
for ll:=memo1.lines.count-1 downto 0 do begin
if strpos(pchar(memo1.lines.strings[ll]),'\\')=nil then
memo1.lines.delete(ll)
else
memo1.lines.Strings[ll]:=delxxx(memo1.lines.Strings[ll]);
{自编1个去'\\'的函数}
end;
timer1.enabled:=False;
end;远程控制篇:通过机器名得到IP地址function procedure TForm1.nametoip(name:string):string;
var
WSAData: TWSAData;
HostEnt: PHostEnt;
begin
result:='';
WSAStartup(2, WSAData);
HostEnt := gethostbyname(PChar(name));
if HostEnt <> nil then
begin
with HostEnt^ do
result:= Format('%d.%d.%d.%d', [Byte(h_addr^[0]), Byte(h_addr^[1]), Byte(h_addr^[2]), Byte(h_addr^[3])]);
end;
WSACleanup;
end;通过IP地址得到机器名function iptoname(ip:string):string;
var
WSAData:TWSAData;
p:PHostEnt;
InetAddr:dword;
begin
WSAStartup(2, WSAData);
InetAddr:= inet_addr(PChar(IP));
try
p:=GetHostByAddr(@InetAddr, Length(IP), PF_Inet);
result:=p^.h_name;
except
result:='';
end;
end;远程控制篇:服务端程序的隐藏1 按ctrl+alt+del时不出现在关闭程序框
function RegisterServiceProcess (dwProcessID, dwType: DWord) : DWord;
stdcall; external 'KERNEL32.DLL';
不出现
RegisterServiceProcess(GetCurrentProcessID, RSPSIMPLESERVICE);
出现
RegisterServiceProcess(GetCurrentProcessID, RSPUNREGISTERSERVICE);2 程序的图标不出现在任务栏
在Application.Initialize;后加上
Application.ShowMainForm:=False;以上做法在WIN2000下是无效的。
编程软件如VC,DELPHI中都带有进程查看工具。
1
服务端关机时的处理一般这类程序在运行时,当进行关机操作,其它程序都被关掉了,只有它们不为所动。所以必须对
关机消息进行处理。procedure exitwin(var msg:TWMQUERYENDSESSION);message WM_QUERYENDSESSION;
procedure TServer.exitwin(var msg: TWMQUERYENDSESSION);
begin
inherited;
server.Close;
end;程序退出时写注册表,防止用regedit或msconfig把服务端程序从注册表中去。这样regedit或msconfig所作的工作白费,除非立即关电源
procedure TServer.FormDestroy(Sender: TObject);
var
reg:Tregistry;
s:string;
begin
s:=application.ExeName;
reg:=Tregistry.Create;
Reg.RootKey:=HKEY_LOCAL_MACHINE;
Reg.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices',True);
Reg.WriteString(...);
reg.free;
end;