2011-03-23 83 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; 
}