2011-03-23 54 views
1

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

回答

0

如果你不希望你的应用程序被虚拟化,那么你使用清单来表明这一点。如果你在你的密钥上使用了REG_KEY_DONT_VIRTUALIZE,那么所有的写操作都会失败,因为你的用户将不能写访问HKLM。

如果您希望所有用户共享配置,那么您必须将配置存储在文件而不是注册表中。注册表中没有任何地方适合所有用户共享,并允许标准用户写入访问权限。

0

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

+0

难道你真的崇尚设置ACL将注册表键HKLM全部每个人都可以访问该密钥?对我来说听起来不太好。 – 2011-03-23 19:00:15

+0

@David - 允许所有用户修改共享资源不是一个好习惯,不管它看起来如何。那艘船已经驶了。 – 2011-03-23 19:13:41

0

在不更改ACL或添加ACL的情况下,可以通过RegistryView.Registry64标志使用RegistryKey.OpenBaseKey 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是假的,此方法将返回null如果指定的键不存在。

我还应该指出,这段代码将需要提升的权限才能打开写入权限的密钥。但我相信它可以确保使用以这种方式打开的密钥的未升级读取操作只能来自注册表的64位视图。

0

迄今为止,没有C#或C API来设置注册表项标志。

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

但是,根据记录,我从this blog它展示了如何利用未公开的API另一种方式粘贴一些“C”代码:

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; 
}