I tried to write a registry subkey and its corresponding value to registry like this:
Microsoft.Win32.RegistryKey mykey;
mykey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\Muhil Software");
mykey.SetValue("Muhil", "TEST");
mykey.close();
As you can see, I used CurrentUser
to write the value to HKEY_CURRENT_USER
, there is nothing in HKEY_CURRENT_USER
. Then I checked the subkey in HKEY_USERS
and find out that the key was written there.
Your installer does not run under the logged on user session but under the Local System session. That explains why the HKCU
points to an other registry hive.
In order to open the registry key of the logged on user, you need to open this registry key HKU/<LOGGED_ON_USER_SID>
. You can get this SID (security identifier) thanks to the Windows Session API.
You can use Microsoft.Win32.Registry.Users
instead of Microsoft.Win32.Registry.CurrentUser
and open the right user key thanks to the user SID.
You can find several topics on stackoverflow on how to get the current logged-on SID, for instance How to get a Unique ID for the current user's logon session in windows - c#
UPDATE : A sample code that is able to get the logged-on user SID string, It will only work in the system session because it requires special privileges SE_TCB_NAME
. There is no error handling for simplicity
static void Main(string[] args)
{
Microsoft.Win32.RegistryKey mykey;
mykey = Microsoft.Win32.Registry.Users.CreateSubKey(GetLoggedOnUserSID() + "\\Software\\Microsoft\\Windows\\Muhil Software");
mykey.SetValue("Muhil", "TEST");
mykey.Close();
}
enum TokenInformationClass
{
TokenOwner = 4,
}
struct TokenOwner
{
public IntPtr Owner;
}
[DllImport("advapi32.dll", EntryPoint = "GetTokenInformation", SetLastError = true)]
static extern bool GetTokenInformation(
IntPtr tokenHandle,
TokenInformationClass tokenInformationClass,
IntPtr tokenInformation,
int tokenInformationLength,
out int ReturnLength);
[DllImport("kernel32.dll")]
private static extern UInt32 WTSGetActiveConsoleSessionId();
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ConvertSidToStringSid(IntPtr sid, [In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
static string GetLoggedOnUserSID()
{
IntPtr tokenOwnerPtr;
int tokenSize;
IntPtr hToken;
// Get a token from the logged on session
// !!! this line will only work within the SYSTEM session !!!
WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken);
// Get the size required to host a SID
GetTokenInformation(hToken, TokenInformationClass.TokenOwner, IntPtr.Zero, 0, out tokenSize);
tokenOwnerPtr = Marshal.AllocHGlobal(tokenSize);
// Get the SID structure within the TokenOwner class
GetTokenInformation(hToken, TokenInformationClass.TokenOwner, tokenOwnerPtr, tokenSize, out tokenSize);
TokenOwner tokenOwner = (TokenOwner)Marshal.PtrToStructure(tokenOwnerPtr, typeof(TokenOwner));
// Convert the SID into a string
string strSID = "";
ConvertSidToStringSid(tokenOwner.Owner, ref strSID);
Marshal.FreeHGlobal(tokenOwnerPtr);
return strSID;
}