How to not trigger exception when trying to write to HKLM on standard user?

delphi, registry, security, uac

Solution

You can't get `TRegistry` to behave the way you want. There are no `TryXXX` methods and there are not parameters that disable exceptions. You can be sure that this is so because the `TRegistry` methods do not provide any error or status codes.

You will have to write your own wrappers around the Win32 registry API.

As an aside, I agree with your opinion, expressed in the comments, that `TRegistry` is lacking in functionality here. We expect registry operations to fail, and so we should not have to catch exceptions to deal with that.

Problem

I am attempting to write a value to the HKLM registry using `TRegistry` component in Delphi. Since I am running on Windows 2000 as a standard user (or XP as a standard user, or Windows Vista as a standard user, or Windows 7 with a standard user), I fully expect that I will not be able to write to the `HKEY_LOCAL_MACHINE` portion of the registry: ``` 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; ``` Unfortunately, the `WriteString` throws an `ERegistryException`: ``` Failed to set data for 'MachineId` ``` This is fully expected, which is why I'm trying to avoid the exception. I do not see any `CanWriteString` or `TryWriteString` in `TRegistry`. How can I not trigger an exception when trying to write to HKLM? Self-evident notes: - if the user actually is an administrator then the write should be able to succeed wrapping the call to `WriteString` in a 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; ``` doesn't prevent the exception from being thrown in the first place. Update: From RTL source: ``` KEY_WRITE = (STANDARD_RIGHTS_WRITE or KEY_SET_VALUE or KEY_CREATE_SUB_KEY) and not SYNCHRONIZE; ``` from MSDN: ``` KEY_WRITE (0x20006) ``` Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.

Original source