由于赢Vista的发布,微软引入了文件虚拟化运行的32位进程的遗留应用程序。 发布作为微软的用户帐户控制(UAC)的任何遗留应用程序试图写入审议了操作系统保护被重定向到VirtualStore任何位置的一部分。
在这一点上,已经采取步骤,以确保有问题的应用程序现在可以作为一个64位的过程,是UAC注意,但是,这无助于解决迁移的用户数据被认为是虚拟化安全的位置的问题。
而解决此问题,我发现有多个用户打交道时占据一些变化已经位于C遗留路径内提出的:\程序文件(x86)\ MyApp的\数据,而在同一时间,已经作了修改,以位于VirtualStore%LOCALAPPDATA%\ VirtualStore \程序\ MyApp的\数据。 这个问题的存在,我怎么能检测是否有文件/文件夹虚拟化正在发生,我怎么能合并这两个位置?
编辑:我发现几个网站,详细的问题,以及如何复制它,但没有包括的方式来解决它。 我没有找到这个参考FILE_ATTRIBUTE_VIRTUAL定义,似乎有希望的文件属性-我发现了另一个参考的地方,虽然我不记得在哪里,指出这是Windows使用的属性来指示文件虚拟化正在发生和标志的请求重定向。
这些链接描述的问题:
http://www.c-sharpcorner.com/uploadfile/GemingLeader/windows-file-and-registry-virtualization/
http://www.codeproject.com/Articles/66275/Windows-Vista-File-and-Registry-Virtualization
http://download.microsoftvirtuallabs.com/download/8/a/7/8a71365b-4c80-4e60-8185-8f12f59bf1d4/UACDataRedirection.pdf
是不容易的,但我发现如何检测UAC虚拟是否启用。 调用GetTokenInformation()
并在通过TokenVirtualizationEnabled
作为信息类将返回文件和注册表虚拟化是否已启用。 这里是一个C函数来做到这一点:
// 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;
}
有点难度的P / Invoke的,但在这里它是包括的P / Invoke标题:
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;
}
我试图关闭UAC虚拟化和关闭使用任务管理器,并验证返回正确的结果。 启用和禁用虚拟化可以通过调用来完成SetTokenInformation()
微软表示,他们计划在未来的Windows版本移除UAC虚拟化和程序不依赖于它现有的。 我看见有人建议制作一个单独的程序,不支持UAC从VirtualStore移动文件到应用程序数据,但我不知道这是一个很好的解决与否。
FWIW,这里是德尔福的检测代码的版本:
unit checkvirtual;
interface
uses windows;
function GetVirtualizationEnabled(var enabled:Boolean):Boolean;
implementation
// Gets whether the current process has UAC virtualization enabled.
// Returns TRUE on success and FALSE on failure.
function GetVirtualizationEnabled(var enabled:Boolean):Boolean;
var
token:THandle;
tmpEnabled:DWORD;
returnLen:DWORD;
begin
result:=false;
enabled:=false;
if not(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)) then exit;
try
if not(GetTokenInformation(token, TokenVirtualizationEnabled,
@tmpEnabled, sizeof(tmpEnabled), returnLen)) then exit;
enabled:=tmpEnabled<>0;
result:=true;
finally
CloseHandle(token);
end;
end;
end.
听起来像是你试图标志,如果你是从本地应用程序数据路径“运行”,在这种情况下:
var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Console.WriteLine(
"Current path is:{0}, AppData Path is {1}, Current is subpath of appdata path:{2}",
currentPath,
appDataPath,
currentPath.StartsWith(appDataPath)
);