Probleme mit SHFileOperation oder FindFirst/FindNext (VCL) unter Win2k



  • hallo!

    ich bastele gerade ein programm, das beim runterfahren und hochfahren von windows bestimmte dateien und ordner hin und her kopiert.
    ich benutze dafür an der basis die FindFirst()- und FindNext()-Funktionen und die WinAPI-Funktion SHFileOperation().
    Mit FindFirst() und FindNext() filtere ich rekursiv Dateien raus, die ein bestimmtes Alter überschreiten.

    Nun habe ich folgendes Problem:

    Beim Sichern der Daten läuft das Programm unter WinXP SP1 "völlig normal", d.h. die Kopieroperationen mittels SHFileOperation() werden in ähnlicher Geschwindigkeit durchgeführt, wie wenn man es von Hand kopieren würde. Unter Win2k allerdings verhält sich das Programm sehr merkwürdig: das Kopieren dauert SUPER lange und wenn ich in den TaskManager gucke wundert mich das auch nicht, denn der Process kriegt einfach keine CPU-Zeit ab, obwohl sonst nichts Großes läuft.

    Das Merkwürdige an der Sache ist, dass die SHFileOperation() für sich allein gut läuft (unter WinXP und Win2k). Die FindFirst()-/FindNext()-Schleifen laufen ohne die Kopieroperation auch einwandfrei (Test über Ausgabe in einem Memo). Nur wenn ich beide zusammenführe, bekomme ich das beschriebene verhalten.

    Weiß jemand wieso???

    Hier noch ein bisschen Quellcode:

    [cpp]// Funktion zum Kopieren/Bewegen von Dateien/Ordnern
    // mode = FO_COPY oder FO_MOVE
    void __fastcall TDataSafeTest::MyCopy(const CHAR source[MAX_PATH], const CHAR dest[MAX_PATH], int mode)
    {
    SHFILEOPSTRUCT fop;
    CHAR l_Dest[MAX_PATH];
    CHAR l_Source[MAX_PATH];

    fill_n(l_Dest, MAX_PATH, '\0');
    fill_n(l_Source, MAX_PATH, '\0');

    strcpy(l_Dest, dest);
    strcpy(l_Source, source);

    fop.hwnd = NULL;
    fop.wFunc = mode;
    fop.pFrom = l_Source;
    fop.pTo = l_Dest;
    fop.fFlags = FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR; // keine Dialoge anzeigen beim Kopieren
    fop.fAnyOperationsAborted = 0;
    fop.hNameMappings = NULL;
    fop.lpszProgressTitle = NULL;

    SHFileOperation( &fop );
    }[/cpp]

    [cpp]// SaveNewerData speichert eine angegebene Quelle an den angegebenen Zielort,
    // wenn die Quelle neuer ist, als das angegebene Datum ( Aufruf von MyCopy() ).
    //
    void __fastcall TDataSafeTest::SaveNewerData( const CHAR Src[MAX_PATH],
    const CHAR Dst[MAX_PATH],
    TDateTime TimeOfLastBackup )
    {
    TSearchRec SR;
    CHAR Source[MAX_PATH]; strcpy(Source, Src);
    CHAR Dest[MAX_PATH]; strcpy(Dest, Dst);
    AnsiString TmpSrc, TmpDest;

    /* ein Versuch, die Prozesspriorität hochzusetzen, leider erfolglos
    int oldPriorityClass, oldPriority;
    oldPriorityClass = GetPriorityClass(GetCurrentProcess);
    oldPriority = GetThreadPriority(GetCurrentThread);
    SetPriorityClass(GetCurrentProcess, IDLE_PRIORITY_CLASS);
    SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_IDLE);
    */

    if( FindFirst( AnsiString(Src), faAnyFile, SR ) == 0 ){

    // Unterscheidung zwischen Dateien und Ordnern
    if( (SR.Attr & faDirectory) == 0 ){ // es handelt sich um eine Datei

    if( FileDateToDateTime(SR.Time) > TimeOfLastBackup ){
    TmpDest = AnsiString(Dst)+"\"+SR.Name;
    strcpy(Dest, TmpDest.c_str() );
    MyCopy( Source, Dest, FO_COPY );
    }
    }
    else if( SR.Name != "." && SR.Name != ".." ){

    // es handelt sich um einen Ordner mit Namen ungleich . und ..
    TmpDest = AnsiString(Dest)+"\"+SR.Name; // neuer Unterordner

    ForceDirectories( TmpDest );

    if( FindFirst(AnsiString(Src)+"\*", faAnyFile, SR) == 0 ){
    if( m_LongLog ) LogAddEntry("FindFirst: "+SR.Name,1);
    // es existieren Dateien/Ordner in dem zu kopierenden Ordner
    TmpSrc = AnsiString(Src)+"\"+SR.Name;

    if( FileExists(TmpSrc) ){
    strcpy(Dest, (TmpDest+"\"+SR.Name).c_str());
    strcpy(Source, (AnsiString(Source)+"\"+SR.Name).c_str());
    MyCopy(Source, Dest, FO_COPY);
    }
    else if( SR.Name != "." && SR.Name != ".." && DirectoryExists(TmpSrc) ){
    strcpy(Dest, TmpDest.c_str());
    strcpy(Source, (AnsiString(Source)+"\"+SR.Name).c_str());
    SaveNewerData(Source, Dest, TimeOfLastBackup);
    }
    if( m_LongLog ) LogAddEntry("EndFind",-1);
    }
    // durchlaufe alle Einträge in dem angegebenen Ordner rekursiv
    while( FindNext(SR) == 0 ){
    if( m_LongLog ) LogAddEntry("FindNext: "+SR.Name,1);
    TmpSrc = AnsiString(Src)+"\"+SR.Name;

    if( FileExists(TmpSrc) ){
    strcpy(Dest, (TmpDest+"\"+SR.Name).c_str());
    strcpy(Source, (AnsiString(Src)+"\"+SR.Name).c_str());

    MyCopy(Source, Dest, FO_COPY);
    }
    else if( SR.Name != "." && SR.Name != ".." && DirectoryExists(TmpSrc) ){
    strcpy(Dest, TmpDest.c_str());
    strcpy(Source, (AnsiString(Src)+"\"+SR.Name).c_str());

    SaveNewerData(Source, Dest, TimeOfLastBackup);
    }
    }
    }
    }
    FindClose(SR);

    /* gehört zum Prioritätsversuch, siehe oben
    SetThreadPriority(GetCurrentThread, oldPriority); // Priorität zurücksetzen
    SetPriorityClass(GetCurrentProcess, oldPriorityClass);
    */
    }[/cpp]

    TDataSafeTest::SaveNewerData wird dann von einer anderen Funktion innerhalb einer for-Schleife aufgerufen.

    Das war's erstmal. Ich erwarte ja keine Wunder, aber vielleicht hat ja jemand einen spontanen Einfall...

    gruß, oli


Anmelden zum Antworten