1. Technology

Your suggestion is on its way!

An email with a link to:

http://delphi.about.com/od/internetintranet/l/aa012004c.htm

was emailed to:

Thanks for sharing About.com with others!

ScreenThief - stealing screen shots over the Network
Page 3: Server and Client: querying and retrieving Client screen shot images
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Page 1: The idea
• Page 2: Server and Client: basic settings
• DOWNLOAD FULL SOURCE
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Exchanging Data over the Network using Delphi - simple CHAT application
• Introduction to INDY
• Network programming with Delphi
• Indy related articles

Now, that you know what the main purpose of ScreenThief is, and what the GUI looks like, it's time to see the true action.

Waiting for me?
First, don't forget that all the ScreenThief source code can be downloaded. The Client project has two nice function (beside TCP handling stuff): the BMPtoJpegStream function is used to convert a BMP picture to a JPEG (as Memory stream); the ScreenShot function takes a screen shot of the Desktop and stores it in the TBitmap object.

Lastly, I'll show you the code in the Client's OnTimer event and the (TIdTCPServer component's) OnExecute event handler code on the Server:

First, the Client side of the story:

procedure TMainFormClient.TimerTimer(Sender: TObject);
var
  JpegStream : TMemoryStream;
  pic : TBitmap;
  sCommand : string;
begin
  if not TCPClient.Connected then Exit;

  Timer.Enabled := False;

  TCPClient.WriteLn('CheckMe'); 
  sCommand := TCPClient.ReadLn;
  if sCommand = 'TakeShot' then
  begin
    pic := TBitmap.Create;
    JpegStream := TMemoryStream.Create;
    ScreenShot(0,0,Screen.Width,Screen.Height,pic);

    BMPtoJPGStream(pic, JpegStream);
    pic.FreeImage;
    FreeAndNil(pic);

    // copy file stream to write stream
    TCPClient.WriteInteger(JpegStream.Size); // first send the size
    TCPClient.OpenWriteBuffer;
    TCPClient.WriteStream(JpegStream); //then send the image
    TCPClient.CloseWriteBuffer;
    FreeAndNil(JpegStream);

    //making sure!
    sCommand := TCPClient.ReadLn;
  end;

  Timer.Enabled := True;
end;

Every 1/2 of a second (Timer's Interval property, set at design time), the Client send command ('CheckMe') to the Server. If Server responds 'TakeShot', the Client takes a screen shot of (its) Desktop and send the Jpeg image (converted from bitmap) to the server using the WriteStream method.

Note: you could/should decide to include the mouse cursor image in the screen shot.

ScreenThief CLIENT at run time

Next, the Server side of the story:

procedure TMainFormServer.TCPServerExecute(AThread: TIdPeerThread);
var
  Client : PClient;
  Command : string;
  Size : integer;
  PicturePathName : string;
  ftmpStream : TFileStream;
begin
  if not AThread.Terminated and AThread.Connection.Connected then
  begin
    Client := PClient(AThread.Data);
    Client.LastAction := Now;

    Command := AThread.Connection.ReadLn;
    if Command = 'CheckMe' then
    begin
      if Client.TakeShot = True then
      begin
        Client.TakeShot := False;

        AThread.Connection.WriteLn('TakeShot');

        PicturePathName := ExtractFileDir(ParamStr(0)) + 
                           '\' + Client.HostName + '_Screen.JPG';
        if FileExists (PicturePathName) then DeleteFile(PicturePathName);
        ftmpStream := TFileStream.Create(PicturePathName,fmCreate);
        Size := AThread.Connection.ReadInteger;
        AThread.Connection.ReadStream(fTmpStream,Size,False);
        FreeAndNil(fTmpStream);

        AThread.Connection.WriteLn('DONE');
      end
      else
        AThread.Connection.WriteLn('DONE');
    end;
  end;
end;

The (TIdTCPServer) OnExecute handler processes commands send from a (connected) client to the Server.
To correctly process the command we *locate* the Client by using the AThread parameter's Data field. If the Client is set to send its screenshot the TakeShot parameter of the PClient (pointer to an instance of TClient record) is True. If this is the case, the Server resonds with 'TakeShot' (or, sends a command back to the Client). The Client then sends the screenshot image (as a Jpeg file) to the Server ... and one "round" is finished.

Note: WriteLn and ReadLn methods of the TIdTCPConnection object must be synchronized between the Server and the Client - or you'll be stuck with either the "frozen" Client or the server (waiting to receive an answer).

Something like:

Server Client communication

Note: Client "actions" are in blue, Server actions are in red.

One screen shot to go, please!
That's all folks. Bear in mind that the code here is working but is written as a prototype - in real world you should have options on both the Server and the Client part to let the user change the IP and the Port where the Server is listening, you would probably like to have a better looking Server, and perhaps a "hidden" Client.

I'll leave you to extend the code as much you can ... if you think your final solution is the_best_screenthief project, send me an email and I'll list it here.

p.s.
Server must be started in order for Clients to connect!

As always I encourage you to post your views, comments, questions and doubts to this article on the Delphi Programming Forum. Discuss!

First page > Network ScreenThief, the idea > Page 1, 2, 3

©2014 About.com. All rights reserved.