HOWTO: How to Back Up the Windows NT Registry

This article was previously published under Q128731
This article has been archived. It is offered "as is" and will no longer be updated.
This article shows by example how to back up portions of the Windows NTregistry to be restored later.
This is normally accomplished by enabling the SeBackupPrivilege and callingRegSaveKey. The operation can fail with ERROR_ACCESS_DENIED if the callerdoes not have access to portions of the key, such as the registry keyHKEY_LOCAL_MACHINE\SECURITY.

If you do not have access to the key, but have backup privilege, pass theREG_OPTION_BACKUP_RESTORE flag to RegCreateKeyEx in the dwOptionsparameter. This has an effect similar to FILE_FLAG_BACKUP_SEMANTICS withCreateFile, allowing you to open the key for backup. The resultant keyhandle can be used in a subsequent call to RegSaveKey.

To back up the registry from the root, it is necessary to enumerate thesubkeys from the root, opening each subkey with RegCreateKeyEx and savingthe subkey with RegSaveKey.

Sample Code

The following sample source code saves the HKEY_LOCAL_MACHINE registrykey, with each subkey saved to a filename matching the subkey name.

The following function performs the save operation:
LONG SaveRegistrySubKey(    HKEY hKey,              // handle of key to save    LPTSTR szSubKey,        // pointer to subkey name to save    LPTSTR szSaveFileName   // pointer to save path/filename    )
If the function succeeds, the return value is ERROR_SUCCESS.If the function fails, the return value is an error value.
/* Save HKEY_LOCAL_MACHINE registry key, each subkey saved to a file of * name subkey * * this allows us to get around security restrictions which prevent * the use of RegSaveKey() on the root key * * the optional target machine name is specified in argv[1] * * v1.21 * Scott Field (sfield) 01-Apr-1995 */ #define RTN_OK 0#define RTN_USAGE 1#define RTN_ERROR 13#include <windows.h>#include <stdio.h>#include <stdlib.h>LONG SaveRegistrySubKey(HKEY hKey, LPTSTR szSubKey, LPTSTR szSaveFileName);void PERR(LPTSTR szAPI, DWORD dwLastError);int main(int argc, char *argv[]){   TOKEN_PRIVILEGES tp;   HANDLE hToken;   LUID luid;   LONG rc;     // contains error value returned by Regxxx()   HKEY hKey;   // handle to key we are interested in   LPTSTR MachineName=NULL; // pointer to machine name   DWORD dwSubKeyIndex=0;   // index into key   char szSubKey[_MAX_FNAME]; // this should be dynamic.                            // _MAX_FNAME is good because this                            // is what we happen to save the                            // subkey as   DWORD dwSubKeyLength=_MAX_FNAME; // length of SubKey buffer/*    if (argc != 2) // usage    {        fprintf(stderr,"Usage: %s [<MachineName>]\n", argv[0]);        return RTN_USAGE;    } */     // set MachineName == argv[1], if appropriate    if (argc == 2) MachineName=argv[1];    //     // enable backup privilege    //     if(!OpenProcessToken(GetCurrentProcess(),                        TOKEN_ADJUST_PRIVILEGES,                        &hToken ))    {        PERR("OpenProcessToken", GetLastError() );        return RTN_ERROR;    }    if(!LookupPrivilegeValue(MachineName, SE_BACKUP_NAME, &luid))    {        PERR("LookupPrivilegeValue", GetLastError() );        return RTN_ERROR;    }    tp.PrivilegeCount           = 1;    tp.Privileges[0].Luid       = luid;    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),                                NULL, NULL );    if (GetLastError() != ERROR_SUCCESS)    {        PERR("AdjustTokenPrivileges", GetLastError() );        return RTN_ERROR;    }    // only connect if a machine name specified    if (MachineName != NULL)    {        if((rc=RegConnectRegistry(MachineName,                                  HKEY_LOCAL_MACHINE,                                  &hKey)) != ERROR_SUCCESS)        {            PERR("RegConnectRegistry", rc);            return RTN_ERROR;        }    }    else hKey=HKEY_LOCAL_MACHINE;    while((rc=RegEnumKeyEx(                        hKey,                        dwSubKeyIndex,                        szSubKey,                        &dwSubKeyLength,                        NULL,                        NULL,                        NULL,                        NULL)                        ) != ERROR_NO_MORE_ITEMS) { // are we done?    if(rc == ERROR_SUCCESS)   {        LONG lRetVal; // return value from SaveRegistrySubKey#ifdef DEBUG        fprintf(stdout,"Saving %s\n", szSubKey);#endif        // save registry subkey szSubKey to filename szSubKey        if( (lRetVal=SaveRegistrySubKey(hKey, szSubKey, szSubKey)            ) != ERROR_SUCCESS)        {            PERR("SaveRegistrySubKey", lRetVal);        }        // increment index into the key       dwSubKeyIndex++;       // reset buffer size        dwSubKeyLength=_MAX_FNAME;        // Continue the festivities        continue;    }    else   {       //        // note: we need to watch for ERROR_MORE_DATA       // this indicates we need a bigger szSubKey buffer       //         PERR("RegEnumKeyEx", rc);        return RTN_ERROR;   }    } // RegEnumKeyEx    // close registry key we have been working with    RegCloseKey(hKey);    // Revoke all privileges this process holds (including backup)    AdjustTokenPrivileges( hToken, TRUE, NULL, 0, NULL, NULL);    // close handle to process token    CloseHandle(hToken);    return RTN_OK;}LONG SaveRegistrySubKey(    HKEY hKey,              // handle of key to save    LPTSTR szSubKey,        // pointer to subkey name to save    LPTSTR szSaveFileName   // pointer to save path/filename    ){    HKEY hKeyToSave;    // Handle of subkey to save    LONG rc;            // result code from RegXxx    DWORD dwDisposition;    if((rc=RegCreateKeyEx(hKey,                          szSubKey, // Name of subkey to open                          0,                          NULL,                          REG_OPTION_BACKUP_RESTORE, // in winnt.h                          KEY_QUERY_VALUE, // minimal access                          NULL,                          &hKeyToSave,                          &dwDisposition)                          ) == ERROR_SUCCESS)    {        // Save registry subkey.  If the registry is remote, files will        // be saved on the remote machine        rc=RegSaveKey(hKeyToSave, szSaveFileName, NULL);        // close registry key we just tried to save        RegCloseKey(hKeyToSave);    }    // return the last registry result code    return rc;}void PERR(    LPTSTR szAPI,       // pointer to failed API name    DWORD dwLastError   // last error value associated with API    ){    LPTSTR MessageBuffer;    DWORD dwBufferLength;    //     // TODO get this fprintf out of here!    //     fprintf(stderr,"%s error! (rc=%lu)\n", szAPI, dwLastError);    if(dwBufferLength=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |                                    FORMAT_MESSAGE_FROM_SYSTEM,                                    NULL,                                    dwLastError,                                    LANG_NEUTRAL,                                    (LPTSTR) &MessageBuffer,                                    0,                                    NULL))    {        DWORD dwBytesWritten;        //         // Output message string on stderr        //         WriteFile(GetStdHandle(STD_ERROR_HANDLE),                  MessageBuffer,                  dwBufferLength,                  &dwBytesWritten,                  NULL);        //         // free the buffer allocated by the system        //         LocalFree(MessageBuffer);    }}				

Article ID: 128731 - Last Review: 02/28/2014 07:56:32 - Revision: 4.2

  • Microsoft Win32 Application Programming Interface
  • kbnosurvey kbarchive kbhowto kbregistry kbapi kbkernbase kbcode KB128731