Microsoft.Win32.RegistryKey.InternalGetValueCore C# (CSharp) Method

InternalGetValueCore() private method

private InternalGetValueCore ( string name, object defaultValue, bool doNotExpand ) : object
name string
defaultValue object
doNotExpand bool
return object
        private object InternalGetValueCore(string name, object defaultValue, bool doNotExpand)
        {
            object data = defaultValue;
            int type = 0;
            int datasize = 0;

            int ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, (byte[])null, ref datasize);

            if (ret != 0)
            {
                if (IsPerfDataKey())
                {
                    int size = 65000;
                    int sizeInput = size;

                    int r;
                    byte[] blob = new byte[size];
                    while (Interop.Errors.ERROR_MORE_DATA == (r = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref sizeInput)))
                    {
                        if (size == Int32.MaxValue)
                        {
                            // ERROR_MORE_DATA was returned however we cannot increase the buffer size beyond Int32.MaxValue
                            Win32Error(r, name);
                        }
                        else if (size > (Int32.MaxValue / 2))
                        {
                            // at this point in the loop "size * 2" would cause an overflow
                            size = Int32.MaxValue;
                        }
                        else
                        {
                            size *= 2;
                        }
                        sizeInput = size;
                        blob = new byte[size];
                    }
                    if (r != 0)
                    {
                        Win32Error(r, name);
                    }
                    return blob;
                }
                else
                {
                    // For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).
                    // Some OS's returned ERROR_MORE_DATA even in success cases, so we 
                    // want to continue on through the function. 
                    if (ret != Interop.Errors.ERROR_MORE_DATA)
                    {
                        return data;
                    }
                }
            }

            if (datasize < 0)
            {
                // unexpected code path
                Debug.Fail("[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
                datasize = 0;
            }

            switch (type)
            {
                case Interop.Advapi32.RegistryValues.REG_NONE:
                case Interop.Advapi32.RegistryValues.REG_DWORD_BIG_ENDIAN:
                case Interop.Advapi32.RegistryValues.REG_BINARY:
                    {
                        byte[] blob = new byte[datasize];
                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
                        data = blob;
                    }
                    break;
                case Interop.Advapi32.RegistryValues.REG_QWORD:
                    {    // also REG_QWORD_LITTLE_ENDIAN
                        if (datasize > 8)
                        {
                            // prevent an AV in the edge case that datasize is larger than sizeof(long)
                            goto case Interop.Advapi32.RegistryValues.REG_BINARY;
                        }
                        long blob = 0;
                        Debug.Assert(datasize == 8, "datasize==8");
                        // Here, datasize must be 8 when calling this
                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);

                        data = blob;
                    }
                    break;
                case Interop.Advapi32.RegistryValues.REG_DWORD:
                    {    // also REG_DWORD_LITTLE_ENDIAN
                        if (datasize > 4)
                        {
                            // prevent an AV in the edge case that datasize is larger than sizeof(int)
                            goto case Interop.Advapi32.RegistryValues.REG_QWORD;
                        }
                        int blob = 0;
                        Debug.Assert(datasize == 4, "datasize==4");
                        // Here, datasize must be four when calling this
                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);

                        data = blob;
                    }
                    break;

                case Interop.Advapi32.RegistryValues.REG_SZ:
                    {
                        if (datasize % 2 == 1)
                        {
                            // handle the case where the registry contains an odd-byte length (corrupt data?)
                            try
                            {
                                datasize = checked(datasize + 1);
                            }
                            catch (OverflowException e)
                            {
                                throw new IOException(SR.Arg_RegGetOverflowBug, e);
                            }
                        }
                        char[] blob = new char[datasize / 2];

                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
                        if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
                        {
                            data = new string(blob, 0, blob.Length - 1);
                        }
                        else
                        {
                            // in the very unlikely case the data is missing null termination, 
                            // pass in the whole char[] to prevent truncating a character
                            data = new string(blob);
                        }
                    }
                    break;

                case Interop.Advapi32.RegistryValues.REG_EXPAND_SZ:
                    {
                        if (datasize % 2 == 1)
                        {
                            // handle the case where the registry contains an odd-byte length (corrupt data?)
                            try
                            {
                                datasize = checked(datasize + 1);
                            }
                            catch (OverflowException e)
                            {
                                throw new IOException(SR.Arg_RegGetOverflowBug, e);
                            }
                        }
                        char[] blob = new char[datasize / 2];

                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);

                        if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
                        {
                            data = new string(blob, 0, blob.Length - 1);
                        }
                        else
                        {
                            // in the very unlikely case the data is missing null termination, 
                            // pass in the whole char[] to prevent truncating a character
                            data = new string(blob);
                        }

                        if (!doNotExpand)
                        {
                            data = Environment.ExpandEnvironmentVariables((string)data);
                        }
                    }
                    break;
                case Interop.Advapi32.RegistryValues.REG_MULTI_SZ:
                    {
                        if (datasize % 2 == 1)
                        {
                            // handle the case where the registry contains an odd-byte length (corrupt data?)
                            try
                            {
                                datasize = checked(datasize + 1);
                            }
                            catch (OverflowException e)
                            {
                                throw new IOException(SR.Arg_RegGetOverflowBug, e);
                            }
                        }
                        char[] blob = new char[datasize / 2];

                        ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);

                        // make sure the string is null terminated before processing the data
                        if (blob.Length > 0 && blob[blob.Length - 1] != (char)0)
                        {
                            Array.Resize(ref blob, blob.Length + 1);
                        }

                        string[] strings = Array.Empty<string>();
                        int stringsCount = 0;

                        int cur = 0;
                        int len = blob.Length;

                        while (ret == 0 && cur < len)
                        {
                            int nextNull = cur;
                            while (nextNull < len && blob[nextNull] != (char)0)
                            {
                                nextNull++;
                            }

                            string toAdd = null;
                            if (nextNull < len)
                            {
                                Debug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
                                if (nextNull - cur > 0)
                                {
                                    toAdd = new string(blob, cur, nextNull - cur);
                                }
                                else
                                {
                                    // we found an empty string.  But if we're at the end of the data, 
                                    // it's just the extra null terminator. 
                                    if (nextNull != len - 1)
                                    {
                                        toAdd = string.Empty;
                                    }
                                }
                            }
                            else
                            {
                                toAdd = new string(blob, cur, len - cur);
                            }
                            cur = nextNull + 1;

                            if (toAdd != null)
                            {
                                if (strings.Length == stringsCount)
                                {
                                    Array.Resize(ref strings, stringsCount > 0 ? stringsCount * 2 : 4);
                                }
                                strings[stringsCount++] = toAdd;
                            }
                        }

                        Array.Resize(ref strings, stringsCount);
                        data = strings;
                    }
                    break;
                case Interop.Advapi32.RegistryValues.REG_LINK:
                default:
                    break;
            }

            return data;
        }