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 istwchar_t *wcscpy( wchar_t *dest, const wchar_t *src )
. Diese Funktion kopiert C-Style string vonsource
nachdest
, 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 duUnicodeStrings
, 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
einenconst wchar_t*
zurückgibt und als erster Parameter vonTarget
nicht zurwcscpy
-Signatur passt. Vermutlich drückt da der klassische Compiler wieder beide Augen zu und lässt den Schreibzugriff auf einenconst
Pointer zu. Abgesehen davon ist auch nicht sichergestellt, dass der Speicherbereich, auf denTarget.c_str()
zeigt, groß genug ist, um den Inhalt vonSource
aufzunehmen.Außerdem:
In Zeile 26 meines Codes rufst duShowMessage
auf. Das Zusammensetzen des Textes funktioniert nicht so, wie du vermutest, sondern so:
"Error: "
wird zu einenconst char*
ausgewertet, auf den du das Ergbnis desGetLastError()
-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 geschachteltetry-catch
Blöcke? In deinem gezeigten Quelltext gibt es keine Stelle, an der eine Exception geworfen werden könnte.Edit:
Du hast diecode-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 istwchar_t *wcscpy( wchar_t *dest, const wchar_t *src )
. Diese Funktion kopiert C-Style string vonsource
nachdest
, 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 duUnicodeStrings
, 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
einenconst wchar_t*
zurückgibt und als erster Parameter vonTarget
nicht zurwcscpy
-Signatur passt. Vermutlich drückt da der klassische Compiler wieder beide Augen zu und lässt den Schreibzugriff auf einenconst
Pointer zu. Abgesehen davon ist auch nicht sichergestellt, dass der Speicherbereich, auf denTarget.c_str()
zeigt, groß genug ist, um den Inhalt vonSource
aufzunehmen.Außerdem:
In Zeile 26 meines Codes rufst duShowMessage
auf. Das Zusammensetzen des Textes funktioniert nicht so, wie du vermutest, sondern so:
"Error: "
wird zu einenconst char*
ausgewertet, auf den du das Ergbnis desGetLastError()
-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 geschachteltetry-catch
Blöcke? In deinem gezeigten Quelltext gibt es keine Stelle, an der eine Exception geworfen werden könnte.Edit:
Du hast diecode-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