Open files and registry keys with minimum access required. |
Windows 2000 introduces new security settings that make it possible for system administrators to restrict access to most of a machine. You can avoid unneccessary errors in your application by only opening registry keys and files with the minimum access you need to get the job done.
These new options make it possible that your program will fail in a read/write operation, it is important that you handle these failures gracefully and continue to operate. If you are reading user preferences for instance, use the defaults, notify the user of the situation and continue.
Typically, programs have greater access to HKEY_CURRENT_USER than HKEY_LOCAL_MACHINE. CSIDL_PERSONAL, CSIDL_APPDATA, CSIDL_LOCAL_APPDATA, and paths returned from GetTempPath normally have write access. While your program is not guaranteed to have write access to these locations, most of the time it will.
First we try to open the user’s settings key with limit write access. All we want to be able to do is work with values is this key, we don’t need access to add sub-keys. So, instead of asking for full write access, we only ask for set value access. If we can’t get that, we try to get read value access.
// Preference dialog
#define USER_SETTINGS_KEY _T("Software\\Microsoft\\STGraph\\Settings")
void CMainFrame::OnPreferences()
{
CDlgPref dlgPref; // Preferences dialog
HKEY hKey;
LONG lResult = ERROR_SUCCESS;
// Since all we want to do is write the user's
// preference, we only need to as for
// KEY_SET_VALUE privilages, instead of
// full write access.
lResult = RegOpenKeyEx(HKEY_CURRENT_USER,
USER_SETTINGS_KEY, NULL,
KEY_SET_VALUE, &hKey)
if (lResult != ERROR_SUCCESS)
{
// Unable to open key with write access.
// Since we can't write the preferences,
// make the dialog Read-Only.
// (Degrade nicely)
dlgPref.m_fReadOnly = TRUE;
// We should also tell the user they
// can't change any of the settings
CString strUserWarning;
try
{
// Load the string from resources (localization)
strUserWarning.LoadString(IDS_SETTINGS_READONLY);
MessageBox(strUserWarning);
}
catch(CMemoryException *pex)
{
// Handle the out of memory error
}
// Since we couldn't get write access, we only
// want to read. We don't need full read
// access, only the right to read key values.
// So, we use KEY_QUERY_VALUE
lResult = RegOpenKeyEx(HKEY_CURRENT_USER,
USER_SETTINGS_KEY, NULL
KEY_QUERY_VALUE, &hKey)
if (lResult != ERROR_SUCCESS)
{
// We can't even read the settings, oh well.
// Instead of showing them the user settings,
// we'll just show the application defaults
// since that's what we're using anyway.
// (Handle Error)
hKey = NULL;
}
}
if (hKey)
{
// Read the settings
}
else
{
// Use application provided defaults
}
// initilize and DoModal the dialog, etc
Opening registry keys with KEY_READ privileges provides performance gains over accessing the same key with KEY_ALL_ACCESS.
Opening registry keys or files multiple times (once for reading, and then again for writing) can degrade performance. This should be balanced against the need for program stability and robustness.
CreateFile, CSIDLs, File Functions, GetTempPath, Registry Functions, Registry Overview, RegOpenKeyEx, SHGetFolderPath