如何在 C# 中设置 REG_KEY_DONT_VIRTUALIZE 标志

发布于 2024-10-25 09:03:16 字数 236 浏览 4 评论 0原文

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

My question is very simple, but i dint found an answer googling long time.
How to set REG_KEY_DONT_VIRTUALIZE flag to registry key created by me (i.e. HKLM\Software\MyApp)?
I want my program to be user-independent. Every user starting my app should have access to the same configuration options located in that location).
Changing application manifest I can disable registry virtualization by running program as administrator, but I want normal user be able to run the program and read registry values.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秉烛思 2024-11-01 09:03:16

如果您不希望您的应用程序被虚拟化,那么您可以使用清单来表明这一点。如果您在密钥上使用 REG_KEY_DONT_VIRTUALIZE ,那么将会发生的情况是所有写入都会失败,因为您的用户没有 HKLM 的写入权限。

如果您希望所有用户共享配置,那么您必须将配置存储在文件中而不是注册表中。注册表中没有适当的地方可供所有用户共享并允许标准用户进行写访问。

If you don't want your app to be virtualized then you use a manifest to indicate that. If you use REG_KEY_DONT_VIRTUALIZE on your key then all that will happen is that all the writes will fail because your users won't have write access to HKLM.

If you want all your users to share configuration then you'll have to store the configuration in a file rather than the registry. There's nowhere appropriate in the registry that is shared by all users and allows standard users write access.

冷了相思 2024-11-01 09:03:16

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

This is pretty unclear, virtualization is only enabled for legacy non-UAC compatible programs and reading is always permitted. I have to assume that writing is the problem. Change the permissions on the key with, say, your installer or Regedit.exe so that Everybody has write access.

静水深流 2024-11-01 09:03:16

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

无论是否为应用程序启用注册表虚拟化,这似乎都适用于 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 位视图。

Without changing or adding ACLs to the key, you can ensure that the key you are using programmatically is viewing the 64-bit part of the registry by using the RegistryKey.OpenBaseKey API with the RegistryView.Registry64 flag.

This appears to work properly for 32-bit applications regardless of whether or not registry virtualization is enabled for the app.

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

If requireWriteAccess is false, this method will return null if the specified key does not exist.

I should also point out that this code will require elevated permissions to open the key for write access. But I believe it ensures that unelevated reads using keys opened in this fashion will only come from the 64-bit view of the registry.

谁对谁错谁最难过 2024-11-01 09:03:16

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

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

但是,作为记录,我粘贴了此博客中的一些“C”代码,其中演示了另一种使用未记录的 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;
}

To date, there is no C# or C API to set the registry key flags.

I assume the safest way is to launch the REG.exe command line tool using CreateProcess.

But, for the record, I have pasted some 'C' code from this blog which demonstrates another way using an undocumented 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文