How to Back Up the Windows NT Registry

Last reviewed: December 16, 1996
Article ID: Q128731
The information in this article applies to:
  • Microsoft Win32 Application Programming Interface (API) included with:

        - Microsoft Windows NT versions 3.5, 3.51, and 4.00
    

SUMMARY

This article shows by example how to back up portions of the Windows NT registry to be restored later.

MORE INFORMATION

This is normally accomplished by enabling the SeBackupPrivilege and calling RegSaveKey. The operation can fail with ERROR_ACCESS_DENIED if the caller does not have access to portions of the key, such as the registry key HKEY_LOCAL_MACHINE\SECURITY.

If you do not have access to the key, but have backup privilege, pass the REG_OPTION_BACKUP_RESTORE flag to RegCreateKeyEx in the dwOptions parameter. This has an effect similar to FILE_FLAG_BACKUP_SEMANTICS with CreateFile, allowing you to open the key for backup. The resultant key handle can be used in a subsequent call to RegSaveKey.

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

Sample Code

The following sample source code saves the HKEY_LOCAL_MACHINE registry key, 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);
    }
}


KBCategory: kbprg kbcode
KBSubcategory: BseSecurity CodeSam BseRegistry
Additional reference words: 3.50 3.51 4.00


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: December 16, 1996
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.