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 löst Exception aus ?! (https://www.delphipraxis.net/46892-shfileoperation-loest-exception-aus.html)

Orakel-von-Delphi 2. Jun 2005 14:23


SHFileOperation löst Exception aus ?!
 
Delphi-Quellcode:
.
.

function CopyDir(DirFrom, DirTo: string; Flags : integer = 0; bErrorHandler : boolean = True) : integer;
var
  shellinfo: TSHFileOpStruct;
  FromBuf, ToBuf : Array [0..255] of char;
begin
  If Not DirectoryExists(DirTo) Then
    begin
      Result := -1;
      Exit;
    end;

  Fillchar(shellinfo, Sizeof(shellinfo), 0 );
  FillChar(FromBuf,       Sizeof(FromBuf),       0 );
  FillChar(ToBuf,         Sizeof(ToBuf),         0 );
  StrPCopy(FromBuf,       DirFrom);
  StrPCopy(ToBuf,         DirTo);

  with shellinfo do
  begin
    Wnd   := 0;
    wFunc := FO_COPY;
    pFrom := @FromBuf;
    pTo   := @ToBuf;
    fFlags :=         FOF_SIMPLEPROGRESS or
              FOF_NOCONFIRMATION;
  end;

  Repeat
     try
      Result := SHFileOperation(shellinfo);
      SHFreeNameMappings(Cardinal(shellinfo.hNameMappings));
     except
      Result := GetLastError;
     end;
     if Not bErrorHandler then Exit;
     if Result <> 0 then
       begin
        if MessageDlg(Format('Das Verzeichnis'#13#10#13#10
                           + '''%s'''#13#10#13#10
                           + 'kann nicht nach'#13#10#13#10 
                           + '''%s'''#13#10#13#10
                           + 'kopiert werden.'#13#10#13#10
                           + 'Grund: %s'#13#10#13#10
                           + 'Soll der Vorgang erneut versucht werden ?'#13#10#13#10
                           + 'Wenn Sie ''Abbrechen'' drücken, muss das Verzeichnis'#13#10
                           + 'oder die Dateien manuell kopiert werden !', [DirFrom, DirTo, GetFormatErrorMessage(Result)]),
                           mtWarning, [mbAbort, mbRetry], -1) <> mrRetry then
           break;
       end;
  until Result = 0;
end;

.
.

Usage:

.
.
CopyDir(IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*', sTemp);
.
.
Die Funktion CopyDir wird im Programm an verschieden Stellen verwendet. Beim Kopiervorgang eines größeren Verzeichnisses (ca. 6,5 MB in 162 Dateien) löst SHFileOperation hin und wieder eine Exception aus. Entweder Fehler 7 (The storage control blocks were destroyed) oder der Thread in dem der Vorgang abläuft stürzt ganz ab ohne einfangen der Exception. Alleine das wundert mich schon, da ein try .. except Block um die Funktion gebaut ist.

http://bugtrack.sporleder.de/image/installer_7.GIF

Weiß jemand Rat ? Googlen hat mir jedenfalls nicht geholfen :(

Orakel-von-Delphi 3. Jun 2005 17:32

msi-Installer ?!
 
Kann es evtl. sein, dass das Problem von dem msi-Installer verursacht wird ? Mein Programm startet nämlich 2 Installationsprogramme mit ShellExecAndWait bevor dieser Fehler auftritt. Wenn man mein angebrochenen Install dann erneut startet, haben die beiden msi-Installer nichts mehr zu installieren und mein Programm läuft Fehler durch.

Luckie 3. Jun 2005 17:33

Re: SHFileOperation löst Exception aus ?!
 
Tja, probier es aus.

Christian Seehase 3. Jun 2005 21:27

Re: SHFileOperation löst Exception aus ?!
 
Moin Orakel,

nur zur Info:
Der MSI-Installer kann zwar theoretisch mehrmals gleichzeitig laufen, da es aber Tabllen gibt, die nicht von mehreren Instanzen gleichzeitig genutzt werden können, kann es leicht zu Problemen kommen.

Orakel-von-Delphi 11. Okt 2005 07:14

Re: SHFileOperation löst Exception aus ?!
 
Ich habe jetzt alle Aufrufe mit Synchronize in den Hauptthread verlegt und die Aufrufe des MSI-Installers testweise ausgeschaltet. Der Fehler tritt immer noch auf !!! Was kann den bloß falsch sein ??? Das Problem tritt auf allen Computern auf, die ich zur Verfügung habe (Win2000, WinXP) und ist unabhängig von der Größe des verfügbaren Speichers.

Wie kann man dieses Problem lösen ??? Sieht schlecht aus, wenn der Kunde sein neu erworbenes Produkt installiert und gleich die oben genannte Fehlermeldung auftritt ...

shmia 11. Okt 2005 08:41

Re: SHFileOperation löst Exception aus ?!
 
Also mir gefällt das Füllen von TSHFileOpStruct nicht.
Du hast
1.) die Struktur nicht mit 0 vorbelegt
2.) feste Puffer benutzt, die sehr leicht überschrieben werden können. => Zerstörung des Stacks
Besser so:
Delphi-Quellcode:
FillChar(shellinfo, SizeOf(shellinfo), #0); // zuerst mit #0 füllen

DirFrom := DirFrom+#0+#0
DirTo  := DirTo+#0#0;
 
with shellinfo do
begin
  Wnd := GetDesktopWindow;
  wFunc := FO_COPY;
  pFrom := PChar(DirFrom);
  pTo := PChar(DirTo);
  fFlags := FOF_SIMPLEPROGRESS or FOF_NOCONFIRMATION;
end;

Orakel-von-Delphi 12. Okt 2005 09:45

Re: SHFileOperation löst Exception aus ?!
 
Danke für den Tipp, aber

der Buffer wurde bereits initialisiert

Delphi-Quellcode:
Fillchar(shellinfo, Sizeof(shellinfo), 0 );
und die statischen Variablen habe ich entfernt

Delphi-Quellcode:
  with shellinfo do
  begin
    Wnd   := 0;
    wFunc := FO_COPY;
    pFrom := PChar(DirFrom + #0 + #0);
    pTo   := PChar(DirTo + #0 + #0);
    fFlags := FOF_SIMPLEPROGRESS or
                   FOF_NOCONFIRMATION;

         .
         .
Leider ohne Erfolg:

http://bugtrack.sporleder.de/image/ERROR_7.jpg

Hast sonst noch jemand eine Idee ???

Olli 12. Okt 2005 10:16

Re: SHFileOperation löst Exception aus ?!
 
Statische Variablen gibt es in Delphi nicht, meint ihr Literale oder was meint ihr?

An dieser Stelle solltest du definitiv einen String mit deinen Daten vorbelegen (wie oben gesehen) und dann den String bei pFrom und pTo in folgender Form zuweisen.
Delphi-Quellcode:
  with shellinfo do
  begin
    Wnd   := 0;
    wFunc := FO_COPY;
    pFrom := @DirFrom[1];
    pTo   := @DirTo[1];
    fFlags := FOF_SIMPLEPROGRESS or
                   FOF_NOCONFIRMATION;

         .
         .
Ansonsten werde ich mal kurz drüberschauen.

Nachtrag:
Was soll das denn?
Delphi-Quellcode:
  FillChar(FromBuf,       Sizeof(FromBuf),       0 );
  FillChar(ToBuf,         Sizeof(ToBuf),         0 );
Bei integralen Datentypen weist man immer Werte zu, wozu nullst du denn einen Pointer aus? Oder was ist FromBuf und ToBuf? Wenn es Strings sind, ist es komplett falsch.

mirage228 12. Okt 2005 10:33

Re: SHFileOperation löst Exception aus ?!
 
Hi,

mir fällt dieser Ausdruck bei Dir auf:
Delphi-Quellcode:
SHFreeNameMappings(Cardinal(shellinfo.hNameMappings));
Also ich glaube nicht, dass Du diesen verwenden muss, wenn Du keine Name Mappings verwendest...

Ansonsten kannst Du das kopieren ja mal mit meinerSHFileOperation Wrapper Unit ausprobieren.

mfG
mirage228

Orakel-von-Delphi 12. Okt 2005 10:45

Re: SHFileOperation löst Exception aus ?!
 
@Olli:

FromBuf und ToBuf ist in der ursprünglichen Variante verwendet worden (array [0..255] of char).

@mirage228:

Ich weiß, dass ich keine Mappings verwende. War auch nur ein Versuch, aber der Fehler tritt mit oder ohne SHFreeNameMappings auf :(

Olli 12. Okt 2005 11:45

Re: SHFileOperation löst Exception aus ?!
 
So, habe es mir angeguckt und mit dem Lesen der Doku scheinst du's ja nicht gerade zu halten :zwinker:

Du kannst mir sicher beispielsweise plausibel machen, wieso du SHFreeNameMappings() verwendest?!

Und wie du Typen (DWORD und Integer zB) und Bedeutungen durcheinanderwürfelst ist eine wahre Freude. So benutzt du Integer als Rückgabetyp, weist aber einen GetLastError()-Wert zu, wobei dieser DWORD ist - bei nichtvorhandenem Verzeichnis wird's -1. Putzigerweise weist du dem gleichen Rückgabewert auch noch das Ergebnis von SHFileOperation() zu, obwohl dort eindeutig steht, daß 0 bedeutet erfolgreich (entspricht GetLastError) und alles andere bedeutet nicht erfolgreich. Dort steht aber nirgends, daß der Rückgabewert ein Fehlercode ist!

Probiere mal, ob folgendes funktioniert.
Delphi-Quellcode:
function CopyDir(DirFrom, DirTo, ProgessTitle: string; Flags: Integer = 0; bErrorHandler: Boolean = True): DWORD;
var
  shellinfo: TSHFileOpStruct;
begin
  // Bail out if the target directory does not exist
  if not DirectoryExists(DirTo) then
  begin
    Result := ERROR_PATH_NOT_FOUND;
    Exit;
  end;

  // Initialize structure
  ZeroMemory(@shellinfo, sizeof(shellinfo));
  // Finalize the strings to be appropriately terminated
  DirFrom := DirFrom + #0#0;
  DirTo := DirTo + #0#0;

  with shellinfo do
  begin
    Wnd := GetDesktopWindow();
    wFunc := FO_COPY; // Copy action
    pFrom := @DirFrom[1]; // Source file(s)/directories
    pTo := @DirTo[1]; // Target directory
    fFlags := FOF_SIMPLEPROGRESS or FOF_NOCONFIRMATION or Flags;
    Flags := fFlags; // For cleaner code
    lpszProgressTitle := @ProgessTitle[1];
  end;

  try
    while ((SHFileOperation(shellinfo) <> NO_ERROR) and (bErrorHandler)) do
    begin
      if MessageDlg(Format('Das Verzeichnis'#13#10#13#10
        + '''%s'''#13#10#13#10
        + 'kann nicht nach'#13#10#13#10
        + '''%s'''#13#10#13#10
        + 'kopiert werden.'#13#10#13#10
        + 'Grund: %s'#13#10#13#10
        + 'Soll der Vorgang erneut versucht werden ?'#13#10#13#10
        + 'Wenn Sie ''Abbrechen'' drücken, muss das Verzeichnis'#13#10
        + 'oder die Dateien manuell kopiert werden !',
        [PChar(DirFrom), PChar(DirTo), GetFormatErrorMessage(GetLastError())]),
        mtWarning, [mbAbort, mbRetry], -1) <> mrRetry then
        break;
    end;
  finally
    if (Flags and FOF_WANTMAPPINGHANDLE <> 0) then
      SHFreeNameMappings(THandle(shellinfo.hNameMappings));
    Result := GetLastError();
  end;
end;
PS: Sorry, hat etwas länger gedauert wegen Mittagbrot ;)

Nachtrag: :oops: Fehlerchen im formatierten String korrigiert ...

Orakel-von-Delphi 12. Okt 2005 12:23

Re: SHFileOperation löst Exception aus ?!
 
@Olli: Since try, aber auch mit Deinem Coding tritt der Fehler noch auf.

Zitat:

Integer -2147483648..2147483647 32 Bit, mit Vorzeichen

.
.

DWORD (Double Word) repräsentiert einen vorzeichenlosen 4-Byte-Integer. Er wird primär für Windows-API-Aufrufe eingesetzt. Die C++ Version ist nur unter Windows verfügbar.
Ich konnte mir auch nicht vorstellen, dass nur wg. dem Unterschied signed/unsigned der Fehler in Erscheinung tritt, da die Länge der Variablen gleich ist :)

Ich bitte oben noch mal genau zu lesen: Das Problem tritt nicht immer auf ! Aber immer beim letzten Kopiervorgang mit über 100 Dateien und ca. 6.5 MB. Die Funktion "CopyDir" wir vorher min. 5x ohne Probleme aufgerufen.

Olli 12. Okt 2005 12:33

Re: SHFileOperation löst Exception aus ?!
 
Zitat:

Zitat von Orakel-von-Delphi
Zitat:

Integer -2147483648..2147483647 32 Bit, mit Vorzeichen

.
.

DWORD (Double Word) repräsentiert einen vorzeichenlosen 4-Byte-Integer. Er wird primär für Windows-API-Aufrufe eingesetzt. Die C++ Version ist nur unter Windows verfügbar.

Das ist, denke ich, allen hier klar. Was du mir mit der C++-Version sagen willst, weiß ich noch nicht ... :roll:

Zitat:

Zitat von Orakel-von-Delphi
Ich konnte mir auch nicht vorstellen, dass nur wg. dem Unterschied signed/unsigned der Fehler in Erscheinung tritt, da die Länge der Variablen gleich ist :)

Die meisten Buffer-Overflow-Löcher basieren auf solchen Dingen ... obwohl es hier unwahrscheinlich war. Dein Code enthielt aber formale Fehler, auf die ich dich aufmerksam machen wollte. Ob es deswegen klappt ist erstmal zweitrangig, denn da können wir uns jetzt dran machen ;)

Zitat:

Zitat von Orakel-von-Delphi
Ich bitte oben noch mal genau zu lesen: Das Problem tritt nicht immer auf ! Aber immer beim letzten Kopiervorgang mit über 100 Dateien und ca. 6.5 MB. Die Funktion "CopyDir" wir vorher min. 5x ohne Probleme aufgerufen.

In diesem Falle sieht es für mich nach 2 Möglichkeiten aus:
1. Die API-Funktion ist fehlerhaft implementiert - dann kannst du nichts machen.
2. Das was bei dir drumherum steht ist von Relevanz und kann das verursachen. In diesem Fall mußt du wohl den Code rausrücken. Denn keiner hier kann deinen Fehler sonst nachvollziehen.

Orakel-von-Delphi 12. Okt 2005 14:59

Re: SHFileOperation löst Exception aus ?!
 
http://bugtrack.sporleder.de/image/ordner_lnk_datei.JPG

Problem solved !

Ich habe mir jetzt mal den Order angesehen, der kopiert wird. Man glaubt wirklich kaum, was die Ursache ist :wall:

Im Order existiert eine html-Datei, die mit einem Ordner verküpft ist (was man erst sieht, wenn man versucht eines von beiden umzubenennen). Der Witz an der Sache ist, dass die Dateien für den Installer auf einer Server-Platte stehen und mit einem Command-Batch (mehrere xcopy-Befehle) auf die lokale Platte kopiert werden. Von dort aus wird dann der eigentliche Installer zusammengestellt und wiederum auf eine andere Server-Platte kopiert. Bei diesen Aktionen wandert die blöde Verknüpfung Datei-Ordner immer mit. Und genau da liegt auch die Ursache für den Fehler:

Der Ordner wurde mit

Delphi-Quellcode:
CopyDir(IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*', sTemp);
kopiert. Dabei kommt SHFileOperation offenbar in eine Rekursion, weil es so dämlich programmiert worden ist die betriebssystemeigenen Eigenarten des Dateisystems zu erkennen. Dabei werden dann wohl die "Speichersteuerblöcke" zerstört.

Workaround:

Delphi-Quellcode:
CopyDir(IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*.pdf' + #0 +
                 IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*.htm' + #0 +
                 IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*.html' + #0 +
                 IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*.doc' + #0 +
                 IncludeTrailingPathDelimiter(GetCurrentDir) + DIRDATA + '\Dokumentation\*.rtf',
                 sTemp);
Fertig :thumb:

mirage228 12. Okt 2005 15:43

Re: SHFileOperation löst Exception aus ?!
 
Hi,

hast Du in diesem Fall mal den FOF_NO_CONNECTED_ELEMENTS (siehe PSDK) ausprobiert?

Ich meine, dass dieser in Delphi nicht definiert ist.
Also einfach selber deklarieren oder meine Unit von oben verwenden:
Delphi-Quellcode:
 FOF_NO_CONNECTED_ELEMENTS = $2000; // don't operate on connected elements.
mfG
mirage228

Orakel-von-Delphi 12. Okt 2005 16:00

Re: SHFileOperation löst Exception aus ?!
 
Schon klar, aber dann musste man erst einmal auf einen Blick erkennen, dass beide miteinander verbunden sind. Der Explorer klärt einen über diese Tatsache erst bei dem Versuch, die Datei od. den Ordner umzubenennen, auf.
Und der Explorer, xcopy etc. kopieren ja auch ohne zu meckern ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:57 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