Unable to query value of CSDVersion

0

I followed this C# example and am able to query some registry values, but not all of them:

How to obtain a registry value from a remote machine if I don't know its type? (C#)

I can reliably get registry keys such as the CurrentVersion, the ProductName, etc. But when I try to get the CSDVersion, it's failing.

I've compiled in both .NET 2.0 and .NET 4.0, but with the same results. I've tried querying the local machine and a remote machine. Both are able to return other registry values, but not this particular one.

Both are x64 machines (Windows 7 Ultimate and Windows 2008 R2) so neither should have any problems with getting to the registry either way.

One weird thing I've found is that the EnumValues function only returns 17 values, and there are 21 in this particular registry key. Of the four that are missing, CSDVersion is one of them.

I'm curious if anyone knows why these four values wouldn't come back, but all of the rest would? Missing Values:

  • CSDVersion - Reg_sz
  • DigitalProductID - Reg_binary
  • DigitalProductId4 - Reg_binary
  • ProductID - Reg_sz

Something that's really bizarre is that I have another project which was written in .NET 2.0 and has a class library that does this kind of thing. When running the NUnit tests for the library, this query works fine and returns all 21 values. But when running this library through another project, it doesn't work.

I've stepped through the code in the project that calls the library and when doing that, it only returns 17 entries. So I'm at a loss to explain what's going on.

Anyone have any ideas of where to go next? Below is the exact code I'm using and it simply doesn't work for the above specific cases

using System;
using System.Management;
using System.Management.Instrumentation;

namespace GetCSDVersion
{
    public enum RegHive : uint
    {
        HKEY_CLASSES_ROOT = 0x80000000,
        HKEY_CURRENT_USER = 0x80000001,
        HKEY_LOCAL_MACHINE = 0x80000002,
        HKEY_USERS = 0x80000003,
        HKEY_CURRENT_CONFIG = 0x80000005
    }

    public enum RegType
    {
        REG_SZ = 1,
        REG_EXPAND_SZ,
        REG_BINARY,
        REG_DWORD,
        REG_MULTI_SZ = 7
    }

    class Program
    {
        static void Main(string[] args)
        {
            const string strComputer = "localhost";

            ConnectionOptions options = new ConnectionOptions();
            options.Impersonation = ImpersonationLevel.Impersonate;
            options.EnablePrivileges = true;
            //options.Username = "";
            //options.Password = "";

            ManagementScope myScope = new ManagementScope("\\\\" + strComputer + "\\root\\default", options);
            ManagementPath mypath = new ManagementPath("StdRegProv");
            ManagementClass mc = new ManagementClass(myScope, mypath, null);

            object oValue = GetValue(mc, RegHive.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "CSDVersion");
            Console.WriteLine(oValue.ToString());
        }

        public static object GetValue(ManagementClass mc, RegHive hDefKey, string sSubKeyName, string sValueName)
        {
            RegType rType = GetValueType(mc, hDefKey, sSubKeyName, sValueName);

            ManagementBaseObject inParams = mc.GetMethodParameters("GetStringValue");
            inParams["hDefKey"] = hDefKey;
            inParams["sSubKeyName"] = sSubKeyName;
            inParams["sValueName"] = sValueName;

            object oValue = null;

            switch (rType)
            {
                case RegType.REG_SZ:
                    ManagementBaseObject outParams = mc.InvokeMethod("GetStringValue", inParams, null);

                    if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
                    {
                        oValue = outParams["sValue"];
                    }
                    else
                    {
                        // GetStringValue call failed
                    }
                    break;

                case RegType.REG_EXPAND_SZ:
                    outParams = mc.InvokeMethod("GetExpandedStringValue", inParams, null);

                    if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
                    {
                        oValue = outParams["sValue"];
                    }
                    else
                    {
                        // GetExpandedStringValue call failed
                    }
                    break;

                case RegType.REG_MULTI_SZ:
                    outParams = mc.InvokeMethod("GetMultiStringValue", inParams, null);

                    if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
                    {
                        oValue = outParams["sValue"];
                    }
                    else
                    {
                        // GetMultiStringValue call failed
                    }
                    break;

                case RegType.REG_DWORD:
                    outParams = mc.InvokeMethod("GetDWORDValue", inParams, null);

                    if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
                    {
                        oValue = outParams["uValue"];
                    }
                    else
                    {
                        // GetDWORDValue call failed
                    }
                    break;

                case RegType.REG_BINARY:
                    outParams = mc.InvokeMethod("GetBinaryValue", inParams, null);

                    if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
                    {
                        oValue = outParams["uValue"] as byte[];
                    }
                    else
                    {
                        // GetBinaryValue call failed
                    }
                    break;
            }

            return oValue;
        }

        public static RegType GetValueType(ManagementClass mc, RegHive hDefKey, string sSubKeyName, string sValueName)
        {
            ManagementBaseObject inParams = mc.GetMethodParameters("EnumValues");
            inParams["hDefKey"] = hDefKey;
            inParams["sSubKeyName"] = sSubKeyName;

            ManagementBaseObject outParams = mc.InvokeMethod("EnumValues", inParams, null);

            if (Convert.ToUInt32(outParams["ReturnValue"]) == 0)
            {
                string[] sNames = outParams["sNames"] as String[];
                int[] iTypes = outParams["Types"] as int[];

                for (int i = 0; i < sNames.Length; i++)
                {
                    if (sNames[i] == sValueName)
                    {
                        return (RegType)iTypes[i];
                    }
                }
                // value not found
            }
            else
            {
                // EnumValues call failed
            }
            // Things have fallen apart and EnumValues didn't get us what we wanted so assume it's a string
            return RegType.REG_SZ;
        }
    }
}
c#
asked on Stack Overflow Aug 27, 2012 by Mike Taber • edited May 23, 2017 by Community

2 Answers

5

Wow. Ok, so having spent hours and hours trying to debug this, I figured out the problem on my own less than 20 minutes after posting this to StackOverflow.

I knew in the back of my head that there were some situations where there was sort of a weird hybrid registry with 32 bit and 64 bit keys out there. I didn't think it applied here, since both of the machines I was working with were 64 bit. But what I'd forgotten was that the project itself has a setting which specifies the Platform target.

Right click on the project, then go to Properties. Select the Build tab. Then change the Platform Target from x86 (which must be the default) to Any CPU. Recompile, and the registry query works just fine.

answered on Stack Overflow Aug 27, 2012 by Mike Taber
0

In VS 2012, if the "Prefer 32-bit" is checked, the behavior is the same, even if the target is "Any CPU".

answered on Stack Overflow Oct 9, 2018 by Sean R

User contributions licensed under CC BY-SA 3.0