尝试在标准用户上写入HKLM时如何不触发异常?

时间:2012-05-01 21:23:30

标签: delphi security registry uac

尝试使用Delphi中的TRegistry组件将值写入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`

这是完全可以预料到的,这就是我试图避免异常的原因。我在CanWriteString中看不到任何TryWriteStringTRegistry

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


不言自明的说明:

  • 如果用户实际上是管理员,则写入应该能够成功
  • 在try-except中包含对WriteString的调用:

    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访问权限。

2 个答案:

答案 0 :(得分:4)

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

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

顺便说一句,我同意你在评论中表达的意见,TRegistry在这里缺乏功能。我们希望注册表操作失败,因此我们不应该捕获异常来处理它。

答案 1 :(得分:1)

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