Czy da się wymusić na aplikacji pisanej w Delphi, aby bez żadnych ustawień w systemie (PPM->Uruchom jako administrator) uruchamiała się w systemie Windows Vista i 7 w trybie administratora?
tak - było ostatnio, trzeba odpowiednio spreparować manifest
Możesz mi wskazać ten temat, bo szukałem, ale nic konkretnego nie mogę znaleźć.
Znalazłem wiele rozwiązać, choć żadne mnie nie zachwyciło, gdyż żadne nie działało jak trzeba jeśli w ogóle działało...
Skorzystałem z poniższego rozwiązania, gdzie style w XP działają poprawnie i podobno w Viście uruchamia się jako administrator, lecz nie u mnie:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
name="CiaoSoftware.Ciao.Shell.Contacts"
processorArchitecture="x86"
version="5.1.0.0"
type="win32"/>
<description>Windows Shell</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
Wyczytałem, że w Windows 7, trzeba dorzucić do tego pliku to:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below indicates application support for Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--The ID below indicates application support for Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
Lecz i to nie dawało żadnych rezultatów. Może po prostu robię coś źle. Wrzucam to do pliku o jakieś dowolnej nazwie z rozszerzeniem 'manifest'. Potem do pliku o tej samej nazwie co plik manifestu, tylko że o rozszerzeniu 'RC' wrzucam to:
1 24 "Nazwa_pliku.Manifest"
Na koniec z konsoli Windows kompiluje to poleceniem:
brcc32 Nazwa_pliku.RC -foNazwa_pliku.REC
(po uprzednim skopiowaniu pliku brcc32.exe do lokalizacji z plikiem manifestu) i w unicie głównym projektu dorzucam:
{$R Nazwa_pliku.REC}
Co jest nie tak?
{
Manifesty aplikacji nie są niczym nowym w Windows Vista - dotychczas używano już ich w Windows XP.
W Windows Vista dodano jednak nowy element, dzięki któremu można określić wymagany poziom
uprawnień dla aplikacji.
Wygląda on przykładowo tak:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
Dostępne wartości dla atrybutu level to:
* requireAdministrator - aplikacja jest uruchamiana od razu w stanie podwyższonych uprawnień
* highestAvaliable - aplikacja jest uruchamiana z maksymalnymi prawami dostępnymi dla danego użytkownika
* asInvoker - aplikacja działa z takimi uprawnieniami, z jakimi została uruchomiona
Atrybut uiAccess odpowiada za pewne zachowania dotyczące aplikacji -
wartość false powinna być stosowana najczęściej, wartość true pozwala aplikacji wysyłać
zdarzenia do okien aplikacji o wyższych uprawnieniach. Aby uruchomić aplikację z uiAccess
ustawionym na true, musi być ta aplikacja podpisana cyfrowo z użyciem mechanizmu Authenticode.
Tworzenie manifestu
UWAGA: Remove all references to XPMan unit from project!!!
UWAGA: Usuń komponent XPMan jeśli chcesz użyć zmodyfikowanego Manifestu dla XP i Visty !
Aby określić wymagany poziom uprawnień w aplikacji, należy najpierw stworzyć odpowiedni plik manifestu
- powinien on mieć taką nazwę jak plik wykonywalny, z rozszerzeniem .manifest.
Na przykład może on wyglądać tak:
Aplikacja: IsUserAdmin.exe
Manifest: IsUserAdmin.exe.manifest
//-->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
processorArchitecture="X86"
name="IsUserAdmin"
type="win32"/>
<description>Opis aplikacji</description>
<!-- Wymagania odpowiedzialne za bezpieczeństwo. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
//<--
Jednak dotyczy to tylko i wyłącznie aplikacji dla Windows Vista. Aplikacje,
które mają pracować także w Windows XP, niestety należy nieco zmodyfikować manifest.
Jest to spowodowane, że aplikacja dodająca manifesty, mt.exe z pakietu Visual Studio 2005,
posiada błąd uniemożliwiający użycie drugiej przestrzeni nazw w pliku XML. Można to obejść
stosując taką konstrukcję pliku:
UWAGA:
Jeśli plik manifestu jest źle sformatowany (zawiera błędne dane),
może pojawiać się BlueScreen w Windows.
Czytaj błąd Microsoft: KB921337.
//-->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-
com:asm.v2">
<ms_asmv2:security>
<ms_asmv2:requestedPrivileges>
<ms_asmv2:requestedExecutionLevel
level="requireAdministrator">
</ms_asmv2:requestedExecutionLevel>
</ms_asmv2:requestedPrivileges>
</ms_asmv2:security>
</ms_asmv2:trustInfo>
</assembly>
//<--
Taki plik manifestu należy dołączyć do zasobów aplikacji.
W pliku .rc powinny się znaleźć przykładowo takie linie:
//-->
#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST "nazwa_aplikacji.exe.manifest"
//<--
Dodanie manifestu w kodzie
}
program
{$R 'ExecetionLevelManifest.res' 'ExecutionLevelManifest.rc'}
uses
Forms,
// ...;
{$R *.res}
begin
Application.Initialize;
//
Application.Run;
end;
{
Zapisuj swoje dane, logi za pomocą funkcji SHGetFolderPath w następujących folderach
(nigdy nie używaj do tego folderów "ProgramFiles", "Windows", "System32" !).
}
CSIDL_PERSONAL { My Documents }
CSIDL_APPDATA { Application Data, new for NT4 }
CSIDL_LOCAL_APPDATA { non roaming, user\Local Settings\Application Data }
CSIDL_COMMON_APPDATA { All Users\Application Data }
CSIDL_MYPICTURES { My Pictures, new for Win2K }
CSIDL_COMMON_DOCUMENTS { All Users\Documents }
uses
SHFolder;
function GetFolder(CSIDL: Integer; ForceFolder: Boolean = False): String;
var
i: Integer;
begin
SetLength(Result, MAX_PATH);
if ForceFolder then SHGetFolderPath(0, CSIDL or CSIDL_FLAG_CREATE, 0, 0, pChar(Result))
else SHGetFolderPath(0, CSIDL, 0, 0, pChar(Result));
i := Pos(#0, Result);
if i > 0 then SetLength(Result, Pred(i));
end;
{Przykład użycia}
function GetLocalAppDataFolder(ForceFolder: Boolean = False): String;
begin
Result := GetFolder(CSIDL_LOCAL_APPDATA, ForceFolder);
end;
{Jak uruchamiać inne programy jako Administrator ?}
procedure RunAsAdmin(hWnd: HWND; aFile, aParam: String);
var
Sei: TShellExecuteInfoA;
begin
FillChar(Sei, SizeOf(Sei), 0);
Sei.cbSize := SizeOf(Sei);
Sei.Wnd := hWnd;
Sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
Sei.lpVerb := 'runas';
Sei.lpFile := pChar(aFile);
Sei.lpParameters := pChar(aParam);
Sei.nShow := SW_SHOWNORMAL;
if not ShellExecuteEx(@Sei) then RaiseLastOSError;
end;
{lub zmodyfikowana procedura w/w}
procedure TFormODK.UruchomProgram(Plik, Param: String);
var
Sei: TShellExecuteInfoA;
begin
{Jeśli nie jest to Win9x}
if Win32Platform <> VER_PLATFORM_WIN32_WINDOWS then
begin
FillChar(Sei, SizeOf(Sei), 0);
Sei.cbSize := SizeOf(Sei);
Sei.Wnd := Application.Handle;
Sei.fMask := SEE_MASK_IDLIST or SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
{Jeśli jest to Vista}
if Win32MajorVersion >= 6 then Sei.lpVerb := 'runas'
else Sei.lpVerb := 'open';
Sei.lpFile := pChar(Plik);
Sei.lpParameters := pChar(Param);
Sei.nShow := SW_SHOWNORMAL;
if not ShellExecuteEx(@Sei) then RaiseLastOSError;
end
else ShellExecute(Application.Handle, 'open', pChar(Plik), pChar(Param), nil, SW_SHOWNORMAL);
end;
{Dodanie do własnej aplikacji ikonki Shield Visty, która informuje iż wymagane są podwyższone uprawnienia}
const
BCM_FIRST = $1600; //Button control messages
BCM_SETSHIELD = BCM_FIRST + $000C;
procedure SetElevationRequiredState(aControl: TWinControl; Requiered: Boolean);
var
i: Integer;
begin
i := Integer(Requiered);
SendMessage(aControl.Handle, BCM_SETSHIELD, 0, i);
end;
{Wywołanie}
SetElevationRequiredState(B_Przycisk.Control, True);
Dobra jutro wszystko przetestuje, ale co z Windows 7? Ten sam manifest co z Visty ma działać?
Od Visty w górę (jeśli chodzi o uprawnienia).
Od XP w górę (jeśli chodzi o style).
Napisałem wszystko tak jak tam jest, ale niestety nie działa.
Tzn co masz na myśli ?
Wiesz o tym, że UAC i tak (jeśli jest włączone) to poprosi Cię o podwyższenie uprawnień ?
Odpada Ci tylko ręczne wybieranie programu przez "Uruchom jako administrator".
Poza tym, pokaż kod.
UAC poprosi o podwyższenie uprawnień, ale oszczędzi to przykrych skutków działania programu na ograniczonych uprawnieniach, szczególnie jeżeli chodzi o zapis plików lub do kluczy innych niż HKCU.
ja zrobiłem to sobie tak i działa fajnie, nie muszę się martwić o to.
Znajdź plik WindowsXP.res w katalogu %PROGRAMFILES%\Borland\Delphi7\Lib
Podmień całą jego zawartość na :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<v3:trustInfo xmlns:v3="urn:schemas-microsoft-com:asm.v3">
<v3:security>
<v3:requestedPrivileges>
<v3:requestedExecutionLevel level="requireAdministrator" />
</v3:requestedPrivileges>
</v3:security>
</v3:trustInfo>
</assembly>
I masz sprawę załatwioną. Do każdej aplikacji dodajesz komponent XPManifest (XPman.pas). Jeżeli go nie masz, sciągnij z neta, zainstaluj w delphi i postępuj tak jak ja Ci napisalem.
Pozdro!