Solved

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

Posted on 2004-04-11
21
5,116 Views
Last Modified: 2007-12-19
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
0
Comment
Question by:enumaelis
21 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 10801361
If Notepad can open the file, then CopyFile must work, too.
0
 
LVL 6

Expert Comment

by:Sergio_Hdez
ID: 10804120
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
 
LVL 20

Expert Comment

by:Madshi
ID: 10804130
When using TFileStream you have to add fmShareDenyNone to the flags. But the CopyFile API should work just fine, as well.
0
 

Author Comment

by:enumaelis
ID: 10812125

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
 
LVL 20

Expert Comment

by:Madshi
ID: 10812158
(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
 

Author Comment

by:enumaelis
ID: 10813875

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
 
LVL 20

Expert Comment

by:Madshi
ID: 10814189
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
 

Author Comment

by:enumaelis
ID: 10815033

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
 

Author Comment

by:enumaelis
ID: 10820995

Nobody can resolve my problem ?

I understand...

It's very very strange....

Ok bye...
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 20

Expert Comment

by:Madshi
ID: 10821388
I've just tried it with Outlook 2002. And you know what? CopyFile worked just fine - just as I said.
0
 

Author Comment

by:enumaelis
ID: 10821679
I've tried with outlook xp... I don't know if there is some differences...

When you have tried outlook was opened ?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 10821811
Yes, Outlook was opened. Please try CopyFile again. If Notepad can read the file, CopyFile *MUST* work.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 10821814
Perhaps you had the parameters of CopyFile in the wrong order?
0
 

Author Comment

by:enumaelis
ID: 10821986

Nothing :-( :-(

0
 
LVL 20

Expert Comment

by:Madshi
ID: 10822028
How does your CopyFile code look like? Does CopyFile return true or false? If it returns false, what does GetLastError say?
0
 

Author Comment

by:enumaelis
ID: 10823150

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
 
LVL 3

Expert Comment

by:fibdev
ID: 10847323
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
 

Accepted Solution

by:
hutelihut earned 125 total points
ID: 11136650
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
PDF library for Delphi 2 89
FMX enumerated colours 2 72
Delphi application Soap connection 5 79
find a node in VST 2 46
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
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…
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.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

707 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

14 Experts available now in Live!

Get 1:1 Help Now