Solved

File Shell Operations

Posted on 2001-07-27
6
1,031 Views
Last Modified: 2007-12-19
Hi, I'm trying to use the
 
 SHFileOperation function (in unit ShellAPI).

What I want to accomplish is:
1) SHMoveFile(SourceFile, TargetFile: String): Boolean;

2) SHCopyFile(SourceFile, TargetFile: String): Boolean;

This is my current code:

-------- BEGIN CODE SNIPPET ------------

function SHOper(Operator: Cardinal; const SourceFile, TargetFile: String): Boolean;
var
 Info: TSHFileOpStruct;

begin
 with Info do begin
  Wnd := frmSort.Handle;
  wFunc := Operator;
  pFrom := PChar(SourceFile);
  pTo := PChar(TargetFile);
  fFlags := FOF_ALLOWUNDO;
 end;

 Result := (SHFileOperation(Info) = 0);
end;

function SHCopyFile(const SourceFile, TargetFile: string): Boolean;
begin
 Result := SHOper(FO_COPY, SourceFile, TargetFile);
end;

function SHMoveFile(const SourceFile, TargetFile: string): Boolean;
begin
 Result := SHOper(FO_MOVE, SourceFile, TargetFile);
end;

-------- END CODE SNIPPET ------------

And, it works SOMETIMES!?!? ...I get the error:
An error occured in the filesystem (error no 1026),
but ONLY on some files (it seems almost random??).

I don't have any faulty disks/filesystems; it's the
same on all machines i've tried; and I can copy
the file in Windows Explorer, which i assume use the
very same function.

The CopyFile(); and MoveFile(); of Windows unit seems
to work perfect, on ALL files. But I need the l33t
progressbar and so on..

So what am I doing wrong?

I simply call my procedures like:

SHCopyFile('c:\autoexec.bat', 'c:\files\autoexec.bat')

I know the destination directory already exist (i did a ForceDirectories before the call).

What might be wrong? Please help me :]
0
Comment
Question by:blasse
  • 3
  • 2
6 Comments
 
LVL 5

Expert Comment

by:scrapdog
ID: 6328252
I don't know if this is what is causing your problem, but I noticed that you didn't clear the TSHFileOpStruct before you began populating it.  This means that the members of the structure you didn't assign (such as hNameMappings) will probably contain random garbage.

Do this:

FillChar(Info, sizeof(Info), 0);

before you start filling the Info structure.
0
 
LVL 5

Expert Comment

by:scrapdog
ID: 6328263
function SHOper(Operator: Cardinal; const SourceFile, TargetFile: String): Boolean;
var
Info: TSHFileOpStruct;

begin
FillChar(Info, sizeof(Info), 0);
with Info do begin
 Wnd := frmSort.Handle;
 wFunc := Operator;
 pFrom := PChar(SourceFile);
 pTo := PChar(TargetFile);
 fFlags := FOF_ALLOWUNDO;
end;

0
 
LVL 1

Accepted Solution

by:
malsoft earned 80 total points
ID: 6329648
Blasse,

The online help forgets to mention one vital piece of information! The filename(s) you pass into the ShellFile Operation are classed as a null separated list, terminating with a null character:

EG

For a single file this means a double null character:

SourceFile := 'Afile.txt'#0#0;

If you want to perform the operation on more than one file at once, this statement would follow this:

SourceFiles:= 'FirstFile.txt'#0'...'#0'LastFile.txt'#0#0

Taking that into account, I'd change your code to the following

-- Begin new code segment --

function SHOper(Operator: Cardinal; const SourceFile, TargetFile: String): Boolean;
var
Info: TSHFileOpStruct;
begin
  // Do a little initialisation first...
  FillChar(Info, sizeof(TSHFileOpStruct), 0);
  SourceFile := SourceFile + ''#0#0;
  TargetFile := TargetFile + ''#0#0;

  with Info do begin
    Wnd := frmSort.Handle;
    wFunc := Operator;
    pFrom := PChar(SourceFile);
    pTo := PChar(TargetFile);
    fFlags := FOF_ALLOWUNDO;
    end;
  Result := (SHFileOperation(Info) = 0);
end;

function SHCopyFile(const SourceFile, TargetFile: string): Boolean;
begin
  Result := SHOper(FO_COPY, SourceFile, TargetFile);
end;

function SHMoveFile(const SourceFile, TargetFile: string): Boolean;
begin
  Result := SHOper(FO_MOVE, SourceFile, TargetFile);
end;

-- End new code segment --

The reasoning behind it actually working sometimes, is that occasionally, the memory area in which the filenames are stored actually contain the proper double-null terminator.

Regards,
Mark Allott
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:blasse
ID: 6329701
Hmm, they really should mention that in the Win32.hlp :]
0
 
LVL 5

Expert Comment

by:scrapdog
ID: 6330494
I was wondering about that too...the Win32 Help DOES mention that, but in any Delphi example code (such as in the Delphi 4 Developer's Guide), it ignores this fact.
0
 
LVL 1

Expert Comment

by:malsoft
ID: 6330937
To be honest, it's been a while since I looked at the latest Win32.hlp file for that function. You are correct, it does now state that the list is null-separated! When I first encountered the problem using Delphi 3, the help wasn't much use at all and MSDN didn't have the correct information either (that is now correct as well).
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
proper way to parse url in delphi 2 163
error 1.1 400 Bad request idhttp delphi 18 55
tidtcpserver connection lost handle 2 71
Create a path if not exists 7 69
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
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…
As a trusted technology advisor to your customers you are likely getting the daily question of, ‘should I put this in the cloud?’ As customer demands for cloud services increases, companies will see a shift from traditional buying patterns to new…

895 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

15 Experts available now in Live!

Get 1:1 Help Now