Programowanie w Delphi7 - UAC

Witam.

Piszę pewien program i napotkałem problem z prawami zapisu pod Vista i Win7.

Program ma tworzyć plik ustawień lub go usuwać (zależnie od akcji wybranej przez użytkownika) w folderze _C:\Users%username%\AppData\Local\MyAppName_ ale niestety plik nie jest ani tworzony ani kasowany ani też nie ma żadnego komunikatu o błędzie.

Podejrzewam że to kwestia UAC i praw dostępu, potrzebuję pomocy w nadaniu mojemu programowi odpowiednich uprawnień.

Na kilku stronach napotkałem wzmianki o programie dodającym odpowiedni manifest do projektu delphi ale nie znalazłem nigdzie działającej jego wersji a Delphi7 którego używam posiada w komponentach jedynie xpmanifest.

Dodam jeszcze kod programu mam poprawny a ze względy na jego przeznaczenie nie mam możliwości wybrania innej ścieżki.

Folder lokalnych danych użytkownika nie jest chroniony przez UAC(dla aktualnie zalogowanego użytkownika). Problem leży gdzie indziej.

Rozwiązanie, które nie ma prawa nie działać: mt.exe z Windows SDK. Tworzysz sobie plik manifest(przykład, jak on ma wyglądać na MSDN) i w regułach “post-build”(nie wiem jak to się może nazywać w Twoim IDE) ręcznie dołączasz dany plik do EXE-ka(

mt.exe -manifest plik.manifest -updateresource:"ścieżka_do.exe;#1"

).

Mógłbyś rozszerzyć myśl? Też mi się wydawało że nie powinno być problemów z dostępem do tego foldera ale jak widać się myliłem…

A nie chciałbym dołączać zewnętrznego pliku manifest bo program ma być programem typu one-file, poza tym win7 podobno często ignoruje zewnętrzne manifesty.

Nie potrzebujesz praw administratora, by mieć odstęp do danych użytkownika(C:\Users%UserName%\AppData) - standardowo ACL ma taką postać:

System - pełna kontrola

Administratorzy - pełna kontrola

Właściciel(%username%) - pełna kontrola

, więc musiałeś coś ręcznie zmienić. Sprawdziłem u siebie(ACL mam takie jak wyżej, mogę tworzyć pliki programowo bez praw administratora).

Temat na TechNet pokazuje, jak to rozwiązać.

Dlatego poleciłem użyć narzędzia mt, które służy do osadzania manifestów. :wink:

Problem właśnie w tym że ja nie mam visty/win7 tylko xp a testy na vista/win7 robię na kompach znajomych więc nie mogę nic im tam zmieniać…

Potrzebuję skutecznej metody umożliwiającej na vist i win7 tworzenie i usuwanie we wspomnianym folderze (w xp program operuje na innym folderze i nie ma żadnych problemów).

Prosiłbym o podanie przyczyn które mogłyby uniemożliwiać zapis w tym folderze.

Możesz, bo mają źle ustawione ACL dla tych folderów(i to nie jest problem programu, tylko błędu użytkownika) :wink:

Jeśli pod Vistą/7 używasz ścieżki zza czasów XP, to program nie zapisze danych w %LOCALAPPDATA%, tylko w %USERPROFILE%/Local Settings/Application Data, tak jak wskazałeś(do Documents and Settings jest link). Ścieżkę do odpowiedniego folderu możesz pobrać za pomocą SHGetKnownFolderPath(XP i wcześniejsze: SHGetFolderPath).

@scripter1

Mimo tego, że jesteś pewien, że program jest napisany dobrze, dodaj jakąś linijkę kodu, która będzie wyświetlać ścieżkę, pod którą następuje próba zapisania pliku konfiguracyjnego i poproś osobę, która testuje Twój program, żeby odczytała Ci tą ścieżkę. Jeśli ścieżka okaże się poprawna, to zapytaj ją czy przypadkiem nie odpala programu w jakiejś piaskownicy. Jeśli nie jest odpalany w piaskownicy, to poproś tą osobę, aby spróbowała odpalić program na innym koncie użytkownika, np. na dopiero co utworzonym.

Możesz też ściągnąć http://technet.microsoft.com/pl-pl/evalcenter/cc442495.aspx testową wersję Windows 7 i zainstalować ją sobie, np. na wirtualnej maszynie, tak żebyś mógł testować samodzielnie. Wymogiem jest jednak posiadanie konta w usłudze Live. Po drodze będziesz też musiał wypełnić jakąś ankietę (ja jej do końca nie wypełniałem).

To zrobiłem na samym początku jak tylko okazało się że coś jest nie tak dlatego napisałem że kod jest poprawny.

To by był dobry pomysł ale nie mam tam konta a nie będę się rejestrował tylko po to, i tak już walczę z jednym portalem bo nie chcą usunąć mojego konta mimo wyraźnego żądania…

@scripter1

A co z tą piaskownicą i próbą odpalenia programu na koncie innego użytkownika (najlepiej nowego)?

Według moich ostatnich testów okazuje się że to nie prawa zapisu są problemem tylko samo deklarowanie ścieżki ze zmienną windowsową.

Po zadeklarowaniu pełnej ścieżki statycznie (do testu) z nazwą usera na którego koncie jest testowane okazało się że działa, teraz tylko muszę zastosować jakąś skuteczną metodę odczytu tej nazwy usera.

Czyli Ty do metody odpowiedzialnej za zapis do pliku przekazywałeś ścieżkę w postaci “C:\Users%username%\AppData\Local\MyAppName” (dokładnie takiej) ? Przecież to jest oczywiste, że to nie może być dobrze. Chyba, że ta metoda samodzielnie dokonywałyby parsowania tej ścieżki, ale to wówczas musiałoby być opisane w dokumentacji. A tak w ogóle to katalog użytkowników nie musi znajdować się na partycji C. Poszukaj metody, która służy do odczytywania wartości zmiennych środowiskowych (ja nie znam Delphi) i odczytuj ścieżkę dla %LOCALAPPDATA%.

Delphi jak mniemam potrafi dostać się do funkcji WinAPI?

Czyli kod NIE JEST poprawny.

Serio uchowałeś się tyle czasu bez Live ID? O.o

Fiołek , kod jest poprawny tylko moja wiedza na temat visty/win7 jest ograniczona ze względu na to że nie mam ani visty ani win7.

I tu włąśnie dochodzimy do meritum bo mój program operuje na ustawieniach innego programu i nie wiem jak dokładnie tamten się odwołuje (czy przez zmienną systemową %LOCALAPPDATA% czy też przez inną) ale wiem że plik na którym ma operować mój program znajduje się właśnie w podanej wyżej przeze mnie ścieżce.

Zakładam że pewnie odwołuje się on do zmiennej %LOCALAPPDATA% bo jakby się odwoływał przez %username% to podejrzewam że by wywalał errory na systemach gdzie faktycznie ten folder nie jest w c:\Users.

W sumie to pierwotnie też odwoływałem się przez %LOCALAPPDATA% ale jak nie działało to zacząłem kombinować inaczej.

PS: Fiołek , uchowałem się i jak już napisałem nie zamierzam tego zmieniać, Live ID jest mi absolutnie zbędne.

Dodane 15.07.2011 (Pt) 22:50

Problem rozwiązany, dziękuję za pomoc.

W razie jakby ktoś szukał rozwiązania to zamieszczam kod który wykorzystałem:

uses:

   ShlObj;


function GetSpecialFolderPath(Folder: Integer; CanCreate: Boolean): string;


var

   FilePath: array [0..255] of char;


begin

 SHGetSpecialFolderPath(0, FilePath, FOLDER, CanCreate);

 Result := FilePath;

end;

Funkcję wywołuję poprzez:

GetSpecialFolderPath ($001c, false);