Delphi экспорт ключа HKEY_CURRENT_USER не работает - пустой файл результатов - PullRequest
3 голосов
/ 15 января 2020

Я пытаюсь экспортировать раздел реестра, используя функции TRegistry.SaveKey или RegSaveKey, но безуспешно. Все, что я получаю, является пустым файлом 0 байтов. Я видел примеры онлайн, но ни один из них не работает на 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;

Также, если я извлекаю существующий ключ из RegEdit, а затем пытаюсь загрузить его в приложение, используя TRegistry.LoadKey или RegLoadKey, ничего не происходит

У меня есть права администратора на компьютере, на котором я запускаю.

Кто-нибудь знаком с проблемой?

Ответы [ 2 ]

10 голосов
/ 15 января 2020

Из документации RegSaveKey:

В вызывающем процессе должна быть включена привилегия SE_BACKUP_NAME.

Я предполагаю, что RegSaveKey возвращает значение, отличное от ERROR_SUCCESS. который ваш код не проверяет.

См. также:

RegSaveKey возвращает ERROR_PRIVILEGE_NOT_HELD

Еще одна вещь, которую нужно проверить, это то, что файл назначения не существует перед попыткой сохранения, иначе функция не будет выполнена (это также упоминается в документации) и, очевидно, у вас есть права на запись в местоположение файла.

3 голосов
/ 15 января 2020

Вот рабочий пример. Помните, что вы должны запустить программу от имени администратора .

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.

. Для восстановления реестра необходимо включить SE_RESTORE_NAME в дополнение к SE_BACKUP_NAME Privilege.

Код был взят (и адаптирован) из этого старого сообщения на форуме

...