5

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.

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Black2910
  • 133
  • 3
  • 9
  • What credentials is the application running under? Are the credentials those of `Muhil`? It might be that to the application, the `CurrentUser` is not `Muhil`. Also, is it running on a remote machine to the machine in question? – Ash Sep 01 '16 at 04:13
  • 1
    This application is windows installer, i created the windows installer to install the program. So i want to add the subkey under HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Muhil Software. I run it on my machine, not remote machine! – Black2910 Sep 01 '16 at 06:35
  • What toolkit do you use for your installer? Usually installation toolkit like Wix for instance allows to impersonate actions so that they are made within the context of the logged in user. – M'hand BOUGHIAS Sep 01 '16 at 09:53
  • If you find the value back in .DEFAULT then is a very simple problem. Regedit.exe does not know that the registry was changed. Press F5 to refresh the view. – Hans Passant Sep 02 '16 at 13:46

1 Answers1

6

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;        
}
Community
  • 1
  • 1
M'hand BOUGHIAS
  • 730
  • 10
  • 13
  • Actually i have the profile user in HKEY_USERS but the installer did not write the key into that folder. The key was written in DEFAULT folder. BTW i already tried the SID way, but the SID is different than HKEY_USERS folder! – Black2910 Sep 02 '16 at 04:53
  • You need to get the SID of the logged on user. Not the current user of your process. – M'hand BOUGHIAS Sep 02 '16 at 05:08
  • But i used the best anwsered code in this link: How to get a Unique ID for the current user's logon session in windows - c# and i got the SID, is it right? – Black2910 Sep 02 '16 at 05:22
  • Take a look at the most up voted answer. Not the accepted one – M'hand BOUGHIAS Sep 02 '16 at 05:28
  • Did you mention [The easiest way to get Session Id is to look at Process.SessionId property] that answer? But i can not get the folder name of current user. http://www.rhyous.com/2013/02/07/get-active-directory-users-guid-and-sid-in-csharp/ Already tried this but get the cast error. – Black2910 Sep 02 '16 at 06:25
  • I can get the right SID now. Thank you so much M'hand BOUGHIAS ! – Black2910 Sep 06 '16 at 00:54
  • This is the only thing that helped... Thanks! – Starwave Oct 28 '19 at 23:55