REGDB.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:35k
源码类别:
Windows编程
开发平台:
Visual C++
- // RegDB.c -- Implements the semantics of the registry interface for this
- // application. The visible interfaces and data structures are
- // defined in RegDB.h.
- /*
- *
- Overview
- --------
- The NT Registry is an object database consisting of keys and values. Keys
- have names and may contain other keys and values. A value is a name paired
- with a data object and a data type. The keys in the registry are analogous
- to the directories in a file system. In that vein the values are analogous
- to files.
- Access to a key and its associated set of values is mediated by a key handle.
- Four key handles are given as predefined constants. Those handles correspond
- to the roots of key trees which have special signifigance. Handles for the
- other keys in the registry database may be constructed via the Registry's
- Open and Create interfaces using an existing key handle and a relative path
- string.
- The predefined key handles are:
- HKEY_LOCAL_MACHINE -- This handle refers to a tree of keys and values
- which characterize the state of the local machine.
- It contains state information global to everyone
- who uses the machine.
- HKEY_CLASSES_ROOT -- This handle refers to a subtree within
- HKEY_LOCAL_MACHINE. It defines the associations
- between file extensions and document types as well
- as the command strings for shell and DDE/OLE actions.
- HKEY_USERS -- This handle refers to a tree of information about
- the people who use this machine. The top level of
- the tree consists of a .DEFAULT key and one or more
- entries for specific people. The specific entries
- are created dynamically and are initially based on
- the content of the .DEFAULT key. The key names for
- the specific entries are SIDs which define the
- permissions given to the corresponding people.
- HKEY_CURRENT_USER -- This handle refers to a specific user key within
- HKEY_USERS. It denotes the information tree for
- the currently active user id.
- Application Conventions
- -----------------------
- Applications need to manipulate three of the above key trees. At installation
- time an application should adjust HKEY_CLASSES_ROOT to define the documents
- which it handles together with their file extensions and its shell and
- DDE/OLE command strings. At the same time it needs to add information global
- to all users to the HKEY_USERS.DEFAULT key.
- Subsequently an application will need to place per-user information in the
- HKEY_CURRENT_USER subtree. That information will include preferences as well
- as historical information such as lists of recently opened files.
- The conventions appropriate to the HKEY_CLASSES_ROOT will not be described
- or demonstrated in this sample application. The focus here will be on
- HKEY_USERS.DEFAULT and HKEY_CURRENT_USER subtrees.
- Within both of those subtrees information related to version 2.5 of the
- Bazooka application published by Trey Software will be clustered in the
- subkey:
- software"Trey Software"Bazooka2.5
- and in general applications will use a path with the structure
- software <company name> <application name> <version number>
- to access their state information.
- After an application has been installed almost all registry changes will
- involve HKEY_CURRENT_USER and will concern a specific user's preferences
- or history.
- */
- #include "multipad.h"
- // #include <windows.H>
- // #include <winbase.h>
- #include <malloc.h>
- #include "regdb.h"
- HKEY hkGlobal = NULL; // Key Handle for global registry data
- HKEY hkPerUser = NULL; // Key Handle for per-user registry data
- BOOL fTextWrapDefault = FALSE; // Set from registry data.
- HANDLE hmtxRegGlobal = NULL; // Mutex for serializing Local Machine Data.
- HANDLE hmtxRegPerUser = NULL; // Mutex for serializing Current User Data
- BOOL RunningAsAdministrator()
- {
- BOOL fAdmin;
- HANDLE htkThread;
- TOKEN_GROUPS *ptg = NULL;
- DWORD cbTokenGroups;
- DWORD iGroup;
- SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;
- PSID psidAdmin;
- // This function returns TRUE if the user identifier associated with this
- // process is a member of the the Administrators group.
- // First we must open a handle to the access token for this thread.
- if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &htkThread))
- if (GetLastError() == ERROR_NO_TOKEN)
- {
- // If the thread does not have an access token, we'll examine the
- // access token associated with the process.
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htkThread))
- return FALSE;
- }
- else return FALSE;
- // Then we must query the size of the group information associated with
- // the token. Note that we expect a FALSE result from GetTokenInformation
- // because we've given it a NULL buffer. On exit cbTokenGroups will tell
- // the size of the group information.
- if (GetTokenInformation(htkThread, TokenGroups, NULL, 0, &cbTokenGroups))
- return FALSE;
- // Here we verify that GetTokenInformation failed for lack of a large
- // enough buffer.
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return FALSE;
- // Now we allocate a buffer for the group information.
- // Since _alloca allocates on the stack, we don't have
- // to explicitly deallocate it. That happens automatically
- // when we exit this function.
- if (!(ptg= _alloca(cbTokenGroups))) return FALSE;
- // Now we ask for the group information again.
- // This may fail if an administrator has added this account
- // to an additional group between our first call to
- // GetTokenInformation and this one.
- if (!GetTokenInformation(htkThread, TokenGroups, ptg, cbTokenGroups,
- &cbTokenGroups
- )
- )
- return FALSE;
- // Now we must create a System Identifier for the Admin group.
- if (!AllocateAndInitializeSid
- (&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
- DOMAIN_ALIAS_RID_ADMINS,
- 0, 0, 0, 0, 0, 0,
- &psidAdmin
- )
- )
- return FALSE;
- // Finally we'll iterate through the list of groups for this access
- // token looking for a match against the SID we created above.
- fAdmin= FALSE;
- for (iGroup= 0; iGroup < ptg->GroupCount; iGroup++)
- if (EqualSid(ptg->Groups[iGroup].Sid, psidAdmin))
- {
- fAdmin= TRUE;
- break;
- }
- // Before we exit we must explicity deallocate the SID
- // we created.
- FreeSid(psidAdmin);
- return(fAdmin);
- }
- BOOL InstallApp(PSZ pszPathBuff)
- {
- // This function attempts to install global data for this
- // application in the HKEY_LOCAL_MACHINE portion of the
- // registry database.
- // The parameter pszPathBuff refers to a null terminated
- // string which defines where the new key should be located
- // in the LOCAL_MACHINE tree.
- // We requires that the current user have administrative
- // privileges. That requirement insures that the owner
- // tag for the global registry entries will be the
- // Administrator group and not a particular user id.
- // We also assume that hmtxRegGlobal is held when this function is called.
- // First we'll see whether this user has admin privileges...
- // Only administrators can install this application...
- if (!RunningAsAdministrator())
- {
- MPError(hwndFrame, MB_OK | MB_ICONHAND, IDS_CANTINSTALL, NULL);
- return FALSE;
- }
- // Then we bring up a dialog to get the global configuration information
- // we'll be storing in the HKEY_LOCAL_MACHINE tree. The dialog proc
- // will call StoreAppConfig with that configuration data.
- if (!DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_INSTALL),
- hwndFrame, InstallDlgProc,
- (LPARAM) pszPathBuff
- )
- ) return FALSE;
- }
- BOOL StoreAppConfig(HWND hwnd, PSZ pszPathBuff, PSZ pszInstallName,
- PSZ pszInstallOrg, BOOL fTextWrapDefault
- )
- {
- // This function attempts to install global data for this
- // application in the HKEY_LOCAL_MACHINE portion of the
- // registry database. It is called from InstallDlgProc.
- // The parameter hwnd denotes the window associated with this
- // call to StoreAppConfig. It's used with the calls to MPError
- // below.
- // The parameter pszPathBuff refers to a null terminated
- // string which defines where the new key should be located
- // in the LOCAL_MACHINE tree.
- // The pszInstallName and pszInstallOrg parameters are text strings
- // which denote the person and the organization which has installed
- // this app in the HKEY_LOCAL_MACHINE portion of the registry.
- // The fTextWrapDefault is a boolean value which will be stored
- // in the DEFAULT subkey. Values in the DEFAULT subkey are copied
- // into the HKEY_PER_USER area during user initialization. (See
- // the InitUser function below.)
- // We assume that hmtxRegGlobal is held when this function is called.
- HKEY hkGlobal = NULL;
- HKEY hkDefaults = NULL;
- PSID psidAdmins = NULL;
- PSID psidEveryone = NULL;
- PACL paclKey = NULL;
- BOOL fInstalled = FALSE;
- long lResult;
- DWORD dwDisposition;
- BYTE abEmptyStringSet[2];
- SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;
- SID_IDENTIFIER_AUTHORITY WorldSidAuthority= SECURITY_WORLD_SID_AUTHORITY;
- SECURITY_ATTRIBUTES sa;
- SECURITY_DESCRIPTOR sdPermissions;
- // Next we'll setup the security attributes we're going to
- // use with the application's global key.
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = FALSE;
- sa.lpSecurityDescriptor = &sdPermissions;
- // Here we're creating a System Identifier (SID) to represent
- // the Admin group.
- if (!AllocateAndInitializeSid
- (&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
- DOMAIN_ALIAS_RID_ADMINS,
- 0, 0, 0, 0, 0, 0,
- &psidAdmins
- )
- )
- goto security_failure;
- // Now we'll construct a System Identifier which represents
- // all users.
- if (!AllocateAndInitializeSid
- (&WorldSidAuthority, 1, SECURITY_WORLD_RID,
- 0, 0, 0, 0, 0, 0, 0,
- &psidEveryone
- )
- )
- goto security_failure;
- if (!InitializeSecurityDescriptor(&sdPermissions,
- SECURITY_DESCRIPTOR_REVISION1
- )
- )
- goto security_failure;
- // We want the admin group to own this key.
- if (!SetSecurityDescriptorOwner(&sdPermissions, psidAdmins, 0))
- goto security_failure;
- // Finally we must allocate and construct the discretionary
- // access control list (DACL) for the key.
- // Note that _alloca allocates memory on the stack frame
- // which will automatically be deallocated when this routine
- // exits.
- if (!(paclKey= (PACL) _alloca(ACL_BUFFER_SIZE)))
- goto memory_limited;
- if (!InitializeAcl(paclKey, ACL_BUFFER_SIZE, ACL_REVISION2))
- goto security_failure;
- // Our DACL will contain two access control entries (ACEs). One which allows
- // members of the Admin group complete access to the key, and one which gives
- // read-only access to everyone.
- if (!AddAccessAllowedAce(paclKey, ACL_REVISION2, KEY_ALL_ACCESS, psidAdmins))
- goto security_failure;
- if (!AddAccessAllowedAce(paclKey, ACL_REVISION2, KEY_READ, psidEveryone))
- goto security_failure;
- // We must bind this DACL to the security descriptor...
- if (!SetSecurityDescriptorDacl(&sdPermissions, TRUE, paclKey, FALSE))
- goto security_failure;
- // Now we'll attempt to create the key with the security attributes...
- lResult= RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszPathBuff, 0,
- "Application Global Data", REG_OPTION_NON_VOLATILE,
- KEY_ALL_ACCESS,
- &sa, &hkGlobal, &dwDisposition
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // Usually the disposition value will indicate that we've created a
- // new key. Sometimes it may instead state that we've opened an existing
- // key. This can happen when installation is incomplete and interrupted,
- // say by loss of electrical power.
- if ( dwDisposition != REG_CREATED_NEW_KEY
- && dwDisposition != REG_OPENED_EXISTING_KEY
- ) goto registry_access_error;
- // Now we'll add two values to the global key.
- // These values are simple strings which identify the name and
- // organization associated with this installation.
- lResult= RegSetValueEx(hkGlobal, KEY_VALUE_INSTALL_NAME, 0, REG_SZ,
- pszInstallName, strlen(pszInstallName)+1
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- lResult= RegSetValueEx(hkGlobal, KEY_VALUE_INSTALL_ORG, 0, REG_SZ,
- pszInstallOrg, strlen(pszInstallOrg)+1
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // We've created the global key. Now we must create the "Defaults" subkey
- // and set its value(s).
- lResult= RegCreateKeyEx(hkGlobal, DEFAULTS_PATH, 0,
- "Defaults for Per-User Data",
- REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
- &sa, &hkDefaults, &dwDisposition
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // Usually the disposition value will indicate that we've created a
- // new key. Sometimes it may instead state that we've opened an existing
- // key. This can happen when installation is incomplete and interrupted,
- // say by loss of electrical power.
- if ( dwDisposition != REG_CREATED_NEW_KEY
- && dwDisposition != REG_OPENED_EXISTING_KEY
- ) goto registry_access_error;
- // Now we'll add a collection of values to the Defaults subkey.
- // When per-user data is constructed for a particular userid, these
- // values will define the initial state of the per-user data.
- // In this demo application we store two items -- a word-wrap flag
- // and a file name set.
- lResult= RegSetValueEx(hkDefaults, WORD_WRAP_DEFAULT, 0, REG_DWORD,
- (LPBYTE) &fTextWrapDefault,
- sizeof(fTextWrapDefault)
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- abEmptyStringSet[0]= ' ';
- abEmptyStringSet[1]= ' ';
- lResult= RegSetValueEx(hkDefaults, LAST_FILE_SET, 0, REG_MULTI_SZ,
- (LPBYTE) &abEmptyStringSet, 2
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // Finally, we'll force our registry data out to disk via the
- // flush key api:
- lResult= RegFlushKey(hkGlobal);
- // Then we'll write out the REG_INSTALLED flag. Note that its
- // value is unimportant. Only its existence matters.
- fInstalled= TRUE;
- lResult= RegSetValueEx(hkGlobal, REG_INSTALLED, 0, REG_DWORD,
- (LPBYTE) &fInstalled, sizeof(fInstalled)
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- RegCloseKey(hkGlobal);
- RegCloseKey(hkDefaults);
- FreeSid(psidAdmins);
- return TRUE;
- registry_access_error:
- MPError(hwnd, MB_OK | MB_ICONHAND, IDS_REG_ACCESS_ERROR, NULL);
- // We've constructed some, but not all of the global key state.
- // So we must remove any keys we created. The Defaults key must
- // be deleted first before the Global key can be deleted.
- if (hkDefaults) RegDeleteKey(hkGlobal, DEFAULTS_PATH);
- if (hkGlobal) RegDeleteKey(HKEY_LOCAL_MACHINE, pszPathBuff);
- goto clean_up_after_failure;
- memory_limited:
- MPError(hwnd, MB_OK | MB_ICONHAND, IDS_MEMORY_LIMITED, NULL);
- goto clean_up_after_failure;
- security_failure:
- MPError(hwnd, MB_OK | MB_ICONHAND, IDS_SECURITY_FAIL_I, NULL);
- clean_up_after_failure:
- if (psidAdmins ) FreeSid(psidAdmins );
- if (psidEveryone) FreeSid(psidEveryone);
- return FALSE;
- }
- PSID GetCurrentUserInfo()
- {
- // This function returns security information about the person who owns
- // this thread.
- HANDLE htkThread;
- TOKEN_USER *ptu;
- DWORD cbtu;
- TOKEN_GROUPS *ptg = NULL;
- SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;
- // First we must open a handle to the access token for this thread.
- if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &htkThread))
- if (GetLastError() == ERROR_NO_TOKEN)
- {
- // If the thread does not have an access token, we'll examine the
- // access token associated with the process.
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htkThread))
- return NULL;
- }
- else return NULL;
- if (GetTokenInformation(htkThread, TokenUser, NULL, 0, &cbtu))
- return NULL;
- // Here we verify that GetTokenInformation failed for lack of a large
- // enough buffer.
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return NULL;
- // Now we allocate a buffer for the group information.
- // Since _alloca allocates on the stack, we don't have
- // to explicitly deallocate it. That happens automatically
- // when we exit this function.
- if (!(ptu= LocalAlloc(LPTR, cbtu))) return NULL;
- // Now we ask for the user information again.
- // This may fail if an administrator has changed SID information
- // for this user.
- if (!GetTokenInformation(htkThread, TokenUser, ptu, cbtu, &cbtu))
- return FALSE;
- // if (GetTokenInformation(htkThread, TokenUser, &tu, sizeof(tu), &cbtu))
- // return NULL;
- return ptu;
- }
- BOOL InitUser(HKEY hkGlobal, PSZ pszPathBuff)
- {
- // This function sets up the per-user key area for a new user.
- // It will be called the very first time a user runs the application.
- // The initial per-user information is copied over from a set of defaults
- // stored in the global key area.
- // We assume that hkGlobal is a registry key for the global area
- // used by this application. We assume pszPathBuff defines where
- // the per-user data should be stored in the CURRENT_USER tree.
- // We also assume that hmtxRegPerUser is held when this function is called.
- HKEY hkPerUser = NULL;
- HKEY hkDefaults = NULL;
- BOOL fInstalled= FALSE;
- LONG lResult;
- DWORD dwType, cbData;
- PSZ pszFileList;
- DWORD dwDisposition;
- TOKEN_USER *ptu = NULL;
- PSID psidUser = NULL,
- psidAdmins = NULL;
- PACL paclKey = NULL;
- BOOL fWordWrap;
- PSZ pszFileSet = NULL;
- SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;
- SECURITY_ATTRIBUTES sa;
- SECURITY_DESCRIPTOR sdPermissions;
- // First we'll setup the security attributes we're going to
- // use with the application's global key.
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = FALSE;
- sa.lpSecurityDescriptor = &sdPermissions;
- // Here we're creating a System Identifier (SID) to represent
- // the Admin group.
- if (!AllocateAndInitializeSid
- (&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
- DOMAIN_ALIAS_RID_ADMINS,
- 0, 0, 0, 0, 0, 0,
- &psidAdmins
- )
- )
- goto security_failure;
- // We also need a SID for the current user.
- if ( !(ptu= GetCurrentUserInfo())
- || !(psidUser= ptu->User.Sid)
- ) goto security_failure;
- if (!InitializeSecurityDescriptor(&sdPermissions,
- SECURITY_DESCRIPTOR_REVISION1
- )
- )
- goto security_failure;
- // We want the current user to own this key.
- if (!SetSecurityDescriptorOwner(&sdPermissions, psidUser, 0))
- goto security_failure;
- // Finally we must allocate and construct the discretionary
- // access control list (DACL) for the key.
- // Note that _alloca allocates memory on the stack frame
- // which will automatically be deallocated when this routine
- // exits.
- if (!(paclKey= (PACL) _alloca(ACL_BUFFER_SIZE)))
- goto memory_limited;
- if (!InitializeAcl(paclKey, ACL_BUFFER_SIZE, ACL_REVISION2))
- goto security_failure;
- // Our DACL will two access control entries (ACEs). The first ACE
- // provides full access to the current user. The second ACE gives
- // the Admin group full access. By default all other users will have
- // no access to the key.
- // The reason for admin access is to allow an administrator to
- // run special utilties to cleanup inconsistencies and disasters
- // in the per-user data area.
- if (!AddAccessAllowedAce(paclKey, ACL_REVISION2, KEY_ALL_ACCESS, psidUser))
- goto security_failure;
- if (!AddAccessAllowedAce(paclKey, ACL_REVISION2, KEY_ALL_ACCESS, psidAdmins))
- goto security_failure;
- // We must bind this DACL to the security descriptor...
- if (!SetSecurityDescriptorDacl(&sdPermissions, TRUE, paclKey, FALSE))
- goto security_failure;
- // Now we'll attempt to create the key with the security attributes...
- lResult= RegCreateKeyEx(HKEY_CURRENT_USER, pszPathBuff, 0,
- "Application Per-User Data", REG_OPTION_NON_VOLATILE,
- KEY_ALL_ACCESS,
- &sa, &hkPerUser, &dwDisposition
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // Usually the disposition value will indicate that we've created a
- // new key. Sometimes it may instead state that we've opened an existing
- // key. This can happen when installation is incomplete and interrupted,
- // say by loss of electrical power.
- if ( dwDisposition != REG_CREATED_NEW_KEY
- && dwDisposition != REG_OPENED_EXISTING_KEY
- ) goto registry_access_error;
- // Now we must open the Defaults subkey in the global area.
- lResult= RegOpenKeyEx(hkGlobal, DEFAULTS_PATH, 0, KEY_READ, &hkDefaults);
- if (lResult != ERROR_SUCCESS)
- {
- // Can't open the "Defaults" subkey for read access.
- // This shouldn't happen normally. The algorithmic sequence for
- // installing this application and then creating user profile
- // data should prevent it.
- // It is possible for someone running RegEdit32 to delete the key,
- // however.
- goto registry_damage_error;
- }
- // Now we'll copy two default values to the per-user key:
- //
- // -- a word-wrap flag
- // -- a list of file names
- cbData= sizeof(fWordWrap);
- lResult= RegQueryValueEx(hkDefaults, WORD_WRAP_DEFAULT, NULL,
- &dwType, (LPBYTE) &fWordWrap, &cbData
- );
- if ( lResult != ERROR_SUCCESS
- || dwType != REG_DWORD
- ) goto registry_damage_error;
- lResult= RegSetValueEx(hkPerUser, WORD_WRAP_DEFAULT, 0, REG_DWORD,
- (LPBYTE) &fWordWrap, sizeof(fWordWrap)
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- cbData= 0;
- lResult= RegQueryValueEx(hkDefaults, LAST_FILE_SET, NULL, &dwType,
- NULL, &cbData
- );
- if ( lResult != ERROR_SUCCESS
- || dwType != REG_MULTI_SZ
- )
- goto registry_damage_error;
- pszFileList= (PSZ) _alloca(cbData);
- if (!pszFileList) goto memory_limited;
- lResult= RegQueryValueEx(hkDefaults, LAST_FILE_SET, NULL, &dwType,
- (LPBYTE) pszFileList, &cbData
- );
- if (lResult != ERROR_SUCCESS) goto registry_damage_error;
- lResult= RegSetValueEx(hkPerUser, LAST_FILE_SET, 0, REG_MULTI_SZ,
- (LPBYTE) pszFileList, cbData
- );
- if (lResult != ERROR_SUCCESS) goto registry_access_error;
- // Now we force our registry subtree out to disk
- // via the flush key api:
- lResult= RegFlushKey(hkPerUser);
- // Finally we store the REG_INSTALLED value in the registry to
- // indicate that installation has completed. Note that its value
- // is irrelevant. Only its presence or absence is meaningful.
- fInstalled= TRUE;
- lResult= RegSetValueEx(hkPerUser, REG_INSTALLED, 0, REG_DWORD,
- (LPBYTE) &fInstalled, sizeof(fInstalled)
- );
- RegCloseKey(hkPerUser);
- RegCloseKey(hkDefaults);
- FreeSid(psidAdmins);
- LocalFree(ptu);
- return(TRUE);
- registry_damage_error:
- // We'll display a warning that the registry info has
- // been damaged.
- MPError(hwndFrame, MB_OK | MB_ICONHAND, IDS_MUTEX_LOGIC_ERR, NULL);
- // Then we discard the REG_INSTALLED flag to insure that a reinstallation
- // can proceed.
- RegDeleteValue(hkGlobal, REG_INSTALLED);
- goto clean_up_registry_keys;
- registry_access_error:
- MPError(hwndFrame, MB_OK | MB_ICONHAND, IDS_REG_ACCESS_ERROR, NULL);
- clean_up_registry_keys:
- // We've constructed some, but not all of the global key state.
- // So we must remove any keys we created. The Defaults key must
- // be deleted first before the Global key can be deleted.
- if (hkPerUser) RegDeleteKey(HKEY_CURRENT_USER, pszPathBuff);
- if (hkDefaults) RegCloseKey(hkDefaults);
- goto clean_up_after_failure;
- memory_limited:
- MPError(hwndFrame, MB_OK | MB_ICONHAND, IDS_MEMORY_LIMITED, NULL);
- goto clean_up_after_failure;
- security_failure:
- MPError(hwndFrame, MB_OK | MB_ICONHAND, IDS_SECURITY_FAIL_I, NULL);
- clean_up_after_failure:
- if (psidAdmins) FreeSid(psidAdmins );
- if (ptu ) LocalFree(psidUser);
- return FALSE;
- }
- BOOL CreateAppKeys()
- {
- long lResult;
- BOOL fSuccess;
- BYTE abPathBuffer[MAX_PATH];
- BYTE abMutexName [MAX_PATH];
- BOOL fInstalled= FALSE;
- DWORD dwType, cbData;
- // Here we're constructing registry key handles for global data and
- // per-user data. The global data is kept in the HKEY_LOCAL_MACHINE
- // tree, and the per-user data is kept in the HKEY_CURRENT_USER tree.
- // For both trees the data for this program is kept in the same
- // relative location.
- // The registry handles are returned in the global variables hkGlobal
- // and hkPerUser. In addition two global mutex handles (hmtxRegGlobal
- // and hmtxRegPerUser are created. The mutexes are used to serialize
- // registry accesses among instances of this application at start-up.
- // That serialization is necessary to insure that a complete registry
- // environment is present when the application starts.
- // Note that individual registry reads and writes do not need to be
- // serialized -- only collections of reads and writes which must be
- // consistent with each other.
- // Note all so the use of the registry value REG_INSTALLED. It is the
- // last value written to the HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER
- // registry tree during the installation sequence. Whenever this application
- // starts, it looks for REG_INSTALLED as a sign that the registry has
- // been properly setup. If it doesn't find it, we assume that either
- // setup hasn't been done or has been done incompletely.
- // First we'll construct a relative path to the keys we're going to
- // open. The path has the structure:
- // Software <Company Name> <Application Name> <Version Number>
- wsprintf(abPathBuffer, "Software\%s\%s\%s",
- COMPANY_NAME, APPLICATION_NAME, VERSION_NUMBER
- );
- // Since two instance of this application could be running simultaneously,
- // we use a named mutext to serialize registry accesses.
- wsprintf(abMutexName, "Software/%s/%s/%s/Globals",
- COMPANY_NAME, APPLICATION_NAME, VERSION_NUMBER
- );
- if (!(hmtxRegGlobal= CreateMutex(NULL, FALSE, abMutexName))) goto failure_exit;
- wsprintf(abMutexName, "Software/%s/%s/%s/PerUser",
- COMPANY_NAME, APPLICATION_NAME, VERSION_NUMBER
- );
- if (!(hmtxRegPerUser= CreateMutex(NULL, FALSE, abMutexName))) goto failure_exit;
- // First we'll attempt to open a key to the global data...
- for (lResult= ~ERROR_SUCCESS; lResult != ERROR_SUCCESS; )
- {
- // We serialize the code in this loop via hmtxRegGlobal.
- lResult= WaitForSingleObject(hmtxRegGlobal, 0xFFFFFFFF);
- if ( lResult != WAIT_ABANDONED
- && lResult != WAIT_OBJECT_0
- ) goto failure_exit;
- lResult= RegOpenKeyEx(HKEY_LOCAL_MACHINE, abPathBuffer, 0, KEY_READ,
- &hkGlobal
- );
- // Note that we also look for the REG_INSTALLED flag.
- cbData= sizeof(fInstalled);
- if ( ERROR_SUCCESS != lResult
- || ERROR_SUCCESS != RegQueryValueEx(hkGlobal, REG_INSTALLED, 0,
- &dwType, (LPBYTE) &fInstalled,
- &cbData
- )
- )
- {
- hkGlobal= NULL;
- // If we can't open the global key, this probably means that the
- // application hasn't been installed yet. So we'll try to install it.
- // If the installation succeeds, we'll try opening the global key
- // again. Otherwise we'll just fail.
- fSuccess= InstallApp(abPathBuffer);
- ReleaseMutex(hmtxRegGlobal);
- if (fSuccess) continue;
- else goto failure_exit;
- }
- ReleaseMutex(hmtxRegGlobal);
- }
- for (lResult= ~ERROR_SUCCESS; lResult != ERROR_SUCCESS; )
- {
- // We serialize the code in this loop via hmtxRegPerUser.
- lResult= WaitForSingleObject(hmtxRegPerUser, 0xFFFFFFFF);
- if ( lResult != WAIT_ABANDONED
- && lResult != WAIT_OBJECT_0
- ) goto failure_exit;
- // Now we'll try to open an handle to the per-user key for this user and
- // this application.
- lResult= RegOpenKeyEx(HKEY_CURRENT_USER, abPathBuffer, 0, KEY_ALL_ACCESS,
- &hkPerUser
- );
- // Note that we also look for the REG_INSTALLED flag.
- cbData= sizeof(fInstalled);
- if ( ERROR_SUCCESS != lResult
- || ERROR_SUCCESS != RegQueryValueEx(hkPerUser, REG_INSTALLED, 0,
- &dwType, (LPBYTE) &fInstalled,
- &cbData
- )
- )
- {
- // The per-user open call failed. We infer that this is the first
- // time this user has invoked this application. So next we'll try
- // to initial a per-user area for them.
- hkPerUser= NULL;
- fSuccess= InitUser(hkGlobal, abPathBuffer);
- ReleaseMutex(hmtxRegPerUser);
- if (fSuccess) continue;
- else goto failure_exit;
- }
- ReleaseMutex(hmtxRegPerUser);
- }
- return TRUE;
- failure_exit:
- // When we're exiting because of a failure, we must clean up
- // by closing any handles we've created along the way.
- if (hmtxRegGlobal) CloseHandle(hmtxRegGlobal);
- if (hmtxRegPerUser) CloseHandle(hmtxRegPerUser);
- if (hkGlobal) RegCloseKey(hkGlobal);
- return FALSE;
- }
- BOOL LoadConfiguration()
- {
- // This routine loads the per-user configuration data.
- // Two items are kept as configuration data:
- //
- // fTextWrapDefault -- a BOOL which defines whether the text windows
- // fold text at the right edge of the window.
- //
- // A REG_MULTI_SZ list of file names.
- //
- // This list represents the files which were open at the end of the
- // last RegMPad session. We'll attempt to reopen those files.
- LONG lResult, cbData;
- DWORD dwType;
- PSZ pszFileList= NULL;
- CHAR *pc;
- cbData= sizeof(fTextWrapDefault);
- lResult= RegQueryValueEx(hkPerUser, WORD_WRAP_DEFAULT, NULL,
- &dwType, (LPBYTE) &fTextWrapDefault, &cbData
- );
- if (lResult != ERROR_SUCCESS) return FALSE;
- cbData= 0;
- lResult= RegQueryValueEx(hkPerUser, LAST_FILE_SET, NULL, &dwType,
- NULL, &cbData
- );
- if ( lResult != ERROR_SUCCESS
- || dwType != REG_MULTI_SZ
- ) return FALSE;
- pszFileList= (PSZ) _alloca(cbData);
- if (!pszFileList) return FALSE;
- lResult= RegQueryValueEx(hkPerUser, LAST_FILE_SET, NULL, &dwType,
- (LPBYTE) pszFileList, &cbData
- );
- if (lResult != ERROR_SUCCESS) return FALSE;
- for (pc= pszFileList; *pc; )
- {
- if (!AlreadyOpen(pc)) AddFile(pc);
- for (; *pc++; );
- }
- return TRUE;
- }
- BOOL SaveConfiguration()
- {
- // This routine saves the per-user configuration data to the registry.
- // That data consists of two items:
- //
- // fTextWrapDefault -- a BOOL which defines whether the text windows
- // fold text at the right edge of the window.
- //
- // A REG_MULTI_SZ list of file names.
- //
- // This list represents the files which were open at the end of the
- // last RegMPad session.
- LONG lResult;
- HWND hwnd;
- PBYTE pb, pbNext;
- LONG cb, cbTotal;
- lResult= RegSetValueEx(hkPerUser, WORD_WRAP_DEFAULT, 0, REG_DWORD,
- (CONST LPBYTE) &fTextWrapDefault,
- sizeof(fTextWrapDefault)
- );
- if (lResult != ERROR_SUCCESS) return FALSE;
- for (hwnd= GetWindow(hwndMDIClient, GW_CHILD), cbTotal= 1;
- hwnd;
- hwnd= GetWindow(hwnd, GW_HWNDNEXT)
- )
- {
- // Skip if this is an icon title window...
- if (GetWindow(hwnd, GW_OWNER)) continue;
- if (GetWindowWord(hwnd, GWW_UNTITLED)) continue;
- cbTotal += GetWindowTextLength(hwnd) + 1;
- }
- pb= (PBYTE) _alloca(cbTotal);
- if (!pb) return FALSE;
- for (hwnd= GetWindow(hwndMDIClient, GW_CHILD), pbNext= pb;
- hwnd;
- hwnd= GetWindow(hwnd, GW_HWNDNEXT)
- )
- {
- // Skip if this is an icon title window...
- if (GetWindow(hwnd, GW_OWNER)) continue;
- if (GetWindowWord(hwnd, GWW_UNTITLED)) continue;
- cb= GetWindowTextLength(hwnd);
- GetWindowText(hwnd, pbNext, cb+1);
- pbNext+= cb+1;
- }
- *pbNext= 0;
- lResult= RegSetValueEx(hkPerUser, LAST_FILE_SET, 0, REG_MULTI_SZ,
- pb, cbTotal
- );
- return (lResult == ERROR_SUCCESS)? TRUE : FALSE;
- }