Windows service unable to read registry keys?

FuturShoc

Active member
Joined
Jul 28, 2006
Messages
27
Location
Hot Springs, Arkansas
Programming Experience
3-5
I have put together a basic service which will need to read a particular registry key value. (It contains a path which is important to what it needs to do.)

Everything appears to be functioning on a basic level. I can install, start and stop the service just fine. And I can write out event log entries for it. My problem is that whenever add in a few lines of code to have the service read a registry key, it always fails to do so.

The service's "ServiceProcessInstaller1" property for "Account" is "LocalSystem". I've also tried changing this to "LocalService" and there was no change in behavior.

As far as I can tell, it seems to be a rights issue. The service, somehow, just can't "see" those registry keys.

NOTE: If I put that same registry-reading code into a basic form application, it reads the values perfectly.

I'm guessing there is something very subtle I haven't yet done in the service which would allow it to read those registry keys. Can someone point me in the right direction? I've been fighting this all afternoon and I'm about to go bald. :p

(I'm using Windows XP and VS .NET 2003)
 
What registry key/hive is it? If it's the Current_User hive the service must be running as the expected user account to see that user accounts 'current user' keys. I think you can also impersonate that user from the service to achieve the same. This is the most likely problem you describe.

Did you check also with the registry editor (regedit.exe), you can review 'permissions...' from a nodes context menu. The System (LocalSystem) account have all access from what I see.
 
What registry key/hive is it? If it's the Current_User hive the service must be running as the expected user account to see that user accounts 'current user' keys. I think you can also impersonate that user from the service to achieve the same. This is the most likely problem you describe.

Here's a bit more detail of the scenario.

Yes, the key is in the CURRENT_USER hive.
I can set and view the user setting which results in this key being written to the registry. I can view this same key using regedit. All from my own user account (domain-based) on my XP install.

Now, I'm coding in .NET 2003, under the same account, same OS install.
I build my service and install, using the InstallUtil command line. Same account. Nothing's changed here.

Then, when I start the service via "My Computer >> Manage >> Services", the service fires at its regular interval just fine. It just never brings back the registry key data. (I'm writing debugging stuff out to the event log.)

Now, is there something I can do to fix this particular scenario? Install the service some other way? If so, how?

You also mentioned "impersonating" onother user. Is there a link somewhere to how I might do this?

Did you check also with the registry editor (regedit.exe), you can review 'permissions...' from a nodes context menu. The System (LocalSystem) account have all access from what I see.
I'll look into this permissions issue on the node. That might be a good lead.

Thanks for taking the time to offer your input, John. Your time is appreciated.
 
You said first you were running the service as the LocalSystem account. In this reply I understand you are running the service under your user "Joe" account. The current user hive is different for the System user and the Joe user, but if you are running service as Joe they should match.
If you TryCatch the registry access you will get exception information if permission is denied also.

Here is a good link for impersonate code, but it wouldn't be any different from running the service directly under user account: http://www.vbdotnetforums.com/showthread.php?t=17261&highlight=impersonate (I have not tried to run this code from a service before, but I think it should work)
 
To clarify, there is a property to the ServiceProcessInstaller in my project. That property is called "Account'. That property is set to "LocalSystem".

I'm incorporating a try/catch in an effort to trap the error and confirm the source of my problem. Here's that part of my code:

VB.NET:
Try
                Dim rk As RegistryKey = Registry.CurrentUser.OpenSubKey("\Software\Fischer\TAO\5.0\OfflinePath")
            Catch err As Exception
                MyLog.WriteEntry("DDS_Service Log", err.Message, EventLogEntryType.Warning)
            End Try
Unfortunately, I'm not getting any errors because it seems to set the rk variable to nothing, which isn't technically an error, so no exception is thrown.
 
Ok, here's the entirety of my service's code. I'm hoping that looking at this, someone might get an idea of what's going wrong. The fact that there seems to be no error trapped, when I had included a try/catch, leads me to wonder if its a rights issue after all... ?

VB.NET:
   Private Sub Timer1_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
        Dim MyLog As New EventLog   ' create a new event log
        ' Check if the the Event Log Exists
        If Not MyLog.SourceExists("DDS_Service") Then
            MyLog.CreateEventSource("DDS_Service", "DDS_Service Log") ' Create Log
        End If
        MyLog.Source = "DDS_Service"
        ' Write to the Log
        Dim configFilePath As String = "D:\DDS_Service.config.txt"
        If File.Exists(configFilePath) Then
            MyLog.WriteEntry("DDS_Service Log", "Config file exists!", EventLogEntryType.Information)

            ' open the registry key
            Dim rk As RegistryKey = Registry.CurrentUser.OpenSubKey("\Software\Fischer\TAO\5.0\OfflinePath")
            If rk Is Nothing Then
                MyLog.WriteEntry("DDS_Service Log", "Can't read Tao offline path registry key", EventLogEntryType.Warning)
            Else
                Try
                    ' read and display the value
                    Dim taoOfflinePath As String = rk.GetValue("")
                    MyLog.WriteEntry("DDS_Service Log", "Tao offline is located at " & taoOfflinePath, EventLogEntryType.Information)
                Finally
                    ' cleanup
                    rk.Close()
                End Try
            End If
        End If
    End Sub
 
To clarify, there is a property to the ServiceProcessInstaller in my project. That property is called "Account'. That property is set to "LocalSystem".
Exactly. This is the 'System' account for the computer. The Current_user hive is specific in registry for each user. I don't think I'm misunderstanding that the registry key you want to read is written by a different account? It is not sufficient that this particular user is logged in at the time when the service tries to access the registry, if the service is a different user account then current_user is not the same. To access this though current_user hive you must also use this account for the service (or impersonate this account at the time of registry access).
 
Exactly. This is the 'System' account for the computer. The Current_user hive is specific in registry for each user. I don't think I'm misunderstanding that the registry key you want to read is written by a different account? It is not sufficient that this particular user is logged in at the time when the service tries to access the registry, if the service is a different user account then current_user is not the same. To access this though current_user hive you must also use this account for the service (or impersonate this account at the time of registry access).

Ok, so the "account" property of my ServiceProcessInstaller can't be set to "LocalSystem" in order for the service to get access to this user-level registry key. Is there a property I can set which *would* give the service access to these registry keys? I've actually done test builds for every value (User, LocalService, LocalSystem) with no change in result.

When this is set to "User", though, I do get prompted by InstallUtil to enter a user and password. But it doesn't seem to want to take *any* account data I give it. :( It fails install every time.


My service needs to be able to access this registry key no matter who the current user is.

I'm not trying to be obtuse here, I promise. I'm just not getting what I need to do differently. (I'm not sure impsersonating is going to help at this point, since I have no way to predict what user to impersonate. We have thousands of PCs being used by that many users.)
 
You don't set it to "any" account if you are targeting one specific account, it is this account you should log in the service with. Alternative if you need the service to handle multiple accounts at the same time is the impersonation.
 
You don't set it to "any" account if you are targeting one specific account, it is this account you should log in the service with. Alternative if you need the service to handle multiple accounts at the same time is the impersonation.

I don't understand what you mean by "... log the service in..." ?
 
That the account it is using to operate, one of the system accounts or a user one, that's what this discussion has been about the whole time (accounts).
 
You really do need to get a better handle of how service programs work, in terms of what LOCAL_SYSTEM account is, and what it can and can't do.

But in the meantime, can't you just store your registry value in HKEY_LOCAL_MACHINE? I mean, it's not like the service is ever going to look in different user registry hives, is it?
 
Ok well then you need to impersonate the logged in user. The only part I'm not sure about, is how you know who the logged on user is. Maybe .net provides a call somewhere that will give that to you...
 
Back
Top