Search code examples
c#winapiregistrysymlinkregistrykey

How to use REG_OPTION_OPEN_LINK in C# Registry class


I want to open a registry key that is a symbolic link.
According to Microsoft I need to use REG_OPTION_OPEN_LINK to open it.
I searched for an option to add it to the OpenSubKey function but I didn't find an option. There are only fiver overload functions but none of them allow to add an optional parameter:

Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, bool writable)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryRights rights)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)

The only way I can think of is to use p\invoke but maybe I am missing it and there is an option in C# classes.


Solution

  • You can't do this with the normal RegistryKey functions. Having checked in the source code, it seems that the ulOptions parameter is always passed as 0.

    The only way is to call RegOpenKeyEx yourself, and pass the resulting SafeRegistryHandle to RegistryKey.FromHandle

    using System.Runtime.InteropServices;
    using System.Security.AccessControl;
    using System.ComponentModel;
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles;
    
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
    static extern int RegOpenKeyExW(SafeRegistryHandle hKey, String lpSubKey,
        int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
    
    public static RegistryKey OpenSubKeySymLink(this RegistryKey key, string name, RegistryRights rights = RegistryRights.ReadKey, RegistryView view = 0)
    {
        const int REG_OPTION_OPEN_LINK = 0x0008;
        var error = RegOpenKeyExW(key.Handle, name, REG_OPTION_OPEN_LINK, ((int)rights) | ((int)view), out var subKey);
        if (error != 0)
        {
            subKey.Dispose();
            throw new Win32Exception(error);
        }
        return RegistryKey.FromHandle(subKey);  // RegistryKey will dispose subKey
    }
    

    It is an extension function, so you can call it on either an existing sub-key, or on one of the main keys, such as Registry.CurrentUser. Don't forget to put a using on the returned RegistryKey:

    using (var key = Registry.CurrentUser.OpenSubKeySymLink(@"SOFTWARE\Microsoft\myKey", RegistryRights.ReadKey))
    {
        // do stuff with key
    }