Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi "SHFileOperation" beschwert sich bei geöffneten Dateien (https://www.delphipraxis.net/78448-shfileoperation-beschwert-sich-bei-geoeffneten-dateien.html)

irata 5. Okt 2006 09:05


"SHFileOperation" beschwert sich bei geöffneten Da
 
Hallo,

ich habe ein kleines Delphi Programm geschrieben, welches alle paar Minuten ein Verzeichnis auf neue Dateien überprüft, und wenn welche da sind, werden diese per Indy "TIdMultiPartFormDataStream" an einen Web-Server übertragen werden.

Nun will ich natürlich nur Dateien übertragen, die auch wirklich komplett geschrieben wurden. Bei grösseren Dateien kann dies ja einen Moment dauern. Daher verschiebe ich die Dateien aus dem Verzeichnis erst in ein Temp-Verzeichnis und von da aus auf den Web-Server. Zum Verschieben der Dateien benutzte ich "SHFileOperation". Mit

sh.fFlags := fof_Silent or FOF_NOCONFIRMATION or FOF_NOERRORUI;

Allerdings erscheint trotzdem immer eine Message-Box, mit "<datei> kann nicht kopiert werden: Die Datei wird von einer anderen Person bzw. einem anderen Programm verwendet." Und genau diesen Fehler möchte ich gerne umgehen. Falls es zu dem Fehler kommt, soll einfach eine Exception ausgelöst werden und dann mit der nächsten Datei fortgefahren werden. Und diese Datei dann im nächsten Schritt übertragen werden. Momentan blockiert das ganze Programm, solange die Fehlermeldung nicht bestätigt wurde...

Hat da irgendwer einen Tipp!?!?!

Danke und Gruss

Tobias

Go2EITS 5. Okt 2006 09:23

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Tobias zeige mal die Procedure Code mit der
Zitat:

sh.fFlags := fof_Silent or FOF_NOCONFIRMATION or FOF_NOERRORUI;
Eigentlich darf keine Anzeige kommen, Dein Fehler liegt m.E. woanders. Ich glaube es liegt evtl. am Timer. Ach hier mal den Code, bitte.

irata 5. Okt 2006 09:38

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Hallo,

hier die "Move" Routine:
Delphi-Quellcode:
function TFmMain.MoveFile(const AOldName, ANewName: string ): boolean;
var
  sh: TSHFileOpStruct;
begin
  try
    FillChar(sh, sizeOf(TSHFileOpStruct), 0);
    sh.Wnd   := Application.Handle;
    sh.wFunc := fo_Move;
    sh.pFrom := PChar(AOldName + #0);
    sh.pTo   := PChar(ANewName + #0);
    sh.fFlags := fof_Silent or FOF_NOCONFIRMATION or FOF_NOERRORUI;
    Result   := ShFileOperation(sh) = 0;
  except
    Result   := false;
  end;
end;
und hier die Timer Routine:
Delphi-Quellcode:
procedure TFmMain.ExportTimerTimer(Sender: TObject);
begin
  if ( not FmOption.checkOptions( CheckExport ) ) then
    LogExport( 'Options empty, please check!' )
  else if ( not FmOption.RegExpEnable ) then

  else
    DoExport();

end;

procedure TFmMain.doExport();
var
  Search:  TSearchRec;
  FileList: TStringList;
  FilePath: String;
  i:       integer;
begin
  if ( DoingExport ) then

  else
  begin
    DoingExport  := true;
    ExportCounter := ExportCounter + 1;
    FileList     := TStringList.Create();

    if ( FindFirst( FmOption.RegExpPath + '\*.*', faAnyFile, Search ) = 0 ) then
    begin
      try
        repeat
          if ( (Search.Name <> '.') and
               (Search.Name <> '..')) then begin
            FileList.Add( Search.Name );
          end;
        until FindNext( Search ) <> 0;
      finally
        FindClose( Search );
      end;
    end;

    FileList.Sort();

    for i := 0 to FileList.Count - 1 do
    begin
      FilePath := FmOption.RegExpPath + '\' + FileList[i];
      exportFile( FilePath, true );
    end;

    DoingExport := false;

    if (ExportCounter mod 10 = 0 ) then
      LogExport( '--- Mark ---' );
  end;
end;

procedure TFmMain.exportFile( const filepath: string;const remove: boolean );
var
  FileName,
  FileTmp,
  Path:       string;
  Stream:     TIdMultiPartFormDataStream;
  Resp:       TMemoryStream;
  result:     Boolean;
begin
  filename := ExtractFileName( filepath );
  Stream  := TIdMultiPartFormDataStream.Create;
  Resp    := TMemoryStream.Create();
  result  := true;
  Resp.Clear();
  Resp.Seek( 0, soFromBeginning );

  try
    if ( remove ) then
    begin
      Path    := FmOption.RegTmpPath;
      FileTmp := FmOption.RegTmpPath + '\' + FileName;
      if ( not MoveFile( FilePath, FileTmp ) ) then
      begin
        LogExport( '[Error] Can''t move file ' + FilePath + ' to ' + FileTmp );
        result := false;
      end;
    end
    else
    begin
      Path    := ExtractFilePath( FilePath );
      FileTmp := FilePath;
    end;

    if ( result ) then
    begin
      chdir( Path );
      Stream.AddFile( 'file', FileName, 'text/plain' );

      HTTPClient.Request.Username := FmOption.RegUsername;
      HTTPClient.Request.Password := FmOption.RegPassword;
      HTTPClient.Request.BasicAuthentication := true;
      HTTPClient.Post( 'https://' + FmOption.RegServer + '/files/import',
                       Stream, Resp );

      lbExpLastFile.Caption := 'Last filename: ' + FileName;
      lbExpLastFile.Width  := 220;

    end;
  except
    on e : exception do
    begin
      LogExport( '[Error] sending file ' + FileName );
      result := false;
    end;
  end;

  Stream.Destroy();
  Resp.Seek(0,soFromBeginning);
  Resp.Free;

  if ( result ) then
    if ( remove and not RemoveFile( FileTmp ) ) then
      LogExport( '[Error] Can''t delete file ' + FileTmp )
    else
      LogExport( 'Export: ' + FileName )
  else
    if ( remove and not MoveFile( FileTmp, FilePath ) ) then
      LogExport( '[Error] Can''t export file and move file ' + FileTmp + ' to ' + FilePath )
    else
      LogExport( '[Error] Can''t export file ' + FileName );
end;
Falls noch die anderen Proceduren benötigt werden nur fragen ;-)

Danke und Gruss

Tobias

SirThornberry 5. Okt 2006 09:58

Re: "SHFileOperation" beschwert sich bei geöffnete
 
also das verschieben finde ich recht unpraktisch. Versuche doch einfach die Dateien exclusiv zu öffnen. Schlägt dies fehl ist die Datei in Verwendung. Wenn es nicht fehl schlägt kannst du die Datei direkt hochladen.

irata 5. Okt 2006 10:08

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Zitat:

Zitat von SirThornberry
also das verschieben finde ich recht unpraktisch. Versuche doch einfach die Dateien exclusiv zu öffnen. Schlägt dies fehl ist die Datei in Verwendung. Wenn es nicht fehl schlägt kannst du die Datei direkt hochladen.

Ähm... das hört sich gut an! Wie öffnet man eine Datei exclusiv? :?

Bin nicht so der Delphi Crack... Programmiere normal meist in Perl.

MuTzE 5. Okt 2006 10:11

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Probiers mal damit:

Delphi-Quellcode:
function IsFileInUse(Path: string): boolean;
var
  hFile: THandle;
begin
  Result := False;
  if not FileExists(Path) then
   Exit;
  hFile := CreateFile(pchar(Path), GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE,
                      0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  Result := hFile = INVALID_HANDLE_VALUE;
  if not Result then
   CloseHandle(hFile);
end;

Go2EITS 5. Okt 2006 10:42

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Nimm mal Mutzes Vorschlag.
Mit Deiner Timerroutine komme ich nicht klar. Der Timer hat generell eine Schwäche. Wenn er usgeführt wird, und die Procedure nicht fertig mit kopieren ist, wird der Timer, ohne Rücksicht auf die ausgeführte Proceduren/Funktionen wieder nach der abgelaufenen Zeit von vorne beginnen. Wenn dann die Aktionen noch im Gange sind, wie z. B. kopieren, bekommst Du Probleme.
Lösung:
In der Timer Routine am Anfang:
Timer1.Enabled:=False;

und am Ende der Timer Routine:
Timer1.Enabled:=True;

Wirkt Wunder! Und wenn Du noch ein IsFileInUse(Path) verwendest, bist Du auf der sicheren Seite:
Delphi-Quellcode:
// Natürlich ist Timer1.enabled:=False; bei Dir in der Procedure zuvor wie oben gesetzt!
if IsFileInUse(Path) then
   begin
   Timer1.enabled:=True; //Sonst bleibt der Timer aus...
   Exit; //Raus aus der Procedur/Function
   end;
Das ist die Grundlage, dass Dein Timer auch funktionert.

Und? Klappts?

irata 5. Okt 2006 11:58

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Danke für den guten Tipp. Jetzt klappt es!

Obwohl es
Delphi-Quellcode:
Result := hFile <> INVALID_HANDLE_VALUE;
heissen müsste!

Und das mit dem Timer disablen könnte ich auch noch testen.


Danke an alle für die guten Tipps!!!

Christian Seehase 5. Okt 2006 12:05

Re: "SHFileOperation" beschwert sich bei geöffnete
 
Moin irata,

Zitat:

Zitat von irata
Obwohl es
Delphi-Quellcode:
Result := hFile <> INVALID_HANDLE_VALUE;
heissen müsste!

nein, muss es nicht, denn die Funktion heisst ja schliesslich "IsFileInUse", was genau dann der Fall ist, wenn man kein gültiges Handle erhält. ;-)

Go2EITS 5. Okt 2006 12:11

Re: "SHFileOperation" beschwert sich bei geöffnete
 
@Seehase
Na da bin aber froh, wunderte mich schon.

@irata
Na das mit dem Timer erspart Ärger: Du musstest sonst alle Proceduren/Functionen, die im Timer aufgerufen werden, prüfen, ob sie noch in "arbeit" sind. Alles viel zu schwammig. Besser: Timer aus, alles abarbeiten, Timer an. Fertig. Ganz einfach.

CU! Go2EITS


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:31 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz