Wieso geht CString::Format zig mal gut und jetzt nicht mehr?



  • 1.) War klar, jetzt will ich die Meldung kopieren, jetzt kommt sie nicht mehr. 😡
    2.) Nein, ich hab den code irgendwann mal irgendwie vermutlich von hier (vor dem Edit) kopiert und dann immer verwendet. 😕
    3.) Zuweisungen klappen immer wieder mal nicht, wann habe ich nicht raus, aber Format war bisher zuverlässig. 🙄
    Hier ist gerade so ein Beispiel:

    CString strCmd = _T("\"") + strCurFolder + _T("\\arj.exe\" a -y -v1440 \"" + strKurzOrdner + "AD3_BU_" + strHeute + "\" \"" + strKurzZiel + _T("\""));
    

    Hier sieht es nach der Addition so aus, als wäre strKurzZiel leer gewesen - ist es aber laut Debugger nicht.
    So geht es dagegen:

    CString strCmd;
    strCmd.Format(_T("\"%s\\arj.exe\" a -y -v1440 \"AD3_BU_%s\" \"%s\""), strCurFolder, strHeute, strKurzZiel);
    

    Übrigens: Replace (das zweite) funktioniert in dem Codestück auch nicht. 😕
    Das tut einfach nix, obwohl in strKurzZiel ein Dateiname steht, der auf .ldf endet.
    Ein Replace ein paar Zeilen drüber hat es nämlich da "grade" hingeschrieben:

    strZiel.Replace(_T(".mdf"), _T(".ldf"));
    // ... wirklich wenige Zeilen
    CString strKurzOrdner, strKurzZiel;
    // Hinten Wildcard setzen
    GetShortPathName(strZiel, strKurzZiel.GetBuffer(strKurzZiel.GetLength()+1), MAX_PATH);
    strKurzZiel.Replace(_T(".ldf"), _T(".*"));
    

    PS: Gibt es eigentlich einfache Möglichkeiten, Dateien zu packen und zu entpacken? Arj streikt irgendwie auch noch fleissig... 🙄



  • @2: Das beantwortet noch nicht die Frage 😉 Wie sieht es denn aus, wenn du das Programm durch den Debugger jagst?

    @3: Eigentlich sollten String-Zuweisungen auch problemlos klappen - zumindest solange du nicht zu viele char* dazwischen reinaddiert hast.

    @Replace:

    GetShortPathName(strZiel, strKurzZiel.GetBuffer(strKurzZiel.GetLength()+1), MAX_PATH);
    

    strKurzZiel war vor dem Aufruf leer - d.h. du forderst von ihm Platz für ein Zeichen und willst dort MAX_PATH Zeichen reinquetschen. (außerdem mußt du den Speicher noch mit ReleaseBuffer() freigeben, bevor du den String wieder verwenden kannst)



  • CStoll schrieb:

    @2: Das beantwortet noch nicht die Frage 😉 Wie sieht es denn aus, wenn du das Programm durch den Debugger jagst?

    Ich hab doch mit "Nein" geantwortet. "Nein, ich bin mir nicht sicher." 😞

    @3: Eigentlich sollten String-Zuweisungen auch problemlos klappen - zumindest solange du nicht zu viele char* dazwischen reinaddiert hast.

    char* vermeide ich nach Möglichkeit, in der Addition kommen nur CStrings vor.

    @Replace:

    GetShortPathName(strZiel, strKurzZiel.GetBuffer(strKurzZiel.GetLength()+1), MAX_PATH);
    

    strKurzZiel war vor dem Aufruf leer - d.h. du forderst von ihm Platz für ein Zeichen und willst dort MAX_PATH Zeichen reinquetschen. (außerdem mußt du den Speicher noch mit ReleaseBuffer() freigeben, bevor du den String wieder verwenden kannst)

    Okay... ich werde also vorher einmal den langen Pfad zuweisen, dann erst GetShortPathName aufrufen. Das sollte genug Platz schaffen. 😃
    Und ReleaseBuffer baue ich gleich mal ein. Das vergesse ich immer. 😞


  • Mod

    CString strCmd; 
    strCmd.Format(_T("\"%s\\arj.exe\" a -y -v1440 \"AD3_BU_%s\" \"%s\""), strCurFolder, strHeute, strKurzZiel);
    

    In einem Ellipsen Operator sollte man vermeiden Objekte zu übergeben.
    Es funktioniert nicht zuverlässig.
    CString ist eben nicht austauschbar mit LPCSTR undhier wird der besagte Operator nicht aufgerufen. Es wird das Objekt auf den Stack gepackt.

    Korrekt wäre nur:

    CString strCmd; 
    strCmd.Format(_T("\"%s\\arj.exe\" a -y -v1440 \"AD3_BU_%s\" \"%s\""), strCurFolder.GetString(), strHeute.GetString(), strKurzZiel.GetString());
    

    Oder entsprechende Varianten mit static_cast<LPCTSTR>();



  • ReleaseBuffer scheint einige der Probleme verursacht zu haben. 😮
    Das Replace klappt jetzt. 👍

    Ich gucke mal weiter. 🙂



  • Martin Richter schrieb:

    CString strCmd; 
    strCmd.Format(_T("\"%s\\arj.exe\" a -y -v1440 \"AD3_BU_%s\" \"%s\""), strCurFolder, strHeute, strKurzZiel);
    

    In einem Ellipsen Operator sollte man vermeiden Objekte zu übergeben.
    Es funktioniert nicht zuverlässig.
    CString ist eben nicht austauschbar mit LPCSTR undhier wird der besagte Operator nicht aufgerufen. Es wird das Objekt auf den Stack gepackt.

    Korrekt wäre nur:

    CString strCmd; 
    strCmd.Format(_T("\"%s\\arj.exe\" a -y -v1440 \"AD3_BU_%s\" \"%s\""), strCurFolder.GetString(), strHeute.GetString(), strKurzZiel.GetString());
    

    Oder entsprechende Varianten mit static_cast<LPCTSTR>();

    Uff, das würde für mich heißen, dass ich zig Projekte nochmal nach sowas durchstöbern muss. 😮
    Wieso liest man sowas nicht öfters/früher? 😞

    Wie schlimm ist es, wenn man das nun nicht anpasst? Ich meine, es läuft bis auf sowas wie eben (wo ich ReleaseBuffer als schuldig abgestempelt hab) einwandfrei. 😕



  • CString "featuring" special Hack so dass es trotzdem geht. (Also nen CString an "..." Funktionen übergeben).
    MS hat dies als non-std Extension so implementiert dass einfach das ganze Objekt auf den Stack gepusht wird.
    Da ein CString genau aus einem Zeiger besteht, und der auf das erste Zeichen des Strings zeigt... geht es.

    Der eigentliche Fehler ist die Verwendung von GetBuffer() mit 1) einer zu kleinen Grösse und 2) ohne dass ReleaseBuffer() aufgerufen wird.



  • hustbaer schrieb:

    CString "featuring" special Hack so dass es trotzdem geht. (Also nen CString an "..." Funktionen übergeben).
    MS hat dies als non-std Extension so implementiert dass einfach das ganze Objekt auf den Stack gepusht wird.
    Da ein CString genau aus einem Zeiger besteht, und der auf das erste Zeichen des Strings zeigt... geht es.

    Puh, danke. 🙂

    Der eigentliche Fehler ist die Verwendung von GetBuffer() mit 1) einer zu kleinen Grösse und 2) ohne dass ReleaseBuffer() aufgerufen wird.

    Okay, das habe ich jetzt an den Stellen behoben. Ich muss jetzt nochmal suchen, wo das noch vorkommt und da nachbessern. 🙂


  • Mod

    hustbaer schrieb:

    CString "featuring" special Hack so dass es trotzdem geht. (Also nen CString an "..." Funktionen übergeben).
    MS hat dies als non-std Extension so implementiert dass einfach das ganze Objekt auf den Stack gepusht wird.
    Da ein CString genau aus einem Zeiger besteht, und der auf das erste Zeichen des Strings zeigt... geht es.

    Hatte ich auch schon geschrieben 😉



  • Martin Richter schrieb:

    hustbaer schrieb:

    CString "featuring" special Hack so dass es trotzdem geht. (Also nen CString an "..." Funktionen übergeben).
    MS hat dies als non-std Extension so implementiert dass einfach das ganze Objekt auf den Stack gepusht wird.
    Da ein CString genau aus einem Zeiger besteht, und der auf das erste Zeichen des Strings zeigt... geht es.

    Hatte ich auch schon geschrieben 😉

    Nicht ganz. Du hast geschrieben warum es eigentlich falsch ist und nicht gehen sollte. Der Trick dabei ist aber dass es eben doch geht, weil MS es absichtlich so hingefummelt hat DAMIT es eben geht.

    Wirklich böse ist nur wenn man einen CString so an einen Mutator ala scanf übergibt - DAS macht dann Probleme, da der CString nix davon mitbekommt dass er gleich "überpinselt" wird. Dadurch hebelt man das COW/Reference Counting aus, und überschreibt im schlimmsten Fall sogar fremden Speicher.

    Daher *immer* den String mit GetBuffer "locken" und mit ReleaseBuffer wieder "freigeben".

    Am Besten man lässt gleich die Finger von CString und nimmt stattdessen std::string (oder boost::shared_ptrstd::string für Leute die unbedingt COW Strings wollen).


  • Mod

    Friede! Ich gebe mich geschlagen 😃


Anmelden zum Antworten