Search code examples
delphiregistryregistrykey

Delphi export HKEY_CURRENT_USER key not working - empty result file


I am trying to export a registry key using either TRegistry.SaveKey or RegSaveKey functions with no luck. All I get is an empty file 0 bytes. I have seen examples online none seems to be working on Windows10.

  reg := TRegistry.Create;

  reg.RootKey := HKEY_CURRENT_USER;
  reg.Access := KEY_ALL_ACCESS;

  if reg.OpenKey('\Software\MyCompanyName\MyApplication\', True) then
  begin
    reg.WriteInteger('background', Self.Color);

    reg.SaveKey('HKEY_CURRENT_USER\Software\MyCompanyName\MyApplication', 'test.txt'); //not working
    RegSaveKey(reg.CurrentKey, 'test.reg', nil); //creates empty file
  end;
  reg.CloseKey;
  reg.Free;

Also if I extract existing key from RegEdit and then try to load it in the application using TRegistry.LoadKey or RegLoadKey nothing is happening

I do have admin right on the machine I run this.

Anyone familiar with the issue?


Solution

  • Here is a working example. Be aware that you must run the program as administrator.

    program SO59753973;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      Registry,
      Windows,
      System.SysUtils;
    
    
    
    function NTSetPrivilege(sPrivilege: string; bEnabled: Boolean): Boolean;
    
    var
     hToken: THandle;
     TokenPriv: TOKEN_PRIVILEGES;
     PrevTokenPriv: TOKEN_PRIVILEGES;
     ReturnLength: Cardinal;
     errval:Cardinal;
    begin
     Result := True;
     errval:=0;
     // Only for Windows NT/2000/XP and later.
     if not (Win32Platform = VER_PLATFORM_WIN32_NT) then Exit;
     Result := False;
     // obtain the processes token
     if OpenProcessToken(GetCurrentProcess(),
     TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
      try
      // Get the locally unique identifier (LUID) .
      if LookupPrivilegeValue(nil, PChar(sPrivilege),TokenPriv.Privileges[0].Luid) then
      begin
       TokenPriv.PrivilegeCount := 1; // one privilege to set
       case bEnabled of
        True: TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        False: TokenPriv.Privileges[0].Attributes := 0;
       end;
    
      ReturnLength := 0; // replaces a var parameter
      PrevTokenPriv := TokenPriv;
       // enable or disable the privilege
      if AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv),PrevTokenPriv, ReturnLength) then
       Result := True
      else
       begin
        errval:= GetLastError;
        Result := errval = 0;
       end;
      end;
     finally
      CloseHandle(hToken);
     end;
     // test the return value of AdjustTokenPrivileges.
     //Result := GetLastError = ERROR_SUCCESS;
     if not Result then
     raise Exception.Create(SysErrorMessage(errval));
    end;
    
    var
      Reg: TRegistry;
      sKeyFileName: String;
    
    begin
     try
      if not NTSetPrivilege('SeBackupPrivilege',true) then
        Exit;
      sKeyFileName := 'C:\temp\tempReg.reg';
      if FileExists(sKeyFileName) then
        DeleteFile(sKeyFileName);
      Reg := TRegistry.Create(KEY_ALL_ACCESS);
       try
        Reg.RootKey := HKEY_CURRENT_USER;
        if Reg.SaveKey('\Software\Microsoft', sKeyFileName)
        then
         Writeln('Registry has been saved!')
        else
         Writeln('Failed to save registry, received error: ' + IntToStr(Reg.LastError) + '!');
       finally
        Reg.Free;
       end;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
     Readln;
    end.
    

    For restoring the registry, you must enable the SE_RESTORE_NAME in addition to the SE_BACKUP_NAME Privilege.

    Code has been taken (and adapted) from this old forum post