5

我正在尝试TRegistry使用Delphi中的组件将值写入 HKLM 注册表。

由于我作为标准用户在 Windows 2000 上运行(或作为标准用户的 XP,或作为标准用户的 Windows Vista,或带有标准用户的 Windows 7),我完全希望我将无法写入该HKEY_LOCAL_MACHINE部分注册表:

reg := TRegistry.Create(KEY_WRITE);
try
   reg.Access := KEY_WRITE; //sure, set it again, why not
   reg.RootKey := HKEY_LOCAL_MACHINE;
   if not reg.OpenKey('\Software\Microsoft\SQMClient', True) then
      Exit;

   reg.WriteString('MachineId', s);
finally
   reg.Free;
end;

不幸的是,WriteString抛出一个ERegistryException

Failed to set data for 'MachineId`

这是完全可以预料的,这就是我试图避免异常的原因。我没有看到任何CanWriteStringTryWriteStringTRegistry.

尝试写入 HKLM 时如何不触发异常?


不言自明的注意事项:

  • 如果用户实际上是管理员,那么写入应该能够成功
  • 将调用包装WriteString在 try-except 中:

    reg := TRegistry.Create(KEY_WRITE);
    try
      reg.RootKey := HKEY_LOCAL_MACHINE;
      if not reg.OpenKey('\Software\Microsoft\SQMClient', True) then
         Exit;
    
      try
         reg.WriteString('MachineId', s);
      except
         on E:ERegistryException do
            {nothing};
      end;
    finally
      reg.Free;
    end;
    

    不会阻止首先抛出异常。

更新:来自 RTL 来源:

KEY_WRITE          = (STANDARD_RIGHTS_WRITE or
                        KEY_SET_VALUE or
                        KEY_CREATE_SUB_KEY) and not
                        SYNCHRONIZE;

来自MSDN

KEY_WRITE (0x20006)  

结合了 STANDARD_RIGHTS_WRITE、KEY_SET_VALUE 和 KEY_CREATE_SUB_KEY 访问权限。

4

2 回答 2

4

你无法TRegistry按照你想要的方式行事。没有TryXXX方法,也没有禁用异常的参数。您可以确定确实如此,因为这些TRegistry方法不提供任何错误或状态代码。

您必须围绕 Win32 注册表 API 编写自己的包装器。

顺便说一句,我同意您在评论中表达的观点,即TRegistry这里缺乏功能。我们预计注册表操作会失败,因此我们不必捕获异常来处理它。

于 2012-05-01T22:13:01.050 回答
1

在打开密钥时使用KEY_SET_VALUE而不是,因为其中包含其他权限。成功的事实意味着您的标准用户帐户具有其中一些权限,因此允许打开密钥,但在您执行此操作之前,密钥不知道您将如何使用它,因此它实际上无法验证如果您不使用它们,请预先设置所有权限。如果您只是使用(这是您的示例中真正需要的),如果您的用户帐户没有任何权限将数据写入密钥,则更有可能立即失败。在访问安全资源时,始终只请求您实际需要的最低权限。KEY_WRITEKEY_WRITEOpenKey()KEY_SET_VALUEOpenKey()

于 2012-05-01T22:51:26.433 回答