Autor |
Beitrag |
s!lenCe
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 10:01
Hallo allerseits,
folgendes Problem:
ich will eine Datei (bzw. mehrere) kopieren, dessen Zielpfad (mit Dateinamen) die Begrenzung von 255 Zeichen
überschreitet. Ich habe CopyFile (CopyFileW, CopyFileA) versucht, jedoch kopiert er mir die Datei damit nicht.
Gibt es eine Alternative zu CopyFile um soetwas realisieren zu können? Oder ist CopyFile mit irgendwelchen Tricks
vielleicht doch dazu in der Lage? Mal jetzt davon abgesehen, dass der Explorer selbst nicht mit einem Pfad klar kommt,
der über 255 Zeichen lang ist.
MfG silenCe
Zuletzt bearbeitet von s!lenCe am Di 03.11.09 12:19, insgesamt 1-mal bearbeitet
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 10:38
Versuch es mal mit UNC Pfadangaben. Ich glaube mal gehört zu haben, dass man damit die Längenbegrenzung der Pfadangabe (260 Zeichen) umgehen kann. Wahrscheinlich musst du dann aber auch CopyFileW benutzen.
|
|
s!lenCe 
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 11:14
Luckie hat folgendes geschrieben : | Versuch es mal mit UNC Pfadangaben. Ich glaube mal gehört zu haben, dass man damit die Längenbegrenzung der Pfadangabe (260 Zeichen) umgehen kann. Wahrscheinlich musst du dann aber auch CopyFileW benutzen. |
Das habe ich auch schon irgendwo gelesen und habe es auch schon ausprobiert, bin aber nicht ganz sicher, ob das so richtig war.
Delphi-Quelltext 1:
| CopyFileW(PWideChar(Quelle), PWideChar('\\?\' + Ziel),false) |
Wie gesagt das mit dem '\\?\' habe ich irgendwo gelesen, da hat es sich aber auf CreateFile bezogen. Ich habe auch versucht das beiden voranzustellen,
also Quelle und Ziel, obwohl nur das Ziel die Länge überschreitet. Hat aber alles nicht funktioniert.
Mit fällt gerade auf ich brauch das selbe auch für ForceDirectories, da ich mit dieser Funktion erst die Verzeichnisse anlege und dann die Datei kopiere.
Und ForceDirectories legt mir auch nicht alle Verzeichnisse an nur bis zu dem Punkt an dem die 260 Zeichen voll sind.
MfG silenCe
Zuletzt bearbeitet von s!lenCe am Di 03.11.09 11:24, insgesamt 1-mal bearbeitet
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 03.11.09 11:24
wikipedia hat folgendes geschrieben: | Das Format für lokale Pfade unter Windows, also Daten, die auf dem verwendeten Rechner selbst vorhanden sind, ist:
Quelltext |
Hast du das mal so ausprobiert?
Edit: Bei deinem Konstrukt ist auch wichtig: Ziel und Quelle müssen WideStrings sein. Der Typecast von Delphi-2007-String nach PWideChar ergibt Unsinn.
Unter D2009 kannst du mit der CopyFile und PChar-Version arbeiten. Da sind das ja die Unicode-Varianten.
_________________ We are, we were and will not be.
|
|
s!lenCe 
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 11:37
Gausi hat folgendes geschrieben : | wikipedia hat folgendes geschrieben: | Das Format für lokale Pfade unter Windows, also Daten, die auf dem verwendeten Rechner selbst vorhanden sind, ist:
Quelltext | Hast du das mal so ausprobiert?
Edit: Bei deinem Konstrukt ist auch wichtig: Ziel und Quelle müssen WideStrings sein. Der Typecast von Delphi-2007-String nach PWideChar ergibt Unsinn.
Unter D2009 kannst du mit der CopyFile und PChar-Version arbeiten. Da sind das ja die Unicode-Varianten. |
Nutze Delphi7 und wenn ich keinen Typecase mache bzw. PChar nehme meckert der Compiler. Also ich habe jetzt auf jeden Fall rausgefunden, dass er die Datei
sowieso gar nicht kopieren kann, da das ForceDirectories, das vor dem Kopieren ausgeführt wird, um die Verzeichnisstruktur für die Datei anzulegen, auch fehlschlägt
mit der Fehlermeldung der angegebene Pfad wäre zu lang - ist er ja auch eigentlich  .
So habe während ich den Beitrag geschrieben habe nun das mit dem ForceDirectories hinbekommen.
Delphi-Quelltext 1:
| ForceDirectories('\\?\' + Pfad) |
So legt er mir einen Pfad an, der auch länger als 260 Zeichen ist. Jetzt muss ich nur noch das CopyFile ans Laufen kriegen.
MfG silenCe
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 03.11.09 11:39
Wie gesagt, der direkte Typecast von String nach PWideChar ergibt Unsinn. Wenn du normale Strings unter D7 benutzt, dann muss das so aussehen:
Delphi-Quelltext 1:
| PWideChar(WideString(myString)) |
_________________ We are, we were and will not be.
|
|
s!lenCe 
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 11:55
Gausi hat folgendes geschrieben : | Wie gesagt, der direkte Typecast von String nach PWideChar ergibt Unsinn. Wenn du normale Strings unter D7 benutzt, dann muss das so aussehen:
Delphi-Quelltext 1:
| PWideChar(WideString(myString)) | |
Es funktioniert! Endlich ~.~
Puhh ich danke dir ^^
Also der Code sieht nun wie folgt aus.
Einmal die Verzeichnisstruktur mit ForceDirectories anlegen und dann die Datei kopieren. Beide kommen nun mit Pfadangaben, die länger als 260 Zeichen sind, klar.
Delphi-Quelltext 1: 2: 3:
| ForceDirectories('\\?\' + ExtractFilePath(Pfad))
CopyFileW(PWideChar(WideString(Quelle)),PWideChar(WideString('\\?\' + Ziel)),false) |
EDIT:
Verdammt habe mich wohl zu früh gefreut. Habe nochmal einen längeren Pfad angelegt (genau 265 Zeichen) und daran scheitert ForceDirectories doch mit der Fehlermeldung
der Pfad sei zu lang. -.-
MfG silenCe
Zuletzt bearbeitet von s!lenCe am Di 03.11.09 13:31, insgesamt 1-mal bearbeitet
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 13:23
Wahrscheinlich weil ForceDirectories keine Widestrings benutzt. Da wirst du dir wohl deine eigene Unicode Variante implementieren müssen.
|
|
s!lenCe 
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 13:48
Ich habe gerade noch diese Funktion gefunden:
SHCreateDirectoryEx
Genau wie ForceDirectories legt sie komplette Verzeichnisstrukturen an. Nur ich bekomm sie nicht ans Laufen, da ich nicht weiß welche Unit ich einbinden soll.
Normal doch nur die Windows?
MfG silenCe
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 14:22
Musst du wahrscheinlich selbst deklarieren oder probier mal Shlobj.
|
|
s!lenCe 
      
Beiträge: 24
Erhaltene Danke: 1
|
Verfasst: Di 03.11.09 16:46
So habe mir jetzt einfach meine eigene Variante geschrieben.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| FUNCTION ForceDirectoriesW(Dir : WideString) : Boolean; VAR tmp : WideString; Position : Integer; BEGIN Result := True; Dir := ExtractFilePath(Dir); Dir := IncludeTrailingPathDelimiter(Dir); tmp := Copy(Dir, 1, 3); Delete(Dir, 1, 3);
WHILE Pos('\', Dir) <> 0 DO BEGIN Position := Pos('\', Dir); tmp := tmp + Copy(Dir, 1, Position); Delete(Dir, 1, Position); IF NOT DirectoryExists(tmp) THEN IF NOT CreateDirectoryW(PWideChar(WideString('\\?\' + tmp)), nil) THEN BEGIN Result := False; Exit; END; END; END; |
MfG silenCe
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 22.05.11 11:25
Ich hab leider auch ein kleines Problem mit CopyFile() - Und zwar soll man in meinem Programm ein Lied (mp3 oder wav) kopieren können. Habe einmal einen Button "Browse", einen anderen "Add".
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| path := ExtractFilePath(Application.ExeName); . . .
procedure TSoundForm.BrowseClick(Sender: TObject); var Endung: String; begin if dlgOpen.Execute then begin NewSong := dlgOpen.FileName; Endung := Copy(NewSong, length(NewSong) - 2, 3); if (Endung <> 'mp3') and (Endung <> 'wav') then begin ShowMessage('Das Lied muss eine mp3- oder wav-Datei sein!'); BrowseClick(Button4); Exit; end else begin Edit1.Text := NewSong; Selected := True; end; end; end;
procedure TSoundForm.AddClick(Sender: TObject); var NewSongName: String; i, i2: Integer; Finished: Boolean; begin Finished := False; if Selected then begin Dec(i, i); repeat begin NewSongName := Copy(NewSong, length(NewSong) - i, 1 + i); if NewSongName[1] = '\' then begin NewSongName := copy(NewSongName, 2, length(NewSongName) - 1); Finished := True; end; Inc(i) end; until Finished; CopyFile(PChar(NewSong),PChar(path + 'Sounds\Background\' + NewSong), False) end else ShowMessage('Bitte wähle erst eine Datei aus!'); end; |
Es kommt KEINE Fehlermeldung, aber andererseits lässt sich unter Sound\Background kein neues lied finden... Geht das möglicherweise nicht mit mp3, etc. - ich hab das bisher nur mit *txt gesehen.
Gruß, Thomas
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 22.05.11 12:16
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 22.05.11 12:51
jaenicke hat folgendes geschrieben : | beastofchaos hat folgendes geschrieben : | Es kommt KEINE Fehlermeldung | Woher auch, die hast die Fehlerbehandlung ja auch komplett ignoriert...
Den Rückgabewert wirfst du genauso weg wie du danach bei einem Fehlschlag nicht mit SysErrorMessage + GetLastError schaust warum es nicht ging...
Siehe Doku...
msdn.microsoft.com/e...363851(v=vs.85).aspx |
Mit Fehlermeldung mein ich cnith die von Delphi, sondern meine Eigene (siehe Quelltext Zeile 16  )
Nachdem ich mir die Namen der SoundNames ausgegeben hab lassen, ist mir aufgefallen, dass ich am Ende die Datei abspeicher mit dem falschen Namen (In Zeile 49 statt "+ NewSong" -> "+ NewSongName").
Das Problem kontne ich also lösen. Ich hab jetzt leider noch ein Problem ,dass nichts mit der CopyFile()-Prozedur zu tun hat, aber in diesem Programmteil vorkommt. Und zwar speicher ich mit der Prozedur "FindFiles()" aus unser Liberary in der TStringList "SoundNames". Jedesmal, wenn ich nun ein Liad hinzufpge mit "Add" speicher ich alles in einer temporören TStringList namens SoundNamesBefore, um abzugleichen, ob ich das Lied shcon einmal hochgeladen habe - Damit will ich nur die neuen Lieder in meine TStringList laden. Quelltext sieht so aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| . . . else begin SoundNamesBefore := SoundNames; SoundNames.Clear; There := False; FindFiles(path + 'Sounds\Background', '*.mp3', False, SoundNames); for i := 0 to SoundNames.Count - 1 do begin for i2 := 0 to SoundNamesBefore.Count - 1 do if (SoundNames[i] = SoundNamesBefore[i2]) then There := True; if not There then begin Memo1.Lines.Add('1'); SetLength(FBackgroundStream, length(FBackgroundStream) + 1); FBackgroundStream[i] := BASS_StreamCreateFile(false, PAnsiChar(AnsiString(SoundNames[i])), 0, 0, 0); end else Memo1.Lines.Add('0'); There := False; end;
Memo1.Lines := SoundNamesBefore; Memo1.Lines.Add('------------'); Memo1.Lines.AddStrings(SoundNames); end; |
Für wen das jetzt zu unverständliches Gelafer war: Ich hab im Moment 4 Pfade(Strings) in SoundNames - die speicher ich dann in SoundNamesBefore und clear SoundNames. Dann ermittel ich mit "FindFiles" alle Namen in dem gesuchten Ordner. Dadurch dass ich eins hinzugefügt habe, sind nun 5 Pfade in SoundNames.
Wenn ich jetzt am Ende SoundNamesBefore mal ausgebe, hat es FÜNF Einträge.
Ist die StringList vll. durch Zeile 6 in meinem Quelltext eine "Referenzvariable geworden???". Und wie löse ich das Problem
Gruß, Thomas
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 22.05.11 13:06
Eine TStringList ist ein Objekt und damit immer nur eine Referenz auf das Objekt.
Da musst du eine neue Instanz erstellen und den Inhalt kopieren, wenn du eine Kopie möchtest.
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 22.05.11 13:10
Was meisnt du mit Instanz?
Auch wenn das in meinen Augen unsauber ist, werd ich einfach die Memo unsichtbar machen lassen, "SoundNamesBefore" da rein schreiben und am Ende das wieder in SoundNamesBefore speichern  Da könnte ich eigentlich sogar SoundNamesBefore ganz weglassen 
|
|
Dude566
      
Beiträge: 1592
Erhaltene Danke: 79
W8, W7 (Chrome, FF, IE)
Delphi XE2 Pro, Eclipse Juno, VS2012
|
Verfasst: So 22.05.11 13:19
Eine Instanz ist ein erzeugtes Exemplar einer Klasse(Objekt).
_________________ Es gibt 10 Gruppen von Menschen: diejenigen, die das Binärsystem verstehen, und die anderen.
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 22.05.11 13:51
Dude566 hat folgendes geschrieben : | Eine Instanz ist ein erzeugtes Exemplar einer Klasse(Objekt). |
Wie sieht das dann im Quelltext aus? xD
Ich verstehe da jetzt nicht den Unterschied zu meinem erzeugten Objekt(TStringList)
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 22.05.11 14:01
Dein Objekt ist eine Instanz der Klasse.  Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| var List1, list2: TStringList; begin List1 := TStringList.Create; try List1.Add('a'); List2.Add('b'); List2 := TStringList.Create; try List2.Assign(List1); ShowMessage(List2[0]); finally List2.Free; end; finally List.Free; end; | Du hast eine Instanz von TStringList in List1 und eine in List2.
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 22.05.11 14:23
Deine Prozedur da gibt mir och "a" aus, oder? Weil du es mit Assign() zuweist - ich vermute mal, dass Assign auch etwas zu einer Referenzvariable macht, obwohl ich das bisher nur vom Textdateien schreiben und auslesen kenne.
Wie mache ich es denn dann richtig? Weil ich iwie nicht den Sinn in deiner Prozedur sehe. Ich würds so machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| List1 := TStringList.Create; List2 := TStringList.Create;
List2 := List1 List1.Add('a');
ShowMessage(List2[0]); List1.Free; List2.Free; |
|
|