Copy a File that is in use/locked by another program

Hi

I want to know if there is a method, with delphi, to copy a file that is in use/locked by another application: I can make some examples:

I've tried to copy some types of locked files, like:

1. A Microsoft Access .mdb file opened by access with exclusive access

2. Some .aspx, .dll files of an opened Visual Studio.net solution

3. The Outlook.pst file while Microsoft Outlook is opened


I've tried with the following methods:

1. Using Windows API function (ShellOp)

2. Using CopyFile e CopyFileW functions

3. Using FileStream, MemoryStream, FileBlock, FileSeek Methods

4. Using Assign File Method


None of theese methods has worked with the Outlook.pst file.

The windows API funtion works for all, but not for Outlook.pst, but has a very bad issue: it prompts the user if there is an error or a overwrite conflict (also if I've set the right flags for NO ERROR UI and NO PROMPTS/NI CONFIRMATION).

The only method for copy the Outlook.pst file is to open it with the notepad (it works !) and then save the file to another location (!?). So copy that file is possible! How with delphi ? (I can accept also a c++ solution, i could make an external .dll)

Thanks
enumaelisAsked:
Who is Participating?
 
hutelihutConnect With a Mentor Commented:
Maybe you can use this article:

http://www.delphicorner.f9.co.uk/articles/misc4.htm

Here are one of the examples from the page:

procedure CopyFile(const FileName, DestName: TFileName);
var
  CopyBuffer: Pointer; { buffer for copying }
  TimeStamp, BytesCopied: Longint;
  Source, Dest: Integer; { handles }
  Destination: TFileName; { holder for expanded destination name }
const
  ChunkSize: Longint = 8192; { copy in 8K chunks }
begin
  Destination := ExpandFileName(DestName); { expand the destination path }
  if HasAttr(Destination, faDirectory) then { if destination is a directory... }
    Destination := Destination + '\' + ExtractFileName(FileName); { ...clone file name }
  TimeStamp := FileAge(FileName); { get source's time stamp }
  GetMem(CopyBuffer, ChunkSize); { allocate the buffer }
  try
    Source := FileOpen(FileName, fmShareDenyWrite); { open source file }
    if Source < 0 then raise EFOpenError.Create(FmtLoadStr(SFOpenError, [FileName]));
    try
      Dest := FileCreate(Destination); { create output file; overwrite existing }
      if Dest < 0 then raise EFCreateError.Create(FmtLoadStr(SFCreateError, [Destination]));
      try
        repeat
          BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize); { read chunk }
          if BytesCopied > 0 then { if we read anything... }
            FileWrite(Dest, CopyBuffer^, BytesCopied); { ...write chunk }
        until BytesCopied < ChunkSize; { until we run out of chunks }
      finally
        FileClose(Dest); { close the destination file }
      end;
    finally
      FileClose(Source); { close the source file }
    end;
  finally
    FreeMem(CopyBuffer, ChunkSize); { free the buffer }
  end;
end;
0
 
MadshiCommented:
If Notepad can open the file, then CopyFile must work, too.
0
 
Sergio_HdezCommented:
Have you opened with a TFileStream.create with the ReadOnly falg to copy it fo another Stream?

Something like this (may not compile at first, not tested in delphi):

F2:= TMemoryStream.Create;
F1:= TFileStream.Create( OldFileName,  fmReadOnly );
F2.CopyFrom(F1, 0);
F1.free;
F2.SaveToFile(NewFileName);
F2.free;

If notepad opens it, it has to be done like this or similar.
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

 
MadshiCommented:
When using TFileStream you have to add fmShareDenyNone to the flags. But the CopyFile API should work just fine, as well.
0
 
enumaelisAuthor Commented:

Does not function... :-)

Here the code of my function:

function CopyFileWithFileStream(sourcefilename, targetfilename: String ): boolean;
Var
  S: TFileStream;
  T: TMemoryStream;
  bReturn:Boolean;
Begin
bReturn:=False;

  try
   //With fmShareDenyNone I don't have the open error (so ok Madshi)
    S := TFileStream.Create( sourcefilename, fmOpenRead or fmShareDenyNone );
  except
    Result :=False;
    Exit;
  end;

  try
  //The following row cause an Stream Read Error
  T.CopyFrom(S, 0);
  S.free;
  T.SaveToFile(targetfilename);
  T.free;

  //The following row raise an exception EFopenError
  //T := TFileStream.Create( targetfilename , fmOpenWrite or fmCreate );
  except
    Result :=False;
    Exit;
  end;

[..............]


Any idea ?
0
 
MadshiCommented:
(1) When calling T.CopyFrom you have not yet created a T instance.
(2) Use either fmOpenWrite or fmCreate, but not both.

Why are not using CopyFile? Would be much easier!
0
 
enumaelisAuthor Commented:

I have fixed the function, but the problem is the same:


function CopyFileWithFileStream(sourcefilename, targetfilename: String ): boolean;
Var
  S: TFileStream;
  T: TMemoryStream;
  bReturn:Boolean;
Begin
bReturn:=False;

  try
    S := TFileStream.Create( sourcefilename, fmOpenRead or fmShareDenyNone);
  except
    Result :=False;
    Exit;
  end;

  try
    showmessage(IntToStr(s.Size));        //This return the exact size (!)
    T := TMemoryStream.Create();
    T.CopyFrom(S, 0);                            //This raise an exception
    S.free;
    T.SaveToFile(targetfilename);
    T.free;
  except
    Result :=False;
    Exit;
  end;

Result:=bReturn;

End;


I cannot use CopyFile: this function doesn't work with locked files...


0
 
MadshiCommented:
If CopyFile doesn't work, then Notepad can't open it, either. And then your stream stuff won't work, either. It's all the same.
0
 
enumaelisAuthor Commented:

Also you can try simply this:

Open Outlook

Try to copy the file outlook.pst with copyfile function or stream functions: you'll have an error in any case.

Try, with windows right click menu, to do "Open With..." and then select Notepad: the notepad opens the file ! And you can save the file with another name !
0
 
enumaelisAuthor Commented:

Nobody can resolve my problem ?

I understand...

It's very very strange....

Ok bye...
0
 
MadshiCommented:
I've just tried it with Outlook 2002. And you know what? CopyFile worked just fine - just as I said.
0
 
enumaelisAuthor Commented:
I've tried with outlook xp... I don't know if there is some differences...

When you have tried outlook was opened ?
0
 
MadshiCommented:
Yes, Outlook was opened. Please try CopyFile again. If Notepad can read the file, CopyFile *MUST* work.
0
 
MadshiCommented:
Perhaps you had the parameters of CopyFile in the wrong order?
0
 
enumaelisAuthor Commented:

Nothing :-( :-(

0
 
MadshiCommented:
How does your CopyFile code look like? Does CopyFile return true or false? If it returns false, what does GetLastError say?
0
 
enumaelisAuthor Commented:

CopyFile(PChar(sSourceFile), PChar(sDestFile), False)

The function return false. No exception is raised.

GetLastError return that the file is in use or locked by another process, or a similar message...

If it can interest, my operating system is Win 2000 Professional SP4 with NTFS filesystem.

And i have seen another thing: also if the notepad can open the file and save it to a new file, the new file result "corrupted": outlook don't recognize it anymore...

I'm beginning to think that this thing is not possible...

I would that anyone give me a portion of code that functions with every file.
I ask too much, that's right? :-)  :-)

Thanks in any case for your patience. :-)

P.S. : and sorry for my bad english :-)

0
 
fibdevCommented:
I haven't read this whole thread, but have you tried setting the file attributes before you copy the file?

procedure TForm1.DoCopy(Source, Dest: string);
var
  SrcFile : Integer;
  DestFile : Integer;
  S : string;
  RetCode : Longint;
  OpenFileBuf   : TOFStruct;
  FName : array[ 0..255 ] of Char;
begin
FileSetAttr(Source, not SysUtils.faReadOnly);  
StrPCopy( FName, Source );
  SrcFile := LZOpenFile( FName, OpenFileBuf, of_Read );
  StrPCopy( FName, Dest );
  DestFile := LZOpenFile( FName, OpenFileBuf, of_Create );

  RetCode := LZCopy( SrcFile, DestFile );
  if RetCode >= 0 then
  begin
    LZClose( SrcFile );
    LZClose( DestFile );
  end
  else
  begin
    Str( RetCode, S );
    MessageDlg( 'Could not copy ' + Source + ' to ' +
                Dest + #13 + 'Error Code = ' + S, mtError, [mbOk], 0 );
  end;
end;
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.