views:

52

answers:

1

So far I have the below which is taken from

http://www.danielmoth.com/Blog/volatile-registrykey.aspx

public static class RegistryHelper
{
    public static RegistryKey CreateVolatileSubKey(RegistryKey rk, string subkey, RegistryKeyPermissionCheck permissionCheck)
    {
        var rk2 = rk.GetType();
        const BindingFlags bfStatic = BindingFlags.NonPublic | BindingFlags.Static;
        const BindingFlags bfInstance = BindingFlags.NonPublic | BindingFlags.Instance;
        rk2.GetMethod("ValidateKeyName", bfStatic).Invoke(null, new object[] { subkey });
        rk2.GetMethod("ValidateKeyMode", bfStatic).Invoke(null, new object[] { permissionCheck });
        rk2.GetMethod("EnsureWriteable", bfInstance).Invoke(rk, null);

        subkey = (string)rk2.GetMethod("FixupName", bfStatic).Invoke(null, new object[] { subkey });
        if (!(bool)rk2.GetField("remoteKey", bfInstance).GetValue(rk))
        {
            var key = (RegistryKey)rk2.GetMethod("InternalOpenSubKey", bfInstance, null, new[] { typeof(string), typeof(bool) }, null).Invoke(rk, new object[] { subkey, permissionCheck != RegistryKeyPermissionCheck.ReadSubTree });
            if (key != null)
            {
                rk2.GetMethod("CheckSubKeyWritePermission", bfInstance).Invoke(rk, new object[] { subkey });
                rk2.GetMethod("CheckSubTreePermission", bfInstance).Invoke(rk, new object[] { subkey, permissionCheck });
                rk2.GetField("checkMode", bfInstance).SetValue(key, permissionCheck);
                return key;
            }
        }
        rk2.GetMethod("CheckSubKeyCreatePermission", bfInstance).Invoke(rk, new object[] { subkey });

        int lpdwDisposition;
        IntPtr hkResult;

        var srh = Type.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
        var temp = rk2.GetField("hkey", bfInstance).GetValue(rk);
        var rkhkey = (SafeHandleZeroOrMinusOneIsInvalid)temp;

        var getregistrykeyaccess = (int)rk2.GetMethod("GetRegistryKeyAccess", bfStatic, null, new[] { typeof(bool) }, null).Invoke(null, new object[] { permissionCheck != RegistryKeyPermissionCheck.ReadSubTree });
        var errorCode = RegCreateKeyEx(rkhkey, subkey, 0, null, 1, getregistrykeyaccess, IntPtr.Zero, out hkResult, out lpdwDisposition);
        var keyNameField = rk2.GetField("keyName", bfInstance);
        var rkkeyName = (string)keyNameField.GetValue(rk);

        if (errorCode == 0 && hkResult.ToInt32() > 0)
        {
            var rkremoteKey = (bool)rk2.GetField("remoteKey", bfInstance).GetValue(rk);
            var hkResult2 = srh.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(IntPtr), typeof(bool) }, null).Invoke(new object[] { hkResult, true });
            var key2 = (RegistryKey)rk2.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { hkResult2.GetType(), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }, null).Invoke(new[] { hkResult2, permissionCheck != RegistryKeyPermissionCheck.ReadSubTree, false, rkremoteKey, false });
            rk2.GetMethod("CheckSubTreePermission", bfInstance).Invoke(rk, new object[] { subkey, permissionCheck });
            rk2.GetField("checkMode", bfInstance).SetValue(key2, permissionCheck);
            if (subkey.Length == 0)
            {
                keyNameField.SetValue(key2, rkkeyName);
            }
            else
            {
                keyNameField.SetValue(key2, rkkeyName + @"\" + subkey);
            }
            key2.Close();
            return rk.OpenSubKey(subkey, true);
        }
        if (errorCode != 0)
            rk2.GetMethod("Win32Error", bfInstance).Invoke(rk, new object[] { errorCode, rkkeyName + @"\" + subkey });
        return null;
    }

    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    private static extern int RegCreateKeyEx(SafeHandleZeroOrMinusOneIsInvalid hKey, string lpSubKey, int reserved, string lpClass, int dwOptions, int samDesigner, IntPtr lpSecurityAttributes, out IntPtr hkResult, out int lpdwDisposition);
}

Which works but is fairly ugly. Is there a better way?

+2  A: 

If you are using .NET 4, you can take advantage of the new RegistryOptions enumeration to create a volatile key using the normal .NET APIs.

Matt Ellis