I\'ve recently written an application that impersonate user account, get a handle to CURRENT_USER registry key (using PInvoke \"LoadUserProfile\" to retrieve ProfileInfo.hPr
Wrote an Impersonation class I posted here to answer the same kind of question: Impersonate admin account to edit registry key not working (C#)
To write to the key, you just do:
string userName = "domain\user";
string password = "whatever";
string KEY_STR = "SomeSubKey\\ASubKeyToThat";
WindowsImpersonationContext adminContext = Impersonation.getWic(userName, password);
if (adminContext != null)
{
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(KEY_STR, true);
key.SetValue("State", 0x60001);
}
catch (Exception ex)
{
Console.Out.WriteLine("\nUnable to set registry value:\n\t" + ex.Message);
Impersonation.endImpersonation();
adminContext.Undo();
}
finally
{
Impersonation.endImpersonation();
// The above line does this --
//if (tokenHandle != IntPtr.Zero) CloseHandle(tokenHandle);
adminContext.Undo();
}
}
No handles or other fancy functions, other than to get the WindowsImpersonationContext
needed. Didn't repost that part because it looks like you already know how to get the WIC.
After days of research, and help from MSDN community to the same question, I've found the way to follow to accomplish my needs.
The initial suggestion was to use Win Api function RegOpenKeyEx
(see P/Invoke website for infos and samples); but according to this MSDN article, I've found that
If your service or application impersonates different users, do not use this function with HKEY_CURRENT_USER. Instead, call the RegOpenCurrentUser function.
Finally, the way to go is RegOpenCurrentUser
function. (unfortunately there's still no trace of this function on P/Invoke website, but you can find some infos on MSDN)
This is how I currently define it:
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenCurrentUser(int samDesired, out IntPtr phkResult);
public enum RegistrySecurity
{
KEY_ALL_ACCESS = 0xF003F,
KEY_CREATE_LINK = 0x0020,
KEY_CREATE_SUB_KEY = 0x0004,
KEY_ENUMERATE_SUB_KEYS = 0x0008,
KEY_EXECUTE = 0x20019,
KEY_NOTIFY = 0x0010,
KEY_QUERY_VALUE = 0x0001,
KEY_READ = 0x20019,
KEY_SET_VALUE = 0x0002,
KEY_WOW64_32KEY = 0x0200,
KEY_WOW64_64KEY = 0x0100,
KEY_WRITE = 0x20006,
}
public IntPtr GetImpersonateUserRegistryHandle(RegistrySecurity _access)
{
IntPtr safeHandle = new IntPtr();
int result = RegOpenCurrentUser((int)_access, out safeHandle);
return safeHandle;
}
/// <summary>
/// Get a registry key from a pointer.
/// </summary>
/// <param name="hKey">Pointer to the registry key</param>
/// <param name="writable">Whether or not the key is writable.</param>
/// <param name="ownsHandle">Whether or not we own the handle.</param>
/// <returns>Registry key pointed to by the given pointer.</returns>
public RegistryKey _pointerToRegistryKey(IntPtr hKey, bool writable, bool ownsHandle)
{
//Get the BindingFlags for private contructors
System.Reflection.BindingFlags privateConstructors = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
//Get the Type for the SafeRegistryHandle
Type safeRegistryHandleType =
typeof(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
//Get the array of types matching the args of the ctor we want
Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(
privateConstructors, null, safeRegistryHandleCtorTypes, null);
//Invoke the constructor, getting us a SafeRegistryHandle
Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle });
//Get the type of a RegistryKey
Type registryKeyType = typeof(RegistryKey);
//Get the array of types matching the args of the ctor we want
Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(
privateConstructors, null, registryKeyConstructorTypes, null);
//Invoke the constructor, getting us a RegistryKey
RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable });
//return the resulting key
return resultKey;
}
And this is how I use it to get registry:
IntPtr localRegistryHandle = GetImpersonateUserRegistryHandle(TestRegistryAccess.RegistrySecurity.KEY_ALL_ACCESS);
using(RegistryKey localRegistry = _pointerToRegistryKey(localRegistryHandle, true, true))
{
// do something with local registry
}