Autor Beitrag
Kwho
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 15.01.09 19:51 
Hallo, liebe Code-Gurus :flehan:

ich beschäftige mich erst seit kurzen mit Delphi oder mit dem proggen überhaupt.
Das ist mein erstes Projekt. Ok, das mal vorweg und nun zu meinem Problem.

Mein Programm soll per Button1click einen Ordner aus dem versteckten Verzeichniss "Anwendungsdaten"
ins Verzeichniss "eigene dateien" kopieren und per Button2click auch umgekehrt.
Das klappt soweit auch alles prima, aber wegen der absoluten Pfadangaben leider nur auf meinem System (was ziemlich speziel ist: tripleboot, xp auf D, vista auf E).
Und dann ist ja auch noch der Benutzername da.

soo, Frage: Wie schaffe ich es das mein Prog auf jedem beliebigen System unter jedem beliebigen Benutzernamen die Ordner "Anwendungsdaten" und "Eigene Dateien" selbstständig findet um den Kopiervorgang auszuführen :?: :nixweiss:

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:
procedure TfmMinifmod.Button1Click(Sender: TObject);
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;
 begin         //button "neues Backup"
  if CopyDir('d:\dokumente und einstellungen\macozx\anwendungsdaten\mozilla',
             'd:\dokumente und einstellungen\macozx\eigene dateien\Bookmark-Saver') = True then
    ShowMessage('Backup erfolgreich nach "Eigene Dateien"');
 end;
procedure TfmMinifmod.Button2Click(Sender: TObject); //button "wiederherstellen"
function CopyDir(const fromDir, toDir: string): Boolean;
 var
fos: TSHFileOpStruct;
begin
showmessage('sicher?');   // neuen unit basteln!  ok, zurück dialog
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;
begin             //button "wiederherstellen"
  if CopyDir('d:\dokumente und einstellungen\macozx\eigene dateien\Bookmark-  Saver\firefox',
             'd:\dokumente und einstellungen\macozx\anwendungsdaten\mozilla')
 = True then
 ShowMessage('erfolgreich wiederhergestellt.');

end;

procedure TfmMinifmod.FormCreate(Sender: TObject);
begin
  module := nil;
  bkm := nil;
end;

end.


Habe die lösung für mein Problem sicher schon vor Augen gehabt (CSIL :?: , SHgetspezialfolderlocation mit ShlObj, ActiveX, SHFolder in der usesklausel :?: ) aber nix kapiert.

Das ist mein erster Beitrag, sry wenn ich was falsch gemacht habe.
danke schon mal im vorraus für Antworten.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 15.01.09 20:12 
Hallo und :welcome: im Forum!

Das habe ich hier in den FAQ inkl. Demo geschrieben:
www.delphi-library.d....php?p=541636#541636
Um die Ordner zu finden habe ich dabei die Funktion GetSpecialFolder von hier benutzt:
www.delphi-library.de/viewtopic.php?t=9428
Kwho Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Do 15.01.09 20:52 
Thx für die flotte Antwort, damit müsste ich etwas anfangen könen.
Ich werde es mal studieren...
Andreas L.
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1703
Erhaltene Danke: 25

Windows Vista / Windows 10
Delphi 2009 Pro (JVCL, DragDrop, rmKlever, ICS, EmbeddedWB, DEC, Indy)
BeitragVerfasst: Fr 16.01.09 05:27 
Du kannst diese Funktion verwenden:

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:
uses
  ..., ShlObj, Windows, ActiveX;
...
...

function GetShellFolder(CSIDL: integer): string;
var
  pidl                   : PItemIdList;
  FolderPath             : string;
  SystemFolder           : Integer;
  Malloc                 : IMalloc;
begin
  Malloc := nil;
  FolderPath := '';
  SHGetMalloc(Malloc);
  if Malloc = nil then
  begin
    Result := FolderPath;
    Exit;
  end;
  try
    SystemFolder := CSIDL;
    if SUCCEEDED(SHGetSpecialFolderLocation(0, SystemFolder, pidl)) then
    begin
      SetLength(FolderPath, max_path);
      if SHGetPathFromIDList(pidl, PChar(FolderPath)) then
      begin
        SetLength(FolderPath, length(PChar(FolderPath)));
      end;
    end;
    Result := FolderPath;
  finally
    Malloc.Free(pidl);
  end;
end;
Quelle: www.michael-puff.de/Artikel/HOMEDIR.shtml

Anwendung:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var
  Pfad: String;
begin
  Pfad := GetShellFolder(CSIDL_APPDATA);
  ShowMessage(Pfad);  //Gibt z. B. aus : C:\Users\USERNAME\AppData\Roaming oder C:\Dokumente und Einstellungen\USERNAME\Anwendungsdaten
end;
Kwho Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Fr 16.01.09 15:50 
Thx @ Andreas, mit eurer Hilfe habe ich nun folgenden code zusammengezimmert:
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:
 function GetShellFolder(CSIDL_appdata: integer): string;   //begin
var
  pidl                   : PItemIdList;
  FolderPath             : string;
  SystemFolder           : Integer;
  Malloc                 : IMalloc;
begin
  Malloc := nil;
  FolderPath := '';
  SHGetMalloc(Malloc);
  if Malloc = nil then
  begin
    Result := FolderPath;
    Exit;
  end;
  try
    SystemFolder := CSIDL_appdata;
    if SUCCEEDED(SHGetSpecialFolderLocation(0, SystemFolder, pidl)) then
    begin
      SetLength(FolderPath, max_path);
      if SHGetPathFromIDList(pidl, PChar(folderpath)) then
      begin
        SetLength(FolderPath, length(PChar(folderpath)));
      end;
    end;
    Result := FolderPath;
  finally
    Malloc.Free(pidl);
  end;
end;                     //  end

procedure TfmMinifmod.Button1Click(Sender: TObject);
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;
var
  Pfad: String;
begin
  Pfad := GetShellFolder(CSIDL_APPDATA);
  ShowMessage(Pfad);
  if CopyDir('e:\users\macoxz\appdata\roaming\mozilla', //HIER!!!
            'bookmarksaver\mozilla') = True then
 ShowMessage('Backup erfolgreich nach "Bookmarksaver"');
 end;
Ich bin nun ein ganzes Stück weiter. Der Zielordner wird nun immer in dem verzeichnis angelegt in dem sich auch meine EXE befindet. Das ist super und noch besser als ich es ursprünglich haben wollte (eigene dateien) :D , so hat der User alles auf einen Fleck und kann es leicht wiederfinden. Nur als Quelle muss ich noch einen absoluten Pfad eingeben (siehe//HIER!!!(ganz unten)). Wahrscheinlich habe ich einen ganz dummen Fehler gemacht. Kann ich den Befehl COPYDIR denn überhaupt so benutzen oder gibt es vieleicht noch einen, der besser geeignet wäre um ganze Ordner zu kopieren :?:

Danke schonmal
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 16.01.09 16:45 
user profile iconKwho hat folgendes geschrieben Zum zitierten Posting springen:
Ich bin nun ein ganzes Stück weiter. Der Zielordner wird nun immer in dem verzeichnis angelegt in dem sich auch meine EXE befindet. Das ist super und noch besser als ich es ursprünglich haben wollte (eigene dateien) :D , so hat der User alles auf einen Fleck und kann es leicht wiederfinden.
Die eigenen Dateien sind auch ungeeignet. Das Verzeichnis mit der Exe ist es aber auch. Denn wenn dieses unter c:\programme liegt, dann hast du dort nicht unbedingt Schreibrechte...
Genau das hab ich in dem Link oben ja auch ausführlich geschrieben...
www.delphi-library.d....php?p=541636#541636
Die Anwendungsdaten sind schon richtig.

Du hast jedenfalls in deinem aktuellen Code gar keinen (absoluten) Pfad angegeben, und das ist noch schlimmer. Das steht weiter oben in dem Link...
www.delphi-library.d...ewtopic.php?p=499701

user profile iconKwho hat folgendes geschrieben Zum zitierten Posting springen:
Nur als Quelle muss ich noch einen absoluten Pfad eingeben (siehe//HIER!!!(ganz unten)).
Du liest zwar den Pfad zu den Anwendungsdaten aus, benutzt ihn aber nicht...
Andreas L.
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1703
Erhaltene Danke: 25

Windows Vista / Windows 10
Delphi 2009 Pro (JVCL, DragDrop, rmKlever, ICS, EmbeddedWB, DEC, Indy)
BeitragVerfasst: Fr 16.01.09 17:57 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  QuellPfad := IncludeTrailingPathDelimiter(GetShellFolder(CSIDL_APPDATA)) + 'Mozilla\';  //IncludeTrailingPathDelimiter hängt einen \ an den Pfad falls nicht vorhanden
  ZielPfad := IncludeTrailingPathDelimiter(GetShellFolder(CSIDL_APPDATA)) + 'DerNameDeinesProgramms\Backup_' + DateTimeToStr(Now) + '\';  //Now gibt das aktuelle Datum + Zeit aus, DateTimeToStr wandelt es in eine Zeichenkette um. So erhältst du für jedes BackUp einen separaten Ordner mit Zeitangabe
  if ForceDirectories(ZielPfad) then  //Ordnerstruktur erstellen, wenns funktioniert wird kopiert
  begin
    if CopyDir(QuellPfad, ZielPfad) then  //niemals direkt auf TRUE oder FALSE prüfen, bei API-Funkionen kann man hier mal gewaltig auf die Schnauze fallen
      ShowMessage('Die Daten wurden erfolgreich gesichert!');
  end
  else
    ShowMessage('Ziel-Verzeichnis konnte nicht erstellt werden!');


Bedenke aber bitte, das zum sichern der Lesezeichen (Bookmarks) lediglich eine Datei (bookmarks.html) kopiert werden muss, nicht der komplette Profilordner.
Kwho Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Fr 16.01.09 21:58 
@ andreas: damit hab ichs hinbekommen. Danke!

@ jaenicke:

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Die eigenen Dateien sind auch ungeeignet. Das Verzeichnis mit der Exe ist es aber auch. Denn wenn dieses unter c:\programme liegt, dann hast du dort nicht unbedingt Schreibrechte...
Genau das hab ich in dem Link oben ja auch ausführlich geschrieben...
www.delphi-library.d....php?p=541636#541636
Die Anwendungsdaten sind schon richtig.


Das mit den Schreibrechten ist mir schon klar, besonders in Vista. Nur wohin mit so kleinen Tools oder Programmen die ohne Installation auskommen aber eine log oder konfigdatei schreiben wie z.B. Prime95, ResourceHacker oder Stinger um mal einige zu nennen. Ich handhabe das indem ich solche Tools in einen extra dafür angelegten Ordner (c:\TOOLS) ablege und eine verknüpfung zum Desktop oder ins Startmenü erstelle.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 16.01.09 22:09 
Wenn du jetzt das Anwendungsdatenverzeichnis benutzt wie in Andreas Quelltext, dann ist ja auch alles normal wie es sein sollte.

user profile iconKwho hat folgendes geschrieben Zum zitierten Posting springen:
Ich handhabe das indem ich solche Tools in einen extra dafür angelegten Ordner (c:\TOOLS) ablege und eine verknüpfung zum Desktop oder ins Startmenü erstelle.
Und ich handhabe das so, dass ich Tools, die im Ordner der Exe versuchen zu schreiben, so weit möglich von der Festplatte verbanne, es gibt fast immer sauberer geschriebene Alternativen (die dann vielleicht ein paar Euro mehr kosten, aber das sind sie dann auch wert). ;-)

Ich selbst überlasse das meistens einfach dem Benutzer und frage ihn vorher wo die Einstellungen hin sollen. Dafür braucht man ja nicht einmal verschiedene Versionen des Programms zu erstellen. Ich arbeite gerade an einem Beitrag und einer entsprechenden Unit, die da etwas Arbeit abnimmt:
www.delphi-library.d...ewtopic.php?p=541637
Kwho Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Fr 16.01.09 23:14 
Naja offen gesagt hab ichs nicht ganz so gemacht wie in Andreas Quelltext, ich habe die gesicherten Lesezeichen im selben Ordner wie meine Exe :? . Aber das hat einen einfachen Grund, und zwar soll die Anwendung mit den gesicherten Lesezeichen mobil sein um sie auf einen externen Datenträger z.B. USB-Stick zu kopieren um die Lesezeichen dann auf einen anderen PC zu übertragen. Oder auch bei einem neuaufsetzen des Systems. Oder hat man wie ich mehrere Betriebssysteme kann man die Lesezeichen zwischen den BS schnell und einfach verwalten ohne versteckte Ordner sichtbar machen zu müssen und Dateien hin und her zu kopieren. Aber generell ist es natürlich sauberer den Ordner Anwendungsdaten zu verwenden für Konfigurationen oder ähnliches. Nur ist dieser für normale User nicht sichtbar.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 16.01.09 23:17 
Deshalb mache ich es einfach so wie ich in dem Beitrag geschrieben habe. Ich suche einfach nacheinander an den möglichen Positionen nach den Einstellungen. Finde ich sie in meinem eigenen Verzeichnis mit der Exe, dann gehe ich von einer portablen Verwendung aus, etc. ;-)

So kann man sich an die Systemstandards halten und trotzdem eine Möglichkeit der portablen Nutzung anbieten.

Wenn deine Anwendung natürlich explizit portabel sein soll, dann ist das natürlich legitim, dass du das auch nur so programmierst. Das sind dann Ausnahmefälle.
Chemiker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 194
Erhaltene Danke: 14

XP, Vista 32 Bit, Vista 64 Bit, Win 7 64 Bit, Win 10, Win 11
BDS 2006, RAD Studio 2009+C++, Delphi 13, VS 2010 Prof.
BeitragVerfasst: Sa 17.01.09 00:14 
Hallo Kwho,

um an bestimmte System-Informationen zu kommen, habe ich mir eine Klasse geschrieben.
Sie ist nicht komplett, aber leicht zu Erweitern.

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:
unit uApplicationsInfos;
{
********************************************************************************
TAppInfos Klasse
--------------------------------------------------------------------------------
Version       : 1.00
Autor         : HPL
Compiler      : BDS 2006 Update: 2
ltz. Änderung : 06.12.2008

TAppInfos ist ein Klasse, die Informationen zurückgibt wie der Path von be-
          stimmten System-Ordner ist.
--------------------------------------------------------------------------------
Klasse
  TAppInfos

Syntax
  TAppInfos.ApplicationsName;

Beschreibung
  Git den Applicationsname zurück. Ist Hilfreich um bestimmte Ordner für die
  Application anzulegen.

Version: 1.00 vom 06.12.2008
--------------------------------------------------------------------------------
Klasse
  TAppInfos

Syntax
  TAppInfos.Anwendungsdaten;

Beschreibung
  Git den AnwendungsdatenPath zurück. In diesem Path werden z.B. die
  INIT-Dateien der Application abgespeichert.
  z.B.: c:\Dokumente und Einstellungen\Benutzer\Anwendungsdaten\

Version: 1.00 vom 06.12.2008
--------------------------------------------------------------------------------
Klasse
  TAppInfos

Syntax
  TAppInfos.EigeneDateien;

Beschreibung
  Git den Eigene Dateien - Path zurück.
  z.B.: d:\Eigene Dateien von Benutzer

Version: 1.00 vom 06.12.2008

--------------------------------------------------------------------------------
Klasse
  TAppInfos

Syntax
  TAppInfos.AppAnwendungsOrdner;

Beschreibung
  Git den AnwendungsdatenPath mit dem Ordner der Application.
  z.B.: c:\Dokumente und Einstellungen\Benutzer\Anwendungsdaten\ApplicationsName

Version: 1.00 vom 06.12.2008
********************************************************************************
}


interface

uses SysUtils, Forms, ShlObj, Windows;

type
  TAppInfos = Class(TObject)
  private
    class function GetSpecialPath(nFolder: Integer): string; static;
    class function GetApplicationsName: String; static;
    class function GetAnwendungsPath: TFileName; static;
    class function GetEigeneDateien: TFileName; static;
    class function GetAppAnwendungsOrdner: TFileName; static;
  public
    class property ApplicationsName : String Read GetApplicationsName;
    class property AnwendungsPath : TFileName Read GetAnwendungsPath;
    class property EigeneDateien : TFileName Read GetEigeneDateien;
    class property AppAnwendungsOrdner: TFileName Read GetAppAnwendungsOrdner;
  End;

implementation

{ TAppInfos }

class function TAppInfos.GetAnwendungsPath: TFileName;
begin
  Result:= IncludeTrailingPathDelimiter(GetSpecialPath(CSIDL_APPDATA));
end;

class function TAppInfos.GetAppAnwendungsOrdner: TFileName;
begin
  Result:= AnwendungsPath+ApplicationsName;
end;

class function TAppInfos.GetApplicationsName: String;
begin
  Result:= ChangeFileExt(ExtractFileName(Application.ExeName),'');
end;

class function TAppInfos.GetEigeneDateien: TFileName;
begin
  Result:= IncludeTrailingPathDelimiter(GetSpecialPath(CSIDL_PERSONAL));
end;

class function TAppInfos.GetSpecialPath(nFolder: Integer): string;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  if SHGetSpecialFolderPath(Application.Handle, Buffer, nFolder, False) then
    Result := Buffer
  else
    RaiseLastOSError;
end;

end.

Bis bald Chemiker
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 17.01.09 00:34 
SHGetSpecialFolderPath wurde übrigens mit Windows 2000 dann durch SHGetFolderPath ersetzt, und ab Windows Vista ist das CSIDL System komplett veraltet. Dort gibt es dann SHGetKnownFolderPath.
Selbiges gilt natürlich für SHGetSpecialFolderLocation aus meinen Links.

Es funktionieren aber natürlich weiterhin erstmal alle Varianten, auch wenn die alten ab Vista nur noch ein Wrapper für SHGetKnownFolderPath sind und selbst keine Funktionalität mehr haben. ;-)
Chemiker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 194
Erhaltene Danke: 14

XP, Vista 32 Bit, Vista 64 Bit, Win 7 64 Bit, Win 10, Win 11
BDS 2006, RAD Studio 2009+C++, Delphi 13, VS 2010 Prof.
BeitragVerfasst: Sa 17.01.09 00:49 
Hallo jaenicke,

das ist klar, aber so bleibt man abwärts kompatibel.

Ein nützlicher Link dazu: msdn.microsoft.com/e...ibrary/bb762181.aspx

Bis bald Chemiker