Aparentemente no debería ser complicado copiar claves del registro arrastrando todos sus valores y subclaves, para eso M$ dispone de las API RegCopyTree y SHCopyKey. El problema es que estas API tienen restricciones de copia. No quedando contento con las pruebas que realicé y para generalizar la solución al problema he escrito una función recursiva que copia una clave a otro lugar.
Primero crea la subclave de destino, luego enumera y copia los valores, y finalmente, copia las subclaves, En este último punto la función se vuelve recursiva para repetir las acciones fasta la última rama del árbol.
delphi
function RegCopyKey(SrcKey, TrgKey: HKEY; TrgSubKeyName: PAnsiChar): integer; var SrcSubKey: HKEY; TrgSubKey: HKEY; ValIndex: integer; KeyIndex: integer; ValName: array [0..MAX_PATH] of AnsiChar; KeyName: array [0..MAX_PATH] of AnsiChar; Size: DWORD; ValType: DWORD; BuffSize: DWORD; Buff: PBYTE; begin ValIndex:= 0; KeyIndex:= 0; Result:= 2; if (SrcKey = 0) or (TrgKey = 0) then exit; // Creando La Clave Destino Result:= RegCreateKeyExA(TrgKey, TrgSubKeyName, 0, nil, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nil, TrgSubKey, nil); if Result = ERROR_SUCCESS then begin Size:= sizeof(ValName); // Copio valores while ERROR_NO_MORE_ITEMS <> RegEnumValueA(SrcKey, ValIndex, ValName, Size, nil, @ValType, nil, @BuffSize) do begin Buff:= VirtualAlloc(nil, BuffSize, MEM_COMMIT, PAGE_READWRITE); RegEnumValueA(SrcKey, ValIndex, ValName, Size, nil, @ValType, Buff, @BuffSize); RegSetValueExA(TrgSubKey, ValName, 0, ValType, Buff, BuffSize); VirtualFree(Buff, 0, MEM_RELEASE); Size:= sizeof(ValName); inc(ValIndex); end; // Copio Claves recursivamente Size:= sizeof(KeyName); while ERROR_NO_MORE_ITEMS <> RegEnumKeyEx(SrcKey, KeyIndex, KeyName, Size, nil, nil, nil, nil) do begin if RegOpenKeyExA(SrcKey, KeyName, 0, KEY_ALL_ACCESS, SrcSubKey) = ERROR_SUCCESS then begin if 0 = lstrcmpi(@KeyName[0], @TrgSubKeyName[0]) then continue; if ERROR_SUCCESS <> RegCopyKey(SrcSubKey, TrgSubKey, KeyName) then break; RegCloseKey(SrcSubKey); end; Size:= sizeof(KeyName); inc(KeyIndex); end; RegCloseKey(TrgSubKey); end; end;
Un ejemplo de uso que copia HKEY_CLASSES_ROOT\batfile\shell en HKEY_CLASSES_ROOT\batfile\bkShell
delphi
var SrcKey, TrgKey: HKEY; begin RegOpenKeyEx(HKEY_CLASSES_ROOT, 'batfile\shell', 0, KEY_READ, SrcKey); RegOpenKeyEx(HKEY_CLASSES_ROOT, 'batfile', 0, KEY_READ, TrgKey); RegCopyKey(SrcKey, TrgKey, 'bkShell'); RegCloseKey(SrcKey); RegCloseKey(TrgKey); end;
Añadiendo el borrado de la clave original, tenemos el código listo para mover claves:
delphi
type function RegDeleteTree(KeyScr: HKEY; lpSubKey: LPCTSTR): integer; stdcall; external 'Advapi32.dll' name 'RegDeleteTreeA'; .................. var SrcKey, TrgKey: HKEY; begin RegOpenKeyEx(HKEY_CLASSES_ROOT, 'batfile\shell\runas', 0, KEY_READ, SrcKey); RegOpenKeyEx(HKEY_CLASSES_ROOT, 'batfile', 0, KEY_READ, TrgKey); RegCopyKey(SrcKey, TrgKey, 'bkRunAs'); RegCloseKey(SrcKey); RegCloseKey(TrgKey); RegDeleteTree(HKEY_CLASSES_ROOT, 'batfile\shell\runas'); end;
Saludos.
PD/ Edito para unificar en AnsiChar