自从Win发布以来,微软为作为32位进程运行的遗留应用程序引入了文件虚拟化。作为微软用户帐户控制(UAC)的一部分发布的任何试图写入操作系统保护的任何位置的遗留应用程序都被重定向到VirtualStore。
此时,已经采取步骤确保所讨论的应用程序现在作为一个64位进程运行,UAC知道这一点,但是,这对于将用户数据迁移到一个被认为不受虚拟化影响的位置的问题并没有起到什么作用。
在排除此问题时,我发现在处理多个用户帐户时,在位于C:\Program Files(x86)\MyApp\Data
的遗留路径中进行了一些更改,同时对位于%localappdata%\VirtualStore\Programs\MyApp\Data
的VirtualStore进行了更改。问题是,如何检测是否正在进行文件/文件夹虚拟化,以及如何合并这两个位置?
编辑:我发现了几个网站详细介绍了这个问题,以及如何复制它,但是没有包括修复它的方法。我确实找到了这个引用虚拟,它定义了一个看起来很有前途的文件属性--我在某个地方找到了另一个引用,尽管我不记得它在哪里,它声明这是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
发布于 2013-01-05 04:53:28
这并不容易,但我发现了如何检测是否启用了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;
}
我试着用Task打开或关闭UAC虚拟化,并验证是否返回了正确的结果。启用和禁用虚拟化可以通过调用SetTokenInformation()
来完成。
微软表示,他们计划在未来的Windows版本中删除UAC虚拟化,并让程序不再依赖它。我看到有人建议创建一个单独的程序,而UAC不知道如何将文件从VirtualStore转移到AppData,但我不知道这是否是一个好的解决方案。
发布于 2014-07-02 01:20:58
FWIW,以下是Delphi中检测代码的版本:
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.
发布于 2012-12-31 18:43:01
如果您正在从本地应用程序数据路径“运行”,听起来就像是在尝试标记,在这种情况下:
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)
);
https://stackoverflow.com/questions/14005081
复制相似问题