Solved

Registry  reading writing...

Posted on 2000-03-14
17
233 Views
Last Modified: 2010-04-04
Hi all,

is there an easy way to do the following:
copy subkey with all subkeys and values from one key to another - let's say there is subkey in HKEY_USERS named "something", and i would like to copy it with all subkeys and values to HKEY_LOCAL_MACHINE as is....
Is there an easy wy to do this or do i have to iterate trough all keys and values one by one?
Thanks
0
Comment
Question by:rpetruni
  • 5
  • 5
  • 3
  • +4
17 Comments
 
LVL 5

Expert Comment

by:TheNeil
ID: 2615747
Under WIndows 95/98 you can use the MoveKey method but under NT it doesn't work so you have to do it manually. This routine does the job for you:

procedure TfrmMMU_RegEditor.RenameRegKey(sOldKey, sNewKey : STRING);
VAR
  regLoc : TRegistry;

  //----------------------------------------------------------------------------
  //This routine handles moving an entire (and sub keys and values) under
  //Windows NT. 95/98 would handle this with just the MoveKey method but NT
  //don't. Be warned: THIS ROUTINE IS RECURSIVE
  //----------------------------------------------------------------------------
  PROCEDURE MoveKeyData(sFrom, sTo : STRING);
  VAR
    stlSub_Keys   : TStringList;
    stlSub_Values : TStringList;
    n          : INTEGER;
    regLoc2    : TRegistry;
  BEGIN
    regLoc.OpenKey(sFrom, False);
    IF sFrom[Length(sFrom)] = '\'  //Add on trailing '\'s if needed to the source...
    THEN
      sFrom := Copy(sFrom, 1, Length(sFrom) - 1);
    IF sFrom[Length(sTo)] = '\'    //...and destination
    THEN
      sFrom := Copy(sTo, 1, Length(sTo) - 1);

    IF sTo[1] <> '\'    //Need to check that the destination also STARTS with a '\'
    THEN
      sTo := '\' + sTo;

    stlSub_Keys := TStringList.Create; //Create something to store the sub key names
    TRY
      regLoc.GetKeyNames(stlSub_Keys); //Get the sub key names
      regLoc.CreateKey(sTo);           //Create our new sub key (at the destination)

      FOR n := 0 TO (stlSub_Keys.Count - 1) //Iterate through the keys moving them one by one
      DO
        MoveKeyData(sFrom + '\' + stlSub_Keys[n], sTo + '\' + stlSub_Keys[n]);
    FINALLY
      stlSub_Keys.Free;    //Don't need the sub key names anymore
    END;

    regLoc.OpenKey(sFrom, False);    //Jump to the SOURCE key

    regLoc2 := TRegistry.Create;     //Create a second registry link so that we can copy the data items across
    TRY
      regLoc2.RootKey := HKEY_LOCAL_MACHINE;
      regLoc2.OpenKey(sTo, False);   //Jump to the DESTINATION key

      stlSub_Values := TStringList.Create;      //Create something to hold the item names
      TRY
        regLoc.GetValueNames(stlSub_Values);    //GET the item names
        FOR n := 0 TO (stlSub_Values.Count - 1) //Iterate through the list, copying each data item across
        DO
          regLoc2.WriteString(stlSub_Values[n], regLoc.ReadString(stlSub_Values[n]));
      FINALLY
        stlSub_Values.Free;
      END;
    FINALLY
      regLoc2.Free;
    END;

    regLoc.DeleteKey(sFrom);         //We can now DELETE the source key
  END;

begin
  regLoc := TRegistry.Create;        //Create the initial link into the registry
  TRY
    regLoc.RootKey := HKEY_LOCAL_MACHINE;
    regLoc.OpenKey(sOldKey, False);
    MoveKeyData(sOldKey, sNewKey);   //Do the actual move
  FINALLY
    regLoc.Free;                     //All done. Clean up
  END;
END;

The Neil
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 2615759
Oops! I just read the question again and you said COPY not MOVE. The above will iterate through it all for you and copy the key(s) across. To stop it from actually deleting the source key as well, just remove the final line from the MoveKeyData routine

The Neil
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2615966
The Neil, correct me if I'm wrong but it looks as would only string keys be copyied/moved with your code. What about all those other key types?

rpetruni,

here's my code to copy/move/rename registry keys:

procedure RenameRegistryItem(AKey: HKEY; Old, New: String);

var
  OldKey,
  NewKey: HKEY;
  Status: Integer;

begin
  // Open Source key
  Status := RegOpenKey(AKey, PChar(Old), OldKey);
  if Status = ERROR_SUCCESS then
  begin
    // Create Destination key
    Status := RegCreateKey(AKey, PChar(New), NewKey);
    if Status = ERROR_SUCCESS then CopyRegistryKey(OldKey, NewKey);
    RegCloseKey(OldKey);
    RegCloseKey(NewKey);
    // Delete last top-level key
    RegDeleteKey(AKey, PChar(Old));
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure CopyRegistryKey(Source, Dest: HKEY);

const
  DefValueSize  = 512;
  DefBufferSize = 8192;

var
  Status: Integer;
  Key: Integer;
  ValueSize,
  BufferSize: Cardinal;
  KeyType: Integer;
  ValueName: String;
  Buffer: Pointer;
  NewTo,
  NewFrom: HKEY;

begin
  SetLength(ValueName, DefValueSize);
  Buffer := AllocMem(DefBufferSize);
  try
    Key := 0;
    repeat
      ValueSize := DefValueSize;
      BufferSize := DefBufferSize;
      //  enumerate data values at current key
      Status := RegEnumValue(Source, Key, PChar(ValueName), ValueSize, nil, @KeyType, Buffer, @BufferSize);
      if Status = ERROR_SUCCESS then
      begin
        // move each value to new place
        Status := RegSetValueEx(Dest, PChar(ValueName), 0, KeyType, Buffer, BufferSize);
         // delete old value
        RegDeleteValue(Source, PChar(ValueName));
      end;
    until Status <> ERROR_SUCCESS; // Loop until all values found

    // start over, looking for keys now instead of values
    Key := 0;
    repeat
      ValueSize := DefValueSize;
      BufferSize := DefBufferSize;
      Status := RegEnumKeyEx(Source, Key, PChar(ValueName), ValueSize, nil, Buffer, @BufferSize, nil);
      // was a valid key found?
      if Status = ERROR_SUCCESS then
      begin
        // open the key if found
        Status := RegCreateKey(Dest, PChar(ValueName), NewTo);
        if Status = ERROR_SUCCESS then
        begin
          //  Create new key of old name
          Status := RegCreateKey(Source, PChar(ValueName), NewFrom);
          if Status = ERROR_SUCCESS then
          begin
            // if that worked, recurse back here
            CopyRegistryKey(NewFrom, NewTo);
            RegCloseKey(NewFrom);
            RegDeleteKey(Source, PChar(ValueName));
          end;
          RegCloseKey(NewTo);
        end;
      end;
    until Status <> ERROR_SUCCESS; // loop until key enum fails
  finally
    FreeMem(Buffer);
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure DeleteRegistryKey(Key: HKEY);

// Deletes all values and subkeys under Key, which must either be one of the predefined keys (NOT recommended) or
// an already open key.
//
// BE CAREFUL: This function will delete ALL keys under the given subkey, so you can damage your
//             registry seriously!

const
  DefValueSize  = 512;
  DefBufferSize = 8192;

var
  Status: Integer;
  Index: Integer;
  ValueSize,
  BufferSize: Cardinal;
  KeyType: Integer;
  ValueName: String;
  Buffer: Pointer;
  SubKey: HKEY;

begin
  SetLength(ValueName, DefValueSize);
  Buffer := AllocMem(DefBufferSize);
  try
    Index := 0;
    repeat
      ValueSize := DefValueSize;
      BufferSize := DefBufferSize;
      // enumerate data values at current key
      Status := RegEnumValue(Key, Index, PChar(ValueName), ValueSize, nil, @KeyType, Buffer, @BufferSize);
      // delete old value
      if Status = ERROR_SUCCESS then RegDeleteValue(Key, PChar(ValueName));
    until Status <> ERROR_SUCCESS; // Loop until all values found

    // start over, looking for keys now instead of values
    Index := 0;
    repeat
      ValueSize := DefValueSize;
      BufferSize := DefBufferSize;
      Status := RegEnumKeyEx(Key, Index, PChar(ValueName), ValueSize, nil, Buffer, @BufferSize, nil);
      // was a valid key found?
      if Status = ERROR_SUCCESS then
      begin
        // open the key if found
        Status := RegOpenKey(Key, PChar(ValueName), SubKey);
        if Status = ERROR_SUCCESS then
        begin
          // if that worked, recurse back here
          DeleteRegistryKey(SubKey);
          RegCloseKey(SubKey);
          RegDeleteKey(Key, PChar(ValueName));
        end;
      end;
    until Status <> ERROR_SUCCESS; // loop until key enum fails
  finally
    FreeMem(Buffer);
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

Ciao, Mike
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 2615994
I might be wrong but it does handle everything. It reads the data as a string but it doesn't care what the original data type was. It's like reading an integer in a file into a string, and then writing it back out - the next access to the file can still treat the data as an integer...or maybe it won't. All I know is, the routine I listed above works for me and until it screws up (there's confidence) I'm happy with it

The Neil
0
 
LVL 1

Expert Comment

by:nrico
ID: 2616208
It will probably read an integer into the string correctly, but write it back as a string.
This question is trickier than it seemed :-).
Isn't there some value-type determination function in TRegistry??
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 2616226
Depends whether or not that then stops you from reading it back out in the desired type (i.e. integer). I'm not saying that it won't work (and I'm not saying that it will) and if anyone wants to argue the point then I'll cave in immediately and promise never to do it again

The Neil =;)
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2616245
..and even if there is a type determination method/property/function then nothing is said about the actual size of the data. As you all know you can store raw data (binary data) in the registry. I doubt that TRegistry will take care about this, while my code does :-)

Ciao, Mike
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 2616270
That's what I like to see: A complete set of tools given to us from day one allowing us to properly work with a pretty fundamental part of Windows. Of course if Borland/Inprise (or maybe this is down to good old Microsoft) had given us the tools to get the job done then developers around the world wouldn't have spent days/weeks/months re-inventing the wheel. Ho hum...

The Neil =;)
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 12

Expert Comment

by:rwilson032697
ID: 2617950
Listening
0
 
LVL 1

Expert Comment

by:fulg0re
ID: 2619334
well, you can just use savetofile and loadfromfile for fast copy...
0
 
LVL 1

Author Comment

by:rpetruni
ID: 2621172
Hi all,

TheNeil - your code does not helping me - or i don't know how to use it :-(...
The point is : i need to copy something like this:
HKEY_USERS\.Default\Software\Something in the HKEY_LOCAL_MACHINE\Software\Something - i don't need the rest data from HKEY_USERS.
Lischke - same goes to u - your code is slooooow..., and it copies whole key...
If i don't know how to use those functions - please tel me...
The function for deleting a key is not needed on Win95/98 machines - you could use DeleteKey ;-)
I was asking if there is a way to do this without this kind of code - i'm writing a function similar to those u write...i will post it here when it will do the yob as i want it to...
fulgOre - those functions are also saving the whole rootkey - i don't need this.
Once more if i'm wrong about those functions - pleqase correct me...
Robert
0
 
LVL 1

Expert Comment

by:yk030299
ID: 2622724
listen
0
 
LVL 10

Accepted Solution

by:
Lischke earned 150 total points
ID: 2622751
Robert,

I doesn't matter whether the code could be much simpler on Win9x. If you are writing software which is expected to run on WinNT too then you have no other choice than to roll your own function and forget the other. I'm doing this all the time because I can forget more than half of ALL APIs available on NT (which are several hundreds if not thousands) because they are missing on Win9x.

That my code is so slow on your machine is very surprising to me. It is using the lowest level of registry access and does no redudant stuff like TRegistry so it should definitly be faster than any other method. And that it copies the whole key is the reason for its existance, isn't it?

Perhaps you are using the stuff not correctly. For my code you would do something like this:

procedure CopyKey(const Source, Target: String);

var
  SourceKey,
  TargetKey: HKEY;
  Disposition: DWORD;
 
begin
  if RegCreateKeyEx(HKEY_USERS, PChar(Source), 0, nil,
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nil, SourceKey, @Disposition) = ERROR_SUCCESS then
  begin
    if RegCreateKeyEx(HKEY_LOCAL_MACHINE, PChar(Target), 0, nil,
      REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nil, TargetKey, @Disposition) = ERROR_SUCCESS then
    begin
      CopyRegistryKey(SourceKey, TargetKey);
      RegCloseKey(TargetKey);
    end;
    RegCloseKey(SourceKey);
  end;
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
  CopyKey('.Default\Software\Something', 'Software\Something');
end;


Note that the base keys (HKU and HKLM)are fixed here, but can also be made flexible.

Ciao, Mike
0
 
LVL 1

Author Comment

by:rpetruni
ID: 2623043
Adjusted points from 100 to 150
0
 
LVL 1

Author Comment

by:rpetruni
ID: 2623044
Yes, Lischke, it was my mistake...
Thanks, here are your 100 pts + bonus for whole code...
                     Robert
0
 
LVL 1

Author Comment

by:rpetruni
ID: 2623050
Ok, now for real :-)
0
 
LVL 1

Author Comment

by:rpetruni
ID: 2623191
One more comment:(for newcommers)

is you want NOT to delete a key with your function (Lischke) (that was what i needed), you have to place inc(Key) when enumerating values, and Keys...
Instead RegDEleteValue(), and RegDeleteKey -> inc(Key)....

Robert
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now