Solved

Background copy in threads

Posted on 1998-04-29
20
221 Views
Last Modified: 2011-09-20
Hi guys,

the goal is to copy files in the background.
I have an app on which you can drop files. I don't want the
app, to freeze, when it copies files. I want to be capable to
drop other files on it, even when there is still a file or files
being copied.
So I thought of using a thead, but I'm not very avare on how it is working.
Anyway I'm to lazy to search about how it is working.

Here is my copy function:

procedure copyFichier(const source, dest: string);
var
     S, D: TFileStream;
begin
     S := TFileStream.Create(source, fmOpenRead or fmShareDenyWrite);
     try
          D := TFileStream.Create(dest, fmCreate or fmOpenWrite or fmShareExclusive);
          try
               D.CopyFrom(S, S.Size);
          finally
               D.Free;
          end;
     finally
          S.Free;
     end;
end;

It is not very important, to have it anyway.
it is called in the middle of another of my procedures:
...
CopyFichier(sourceFile, destDir);
...

I want that copy to happen in background, how can I do that ?

I need a counter of how many copy are still active.
I want working source code please.
Thanks for your help.
0
Comment
Question by:jeurk
  • 10
  • 6
  • 3
  • +1
20 Comments
 
LVL 4

Expert Comment

by:d003303
Comment Utility
Yo,
I think you should better work with a copy list. Take the first file on the list and start the copy thread. When copying is finished, delete the entry and repeat until the list is empty. During copying, the list can be extended with dropping entries onto it. Copying several files at once may be good when ftping in the internet, but not on local networks or on the same machine.
Also, the copy thread should give feedback about the copying status and provide an abort handler. For that you have to copy in small buffers, not one stream into another.
I'll take a look at it.

Slash/d003303
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
Yo,
here's some code about what I mentioned above.

/////////////////////
// to be ThrdCopy.dpr
program ThrdCopy;

uses
  Forms,
  copywnd in 'copywnd.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

/////////////////////
// to be copywnd.pas
unit copywnd;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls, cpythrd, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Button2: TButton;
    ProgressBar1: TProgressBar;
    Panel1: TPanel;
    Label1: TLabel;
    Animate1: TAnimate;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    FCopyThread : TCopyThread;
  public
    { Public declarations }
    procedure ThreadFeedback(Sender : TObject);
    procedure ThreadTerminate(Sender : TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  FCopyThread := TCopyThread.Create(Edit1.Text, Edit2.Text);
  FCopyThread.OnFeedback := ThreadFeedback;
  FCopyThread.OnTerminate := ThreadTerminate;
  FCopyThread.FreeOnTerminate := false;
  Button2.Enabled := true;
  Button1.Enabled := false;
  Animate1.Visible := true;
  Animate1.Active := true;
  FCopyThread.StartCopy;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FCopyThread.Terminate;
end;

procedure TForm1.ThreadFeedback(Sender : TObject);
begin
  if Sender is TCopyThread then
   with Sender as TCopyThread do
    begin
      Panel1.Caption := Format('  %d of %d bytes copied', [BytesCopied, SourceSize]);
      Panel1.Refresh;
      ProgressBar1.Position := PercentCopied;
      ProgressBar1.Refresh;
      Application.ProcessMessages;
    end;
end;

procedure TForm1.ThreadTerminate(Sender : TObject);
begin
  if Sender is TCopyThread then
   begin
     Button2.Enabled := false;
     Button1.Enabled := true;
     Animate1.Visible := false;
     Animate1.Active := false;
     ProgressBar1.Position := 0;
     if (Sender as TCopyThread).ReturnValue = 0
      then Panel1.Caption := '  copying succeeded.'
      else Panel1.Caption := '  copying not succeeded.';
     Sender.Free;
   end;
end;

end.

/////////////////////
// to be copywnd.dfm
object Form1: TForm1
  Left = 200
  Top = 108
  Width = 340
  Height = 211
  BorderStyle = bsSizeToolWin
  Caption = 'Thread-Copy'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 160
    Top = 12
    Width = 9
    Height = 13
    Caption = '->'
  end
  object Edit1: TEdit
    Left = 4
    Top = 8
    Width = 153
    Height = 21
    TabOrder = 0
  end
  object Edit2: TEdit
    Left = 172
    Top = 8
    Width = 153
    Height = 21
    TabOrder = 1
  end
  object Button1: TButton
    Left = 84
    Top = 64
    Width = 75
    Height = 25
    Caption = 'Copy'
    TabOrder = 2
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 172
    Top = 64
    Width = 75
    Height = 25
    Caption = 'Cancel'
    Enabled = False
    TabOrder = 3
    OnClick = Button2Click
  end
  object ProgressBar1: TProgressBar
    Left = 4
    Top = 40
    Width = 321
    Height = 16
    Min = 0
    Max = 100
    TabOrder = 4
  end
  object Panel1: TPanel
    Left = 0
    Top = 164
    Width = 332
    Height = 20
    Align = alBottom
    Alignment = taLeftJustify
    BevelOuter = bvLowered
    TabOrder = 5
  end
  object Animate1: TAnimate
    Left = 24
    Top = 96
    Width = 272
    Height = 60
    Active = False
    CommonAVI = aviCopyFiles
    StopFrame = 34
    Visible = False
  end
end

/////////////////////
// to be cpythrd.pas

unit cpythrd;

interface

uses
  Windows, Classes;

const
  MaxBufSize = 4096;

type

  TCopyThread = class(TThread)
  private
    FCopyBuffer    : array[0..MaxBufSize - 1] of Byte;
    FSource,
    FDestination   : string;
    FHSource,
    FHDestination  : THandle;
    FSourceSize,
    FBytesCopied   : LongInt;
    FPercentCopied : Integer;
    FOnFeedback    : TNotifyEvent;
    procedure GiveFeedback;
  protected
    procedure Execute; override;
  public
    procedure StartCopy;
    constructor Create(Source, Destination : string);
    destructor Destroy; override;
    property Source: string read FSource;
    property Destination: string read FDestination;
    property PercentCopied: Integer read FPercentCopied;
    property SourceSize: LongInt read FSourceSize;
    property BytesCopied: LongInt read FBytesCopied;
    property ReturnValue;
    property OnFeedback: TNotifyEvent read FOnFeedback write FOnFeedback;
  end;

implementation

procedure TCopyThread.GiveFeedback;
begin
  if Assigned(FOnFeedback)
   then FOnFeedback(Self);
end;

procedure TCopyThread.Execute;
var BytesRead,
    BytesWritten : Integer;
begin
  repeat
    if not ReadFile(FHSource, FCopyBuffer, MaxBufSize, BytesRead, nil)
     then Exit;
    if not WriteFile(FHDestination, FCopyBuffer, BytesRead, BytesWritten, nil)
     then Exit;
    if BytesRead <> BytesWritten
     then Exit;
    FBytesCopied := FBytesCopied + BytesWritten;
    FPercentCopied := Trunc(100 / FSourceSize * FBytesCopied);
    Synchronize(GiveFeedback);
    if Terminated then Exit;
  until FBytesCopied = FSourceSize;
  ReturnValue := 0;
end;

procedure TCopyThread.StartCopy;
begin
  Execute;
end;

constructor TCopyThread.Create(Source, Destination : string);
var OFStruct : TOFStruct;
begin
  inherited Create(false);
  ReturnValue := 1;
  FSource := Source;
  FDestination := Destination;
  // check source file
  OFStruct.cBytes := SizeOf(TOFStruct);
  FHSource := OpenFile(PChar(FSource), OFStruct, OF_READ);
  if FHSource = HFILE_ERROR
   then Exit;
  FSourceSize := GetFileSize(FHSource,nil);
  if FSourceSize = $FFFFFFFF
   then Exit;
  // check destination
  FHDestination := OpenFile(PChar(FDestination), OFStruct, OF_CREATE);
  if FHDestination = HFILE_ERROR
   then Exit;
  FBytesCopied := 0;
  FPercentCopied := 0;
end;

destructor TCopyThread.Destroy;
begin
  if FHSource <> HFILE_ERROR
   then CloseHandle(FHSource);
  if FHDestination <> HFILE_ERROR
   then CloseHandle(FHDestination);
  inherited Destroy;
end;

end.

/////////////////////////////////////////////////////////////////

The stuff uses VERY basic error-handling, that's still to do.

Have fun,
Slash/d003303
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Hi,
Thanks for the answer, I'll try out the things.
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Hi, I reject your answer, cause it is not working properly,
the copy does never stop. If you want to change the thing
and it works you will earn a B, but if you want you can say
that you won't change the answer and only earn a D.
What do you think d003303 ?
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
Yo,
on all my machines it works fine (NT 4.0), have you tracked the value of the FBytesCopied variable in the debugger ? Or is your file larger than 4294967295 bytes (32 bit boundary) ?

Slash/d003303
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Hi,
I tryed it under W95, even on small files.
Maybe you could send me the whole project that you have on
your computer ? that would avoid some typos ?

Mailto://knipjo@citeweb.net

Thanks.
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Have you sent the projects or not ?
Will you send it or not ?
Do you want the points ?
Let me hear from you.

Jeurk
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
huh, totaly forgot about this one ! I've send you the project including my EXE. Let's work it out until it works on your machine.

Slash/d003303
0
 
LVL 7

Expert Comment

by:BlackMan
Comment Utility
How about this: "Multithread copy is what should have been done in any decent file manager under Windows 95/NT. It allows to launch as many copy operations as wanted without any need to wait till the operation's completed - by Daniel Doubrovkine "

It comes with complete source!!
It's on Delphi Super Page (http://sunsite.icm.edu.pl/delphi), search for MUCOPY
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Where is your cool answer blackman ?
Huh?

0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 7

Expert Comment

by:BlackMan
Comment Utility
Oops, I'm sorry I tried to help you...
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
I apologize :
In your answer there was nothing but an empty box, so I thought you
made a mistake. I'm really sorry. There might have been a problem.
I'll take a look at what you say.
Thanks.

[d003303] I tryed what you sent : it is working an small files, but this time
on large files it copys everything, stops when the bytes number are equal
in src and dest but don't gives the hand back.


0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
It seems cool,
I'll let ya know what I think of it.
Jeurk
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
I'll take a look at it.
0
 
LVL 1

Expert Comment

by:Edo082297
Comment Utility
Hi
  I don't know if this is your problem, but you should try moving the inherited create to the last statement in your constructor. That way, the initial initialization will be done, and the process can get underway (i.e. Execute) immediately.
  I could be way off on this one.

HTH

Edo
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Thanks for the help EDO.

Anyway, blackman : I think you're gonna earn the points cause the link you
submitted shows a perfectly working solution.
If everyone agrees ?
d003 ?

Regards
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
It has to work for *you*, so if you think so, no prob.
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
Cool that you take it like that d003303. Anyway we will meet again
around others questions. I am aware that you gave out some work here.
Nochmal danke.
Jeurk.

Blackman : answer that question please.


0
 
LVL 7

Accepted Solution

by:
BlackMan earned 100 total points
Comment Utility
How about this: "Multithread copy is what should have been done in any decent file manager under Windows 95/NT. It allows to launch as many copy operations as wanted without any need to wait till the operation's completed - by Daniel Doubrovkine "

It comes with complete source!!
It's on Delphi Super Page (http://sunsite.icm.edu.pl/delphi), search for MUCOPY
0
 
LVL 4

Author Comment

by:jeurk
Comment Utility
I apologize again ;)
Thanks for the links it does the job well.
Jeurk
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now