Autor Beitrag
Kay E.
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: Mo 18.07.11 23:50 
Hallo zusammen!

Ich wollte mir ein kleines Konsolenprogramm schreiben, dass mir (hardcoded) meine Diplomarbeit sichert. Dazu soll von einem USB-Stick, der die aktuellen Daten enthält (das ist der 'Store N Go'-Stick, s.u.) zuerst eine Kopie auf die Festplatte gemacht werden und von dort auf einen anderen USB-Stick (der 'Corsair'), sofern gewünscht. Die Backups sollen fortlaufend numeriert werden.
Ich hab jetzt folgenden Code:

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:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
program KopiererDA;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ShellAPI,
  Windows,
  Classes;

var
  VolumeName: String;
  DriveOrig, DrivePlatte, DriveUSB: Char;
  DirName: string;
  DirNameOld: string;
  DirNameTemp: string;
  StdInput: String;
  i, j: Integer;

const
  cOrdnerName = 'Diplomarbeit';
  cDAOrdnerOriginal = '\Diplomarbeit\Diplomarbeit\';
  cDAKopiePlatte = '\Universität & Studium\DA Backup\';
  cPlattenName: string = 'Sonstiges';
  cUSBName: string = 'Corsair';
  cOrigName: string = 'STORE N GO';
  cDAKopieUSB = '\Backup DA\';

function CopyDir(const fromDir, toDir: string): Boolean;
var
   fos: TSHFileOpStruct;
begin
   ZeroMemory(@fos, SizeOf(fos));
   with fos do
   begin
     wFunc := FO_COPY;
     fFlags := FOF_FILESONLY;
     pFrom := PChar(fromDir + #0);
     pTo := PChar(toDir)
   end;
   Result := (0 = ShFileOperation(fos));
end;

function GetVolumeName(DriveLetter: Char): String;   //http://www.swissdelphicenter.ch/de/showcode.php?id=153
var
   dummy: DWORD;
   buffer: array[0..MAX_PATH] of Char;
   oldmode: LongInt;
begin
   oldmode := SetErrorMode(SEM_FAILCRITICALERRORS);
   try
     GetVolumeInformation(PChar(DriveLetter + ':\'),
                          buffer,
                          SizeOf(buffer),
                          nil,
                          dummy,
                          dummy,
                          nil,
                          0);
     Result := StrPas(buffer);
   finally
     SetErrorMode(oldmode);
   end;
end;




begin
  try
    for i := ord('c'to ord('z'do
    begin
      if CompareText(GetVolumeName(char(i)), cOrigName) = 0 then
        DriveOrig := char(i);
      if CompareText(GetVolumeName(char(i)), cUSBName) = 0 then
        DriveUSB := char(i);
      if CompareText(GetVolumeName(char(i)), cPlattenName) = 0 then
        DrivePlatte := char(i);
    end;

    if DriveOrig = '' then
    begin
      WriteLn('Laufwerk von Original kann nicht gefunden werden - Abbruch');
      ReadLn;
      exit;
    end;
    if DrivePlatte = '' then
    begin
      WriteLn('Laufwerk von Platte kann nicht gefunden werden - Abbruch');
      ReadLn;
      exit;
    end;
    if DriveOrig = '' then
    begin
      WriteLn('Laufwerk von USB-Sicherung kann nicht gefunden werden - Überspringen? [j,n]');
      ReadLn(StdInput);
      if StdInput <> 'j' then
        exit;
    end;

    for i := 1 to 255 do
    begin
      DirNameTemp := cOrdnerName + 'Bkp' + inttostr(i);
      if not DirectoryExists(DrivePlatte + ':\' + cDAKopiePlatte + DirNameTemp + '\'then
      begin
        DirName := DrivePlatte + ':' + cDAKopiePlatte + DirNameTemp + '\';
        break;
      end;
    end;

    if DirectoryExists(DriveOrig + ':' + cDAOrdnerOriginal) then
      if not CopyDir(DriveOrig + cDAOrdnerOriginal, DirName) then
      begin
        WriteLn('Fehler beim kopieren von Original zu Platte aufgetreten - Abbruch');
        ReadLn;
        exit;
      end
    else
    begin
      WriteLn('Kann Originalordner nicht finden - Abbruch');
      ReadLn;
      exit;
    end;

    DirNameOld := DirName;
    DirName := DriveUSB + ':' + cDAKopieUSB + DirNameTemp + '\';

    if DirectoryExists(DirNameTemp) then
      if not CopyDir(DirNameTemp, DirName) then
      begin
        WriteLn('Fehler beim kopieren von Platte zu USB-Stick aufgetreten - Abbruch');
        ReadLn;
        exit;
      end
    else
    begin
      WriteLn('Kann Plattenordner nicht finden - Abbruch');
      ReadLn;
      exit;
    end;

    WriteLn('Ordner erfolgreich kopiert. Schönen Tag noch!');
    ReadLn;
       
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.


Ich hab das Problem, dass er völlig falsche Laufwerksbuchstaben findet und damit eben auch nicht den Originalordner. Aber anstatt bei der entsprechenden if-Abfrage in den else-Zweig zu springen, überspringt er die und geht zur nächsten Anweisung.
Ich steh grad aufm Schlauch. Wo ist das Problem? Warum findet er die Laufwerke nicht richtig? Warum überspringt er den Else-Zweig?

Ich hoff, ihr könnt mir helfen!

Grüße Kay
Kay E. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: Di 19.07.11 21:25 
Push
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 19.07.11 22:54 
Naja, weshalb ich dazu nichts geschrieben hatte ist, dass du nicht dazu geschrieben hast was beim Debuggen denn genau passiert. Denn wenn da ein falscher Laufwerksbuchstabe herauskommt, musst du ja beim Debuggen sehen warum.

Wenn du in der Schleife an der Stelle bist, dass der richtige Buchstabe vorliegt, dann sollte CompareText ja auch 0 liefern. Das musst du eben im Debugger auswerten und analysieren was da schief geht...
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 20.07.11 07:57 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
if DriveOrig = '' then
    begin
      WriteLn('Laufwerk von Original kann nicht gefunden werden - Abbruch');
      ReadLn;
      exit;
    end;
    if DrivePlatte = '' then
    begin
      WriteLn('Laufwerk von Platte kann nicht gefunden werden - Abbruch');
      ReadLn;
      exit;
    end;
    if DriveOrig = '' then //<------- DriveUSB ???


Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt
Moderiert von user profile iconMartok: Highlight-Tags hinzugefügt
Kay E. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: Mi 20.07.11 18:19 
@ Jaenicke: Ähm, ja... Und daurch, dass du nichts geschrieben hast, hab ich natürlich auch gewusst, was für Informationen noch gebraucht werden, nicht wahr? Und den Debugger hab ich durchaus auch schon mal genutzt. Da ich aber ja nichts sinnvolles gefunden habe, hab ich die Frage hier gestellt. Alles andere wäre irgendwie ein wenig... witzlos.

@ Hathor: Du hast Recht, das war ein kleiner Copy-Paste Fehler. Ist behoben.

-------------------------

Das Problem mit den Laufwerksbuchstaben hab ich jetzt rausgefunden. Das liegt daran, dass der Buffer in GetVolumeName seinen alten Wert behält. Mit einem reinitialisieren auf #0 nach dem result oder vor GetVolumeInformation behebt das Problem.

Dafür gibt es ein neues Problem: Das Kopieren an sich funktioniert nicht. Mit einfachen Testordnern (ein Ordner, ein leeres txt-file darin) funktionierts, aber bei meinen Ordnern klappts nicht (mehrere Dateien und Unterordner). Ich habe mir nochmal eingehend die Structs und den API-Aufruf angeschaut und die oben gepostete CopyDir-Funktion nochmal ein wenig abgeändert.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function CopyDir(const fromDir, toDir: string): Boolean;
var
   fos: TSHFileOpStruct;
begin
   ZeroMemory(@fos, SizeOf(fos));
   with fos do
   begin
     wFunc := FO_COPY;
     fFlags := FOF_NOCONFIRMMKDIR;
     pFrom := PChar(fromDir + #0);
     pTo := PChar(toDir + #0)
   end;
   Result := (0 = ShFileOperation(fos));
end;


Ich hab bei den Flags FOF_FILESONLY rausgenommen, so dass ich sicher sein kann, dass auch die Unterordner kopiert werden.
FOF_NOCONFIRMMKDIR hab ich dazugenommen, mit dem Gedanken, dass das Kopieren deswegen vlt. nicht klappt (und es sinnvoll ist)
Und dann steht in der Hilfe, dass pTo auch doppelt Nullterminiert sein soll, deswegen dann noch ein #0 hinten dran.

Nichts desto trotz funktionierts nicht. Ich bekomm aber keine Fehler, sondern ShFileOperation liefert einfach nicht 0 zurück.
Der pFrom-Pfad existiert (wird geprüft) und der pTo-Pfad soll ohne Nachfrage angelegt werden, wobei das Laufwerk auch existiert (wird auch geprüft). Was kann ich also tun, um rauszufinden, wo mein Fehler liegt? Was mach ich bei dem Aufruf falsch?

Grüße Kay
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 20.07.11 18:48 
Welcher Wert kommt denn zurück?

Und sagt GetLastError vielleicht etwas?
Kay E. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: Mi 20.07.11 19:15 
Hat sich erledigt.
Im oberen Code prüf ich in Zeile 110, ob das Folder existiert. In Zeile 111 hab ich aber ':' vergessen. Im Debugger hab ich das dann gefühlte 10000 mal übersehen. Naja, manchmal sieht man den Wald vor lauter Bäumen nicht.

Danke euch allen!


P.S: @jaenicke: Der Wert war immer ein anderer, nie gleich. Just for information.