Search code examples
c#.netwindowswindows-servicesregistry

C#/.net Program compares a registry directory for differences over time. Works for the console test app, but not for the service


I have a service I am trying to create in Visual Studio that checks the values of 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall' when the service starts and stores it as a hashset. Every 20 minutes, it pulls another hashset of the directory and compares the two sets to effectively see if a program is installed based on the addition of the uninstalled value in the registry. I used a separate project, also using Visual Studio that is a console app for ease of testing the logic before I created the service app.

The issue I am running into is that the code is logically the same from the service to the console app, however only the console app functions as anticipated. When I install a program, my test is TeamViewer, it sees the new entry in the registry and set, then sends an email/writes to console that a change was found. I believe the main difference is that the service was forced to be built with .net framework and the console app is just .net.

The main service directory is WatchTower. The console testing directory is Consoletest. The class file in question is InstalledApps.cs for both directories.

the code can be found here: https://github.com/TartCart/WatchTower.git


I have printed the output of the service to a logfile and see that it is able to access the registry, and populate the hash sets, but it seems like the service is unable to get an updates set from the registry after it accesses it for the first time.. whereas in the console app it gets the updated set. I've checked permissions and utilized chatGPT to its fullest extent for testing/debugging but something under the hood is just not giving as far as I can tell with my limited experience.

I am inexperienced with software development as I am sure my code will reveal - any feedback would be greatly appreciated. Thanks


Solution

  • Make sure you are checking both the 32-bit and 64-bit registry locations.

    SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
    SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
    

    You can do that by specifying the RegistryView on the base key:

    const string KeyName = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
    var allSubKeyNames = new List<string>();
    
    foreach (var regView in new List<RegistryView> { RegistryView.Registry32, RegistryView.Registry64 })
    {
        using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView))
        {
            using (var subKey = baseKey.OpenSubKey(KeyName))
            {
                allSubKeyNames.AddRange(subKey.GetSubKeyNames());
            }
        }
    }
    
    using (var subKey = Registry.CurrentUser.OpenSubKey(KeyName))
    {
        allSubKeyNames.AddRange(subKey.GetSubKeyNames());
    }
    
    //do something with allSubKeyNames
    

    More info here

    Additionally, you should probably open and close the key inside Timer_Elapsed rather than opening it and holding it static.