Link to home
Start Free TrialLog in
Avatar of routerboy309
routerboy309

asked on

Copy files and create folders from CD-ROM to PC

Hello All -

I need to copy the contents of a CD-ROM to a pre-selected path. The path (edSelected) gets picked when
the user clicks Btn2 and navigates to the folder (browse folder), and then I'll append the folder 'app'
to that path.

For example:

They select:

C:\Program Files

When they click the button, the folder 'app' gets added (C:\Program Files\app) and the contents of the
CD-ROM gets copied.

The code below works, but I have two issues:

A) The pathing issue places an extra '\' when they select the root to be the path. C:\ - becomes C:\\app

B) I can't get the value - StrECopy to read the CD-ROM drive letter so I can copy. Trying to use ExtractFileDir(Application.ExeName), but that fails.

I can get the folders and files to copy from one folder on the PC to another on the PC, but not from the CD-ROM to PC.


procedure CopyFiles(const FromFolder: string; const ToFolder: string);
var
  Fo      : TSHFileOpStruct;
  buffer  : array[0..4096] of char;
  p       : pchar;
begin
  FillChar(Buffer, sizeof(Buffer), #0);
  p := @buffer;
  StrECopy(p, PChar(FromFolder)); //this is folder that you want to copy
  FillChar(Fo, sizeof(Fo), #0);
  Fo.Wnd    := Application.Handle;
  Fo.wFunc  := FO_COPY;
  Fo.pFrom  := @Buffer;
  Fo.pTo    := PChar(ToFolder); //this is where the folder will go
  Fo.fFlags := 0;
  if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then
    ShowMessage('File copy process cancelled')
end;

procedure TForm1.Btn1Click(Sender: TObject);
begin
Close;
end;

// problem here: If you pick the root of the drive, you get two '\\'
// example: pick C: drive and you get C:\\App
//pick a normal folder, and it works

procedure TForm1.Btn2Click(Sender: TObject);
var
s: string;
begin
 if SelectDirectory('Select Directory','',S) then
     edSelected.Caption := s + '\app';
end;

//need StrECopy to default to the CD-ROM. On it an eniter group of folders and files
//need to copied

procedure TForm1.Btn3Click(Sender: TObject);
var
Fo      : TSHFileOpStruct;
buffer  : array[0..4096] of char;
p       : pchar;
begin
FillChar(Buffer, sizeof(Buffer), #0);
p := @buffer;
StrECopy(p, 'C:\MyDir\*.*');
FillChar(Fo, sizeof(Fo), #0);
Fo.Wnd    := Handle;
Fo.wFunc  := FO_COPY;
Fo.pFrom  := @Buffer;
Fo.pTo    := pchar(edSelected.caption);
 if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then
   ShowMessage('Cancelled')
end;


Since this is a double questions, I've double up on the points.

RB
Avatar of Cynna
Cynna

routerboy309,


> A) The pathing issue places an extra '\' when they select the root to be the path. C:\ - becomes C:\\app

This is quite normal. Simply change your code:

  procedure TForm1.Btn2Click(Sender: TObject);
  var
  s: string;
  begin
    if SelectDirectory('Select Directory','',S) then
       edSelected.Caption := s + '\app';
  end;


to this:


  procedure TForm1.Button8Click(Sender: TObject);
  var s: string;
  begin
    if SelectDirectory('Select Directory','',S) then begin
       if s[Length(s)]<>'\' then s:=s+'\';
       edSelected.Caption := s + 'app';
    end;  
  end



B) I can't get the value - StrECopy to read the CD-ROM drive letter so I can copy. Trying to use ExtractFileDir(Application.ExeName), but that fails.

Hmmm... I don't quite understand you here.
I'll assume you want to extract drive letter of the CD-ROM.
If this is true, this function will get you first available CD drive letter in system:


function GrabCDLetter: String;
// search for first available CD drive letter in system
var i: Integer;
    DriveLetters: String;
begin
  DriveLetters:='DEFGHIJK';
  for i:=1 to Length(DriveLetters) do begin
      Result:=DriveLetters[i]+':\';
      if GetDriveType(PChar(Result))=DRIVE_CDROM then Exit;
  end;
end;


If this isn't what you need, please give simplified example (I have this: ...., but I need this: .....) to explain B) futher.

oops,

change
 
  procedure TForm1.Button8Click(Sender: TObject);

to

  procedure TForm1.Btn2Click(Sender: TObject);
One hint for copying from CD-ROM. All files on a CD-ROM are read only and may stay read only when copied. You may need to change the file attributes.
Avatar of routerboy309

ASKER

Cynna -

Thanks for the iinfo. I'm testing it now.

robert_marquardt -

You bring up a good point. 3 of 6 files will need to be changed.


RB
Cynna -

A) Is solved. :)

B) I have this:

StrECopy(p, 'C:\MyDir\*.*');
StrECopy = the copy folder - but right now its hard coded. I need the application to know where its at, so StrECopy can gets its value and then appending a folder to that.

For example:

My CD-ROM is F. So StrECopy reads the value and adds the folder APP to it for a result of

StrECopy(p, 'F:\App\*.*');

In short, when the user clicks the button, the folder App gets created and its contents of F:\App gets moved to the Hard drive location (the part you fix 'A' of this question already).

I tried using ExtractFilePath(Application.EXEName)+'\app\*.*' but this falied:

StrECopy(p, ExtractFilePath(Application.EXEName)+'\app\*.*);


Does this help?

RB





I may have found the solution.

StrECopy(p,pchar(ExtractFilePath(Application.EXEName)+'\app\*.*'));

Cynna -

Can you check my code? Looking for options towards 'read only' changing attribute situation, too.

RB
ASKER CERTIFIED SOLUTION
Avatar of Cynna
Cynna

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry,

Forgot to add cast PChar() to StrECopy(p, ...) statements:
Wherever you have StrECopy(p,...), change it to StrECopy(p, PChar(...));

For example:

  StrECopy(p, s+'*.*');

change to:

  StrECopy(p, PChar(s+'*.*'));

> Looking for options towards 'read only' changing attribute situation, too

Copy/Paste:
------------------

procedure ClearReadOnlyAttrib(const Filename: string );
var
  Attributes: word;
begin
  Attributes := FileGetAttr( Filename );
  FileSetAttr( Filename, (Attributes and not faReadOnly));
end;

Your due dilegence is certainly worth me giving you the points. :)


"You need to let user decide FROM where files should be
  copied (choose source folder)."

No. The User doesn't get the option to change where the files are to be copied FROM. Only gets to change where to PUT the files. So I Guess #2 is closest.

StrECopy is set based on where the CD-ROM was inserted with appending the value of 'APP' for the folder (and its contents).

I want the code to read the drive where the CD-ROM was inserted, append the path of that value with APP, and then when the user clicks the btn, the entire contents of the folder is transferred to the PC.

I think you have plenty of GOOD examples for me to test with. Plus, I like the fact you provided the code sample for the read only issue, hense, I've changed the point value. If my explaination is still unclear, please let me know.

>I want the code to read the drive where the CD-ROM was inserted,

Did you solve this problem? How do you know in which CD drive the
CD has been inserted?
Previously you mentioned you have CD drive F:\ - if this is the case,
why bother finding out the letter of the CD drive with CD in question?
This makes sense only if you have multiple CD drives in your target system,
(for example, CD-ROM and CD-RW could be E: and F:), and you don't know
which one contains the CD.
If you want to automatically find the drive letter of the drive that
contains desired CD, you should know the CD title.
Its a bit more complicated then what you needed so far.



>... append the path of that value with APP, and then when the user clicks the btn,
>the entire contents of the folder is transferred to the PC.

This is very easy.
CopyFiles() does everything you need, so I'm puzzled, why did you use
Btn3Click() code at all?

It can be done much more easily. Assuming you know CD drive letter
(let's say F:),  then just use your CopyFiles() function this way:


procedure TForm1.Btn2Click(Sender: TObject);
var DriveLetter, TargetDir: String;
begin
  DriveLetter:='F:\';
  if SelectDirectory('Select target folder','', TargetDir) then begin
     // Be sure selected dir ends with '\':
     if TargetDir[Length(TargetDir)]<>'\' then TargetDir:=TargetDir+'\';
     // We want to copy files to subfolder APP of selected dir
     TargetDir:=TargetDir+'APP';
     // Finally copy all items from F:\APP:
     CopyFiles(DriveLetter+'APP', TargetDir);
  end;
end;



Just copy/paste this code, and be sure you leave CopyFiles() function.
I only used the F letter as a reference to the question. While I have mulitple CD-ROM drives, I sure many don't. So based on using the code:

(ExtractFilePath(Application.EXEName)+'\app\*.*'));

adds the Drive letter to the path, right?

I just applied the answer to the read-only issue and it worked perfectly.

RB


1. ExtractFilePath(Application.EXEName)+'\app\*.*'
   
   should be (read my previous post, or go to Help about ExtractFilePath):

   ExtractFilePath(Application.EXEName)+'app\*.*'


2. > adds the Drive letter to the path, right?

Well, not quite. It extracts path of your application and and '\app\*.*' to it... :)

For example, if your app is called Project1, and is saved
in 'C:\Program Files\Delphi5\Projects\testing'

Application.ExeName='C:\Program Files\Delphi5\Projects\testing\Project1.exe'

ExtractFilePath(Application.EXEName)='C:\Program Files\Delphi5\Projects\testing\'

ExtractFilePath(Application.EXEName)+'\app\*.*'='C:\Program Files\Delphi5\Projects\testing\\app\*.*'
Excallant! I think you just solved another issue I had. I was using Application.ExeName (and appending to it) to find a Word doc so my app would open it. But I should be using ExtractFilePath.

Also, something else just bit me in as$. My copy file routine fails on Win98... I get an error - Cannot copy File File System Error (1026). So I guess its back to the drawing board...:(

procedure TForm1.btncopyClick(Sender: TObject);
var
Fo      : TSHFileOpStruct;
buffer  : array[0..4096] of char;
p       : pchar;
begin
 FillChar(Buffer, sizeof(Buffer), #0);
 p := @buffer;
 StrECopy(p,pchar(ExtractFilePath(Application.EXEName)+'\app\*.*'));
 FillChar(Fo, sizeof(Fo), #0);
 Fo.Wnd    := Handle;
 Fo.wFunc  := FO_COPY;
 Fo.pFrom  := @Buffer;
 Fo.pTo    := pchar(edSelected.caption);
    if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then
    ShowMessage('Cancelled');
     ClearReadOnlyAttrib(edSelected.caption + '\settings.txt');
end;
Are you shure you have
  ExtractFilePath(Application.EXEName)+'\app\
folder?
If you do, what is it (copy/paste it here)?

Ah---You're right again. Too many '\'. Once I changed it, everythign worked right.

Thanks again!

RB
No problem, hope it turns out OK...

Cy.
It did. :) Many thanks.

I'm about to post another issue surrounding the ExtractFilePath(Application.EXEName) function and two OpenDialog components (They fail to find the proper path, sharing one path for both).

It seems you have plenty of experience and I'd like you to get the points. Since I'm not sure how the 'expert side' works, is there a way to post and hope you get the chance to answer?

RB
routerboy309,

Sorry I didn't get your last comment. When you post comment on answered question, I don't get any mail notification, so I really don't know when you posted something here.

Thank you for your trust in me, but you should give everybody a chance to give you your answer. But still, if you'd like your question to be targeted at me, probably the best way would be asking the question titled 'For Cynna: files followup' or something; that will soon get my attention ;) ....

And please remember, I tipically look only at the questions I get notified on by mail (except the new ones, of course).
Thanks!