如何在c#中设置REG_KEY_DONT_VIRTUALIZE标志

时间:2011-03-23 17:41:02

标签: c# windows-7 registry uac

我的问题非常简单,但我找到了一个长时间的谷歌搜索答案 如何将REG_KEY_DONT_VIRTUALIZE标志设置为我创建的注册表项(即HKLM\Software\MyApp)? 我希望我的程序与用户无关。启动我的应用程序的每个用户都应该可以访问位于该位置的相同配置选项。 更改应用程序清单我可以通过以管理员身份运行程序来禁用注册表虚拟化,但我希望普通用户能够运行该程序并读取注册表值。

4 个答案:

答案 0 :(得分:0)

如果您不希望虚拟化您的应用,那么您可以使用清单来表明。如果您在密钥上使用REG_KEY_DONT_VIRTUALIZE,那么所有发生的操作都将失败,因为您的用户将无权使用HKLM。

如果您希望所有用户共享配置,则必须将配置存储在文件而不是注册表中。注册表中没有适合所有用户共享的内容,并允许标准用户编写访问权限。

答案 1 :(得分:0)

目前尚不清楚,虚拟化仅针对传统的非UAC兼容程序启用,并且始终允许读取。我必须假设是问题所在。例如,使用安装程序或Regedit.exe更改密钥的权限,以便Everybody具有写入权限。

答案 2 :(得分:0)

在不更改或添加ACL的情况下,您可以使用带有RegistryKey.OpenBaseKey标志的RegistryView.Registry64 API,确保以编程方式使用的密钥正在查看注册表的64位部分。

无论是否为应用程序启用了注册表虚拟化,这似乎都适用于32位应用程序。

private const string MyRegistryKeyPath = "Software\\My Company\\My App";

private static RegistryKey OpenMyAppRegistryKey(bool requireWriteAccess = false)
{
    using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
    {
        return requireWriteAccess
            ? baseKey.CreateSubKey(MyRegistryKeyPath, RegistryKeyPermissionCheck.ReadWriteSubTree)
            : baseKey.OpenSubKey(MyRegistryKeyPath, RegistryKeyPermissionCheck.ReadSubTree);
    }
}

如果requireWriteAccess为false,则如果指定的密钥不存在,此方法将返回null

我还应该指出,此代码需要提升权限才能打开密钥以进行写访问。但我相信它确保使用以这种方式打开的密钥的非高速读取只会来自注册表的64位视图。

答案 3 :(得分:0)

到目前为止,没有C#或C API来设置注册表项标志。

我认为最安全的方法是使用CreateProcess启动REG.exe命令行工具。

但是,为了记录,我已经粘贴了一些' C'来自this blog的代码,演示了使用未记录的API的另一种方式:

typedef enum _CONTROL_FLAGS {
    RegKeyClearFlags = 0,
    RegKeyDontVirtualize = 2,
    RegKeyDontSilentFail = 4,
    RegKeyRecurseFlag = 8
} CONTROL_FLAGS;

typedef struct _KEY_CONTROL_FLAGS_INFORMATION {
    ULONG   ControlFlags;
} KEY_CONTROL_FLAGS_INFORMATION, *PKEY_CONTROL_FLAGS_INFORMATION;

typedef enum _KEY_SET_INFORMATION_CLASS {
    KeyWriteTimeInformation,
    KeyWow64FlagsInformation,
    KeyControlFlagsInformation,
    KeySetVirtualizationInformation,
    KeySetDebugInformation,
    MaxKeySetInfoClass  // MaxKeySetInfoClass should always be the last enum

} KEY_SET_INFORMATION_CLASS;

NTSYSAPI NTSTATUS NTAPI NtSetInformationKey(
IN HANDLE               KeyHandle,
IN KEY_SET_INFORMATION_CLASS InformationClass,
IN PVOID                KeyInformationData,
IN ULONG                DataLength );

typedef NTSYSAPI NTSTATUS (NTAPI* FuncNtSetInformationKey) (
    HANDLE KeyHandle,
    KEY_SET_INFORMATION_CLASS InformationClass,
    PVOID KeyInformationData,
    ULONG DataLength ); 

BOOL CRegLonMigration::SetDontVirtualizeFlag(LPCTSTR keyPath)
{
    FuncNtSetInformationKey ntsik = (FuncNtSetInformationKey)GetProcAddress(GetModuleHandle( _T("ntdll.dll") ), "NtSetInformationKey" ); 
    KEY_CONTROL_FLAGS_INFORMATION kcfi = {0}; 

    kcfi.ControlFlags = RegKeyDontVirtualize | RegKeyRecurseFlag; 
    HKEY hKey = NULL;
    LSTATUS status;
    if (ERROR_SUCCESS == (status = ::RegOpenKeyEx(ROOT_KEY, keyPath, 0, KEY_ALL_ACCESS, &hKey)))
    {
        NTSTATUS status = ntsik( hKey, KeyControlFlagsInformation, &kcfi, sizeof( KEY_CONTROL_FLAGS_INFORMATION ) ); 
        RegCloseKey( hKey ); 
        return TRUE;
    }

    return FALSE;
}