Zapis pliku INI do %AppData% w Windows 7

0

Witajcie :)

Problem dotyczy Windows 7. Jak wytłumaczyć brak dostępu do zapisu pliku INI (klasa TIniFile) do folderu %AppData%, podczas gdy zapis łańcuchów do pliku w tym folderze metodą SaveToFile klasy TStringList (również TMemo) przebiega bez problemu?

Pzdr.
Marogo

0

Powinno działać. Może daj kod co działa, a co nie?

0

A sprawdzałeś, czy tylko domniemasz że powinno działać? Co do kodu, to jest to zwykła operacja zapisu do pliku INI oraz StringList-y do pliku. Na XP działa w obu przypadkach.

Przypuszczam, że chodzi tu o uprawnienia funkcji na których bazują obie klasy, bo dla zapisu TStringList używa funkcji CreateFile i WriteFile, a TIniFile funkcji WritePrivateProfileString, która być może nie ma takiego "przebicia" do zasobów dysku jak te pozostałe.

0

a spróbuj zapisywać ini najpierw w TEMP-ie, a potem dowolnym sposobem przenieść go do ządanego katalogu.

poza tym, wydaje mi się że do WritePrivateProfileString nie podajemy katalogu, a jedynie nazwę pliku – system już go sobie zapisze tam gdzie lubi.

0

Ja zapisuje ini w podkatalogu w %AppData% i nie ma problemów. Domyślnie funkcje WinAPI do obsługi plików INi, jak i klasa TIniFile, będąca na nie opakowaniem w Delphi 7 chcą zapisywać plik ini do katalogu Windowsa, jeżeli nie podamy konkretniej ściezki. Co wiadomo - przy włączonym UAC i bez zezwolenia programowi na uruchomienie jako Administrator - się nie powiedzie.

0

Może ktoś byłby tak uprzejmy i sprawdził na 7-ce i w Delphi 2009 czy działa mu to co mi nie działa...:)
Oto przykładowy kod:

Function IniPath: String; 
 Var
  FolderSpec: array[0..MAX_PATH] of Char;
  FolderSpecjalny: String;
 Const
   CSIDL_COMMON_APPDATA = $23;
begin
  SHGetSpecialFolderPath(0, FolderSpec, CSIDL_COMMON_APPDATA , False);
  FolderSpecjalny:=FolderSpec;
  If Not DirectoryExists(FolderSpecjalny+'\TestIni') then ForceDirectories(FolderSpecjalny+'\TestIni');
  Result:=FolderSpecjalny+'\TestIni\';
end;


procedure TForm1.Button1Click(Sender: TObject);
Var
 INI: TIniFile;
 SL: TStringList;
begin
  ShowMessage('Folder specjalny: ' +IniPath); 
  INI:=TIniFile.Create(IniPath+'IniFile.Ini');
  try
    INI.WriteString('Sekcja','Klucz', 'Wartość');
  finally
    INI.Free;
  end;
  //-------------------------------------
  SL:=TStringList.Create;
  try
    SL.Add('Łańcuch stringlisty');
    SL.SaveToFile(IniPath+'StringList.txt');
  finally
    SL.Free;
  end;
end;
 
0

Nie mam Delphi 2009, ale pod Windows 7 oraz Delphi 7 ten kod działa ok...

//...
uses
  ShlObj;

function AddBackSlash(Path : string) : string;
begin
  Result := '';
  if Path = '' then
  begin
    Exit;
  end;
  if Path[Length(Path)] <> '\' then
  begin
    Result := Path + '\'
  end
  else
  begin
    Result := Path;
  end;
end;

function GetAppDataDirectory : string;
var
  Pidl : PItemIDList;
  Folder : array[0..MAX_PATH] of Char;
begin
  SHGetSpecialFolderLocation(0, CSIDL_APPDATA, Pidl);
  SHGetPathFromIDList(PIDL, Folder);
  Result := AddBackSlash(Folder);
end;

Sprawdź sobie co zwróci:

  Edit1.Text := GetAppDataDirectory;

Natomiast do ewentualnego tworzenia podkatalogów w podanej ścieżce stosuje zwykle taką funkcję jak poniżej, którą kiedyś wygooglowałem i nie zmieniałem jej, bo jak dla mnie działa idealnie.

function MakeDirectory(Dir : string) : boolean;
  function Last(What : string; Where : string) : integer;
  var
    Ind : Integer;
  begin
    Result := 0;
    for Ind := (Length(Where) - Length(What) + 1) downto 1 do
      if Copy(Where, Ind, Length(What)) = What then
      begin
        Result := Ind;
        Break;
      end;
  end;

var
  Ind : integer;
  PrevDir : string;
begin
  Result := True;
  if Copy(Dir, 2, 1) <> ':' then
    if Copy(Dir, 3, 1) <> '\' then
      if Copy(Dir, 1, 1) = '\' then
        Dir := 'C:' + Dir
      else
        Dir := 'C:\' + Dir
    else
      Dir := 'C:' + Dir;
  if DirectoryExists(Dir) = False then
  begin
    Ind := Last('\', Dir);
    PrevDir := Copy(Dir, 1, Ind - 1);
    if DirectoryExists(PrevDir) = False then
    begin
      MakeDirectory(PrevDir);
    end;
    Result := CreateDir(Dir);
  end;
end;
0

Zastosowałem komponent TBigIniFile dostępny na Torry.net (fajny też jest TIniFilesEx), który bazuje na TStringList, a zapis na Writeln.
Jak wynika z opisu tego drugiego komponentu, coś jest na rzeczy z dostępem do folderów specjalnych w klasie TIniFile:

"TMemIniFileEx and TIniFileEx extend the respective baseclasses to use the Windows special folders APP_DATA, LOCAL_APP_DATA and COMMON_APP_DATA." :D

0

Myślcie! CSIDL_COMMON_APPDATA to nie to samo co CSIDL_APPDATA. CSIDL_COMMON_APPDATA to folder AllUsers/Dane aplikacji, do niego także na XP mógł zapisywać tylko administrator, to folder tylko do odczytu z globalnymi ustawieniami programu widocznymi dla wszystkich użytkowników. CSIDL_APPDATA to {użytkownik}/Dane aplikacji, folder prywatny, do zapisu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1