Autor Beitrag
s!lenCe
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: 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



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: Di 03.11.09 11:14 
user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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:
ausblenden Quelltext
1:
\\.\C:\Daten\null					
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: Di 03.11.09 11:37 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
wikipedia hat folgendes geschrieben:
Das Format für lokale Pfade unter Windows, also Daten, die auf dem verwendeten Rechner selbst vorhanden sind, ist:
ausblenden Quelltext
1:
\\.\C:\Daten\null					
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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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:

ausblenden Delphi-Quelltext
1:
PWideChar(WideString(myString))					

_________________
We are, we were and will not be.
s!lenCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: Di 03.11.09 11:55 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Wie gesagt, der direkte Typecast von String nach PWideChar ergibt Unsinn. Wenn du normale Strings unter D7 benutzt, dann muss das so aussehen:

ausblenden 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.

ausblenden 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



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: 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



BeitragVerfasst: Di 03.11.09 14:22 
Musst du wahrscheinlich selbst deklarieren oder probier mal Shlobj.
s!lenCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 24
Erhaltene Danke: 1



BeitragVerfasst: Di 03.11.09 16:46 
So habe mir jetzt einfach meine eigene Variante geschrieben.

ausblenden 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;
  // Dateinamen entfernen und letzten Backslash anfügen
  Dir := ExtractFilePath(Dir);
  Dir := IncludeTrailingPathDelimiter(Dir);
  // Laufwerksbuchstaben ausschneiden
  tmp := Copy(Dir, 13);
  Delete(Dir, 13);

  // Bis zum letzten Verzeichnis durchgehen
  WHILE Pos('\', Dir) <> 0 DO
    BEGIN
      // Position des nächsten Backslash ermitteln
      Position := Pos('\', Dir);
      // Nächstes Verzeichnis an den Pfad hängen
      tmp := tmp + Copy(Dir, 1, Position);
      Delete(Dir, 1, Position);
      // Verzeichnis erstellen
      IF NOT DirectoryExists(tmp) THEN
        IF NOT CreateDirectoryW(PWideChar(WideString('\\?\' + tmp)), nilTHEN
          BEGIN
            Result := False;
            Exit;
          END;
    END;
END;




MfG silenCe
beastofchaos
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: 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".

ausblenden volle Höhe 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:
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) - 23);        
    if (Endung <> 'mp3'and (Endung <> 'wav'then
      begin
      ShowMessage('Das Lied muss eine mp3- oder wav-Datei sein!');  // Fehlermeldung
      BrowseClick(Button4);                                         // Man kann erneut ein Lied aussuchen
      Exit;
      end
    else
      begin
      Edit1.Text := NewSong;                                        // NewSong enthält Pfad (+Name und Endung)
      Selected := True;                                             // Button Add weiß nun, dass ein Lied ausgewählt ist
      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                                                               // mit repeat...until filter ich den Pfad aus "NewSong", so dass ich am Ende nur noch den Namen (+ Endung) habe in "NewSongName"
      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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 22.05.11 12:16 
user profile iconbeastofchaos hat folgendes geschrieben Zum zitierten Posting springen:
Es kommt KEINE Fehlermeldung
Woher auch, die hast die Fehlerbehandlung ja auch komplett ignoriert... :roll: :autsch:

Den Rückgabewert wirfst du genauso weg wie du danach bei einem Fehlschlag nicht mit SysErrorMessage + GetLastError schaust warum es nicht ging... :roll:

Siehe Doku...
msdn.microsoft.com/e...363851(v=vs.85).aspx
beastofchaos
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: So 22.05.11 12:51 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconbeastofchaos hat folgendes geschrieben Zum zitierten Posting springen:
Es kommt KEINE Fehlermeldung
Woher auch, die hast die Fehlerbehandlung ja auch komplett ignoriert... :roll: :autsch:

Den Rückgabewert wirfst du genauso weg wie du danach bei einem Fehlschlag nicht mit SysErrorMessage + GetLastError schaust warum es nicht ging... :roll:

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 :P)

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:

ausblenden 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])), 000);
        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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: 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 :P Da könnte ich eigentlich sogar SoundNamesBefore ganz weglassen :)
Dude566
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1592
Erhaltene Danke: 79

W8, W7 (Chrome, FF, IE)
Delphi XE2 Pro, Eclipse Juno, VS2012
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: So 22.05.11 13:51 
user profile iconDude566 hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 22.05.11 14:01 
Dein Objekt ist eine Instanz der Klasse. ;-)
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  List1 := TStringList.Create;
  List2 := TStringList.Create;

  List2 := List1    // List2 wird eine Referenz von List1

  List1.Add('a');

  ShowMessage(List2[0]);    // Gibt 'a' aus, da es auf List1 verweist! Das will ich aber umgehen

  List1.Free;
  List2.Free;