CopyFile, CopyFileW und wcscpy



  • Hallo

    Ich programmiere mit dem C++ Builder 2009 und habe mit der Funktion CopyFile
    bzw. CopyFileW meine Probleme und zwar nur dann, wenn die Pfade und Dateinamen
    nicht als Text eingebe (z.B "C:\\Program Files\.....") sonder UnicodeString-Variable einsetze.
    Im Fundus von C++Com habe ich einen Beitrag vom Mitglied Sidewinder gefunden,
    der aber nicht explizit mein Problem trifft, deshalb bitte ich um Hilfe und
    füge den entsprechenden Code-Auszug nachfogend an.

    [code="cpp"]bool Getan;
    UnicodeString Source;
    UnicodeString Target = FDBModul->ExePfad + "HotSave\\" + strWTag + "\\";
    try {
      for (int i = 0; i < FileListBox3->Items->Count; i++) {
      try {
        Source = FDBModul->DBPfad + FileListBox3->Items->Strings[i];
    
        Getan = CopyFileW(Source.w_str(), Target.w_str(), false);   // Variante 1
        // keine Fehlermeldung vom compiler aber nur beim ersten Durchlauf Kopien
        // gemacht
    
        Getan = wcscpy(Source, Target);                         // Variante 2 
        // Fehlermeldung: keine Kovertierung von Unicode nach wchar_t  
    
        Getan = wcscpy(Source.w_str(), Target.w_str());	       // Variante 3
        // keine Fehlermeldung vom compiler aber auch keine Kopien gemacht, Getan
        // wurde aber 135x auf true gesetzt
    

    if (Getan)
    Count++;
    }
    catch(...) { }
    if (!Getan)
    ShowMessage("Error: " + GetLastError()); // Bei der Anzeige kam nur "or."
    // diese Fehlermeldung habe ich natürlich nur mit 2 oder 3 Files probiert
    Getan = false;
    }[/code]

    Die 3 Varianten habe ich einzln ausprobiert und das Ergebnis als Kommentar
    dazugeschrieben. Erstaunlicherweise hat die Funktion in Variante 1 einmal
    geklappt und 135 Files kopiert, aber eben nur einmal!
    Die Fehlersuch mit der Funktion GetLastError() hat auch keine Erkenntnisse
    gebracht, so dass ich mich an "Euch" wende, ob Ihr in meinem Falle Rat wüsstet.

    Gruß Gert

    Anmerkung: Warum das System den letzten Teil des Codes nicht ordentlich dar-
    stellt, weiß ich nicht.



  • Beim ersten Durchlauf, oder nur ein Mal? Du änderst Target nicht 🙂
    Es könnten aber natürlich noch andere Fehler da sein.



  • Ein paar Worte zu wcscpy :
    Die Signatur ist wchar_t *wcscpy( wchar_t *dest, const wchar_t *src ) . Diese Funktion kopiert C-Style string von source nach dest , der String muss nullterminiert sein. Der erste Parameter ist das Ziel, der zweite die Quelle, das ist in deinem Code schon mal falsch. Außerdem bist du als Aufrufer dafür verantwortlich, dass der Speicherbereich des Ziels groß genug ist, um den kompletten String aufzunehmen.
    In deiner Variante 2 übergibst du UnicodeStrings , das passt von der Signatur nicht und wird vom Compiler zu recht als Fehler erkannt.

    Variante 3 dürfte eigentlich auch nicht übersetzt werden, da UnicodeString::c_str einen const wchar_t* zurückgibt und als erster Parameter von Target nicht zur wcscpy -Signatur passt. Vermutlich drückt da der klassische Compiler wieder beide Augen zu und lässt den Schreibzugriff auf einen const Pointer zu. Abgesehen davon ist auch nicht sichergestellt, dass der Speicherbereich, auf den Target.c_str() zeigt, groß genug ist, um den Inhalt von Source aufzunehmen.

    Außerdem:
    In Zeile 26 meines Codes rufst du ShowMessage auf. Das Zusammensetzen des Textes funktioniert nicht so, wie du vermutest, sondern so:
    "Error: " wird zu einen const char* ausgewertet, auf den du das Ergbnis des GetLastError() -Aufrufs addierst. Damit verschiebst du den Zeiger um ein paar Bytes nach vorne und deshalb wird auch nicht die korrekte Fehlermeldung angezeigt, sondern nur ein Bruchteil des Textes. Bei Rückgabewerten >7 greifst du auf ungültigen Speicher zu und erzeugst mit deinem Programm undefiniertes Verhalten.
    Ich habe den Eindruck, dass die bei ein paar Sachen das grundlegende Verständnis fehlt, da solltest du dir noch mal dein C++ Buch schnappen und lesen.

    Aus Interesse:
    Warum gibt´s zwei geschachtelte try-catch Blöcke? In deinem gezeigten Quelltext gibt es keine Stelle, an der eine Exception geworfen werden könnte.

    Edit:
    Du hast die code-tags geschachtelt und das mag der Parser nicht.

    UnicodeString Source; 
    UnicodeString Target = FDBModul->ExePfad + "HotSave\\" + strWTag + "\\"; 
    try { 
      for (int i = 0; i < FileListBox3->Items->Count; i++) { 
      try { 
        Source = FDBModul->DBPfad + FileListBox3->Items->Strings[i]; 
    
        Getan = CopyFileW(Source.w_str(), Target.w_str(), false);   // Variante 1 
        // keine Fehlermeldung vom compiler aber nur beim ersten Durchlauf Kopien 
        // gemacht 
    
        Getan = wcscpy(Source, Target);                         // Variante 2 
        // Fehlermeldung: keine Kovertierung von Unicode nach wchar_t   
    
        Getan = wcscpy(Source.w_str(), Target.w_str());        // Variante 3 
        // keine Fehlermeldung vom compiler aber auch keine Kopien gemacht, Getan 
        // wurde aber 135x auf true gesetzt	
    
        if (Getan) 
          Count++; 
       } 
       catch(...) { } 
       if (!Getan) 
          ShowMessage("Error: " + GetLastError()); // Bei der Anzeige kam nur "or." 
        // diese Fehlermeldung habe ich natürlich nur mit 2 oder 3 Files probiert 
        Getan = false; 
    }
    


  • DocShoe schrieb:

    Ein paar Worte zu wcscpy :
    Die Signatur ist wchar_t *wcscpy( wchar_t *dest, const wchar_t *src ) . Diese Funktion kopiert C-Style string von source nach dest , der String muss nullterminiert sein. Der erste Parameter ist das Ziel, der zweite die Quelle, das ist in deinem Code schon mal falsch. Außerdem bist du als Aufrufer dafür verantwortlich, dass der Speicherbereich des Ziels groß genug ist, um den kompletten String aufzunehmen.
    In deiner Variante 2 übergibst du UnicodeStrings , das passt von der Signatur nicht und wird vom Compiler zu recht als Fehler erkannt.

    Variante 3 dürfte eigentlich auch nicht übersetzt werden, da UnicodeString::c_str einen const wchar_t* zurückgibt und als erster Parameter von Target nicht zur wcscpy -Signatur passt. Vermutlich drückt da der klassische Compiler wieder beide Augen zu und lässt den Schreibzugriff auf einen const Pointer zu. Abgesehen davon ist auch nicht sichergestellt, dass der Speicherbereich, auf den Target.c_str() zeigt, groß genug ist, um den Inhalt von Source aufzunehmen.

    Außerdem:
    In Zeile 26 meines Codes rufst du ShowMessage auf. Das Zusammensetzen des Textes funktioniert nicht so, wie du vermutest, sondern so:
    "Error: " wird zu einen const char* ausgewertet, auf den du das Ergbnis des GetLastError() -Aufrufs addierst. Damit verschiebst du den Zeiger um ein paar Bytes nach vorne und deshalb wird auch nicht die korrekte Fehlermeldung angezeigt, sondern nur ein Bruchteil des Textes. Bei Rückgabewerten >7 greifst du auf ungültigen Speicher zu und erzeugst mit deinem Programm undefiniertes Verhalten.
    Ich habe den Eindruck, dass die bei ein paar Sachen das grundlegende Verständnis fehlt, da solltest du dir noch mal dein C++ Buch schnappen und lesen.

    Aus Interesse:
    Warum gibt´s zwei geschachtelte try-catch Blöcke? In deinem gezeigten Quelltext gibt es keine Stelle, an der eine Exception geworfen werden könnte.

    Edit:
    Du hast die code-tags geschachtelt und das mag der Parser nicht.

    UnicodeString Source; 
    UnicodeString Target = FDBModul->ExePfad + "HotSave\\" + strWTag + "\\"; 
    try { 
      for (int i = 0; i < FileListBox3->Items->Count; i++) { 
      try { 
        Source = FDBModul->DBPfad + FileListBox3->Items->Strings[i]; 
        
        Getan = CopyFileW(Source.w_str(), Target.w_str(), false);   // Variante 1 
        // keine Fehlermeldung vom compiler aber nur beim ersten Durchlauf Kopien 
        // gemacht 
        
      
        Getan = wcscpy(Source, Target);                         // Variante 2 
        // Fehlermeldung: keine Kovertierung von Unicode nach wchar_t   
        
        Getan = wcscpy(Source.w_str(), Target.w_str());        // Variante 3 
        // keine Fehlermeldung vom compiler aber auch keine Kopien gemacht, Getan 
        // wurde aber 135x auf true gesetzt	
    
        if (Getan) 
          Count++; 
       } 
       catch(...) { } 
       if (!Getan) 
          ShowMessage("Error: " + GetLastError()); // Bei der Anzeige kam nur "or." 
        // diese Fehlermeldung habe ich natürlich nur mit 2 oder 3 Files probiert 
        Getan = false; 
    }
    

    Hallo DocShoe

    Vielen Dank für die prompte Antwort, dazu folgende Stellungname:

    Variante 1

    Die Original-Definition von MS für die Fuktion CopyFile lautet:

    BOOL CopyFile(
    LPCTSTR lpExistingFileName,
    LPCTSTR lpNewFileName,
    BOOL bFailIfExists
    );

    somit ist der erste Parameter die Quelle und der zweite das Ziel.

    Es muss aber einen Grund haben, warum der Compiler den Code akzeptiert, die Ausführung nur 1x geklappt hat?

    Eine Abfrage nach dem Ziel-Speicherplatz erübrigt sich bei meiner Anwendung, da es sich um festgelegte, ausreichend dimensionierte Ordner handelt, zwischen denen jeweils hin und her kopiert wird.

    Variante 2

    Dass der Compiler die Signatur nicht akzeptiert, ist mir klar aber ich möchte gerne wissen, wie der Code aussehen muss, dass ich mit den UnicodeString-Variablen die Dateien kopieren kann.

    Variante 3

    Hier ist die Sache genauso gelagert wie bei Variante 1, dass der Compiler den Ausdruck "Source.w_str()" klaglos akzeptiert aber das Programm das Kopieren nicht auführt.

    Dass die doppelten try-Blöcken unnötig sind, das hast Du natürlich richtig erkannt, wie es zu diesen Lapsus kam kann ich nicht mehr sagen!

    Gruß Gert


Anmelden zum Antworten