Non è stato facile, ma ho scoperto come rilevare se la virtualizzazione del controllo dell'account utente è abilitata. Chiamando GetTokenInformation()
e passando TokenVirtualizationEnabled
come classe di informazioni restituirà se la virtualizzazione di file e registro è abilitata. Ecco una funzione C per farlo:
// Gets whether the current process has UAC virtualization enabled.
// Returns TRUE on success and FALSE on failure.
BOOL GetVirtualizationEnabled(BOOL *enabled) {
HANDLE token;
DWORD tmpEnabled;
DWORD returnLen;
BOOL retVal = TRUE;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
return FALSE;
if(!GetTokenInformation(token, TokenVirtualizationEnabled,
&tmpEnabled, sizeof(tmpEnabled), &returnLen)) {
retVal = FALSE;
goto err;
}
*enabled = tmpEnabled;
err:
CloseHandle(token);
return retVal;
}
Un po 'più difficile con P/Invoke, ma qui è, tra cui il P/Invoke intestazioni:
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass
}
public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
public const UInt32 TOKEN_DUPLICATE = 0x0002;
public const UInt32 TOKEN_IMPERSONATE = 0x0004;
public const UInt32 TOKEN_QUERY = 0x0008;
public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID);
[DllImport("advapi32.dll", SetLastError=true)]
static extern bool GetTokenInformation(
IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
int TokenInformationLength,
out uint ReturnLength);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
ref uint TokenInformation, uint TokenInformationLength);
[DllImport("advapi32.dll", SetLastError=true)]
static extern bool OpenProcessToken(IntPtr ProcessHandle,
uint DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool CloseHandle(IntPtr hObject);
static bool TryGetVirtualizationEnabled(out bool enabled) {
IntPtr processHandle = Process.GetCurrentProcess().Handle;
IntPtr token;
uint returnLen;
object tmpEnabled = new uint();
enabled = false;
GCHandle handle = GCHandle.Alloc(tmpEnabled, GCHandleType.Pinned);
try {
if(!OpenProcessToken(processHandle, TOKEN_QUERY, out token))
return false;
try {
if(!GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenVirtualizationEnabled,
handle.AddrOfPinnedObject(), Marshal.SizeOf(typeof(uint)), out returnLen))
return false;
enabled = (uint)tmpEnabled != 0;
} finally {
CloseHandle(token);
}
} finally {
handle.Free();
}
return true;
}
Ho provato a girare la virtualizzazione UAC e spento con Task Manager e verificato che venga restituito il risultato corretto. L'abilitazione e disabilitazione della virtualizzazione può essere effettuata chiamando SetTokenInformation()
.
Microsoft dichiara di aver intenzione di rimuovere la virtualizzazione UAC in una versione futura di Windows e che i programmi non si basino su di essa esistenti. Ho visto un suggerimento da parte di qualcuno di creare un programma separato che non è in grado di controllare i file dal VirtualStore ad AppData, ma non so se sia una buona soluzione o meno.
Questo metodo rileva se la virtualizzazione è abilitata in generale o se è abilitata per uno specifico file/cartella? – Simpleton
In generale. Se la virtualizzazione è abilitata in un processo, tutte le scritture da quel processo nella cartella Programmi, la cartella Windows e HKEY_LOCAL_MACHINE nel registro vengono reindirizzati (e un altro paio). Non può essere abilitato per alcune di queste cartelle e non per altre. –
Rileggendo la tua domanda iniziale, sembra che tu non voglia scoprire se la virtualizzazione è in atto. Se si sta eseguendo un processo a 64 bit con conoscenza del controllo dell'account utente, la virtualizzazione è disabilitata. Per accedere ai dati inseriti nel VirtualStore da una vecchia versione del programma (che aveva la virtualizzazione abilitata), il programma può cercare in% LOCALAPPDATA% \ VirtualStore per vedere se ci sono dei suoi dati lì dentro. Se esiste, può spostare i dati nella posizione corretta, unendola se necessario. –