Click here to Skip to main content
15,888,521 members
Articles / Programming Languages / C++
Article

How to Save and Restore Registry Keys

Rate me:
Please Sign up or sign in to vote.
3.56/5 (13 votes)
17 Nov 2005CPOL4 min read 111.7K   4K   30   10
This article shows how to save and restore registry keys and provides a command-line tool demonstrating how to do it.

Image 1

What's new in this update

  • The provided tool has one more optional parameter /F: This parameter can be used to force the restore operation. Using this parameter can be necessary in many cases in which the restore registry keys operation including hives (HKCU and HKLM) is not possible if keys are locked, i.e., handles are opened and not closed on some sub-keys by some processes.
  • Saving/Restoring whole registry is now possible: As a consequence of using the parameter /F in restoring the registry, it is now possible to save and restore user registry hives, for example:
    RegsaveRestore /s hkcu "" c:\cu.dat
    RegsaveRestore /r hkcu "" c:\cu.dat
  • If some error occurs, the error code and description are printed in the DOS console, but the program still returns 1 if success and 0 otherwise.

Introduction

First of all, I apologize for my bad English. This article shows how to save and restore registry keys using the Windows API functions: RegSaveKey and RegRestoreKey respectively and provides a tool to achieve these two tasks.

According to MSDN, these two API functions require two privileges, namely SE_BACKUP_NAME (SeBackupPrivilege) and/or SE_RESTORE_NAME (SeRestorePrivilege) even if the current process token has administrator rights. As a consequence, the tool presented in this article should be used by an administrator account.

These are some situations where the article's attached utility program can be used:

  • Profiles manager for only important parts of the registry that must be saved and restored and not necessarily the whole user registry.
  • Printers manager to save and restore users' printer configurations in the OS migration process, for example.
  • Software configuration. Instead of using .REG files by exporting registry keys and then importing them, we can save keys to files using this utility and when it's time to configure the software, we restore the produced output files to the registry.

How to use the tool

Syntax:

This is the tool syntax as indicated in the picture above:

RegSaveRestore /S|/R ROOT KEY FILE [/F]
/S   To save a registry key to file.
/R   To restore a registry key from file.
ROOT Take HKCU or HHLM.
KEY  Subkey path.
FILE Input file in restore mode or Output file in save mode.
/F   This parameter can be used optionnally to force restoring operation.

The tool returns 0 if success, otherwise it returns 1 without any consideration of the real error code.

Examples:

These are two simple examples to show how to use the tool. The first one saves the key HKLM\Software\MyKey (with all MyKey subkeys and values) to the file C:\MyKey.dat and the second one restores this file in force mode to the same key HKLM\Software\MyKey. Make sure that you are not editing by using Regedit or any other way; otherwise the program will fail by the Access denied error, since Regedit locks the key in edit mode.

Saving HKLM\Software\MyKey in C:\MyKey.dat:

RegSaveRestore /S HKLM Software\MyKey C:\MyKey.dat

Restoring HKLM\Software\MyKey using C:\MyKey.dat:

RegSaveRestore /R HKLM Software\MyKey C:\MyKey.dat /F

Saving HKLM\Software in C:\Software .dat:

RegSaveRestore /S HKLM Software C:\Software.dat

Restoring HKLM\Software using C:\Software.dat:

RegSaveRestore /R HKLM Software C:\Software.dat /F

Remark:

The tool does not provide any means to secure backup files for the restore phase. To be more precise, suppose that MyKet.dat has been provided by Example 1., and then the file has been changed incorrectly or corrupted, then when it comes the time to restore it, the tool will fail, and worst, the key HKLM\Software\MyKey will be deleted automatically when RegRestoreKey is called. I hope that I will present in a future article an easy way to make such a task 99.99% secure! In order to make it secure and automatic, we have to answer two basic questions:

  1. Which file goes to which key?
  2. How to be sure that the file going to a corresponding key is the right one?

Using the code

The tool project is a console MFC application and it can be freely changed to MFC by making some minor changes. The function used to save the registry key to a file is:

//  Save registry key SubKey to file OutFile
//  Return TRUE if success, otherwise it returns FALSE
//  Note that the error code d is used only as a local variable information
BOOL SaveRegKeyPath(CString &Root, CString &SubKey, CString &OutFile)
{
  BOOL  ret=TRUE;
  HKEY  hKey=NULL;
  DWORD  d;
  HKEY  hRoot;

  //  Set SE_BACKUP_NAME privilege
  
  SetPrivilege(SE_BACKUP_NAME,TRUE);
  //  Determine the hive
 
  hRoot=(Root.CompareNoCase(HKCU)==0)?HKEY_CURRENT_USER:HKEY_LOCAL_MACHINE;
  //  We have to save only existing key ! (KEY_READ parameter below)
  if (RegOpenKeyEx(hRoot, SubKey,0,KEY_READ, &hKey)==ERROR_SUCCESS)  {
    if (IsFileExist(OutFile)){
      //we must delete file before saving, otherwise it doesn't work !
      if (DeleteFile(OutFile)) 
        d=RegSaveKey(hKey,OutFile,NULL);
    } else d=RegSaveKey(hKey,OutFile,NULL);
    if (d!=ERROR_SUCCESS)
      ret=FALSE;
   
    RegCloseKey(hKey); 
  }
  else {
    if (IsKeyExist(hRoot,SubKey)==FALSE)
      d=ERROR_FILE_NOT_FOUND;
    else d=0;
    ret=FALSE;
  }
 
  SetPrivilege(SE_BACKUP_NAME,FALSE);

  return ret;
}

The function used to restore the registry key from a file is:

// Restore registry key SubKey from file InFile
// If Force=TRUE then we force the restore operation
// Return TRUE if success, otherwise it returns FALSE
BOOL LoadRegKeyPath(CString &Root, CString &SubKey, CString &InFile, BOOL Force)
{
    BOOL    ret=TRUE;
    HKEY    hKey=NULL;
    DWORD    d;
    HKEY    hRoot;

    SetPrivilege(SE_RESTORE_NAME,TRUE);
    SetPrivilege(SE_BACKUP_NAME,TRUE);

    hRoot=(Root.CompareNoCase(HKCU)==0)?HKEY_CURRENT_USER:HKEY_LOCAL_MACHINE;
    if (!IsFileExist(InFile)) {
        d=ERROR_FILE_NOT_FOUND;
        PrintError(d);
        ret=FALSE;
    }
    else {
        HKEY    hhKey;
        char    lpClass[80];
        DWORD    lpDisposition=0;
        if (RegCreateKeyEx(hRoot,SubKey,0,lpClass, REG_OPTION_BACKUP_RESTORE,
            KEY_ALL_ACCESS, NULL, &hhKey, 
            &lpDisposition)==ERROR_SUCCESS) {

            d=RegRestoreKey(hhKey,InFile,
              (Force==FALSE)?REG_NO_LAZY_FLUSH:REG_FORCE_RESTORE);
            RegCloseKey(hhKey);
            if (d!=ERROR_SUCCESS) {
                PrintError(d);
                ret=FALSE;
            }
        } else ret=FALSE; 
    }

    SetPrivilege(SE_RESTORE_NAME,FALSE);
    SetPrivilege(SE_BACKUP_NAME,FALSE);

    return ret;
}

I invite readers to go into the source code to take a look at the intermediate functions SetPrivilege, IsKeyExist and IsFileExist used in the code above.

Conclusion

I hope that you have learned some thing new in this article and the accompanying tool will be of help for you. As I said before, I hope that in a future article I will provide a secure method to use this tool. In fact, the article should just answer the two questions above.

History

  • Version 1.0.0.1 - August 1, 2004
  • Version 2.0.0.0 - November 16, 2005

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionYour code does not work on Win10 Pin
William Sadkin31-Aug-20 12:12
William Sadkin31-Aug-20 12:12 
QuestionVista compatible version? Pin
Beiley31-Jul-08 9:43
Beiley31-Jul-08 9:43 
GeneralMore about function SetPrivileges() Pin
Tannoge14-Jul-06 8:54
Tannoge14-Jul-06 8:54 
QuestionError Pin
dipali_be200319-Mar-06 18:54
dipali_be200319-Mar-06 18:54 
AnswerRe: Error Pin
JOHN1120-Mar-06 9:09
JOHN1120-Mar-06 9:09 
I am not sure that the header file Sddl.h is really needed (it contains Security Descriptors constants and SID conversion functions as a security data language). Try to comment the line #include Sddl.h and rebuild the project.

In fact the file comes with the SDK which you can download from the Microsoft site (necessary for UNICODE and for Windows XP and + development in particular) and it comes as a part of the .NET IDE.

Here is the header file content:


/*++

Copyright (c) 1997-1998 Microsoft Corporation

Module Name:

sddl.w

Abstract:

This module defines the support and conversions routines necessary for SDDL.

Revision History:

--*/

#ifndef __SDDL_H__
#define __SDDL_H__


#ifdef __cplusplus
extern "C" {
#endif

//
// SDDL Version information
//
#define SDDL_REVISION_1 1
#define SDDL_REVISION SDDL_REVISION_1

//
// SDDL Component tags
//
#define SDDL_OWNER TEXT("O") // Owner tag
#define SDDL_GROUP TEXT("G") // Group tag
#define SDDL_DACL TEXT("D") // DACL tag
#define SDDL_SACL TEXT("S") // SACL tag

//
// SDDL Security descriptor controls
//
#define SDDL_PROTECTED TEXT("P") // DACL or SACL Protected
#define SDDL_AUTO_INHERIT_REQ TEXT("AR") // Auto inherit request
#define SDDL_AUTO_INHERITED TEXT("AI") // DACL/SACL are auto inherited

//
// SDDL Ace types
//
#define SDDL_ACCESS_ALLOWED TEXT("A") // Access allowed
#define SDDL_ACCESS_DENIED TEXT("D") // Access denied
#define SDDL_OBJECT_ACCESS_ALLOWED TEXT("OA") // Object access allowed
#define SDDL_OBJECT_ACCESS_DENIED TEXT("OD") // Object access denied
#define SDDL_AUDIT TEXT("AU") // Audit
#define SDDL_ALARM TEXT("AL") // Alarm
#define SDDL_OBJECT_AUDIT TEXT("OU") // Object audit
#define SDDL_OBJECT_ALARM TEXT("OL") // Object alarm

//
// SDDL Ace flags
//
#define SDDL_CONTAINER_INHERIT TEXT("CI") // Container inherit
#define SDDL_OBJECT_INHERIT TEXT("OI") // Object inherit
#define SDDL_NO_PROPAGATE TEXT("NP") // Inherit no propagate
#define SDDL_INHERIT_ONLY TEXT("IO") // Inherit only
#define SDDL_INHERITED TEXT("ID") // Inherited
#define SDDL_AUDIT_SUCCESS TEXT("SA") // Audit success
#define SDDL_AUDIT_FAILURE TEXT("FA") // Audit failure


//
// SDDL Rights
//
#define SDDL_READ_PROPERTY TEXT("RP")
#define SDDL_WRITE_PROPERTY TEXT("WP")
#define SDDL_CREATE_CHILD TEXT("CC")
#define SDDL_DELETE_CHILD TEXT("DC")
#define SDDL_LIST_CHILDREN TEXT("LC")
#define SDDL_SELF_WRITE TEXT("SW")
#define SDDL_LIST_OBJECT TEXT("LO")
#define SDDL_DELETE_TREE TEXT("DT")
#define SDDL_CONTROL_ACCESS TEXT("CR")
#define SDDL_READ_CONTROL TEXT("RC")
#define SDDL_WRITE_DAC TEXT("WD")
#define SDDL_WRITE_OWNER TEXT("WO")
#define SDDL_STANDARD_DELETE TEXT("SD")
#define SDDL_GENERIC_ALL TEXT("GA")
#define SDDL_GENERIC_READ TEXT("GR")
#define SDDL_GENERIC_WRITE TEXT("GW")
#define SDDL_GENERIC_EXECUTE TEXT("GX")
#define SDDL_FILE_ALL TEXT("FA")
#define SDDL_FILE_READ TEXT("FR")
#define SDDL_FILE_WRITE TEXT("FW")
#define SDDL_FILE_EXECUTE TEXT("FX")
#define SDDL_KEY_ALL TEXT("KA")
#define SDDL_KEY_READ TEXT("KR")
#define SDDL_KEY_WRITE TEXT("KW")
#define SDDL_KEY_EXECUTE TEXT("KX")

//
// SDDL User alias max size
// - currently, upto two supported eg. "DA"
// - modify this if more WCHARs need to be there in future e.g. "DAX"
//

#define SDDL_ALIAS_SIZE 2

//
// SDDL User aliases
//
#define SDDL_DOMAIN_ADMINISTRATORS TEXT("DA") // Domain admins
#define SDDL_DOMAIN_GUESTS TEXT("DG") // Domain guests
#define SDDL_DOMAIN_USERS TEXT("DU") // Domain users
#define SDDL_ENTERPRISE_DOMAIN_CONTROLLERS TEXT("ED") // Enterprise domain controllers
#define SDDL_DOMAIN_DOMAIN_CONTROLLERS TEXT("DD") // Domain domain controllers
#define SDDL_DOMAIN_COMPUTERS TEXT("DC") // Domain computers
#define SDDL_BUILTIN_ADMINISTRATORS TEXT("BA") // Builtin (local ) administrators
#define SDDL_BUILTIN_GUESTS TEXT("BG") // Builtin (local ) guests
#define SDDL_BUILTIN_USERS TEXT("BU") // Builtin (local ) users
#define SDDL_LOCAL_ADMIN TEXT("LA") // Local administrator account
#define SDDL_LOCAL_GUEST TEXT("LG") // Local group account
#define SDDL_ACCOUNT_OPERATORS TEXT("AO") // Account operators
#define SDDL_BACKUP_OPERATORS TEXT("BO") // Backup operators
#define SDDL_PRINTER_OPERATORS TEXT("PO") // Printer operators
#define SDDL_SERVER_OPERATORS TEXT("SO") // Server operators
#define SDDL_AUTHENTICATED_USERS TEXT("AU") // Authenticated users
#define SDDL_PERSONAL_SELF TEXT("PS") // Personal self
#define SDDL_CREATOR_OWNER TEXT("CO") // Creator owner
#define SDDL_CREATOR_GROUP TEXT("CG") // Creator group
#define SDDL_LOCAL_SYSTEM TEXT("SY") // Local system
#define SDDL_POWER_USERS TEXT("PU") // Power users
#define SDDL_EVERYONE TEXT("WD") // Everyone ( World )
#define SDDL_REPLICATOR TEXT("RE") // Replicator
#define SDDL_INTERACTIVE TEXT("IU") // Interactive logon user
#define SDDL_NETWORK TEXT("NU") // Nework logon user
#define SDDL_SERVICE TEXT("SU") // Service logon user
#define SDDL_RESTRICTED_CODE TEXT("RC") // Restricted code
#define SDDL_ANONYMOUS TEXT("AN") // Anonymous Logon
#define SDDL_SCHEMA_ADMINISTRATORS TEXT("SA") // Schema Administrators
#define SDDL_CERT_SERV_ADMINISTRATORS TEXT("CA") // Certificate Server Administrators
#define SDDL_RAS_SERVERS TEXT("RS") // RAS servers group
#define SDDL_ENTERPRISE_ADMINS TEXT("EA") // Enterprise administrators
#define SDDL_GROUP_POLICY_ADMINS TEXT("PA") // Group Policy administrators
#define SDDL_ALIAS_PREW2KCOMPACC TEXT("RU") // alias to allow previous windows 2000
#define SDDL_LOCAL_SERVICE TEXT("LS") // Local service account (for services)
#define SDDL_NETWORK_SERVICE TEXT("NS") // Network service account (for services)
#define SDDL_REMOTE_DESKTOP TEXT("RD") // Remote desktop users (for terminal server)
#define SDDL_NETWORK_CONFIGURATION_OPS TEXT("NO") // Network configuration operators ( to manage configuration of networking features)
#define SDDL_PERFMON_USERS TEXT("MU") // Performance Monitor Users
#define SDDL_PERFLOG_USERS TEXT("LU") // Performance Log Users



//
// SDDL Seperators - character version
//
#define SDDL_SEPERATORC TEXT(';')
#define SDDL_DELIMINATORC TEXT(':')
#define SDDL_ACE_BEGINC TEXT('(')
#define SDDL_ACE_ENDC TEXT(')')

//
// SDDL Seperators - string version
//
#define SDDL_SEPERATOR TEXT(";")
#define SDDL_DELIMINATOR TEXT(":")
#define SDDL_ACE_BEGIN TEXT("(")
#define SDDL_ACE_END TEXT(")")

#if !defined(_NTDDK_)

#if(_WIN32_WINNT >= 0x0500)

WINADVAPI
BOOL
WINAPI
ConvertSidToStringSidA(
IN PSID Sid,
OUT LPSTR *StringSid
);
WINADVAPI
BOOL
WINAPI
ConvertSidToStringSidW(
IN PSID Sid,
OUT LPWSTR *StringSid
);
#ifdef UNICODE
#define ConvertSidToStringSid ConvertSidToStringSidW
#else
#define ConvertSidToStringSid ConvertSidToStringSidA
#endif // !UNICODE

WINADVAPI
BOOL
WINAPI
ConvertStringSidToSidA(
IN LPCSTR StringSid,
OUT PSID *Sid
);
WINADVAPI
BOOL
WINAPI
ConvertStringSidToSidW(
IN LPCWSTR StringSid,
OUT PSID *Sid
);
#ifdef UNICODE
#define ConvertStringSidToSid ConvertStringSidToSidW
#else
#define ConvertStringSidToSid ConvertStringSidToSidA
#endif // !UNICODE

WINADVAPI
BOOL
WINAPI
ConvertStringSecurityDescriptorToSecurityDescriptorA(
IN LPCSTR StringSecurityDescriptor,
IN DWORD StringSDRevision,
OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
OUT PULONG SecurityDescriptorSize OPTIONAL
);
WINADVAPI
BOOL
WINAPI
ConvertStringSecurityDescriptorToSecurityDescriptorW(
IN LPCWSTR StringSecurityDescriptor,
IN DWORD StringSDRevision,
OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
OUT PULONG SecurityDescriptorSize OPTIONAL
);
#ifdef UNICODE
#define ConvertStringSecurityDescriptorToSecurityDescriptor ConvertStringSecurityDescriptorToSecurityDescriptorW
#else
#define ConvertStringSecurityDescriptorToSecurityDescriptor ConvertStringSecurityDescriptorToSecurityDescriptorA
#endif // !UNICODE


WINADVAPI
BOOL
WINAPI
ConvertSecurityDescriptorToStringSecurityDescriptorA(
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN DWORD RequestedStringSDRevision,
IN SECURITY_INFORMATION SecurityInformation,
OUT LPSTR *StringSecurityDescriptor OPTIONAL,
OUT PULONG StringSecurityDescriptorLen OPTIONAL
);
WINADVAPI
BOOL
WINAPI
ConvertSecurityDescriptorToStringSecurityDescriptorW(
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN DWORD RequestedStringSDRevision,
IN SECURITY_INFORMATION SecurityInformation,
OUT LPWSTR *StringSecurityDescriptor OPTIONAL,
OUT PULONG StringSecurityDescriptorLen OPTIONAL
);
#ifdef UNICODE
#define ConvertSecurityDescriptorToStringSecurityDescriptor ConvertSecurityDescriptorToStringSecurityDescriptorW
#else
#define ConvertSecurityDescriptorToStringSecurityDescriptor ConvertSecurityDescriptorToStringSecurityDescriptorA
#endif // !UNICODE

#endif /* _WIN32_WINNT >= 0x0500 */

#endif /* !defined(_NTDDK_) */


#ifdef __cplusplus
}
#endif

#endif // endif __SDDL_H__
GeneralUsefull info Pin
Alexander Arhipenko25-Jan-06 0:51
Alexander Arhipenko25-Jan-06 0:51 
GeneralRe: Usefull info Pin
JOHN1128-Jan-06 21:42
JOHN1128-Jan-06 21:42 
QuestionWhy does not restore of "Software" subkey work? Pin
Aasia Haroon24-Oct-05 22:50
Aasia Haroon24-Oct-05 22:50 
AnswerRe: Why does not restore of "Software" subkey work? Pin
JOHN1110-Nov-05 22:09
JOHN1110-Nov-05 22:09 
AnswerRe: Why does not restore of "Software" subkey work? Pin
JOHN1116-Nov-05 4:39
JOHN1116-Nov-05 4:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.