Click here to Skip to main content
Click here to Skip to main content

Copy an entire registry key with one simple function

By , 31 Mar 2001
 

Introduction

This small function will copy an entire registry key including all it's values and sub-keys to a new key.

For example, if you wish to copy: HKEY_CURRENT_USER\SoftWare\MySoftware to HKEY_CURRENT_USER\SoftWare\$MYTEMP$, you'll need to do the following:

HKEY SrcKey;
HKEY TrgKey;

RegOpenKeyEx(HKEY_CURRENT_USER,"SoftWare\\MySoftware", 
                                 0, KEY_READ, &SrcKey);
RegOpenKeyEx(HKEY_CURRENT_USER,"SoftWare", 
                                 0, KEY_READ, &TrgKey);

if (RegCopyKey(SrcKey, TrgKey, "$MYTEMP$") == 
                                        ERROR_SUCCESS)
; // All went okay
else
; // Something went wrong

The code

//------------------------------------------------
//  free buffer
//------------------------------------------------
__forceinline void FreeBuff(unsigned char** Buff)
{
    if (*Buff) {
        free(*Buff);
        *Buff = NULL;
    }
}

//-------------------------------------------------
//  allocate buffer
//-------------------------------------------------
__forceinline void AllocBuff(unsigned char** Buff, 
                                    DWORD BuffSize)
{
    FreeBuff(Buff);
    *Buff = (unsigned char*)malloc(BuffSize);
}

//--------------------------------------------------
//  copy key to new position
//--------------------------------------------------
LONG RegCopyKey(HKEY SrcKey, HKEY TrgKey, 
                           char* TrgSubKeyName)
{

    HKEY    SrcSubKey;
    HKEY    TrgSubKey;
    int    ValEnumIndx=0;
    int    KeyEnumIndx=0;
    char    ValName[MAX_PATH+1];
    char    KeyName[MAX_PATH+1];
    DWORD    size;    
    DWORD    VarType;
    DWORD    BuffSize;
    unsigned char*    Buff=NULL;
    LONG    Err;
    DWORD    KeyDisposition;
    FILETIME LastWriteTime; 

    // create target key
    if (RegCreateKeyEx(TrgKey,TrgSubKeyName,
             NULL,NULL,
             REG_OPTION_NON_VOLATILE,
             KEY_ALL_ACCESS,NULL,&TrgSubKey,
             &KeyDisposition) != ERROR_SUCCESS)
        return GetLastError();

    do {
        do {
            // read value from source key
            Err = ERROR_NOT_ENOUGH_MEMORY;
            BuffSize = 1024;
            do {                         
                AllocBuff(&Buff,BuffSize);
                size=MAX_PATH+1;
                Err = RegEnumValue(SrcKey,ValEnumIndx,
                          ValName,&size,NULL,&VarType,
                          Buff,&BuffSize);
                if ((Err != ERROR_SUCCESS) && 
                         (Err != ERROR_NO_MORE_ITEMS))
                    Err = GetLastError();
            } while (Err == ERROR_NOT_ENOUGH_MEMORY);

            // done copying this key
            if (Err == ERROR_NO_MORE_ITEMS)
                break;

            // unknown error return
            if (Err != ERROR_SUCCESS)
                goto quit_err;

            // write value to target key
            if (RegSetValueEx(TrgSubKey,ValName,
                       NULL,VarType,Buff,
                       BuffSize) != ERROR_SUCCESS)
                goto quit_get_err;

            // read next value
            ValEnumIndx++;
        } while (true);

        // free buffer
        FreeBuff(&Buff);

        // if copying under the same 
        // key avoid endless recursions
        do {
            // enum sub keys
            size=MAX_PATH+1;
            Err = RegEnumKeyEx(SrcKey,KeyEnumIndx++,
                            KeyName,&size,NULL,NULL,
                            NULL,&LastWriteTime);
        } while ((SrcKey == TrgKey) && 
           !strnicmp(KeyName,TrgSubKeyName,strlen(KeyName)) && 
           (Err == ERROR_SUCCESS));

        // done copying this key        
        if (Err == ERROR_NO_MORE_ITEMS)
            break;

        // unknown error return
        if (Err != ERROR_SUCCESS)
            goto quit_get_err;

        // open the source subkey
        if (RegOpenKeyEx(SrcKey,KeyName,NULL,
                   KEY_ALL_ACCESS,
                   &SrcSubKey) != ERROR_SUCCESS)
            goto quit_get_err;

        // recurs with the subkey
        if ((Err = CopyKey(SrcSubKey, TrgSubKey, 
                        KeyName)) != ERROR_SUCCESS)
            break;

        if (RegCloseKey(SrcSubKey) != ERROR_SUCCESS)
            goto quit_get_err;
    } while (true);

// normal quit
quit_err:
    FreeBuff(&Buff);
    RegCloseKey(TrgSubKey);
    if (Err == ERROR_NO_MORE_ITEMS)
        return ERROR_SUCCESS;    
    else
        return Err;

// abnormal quit
quit_get_err:
    FreeBuff(&Buff);
    RegCloseKey(TrgSubKey);
    return GetLastError();
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Ziv Ayalon
Israel Israel
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionUse SHCopyKey() insteadmemberTornacious12 Mar '12 - 12:30 
// There is already Windows Shell API function for this, although it doesn't copy security attributes.
// Here is how to use it.
 
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
 
bool bResult = false;
HKEY hOldKey;
HKEY hNewKey;
CString oldKey("SOFTWARE\\MyCompany\\MyProduce\\Oldkey");
CString newKey("SOFTWARE\\MyCompany\\MyProduce\\Newkey");
 
if (RegOpenKey(HKEY_LOCAL_MACHINE, oldKey, &hOldKey) == 0)
{
   if (RegCreateKey(HKEY_LOCAL_MACHINE, newKey, &hNewKey) == 0)
   {
      bResult = (SHCopyKey(hOldKey, NULL, hNewKey, 0) == 0);
      RegCloseKey(hNewKey);
   }
   RegCloseKey(hOldKey);
 
   if (bResult)
   {
      RegDeleteKey(HKEY_LOCAL_MACHINE, oldKey);
   }
}
 
Ever had a bug that fixed itself? I hate those!

GeneralMy vote of 3memberTornacious12 Mar '12 - 12:21 
Doesn't handle UNICODE or security, and has a few bugs.
GeneralMy vote of 2memberoren.shnitzer30 Oct '11 - 4:52 
no treatment of security
GeneralMy vote of 2memberkpavelko24 Nov '08 - 6:26 
ugly code
GeneralThank you!!memberpointer19 Aug '08 - 3:38 
This is wonderful. Just what i needed.
Save me huge burden.
Thank you one more time.
Generalin additionmemberValery A. Boronin5 May '06 - 9:43 
...and ValueName can be longer then MAX_PATH
also, I don't see reason to allocate/deallocate buffers in the loop
RegQueryInfoKey would be definitely a reasonable choice
or at least do buffer reallocation only if need, not every time Smile | :)
 
code mark should be less then 4, I made a mistake Wink | ;)
Generalunicode & securitymemberValery A. Boronin5 May '06 - 7:53 
After the first look I got few issues/ToDo for the author:
- UNICODE
--- why don't write with TCHARs from the beginning?
- security
--- are security attributes also copied from one key to another?
--- what if few subkeys has security settings which are not allowed to look into, etc?
 
it's just after 1 minute review, I must say that code is very far from ideal.
 
PS last remark, recursion is very easy to implement but a little bit limit usage of this code
 
Valery A. Boronin
Generali get errors C3861memberE-Male19 May '04 - 0:08 
i added this function to a program (which for now does nothing)
then i got these errors:
 
p:\regtest2\regtest2.cpp(20) : error C3861: 'free': identifier not found, even with argument-dependent lookup
p:\regtest2\regtest2.cpp(31) : error C3861: 'malloc': identifier not found, even with argument-dependent lookup
p:\regtest2\regtest2.cpp(110) : error C3861: 'CopyKey': identifier not found, even with argument-dependent lookup
 
did i do anythign wrong?
maybe forgot to include something or add a namespace?
 
i use ms visual studio .net 2003 c++
 
thx in advance
E-Male
GeneralFixed &gt; 1024 issuesussHarlan Seymour12 Feb '04 - 9:01 
Nice code!   I had a binary key that was > 1024 bytes, and the code created a corrupted copy in this case.   I fixed the problem by querying for the value length just *before* the AllocBuff in the innermost loop:
 
      Err = RegQueryInfoKey(SrcKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &BuffSize, NULL, NULL);                   
      // if (Err != ERROR_SUCCESS) ...
      BuffSize = __max(BuffSize, 1024); // just to be safe minsize is 1024

GeneralRe: Fixed &gt; 1024 issuememberwschmidt21 Feb '04 - 3:00 
An alternate way to handle > 1024 bytes of data.
 
Err = ERROR_MORE_DATA;
BuffSize = 1024;
Retries = -1;
do {
++Retries;
AllocBuff(&Buff,BuffSize);
size=MAX_PATH+1;
Err = RegEnumValue(SrcKey,ValEnumIndx,ValName,&size,NULL,&VarType,Buff,&BuffSize);
} while (Err == ERROR_MORE_DATA && Retries < 2);


GeneralThe best i&#180;ve ever seensussAnonymous26 Nov '03 - 5:30 
Very good code, u saved me, and very clean that recurse but it´s wrong called, i think it should be RegCopyKey(...) instead of CopyKey(...) as the comment says is a recursive call. But Anyway, with that little change it works!! Thanks again Big Grin | :-D
GeneralThank you!memberEugene Plokhov26 Oct '03 - 18:07 
Thank you, Ziv!
 
Yesterday I was thinking how tedious it would be to write registry copying function... and now I get it without any coding!
 
Very useful function! Thanks!
GeneralDeserves a big 5!memberGeert Delmeiren4 Apr '02 - 1:13 
As a matter of fact very easy.
But it was just what I came looking for on CP today.
Big Grin | :-D
 
Thanks. Rose | [Rose]
GeneralSome bugsmemberMichael Walz20 Mar '02 - 3:18 
There are some bugs or typos :
 
I changed the prototype, the char* is now const, this is cleaner.
 
LONG RegCopyKey(HKEY SrcKey, HKEY TrgKey, const char* TrgSubKeyName)
 
and
if ((Err = CopyKey(SrcSubKey, TrgSubKey, KeyName)) != ERROR_SUCCESS)
changed to
if ((Err = RegCopyKey(SrcSubKey, TrgSubKey, KeyName)) != ERROR_SUCCESS)
 

Otherwise it works great. Thank you, this saved me at leat one and a half
hour of work.

GeneralExcellentmemberMandalis16 Mar '02 - 6:24 
I had been looking for such a function for days when I finally came upon this article. How could I have missed it all this time? Anyway, it's exactly what I was looking for, I could put it to use in my registry class in 10 minutes.
I just modified it a little so that it would not overwrite existing values.
For this I replaced
...
// write value to target key
if (RegSetValueEx(TrgSubKey,ValName,NULL,VarType,Buff,BuffSize) != ERROR_SUCCESS)
goto quit_get_err;
...
 
with
...
if (RegGetValueEx(TrgSubKey,ValName,NULL,&VarType,NULL,NULL) == ERROR_SUCCESS)
{
// don't do anything, there is already such a value
}
else // write value to target key
if (RegSetValueEx(TrgSubKey,ValName,NULL,VarType,Buff,BuffSize) != ERROR_SUCCESS)
{
goto quit_get_err;
}
...
 

 

 

GeneralRegKeyOpenExmemberAnonymous7 Mar '02 - 11:33 
GoodBig Grin | :-D
GeneralImporting Reg filesmemberKunjan14 Jan '02 - 23:48 
any function to import reg files within program???
GeneralRe: Importing Reg filesmemberAnonymous7 May '02 - 4:36 
You could use ShellExecute with the path of the reg file you want to import.
 
g
QuestionKEY_READ?memberIstrebitjel6 Nov '01 - 22:25 
Hi,
nice one, but shouldn't you open the TrgKey in KEY_WRITE mode if you copy to it?
 
Regards,
Marco
AnswerRe: KEY_READ?memberZiv Ayalon8 Nov '01 - 5:05 
Hi,
Since the subkey(TrgSubKey) is created with KEY_ALL_ACCESS, this is not necessary.
 
Cheers ZivSmile | :)
GeneralRe: KEY_READ?memberXIIX11 Aug '02 - 9:52 
It is so!
GeneralGood jobmemberAnonymous1 Apr '01 - 20:30 
Hey this is very useful. Nice code,man.Smile | :)
GeneralNice, but...memberAnonymous26 Feb '01 - 5:53 
The code is very useful to me, thank you!
 
But, what has this code to do with 'Book Chapters', as it is in the Book Chapters category of the site.
GeneralRe: Nice, but...memberJohn Miller Smith Ann28 Feb '02 - 8:18 
Anonymous wrote:
But, what has this code to do with 'Book Chapters', as it is in the Book Chapters category of the site.
 
HE IS A BOOK HAHAHAHAH BOOD BUG ! HAHAHAH Mad | :mad:

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 1 Apr 2001
Article Copyright 2001 by Ziv Ayalon
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid