Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
TransactedRegistryKey.cs2058 linesDownload Raw Back to namespaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4//5// NOTE: A vast majority of this code was copied from BCL in6// ndp\clr\src\BCL\Microsoft\Win32\RegistryKey.cs.7// Namespace: Microsoft.Win328//9/*10  Note on transaction support:11  Eventually we will want to add support for NT's transactions to our12  TransactedRegistryKey API's (possibly Whidbey M3?).  When we do this, here's13  the list of API's we need to make transaction-aware:14 15  RegCreateKeyEx16  RegDeleteKey17  RegDeleteValue18  RegEnumKeyEx19  RegEnumValue20  RegOpenKeyEx21  RegQueryInfoKey22  RegQueryValueEx23  RegSetValueEx24 25  We can ignore RegConnectRegistry (remote registry access doesn't yet have26  transaction support) and RegFlushKey.  RegCloseKey doesn't require any27  additional work.  .28 */29 30/*31  Note on ACL support:32  The key thing to note about ACL's is you set them on a kernel object like a33  registry key, then the ACL only gets checked when you construct handles to34  them.  So if you set an ACL to deny read access to yourself, you'll still be35  able to read with that handle, but not with new handles.36 37  Another peculiarity is a Terminal Server app compatibility hack.  The OS38  will second guess your attempt to open a handle sometimes.  If a certain39  combination of Terminal Server app compat registry keys are set, then the40  OS will try to reopen your handle with lesser permissions if you couldn't41  open it in the specified mode.  So on some machines, we will see handles that42  may not be able to read or write to a registry key.  It's very strange.  But43  the real test of these handles is attempting to read or set a value in an44  affected registry key.45 46  For reference, at least two registry keys must be set to particular values47  for this behavior:48  HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\RegistryExtensionFlags, the least significant bit must be 1.49  HKLM\SYSTEM\CurrentControlSet\Control\TerminalServer\TSAppCompat must be 150  There might possibly be an interaction with yet a third registry key as well.51 52*/53 54using BCLDebug = System.Diagnostics.Debug;55 56namespace Microsoft.PowerShell.Commands.Internal57{58    using System;59    using System.Collections.Generic;60    using System.Security;61    using System.Security.AccessControl;62    using System.Security.Permissions;63    using System.Text;64    using System.IO;65    using System.Runtime.InteropServices;66    using Microsoft.Win32;67    using System.Runtime.Versioning;68    using System.Globalization;69    using System.Transactions;70    using System.Diagnostics.CodeAnalysis;71 72    // Putting this in a separate internal class to avoid OACR warning DoNotDeclareReadOnlyMutableReferenceTypes.73    internal sealed class BaseRegistryKeys74    {75        // We could use const here, if C# supported ELEMENT_TYPE_I fully.76        internal static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));77        internal static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));78        internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));79        internal static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));80        internal static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));81    }82 83    /// <summary>84    /// Registry encapsulation. To get an instance of a TransactedRegistryKey use the85    /// Registry class's static members then call OpenSubKey.86    ///87    /// @see Registry88    /// @security(checkDllCalls=off)89    /// @security(checkClassLinking=on)90    /// </summary>91    [ComVisible(true)]92    // Suppressed because these objects are written to the pipeline so need to be accessible.93    [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]94    public sealed class TransactedRegistryKey : MarshalByRefObject, IDisposable95    {96        private const string resBaseName = "RegistryProviderStrings";97 98        // Dirty indicates that we have munged data that should be potentially99        // written to disk.100        //101        private const int STATE_DIRTY = 0x0001;102 103        // SystemKey indicates that this is a "SYSTEMKEY" and shouldn't be "opened"104        // or "closed".105        //106        private const int STATE_SYSTEMKEY = 0x0002;107 108        // Access109        //110        private const int STATE_WRITEACCESS = 0x0004;111 112        // Names of keys.  This array must be in the same order as the HKEY values listed above.113        //114        private static readonly string[] s_hkeyNames = new string[] {115                "HKEY_CLASSES_ROOT",116                "HKEY_CURRENT_USER",117                "HKEY_LOCAL_MACHINE",118                "HKEY_USERS",119                "HKEY_PERFORMANCE_DATA",120                "HKEY_CURRENT_CONFIG",121                "HKEY_DYN_DATA"122                };123 124        // MSDN defines the following limits for registry key names & values:125        // Key Name: 255 characters126        // Value name:  Win9x: 255 NT: 16,383 Unicode characters, or 260 ANSI chars127        // Value: either 1 MB or current available memory, depending on registry format.128        private const int MaxKeyLength = 255;129        private const int MaxValueNameLength = 16383;130        private const int MaxValueDataLength = 1024 * 1024;131 132        private SafeRegistryHandle _hkey = null;133        private int _state = 0;134        private string _keyName;135        private RegistryKeyPermissionCheck _checkMode;136        private System.Transactions.Transaction _myTransaction;137        private SafeTransactionHandle _myTransactionHandle;138 139        // This is a wrapper around RegOpenKeyTransacted that implements a workaround140        // to TxF bug number 181242 After calling RegOpenKeyTransacted, it calls RegQueryInfoKey.141        // If that call fails with ERROR_INVALID_TRANSACTION, we have possibly run into bug 181242. To workaround142        // this, we open the key without a transaction and then open it again with143        // a transaction and return THAT hkey.144        private int RegOpenKeyTransactedWrapper(SafeRegistryHandle hKey, string lpSubKey,145                    int ulOptions, int samDesired, out SafeRegistryHandle hkResult,146                    SafeTransactionHandle hTransaction, IntPtr pExtendedParameter)147        {148            int error = Win32Native.ERROR_SUCCESS;149            SafeRegistryHandle hKeyToReturn = null;150 151            error = Win32Native.RegOpenKeyTransacted(_hkey, lpSubKey, ulOptions, samDesired, out hKeyToReturn, hTransaction, pExtendedParameter);152 153            if (Win32Native.ERROR_SUCCESS == error && !hKeyToReturn.IsInvalid)154            {155                // This is a check and workaround for TxR bug 181242. If we try to use the transacted hKey we just opened156                // for a call to RegQueryInfoKey and get back a ERROR_INVALID_TRANSACTION error, then the key might be a symbolic link and TxR didn't157                // do the open correctly. The workaround is to open it non-transacted, then open it again transacted without158                // a subkey string. If we get some error other than ERROR_INVALID_TRANSACTION from RegQueryInfoKey, just ignore it for now.159                int subkeyCount = 0;160                int valueCount = 0;161                error = Win32Native.RegQueryInfoKey(hKeyToReturn,162                                          null,163                                          null,164                                          Win32Native.NULL,165                                          ref subkeyCount,  // subkeys166                                          null,167                                          null,168                                          ref valueCount,     // values169                                          null,170                                          null,171                                          null,172                                          null);173                if (Win32Native.ERROR_INVALID_TRANSACTION == error)174                {175                    SafeRegistryHandle nonTxKey = null;176                    SafeRegistryHandle txKey = null;177                    error = Win32Native.RegOpenKeyEx(_hkey, lpSubKey, ulOptions, samDesired, out nonTxKey);178                    // If we got some error on this open, just ignore it and continue on with the handle179                    // we got on the original RegOpenKeyTransacted.180                    if (Win32Native.ERROR_SUCCESS == error)181                    {182                        // Now do an RegOpenKeyTransacted with the non-transacted key and no "subKey" parameter.183                        error = Win32Native.RegOpenKeyTransacted(nonTxKey, null, ulOptions, samDesired, out txKey, hTransaction, pExtendedParameter);184                        if (Win32Native.ERROR_SUCCESS == error)185                        {186                            // Let's use this hkey instead.187                            hKeyToReturn.Dispose();188                            hKeyToReturn = txKey;189                        }190 191                        nonTxKey.Dispose();192                        nonTxKey = null;193                    }194                }195            }196 197            hkResult = hKeyToReturn;198            return error;199        }200 201        /**202         * Creates a TransactedRegistryKey.203         *204         * This key is bound to hkey, if writable is <b>false</b> then no write operations205         * will be allowed. If systemkey is set then the hkey won't be released206         * when the object is GC'ed.207         */208        private TransactedRegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey,209                                      System.Transactions.Transaction transaction, SafeTransactionHandle txHandle)210        {211            _hkey = hkey;212            _keyName = string.Empty;213            if (systemkey)214            {215                _state |= STATE_SYSTEMKEY;216            }217 218            if (writable)219            {220                _state |= STATE_WRITEACCESS;221            }222            // We want to take our own clone so we can dispose it when we want and223            // aren't susceptible to the caller disposing it.224            if (transaction != null)225            {226                _myTransaction = transaction.Clone();227                _myTransactionHandle = txHandle;228            }229            else230            {231                _myTransaction = null;232                _myTransactionHandle = null;233            }234        }235 236        private SafeTransactionHandle GetTransactionHandle()237        {238            SafeTransactionHandle safeTransactionHandle = null;239 240            // If myTransaction is not null and is not the same as Transaction.Current241            // this is an invalid operation. The transaction within which the RegistryKey object was created242            // needs to be the same as the transaction being used now.243            if (_myTransaction != null)244            {245                if (!_myTransaction.Equals(Transaction.Current))246                {247                    throw new InvalidOperationException(RegistryProviderStrings.InvalidOperation_MustUseSameTransaction);248                }249                else250                {251                    safeTransactionHandle = _myTransactionHandle;252                }253            }254            else  // we want to use Transaction.Current for the transaction.255            {256                safeTransactionHandle = SafeTransactionHandle.Create();257            }258 259            return safeTransactionHandle;260        }261 262        /// <summary>TransactedRegistryKey.Close263        /// <para>Closes this key, flushes it to disk if the contents have been modified.264        /// Utilizes Transaction.Current for its transaction.</para>265        /// </summary>266        public void Close()267        {268            Dispose(true);269        }270 271        private void Dispose(bool disposing)272        {273            if (_hkey != null)274            {275                if (!IsSystemKey())276                {277                    try278                    {279                        _hkey.Dispose();280                    }281                    catch (IOException)282                    {283                        // we don't really care if the handle is invalid at this point284                    }285                    finally286                    {287                        _hkey = null;288                    }289                }290            }291 292            if (_myTransaction != null)293            {294                // Dispose the transaction because we cloned it.295                try296                {297                    _myTransaction.Dispose();298                }299                catch (TransactionException)300                {301                    // ignore.302                }303                finally304                {305                    _myTransaction = null;306                }307            }308        }309 310        /// <summary>TransactedRegistryKey.Flush311        /// <para>Flushes this key. Utilizes Transaction.Current for its transaction.</para>312        /// </summary>313        public void Flush()314        {315            // Require a transaction. This will throw for "Base" keys because they aren't associated with a transaction.316            VerifyTransaction();317            if (_hkey != null)318            {319                if (IsDirty())320                {321                    int ret = Win32Native.RegFlushKey(_hkey);322                    if (Win32Native.ERROR_SUCCESS != ret)323                    {324                        throw new IOException(Win32Native.GetMessage(ret), ret);325                    }326                }327            }328        }329 330        /// <summary>TransactedRegistryKey.Dispose331        /// <para>Disposes this key. Utilizes Transaction.Current for its transaction.</para>332        /// </summary>333        public void Dispose()334        {335            Dispose(true);336        }337 338        /// <summary>339        /// <para>Creates a new subkey, or opens an existing one.340        /// Utilizes Transaction.Current for its transaction.</para>341        /// </summary>342        /// <param name='subkey'>Name or path to subkey to create or open. Cannot be null or an empty string,343        /// otherwise an ArgumentException is thrown.</param>344        /// <returns>A TransactedRegistryKey object for the subkey, which is associated with Transaction.Current.345        /// returns null if the operation failed.</returns>346        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey347        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]348        public TransactedRegistryKey CreateSubKey(string subkey)349        {350            return CreateSubKey(subkey, _checkMode);351        }352 353        /// <summary>354        /// <para>Creates a new subkey, or opens an existing one.355        /// Utilizes Transaction.Current for its transaction.</para>356        /// </summary>357        /// <returns>A TransactedRegistryKey object for the subkey, which is associated with Transaction.Current.358        /// returns null if the operation failed.</returns>359        /// <param name='subkey'>Name or path to subkey to create or open. Cannot be null or an empty string,360        /// otherwise an ArgumentException is thrown.</param>361        /// <param name='permissionCheck'>One of the Microsoft.Win32.RegistryKeyPermissionCheck values that362        /// specifies whether the key is opened for read or read/write access.</param>363        [ComVisible(false)]364        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey365        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]366        public TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck)367        {368            return CreateSubKeyInternal(subkey, permissionCheck, (TransactedRegistrySecurity)null);369        }370 371        /// <summary>372        /// <para>Creates a new subkey, or opens an existing one.373        /// Utilizes Transaction.Current for its transaction.</para>374        /// </summary>375        /// <returns>A TransactedRegistryKey object for the subkey, which is associated with Transaction.Current.376        /// returns null if the operation failed.</returns>377        /// <param name='subkey'>Name or path to subkey to create or open. Cannot be null or an empty string,378        /// otherwise an ArgumentException is thrown.</param>379        /// <param name='permissionCheck'>One of the Microsoft.Win32.RegistryKeyPermissionCheck values that380        /// specifies whether the key is opened for read or read/write access.</param>381        /// <param name='registrySecurity'>A TransactedRegistrySecurity object that specifies the access control security for the new key.</param>382        [ComVisible(false)]383        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey384        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]385        public unsafe TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck, TransactedRegistrySecurity registrySecurity)386        {387            return CreateSubKeyInternal(subkey, permissionCheck, registrySecurity);388        }389 390        [ComVisible(false)]391        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey392        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]393        private unsafe TransactedRegistryKey CreateSubKeyInternal(string subkey, RegistryKeyPermissionCheck permissionCheck, object registrySecurityObj)394        {395            ValidateKeyName(subkey);396            // RegCreateKeyTransacted requires a non-empty key name, so let's deal with that here.397            if (string.Empty == subkey)398            {399                throw new ArgumentException(RegistryProviderStrings.Arg_RegKeyStrEmpty);400            }401 402            ValidateKeyMode(permissionCheck);403            EnsureWriteable();404            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash405 406            // only keys opened under read mode is not writable407            TransactedRegistryKey existingKey = InternalOpenSubKey(subkey, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree));408            if (existingKey != null)409            { // Key already exits410                CheckSubKeyWritePermission(subkey);411                CheckSubTreePermission(subkey, permissionCheck);412                existingKey._checkMode = permissionCheck;413                return existingKey;414            }415 416            CheckSubKeyCreatePermission(subkey);417 418            Win32Native.SECURITY_ATTRIBUTES secAttrs = null;419            TransactedRegistrySecurity registrySecurity = registrySecurityObj as TransactedRegistrySecurity;420            // For ACL's, get the security descriptor from the RegistrySecurity.421            if (registrySecurity != null)422            {423                secAttrs = new Win32Native.SECURITY_ATTRIBUTES();424                secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);425 426                byte[] sd = registrySecurity.GetSecurityDescriptorBinaryForm();427                // We allocate memory on the stack to improve the speed.428                // So this part of code can't be refactored into a method.429                byte* pSecDescriptor = stackalloc byte[sd.Length];430                Microsoft.PowerShell.Commands.Internal.Buffer.memcpy(sd, 0, pSecDescriptor, 0, sd.Length);431                secAttrs.pSecurityDescriptor = pSecDescriptor;432            }433 434            int disposition = 0;435 436            // By default, the new key will be writable.437            SafeRegistryHandle result = null;438            int ret = 0;439            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();440 441            ret = Win32Native.RegCreateKeyTransacted(_hkey,442                subkey,443                0,444                null,445                0,446                GetRegistryKeyAccess(permissionCheck != RegistryKeyPermissionCheck.ReadSubTree),447                secAttrs,448                out result,449                out disposition,450                safeTransactionHandle,451                IntPtr.Zero452                );453 454            if (ret == 0 && !result.IsInvalid)455            {456                TransactedRegistryKey key = new TransactedRegistryKey(result, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree), false,457                                                                      Transaction.Current, safeTransactionHandle);458                CheckSubTreePermission(subkey, permissionCheck);459                key._checkMode = permissionCheck;460 461                if (subkey.Length == 0)462                    key._keyName = _keyName;463                else464                    key._keyName = _keyName + "\\" + subkey;465                return key;466            }467            else if (ret != 0) // syscall failed, ret is an error code.468                Win32Error(ret, _keyName + "\\" + subkey);  // Access denied?469 470            BCLDebug.Assert(false, "Unexpected code path in RegistryKey::CreateSubKey");471            return null;472        }473 474        /// <summary>475        /// <para>Deletes the specified subkey. Will throw an exception if the subkey has476        /// subkeys. To delete a tree of subkeys use, DeleteSubKeyTree.477        /// Utilizes Transaction.Current for its transaction.</para>478        /// <exception cref="InvalidOperationException">Thrown if the subkey as child subkeys.</exception>479        /// </summary>480        /// <param name='subkey'>The subkey to delete.</param>481        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey482        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]483        public void DeleteSubKey(string subkey)484        {485            DeleteSubKey(subkey, true);486        }487 488        /// <summary>489        /// <para>Deletes the specified subkey. Will throw an exception if the subkey has490        /// subkeys. To delete a tree of subkeys use, DeleteSubKeyTree.491        /// Utilizes Transaction.Current for its transaction.</para>492        /// <exception cref="InvalidOperationException">Thrown if the subkey as child subkeys.</exception>493        /// <exception cref="ArgumentException">Thrown if true is specified for throwOnMissingSubKey and the494        /// specified subkey does not exist.</exception>495        /// </summary>496        /// <param name='subkey'>The subkey to delete.</param>497        /// <param name='throwOnMissingSubKey'>Specify true if an ArgumentException should be thrown if498        /// the specified subkey does not exist. If false is specified, a missing subkey does not throw499        /// an exception.</param>500        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey501        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]502        public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)503        {504            ValidateKeyName(subkey);505            EnsureWriteable();506            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash507            CheckSubKeyWritePermission(subkey);508 509            // Open the key we are deleting and check for children. Be sure to510            // explicitly call close to avoid keeping an extra HKEY open.511            //512            TransactedRegistryKey key = InternalOpenSubKey(subkey, false);513            if (key != null)514            {515                try516                {517                    if (key.InternalSubKeyCount() > 0)518                    {519                        throw new InvalidOperationException(RegistryProviderStrings.InvalidOperation_RegRemoveSubKey);520                    }521                }522                finally523                {524                    key.Close();525                }526 527                int ret = 0;528 529                SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();530                ret = Win32Native.RegDeleteKeyTransacted(_hkey, subkey, 0, 0, safeTransactionHandle, IntPtr.Zero);531 532                if (ret != 0)533                {534                    if (ret == Win32Native.ERROR_FILE_NOT_FOUND)535                    {536                        if (throwOnMissingSubKey)537                        {538                            throw new ArgumentException(RegistryProviderStrings.ArgumentException_RegSubKeyAbsent);539                        }540                    }541                    else542                        Win32Error(ret, null);543                }544            }545            else546            { // there is no key which also means there is no subkey547                if (throwOnMissingSubKey)548                    throw new ArgumentException(RegistryProviderStrings.ArgumentException_RegSubKeyAbsent);549            }550        }551 552        /// <summary>553        /// <para>Recursively deletes a subkey and any child subkeys.554        /// Utilizes Transaction.Current for its transaction.</para>555        /// </summary>556        /// <param name="subkey">The subkey to delete.</param>557        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey558        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]559        public void DeleteSubKeyTree(string subkey)560        {561            ValidateKeyName(subkey);562 563            // Security concern: Deleting a hive's "" subkey would delete all564            // of that hive's contents.  Don't allow "".565            if ((string.IsNullOrEmpty(subkey) || subkey.Length == 0) && IsSystemKey())566            {567                throw new ArgumentException(RegistryProviderStrings.ArgRegKeyDelHive);568            }569 570            EnsureWriteable();571 572            int ret = 0;573 574            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();575            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash576            CheckSubTreeWritePermission(subkey);577 578            TransactedRegistryKey key = InternalOpenSubKey(subkey, true);579            if (key != null)580            {581                try582                {583                    if (key.InternalSubKeyCount() > 0)584                    {585                        string[] keys = key.InternalGetSubKeyNames();586 587                        for (int i = 0; i < keys.Length; i++)588                        {589                            key.DeleteSubKeyTreeInternal(keys[i]);590                        }591                    }592                }593                finally594                {595                    key.Close();596                }597 598                ret = Win32Native.RegDeleteKeyTransacted(_hkey, subkey, 0, 0, safeTransactionHandle, IntPtr.Zero);599                if (ret != 0)600                {601                    Win32Error(ret, null);602                }603            }604            else605            {606                throw new ArgumentException(RegistryProviderStrings.Arg_RegSubKeyAbsent);607            }608        }609 610        // An internal version which does no security checks or argument checking.  Skipping the611        // security checks should give us a slight perf gain on large trees.612        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey613        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]614        private void DeleteSubKeyTreeInternal(string subkey)615        {616            int ret = 0;617 618            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();619            TransactedRegistryKey key = InternalOpenSubKey(subkey, true);620            if (key != null)621            {622                try623                {624                    if (key.InternalSubKeyCount() > 0)625                    {626                        string[] keys = key.InternalGetSubKeyNames();627 628                        for (int i = 0; i < keys.Length; i++)629                        {630                            key.DeleteSubKeyTreeInternal(keys[i]);631                        }632                    }633                }634                finally635                {636                    key.Close();637                }638 639                ret = Win32Native.RegDeleteKeyTransacted(_hkey, subkey, 0, 0, safeTransactionHandle, IntPtr.Zero);640                if (ret != 0)641                {642                    Win32Error(ret, null);643                }644            }645            else646            {647                throw new ArgumentException(RegistryProviderStrings.Arg_RegSubKeyAbsent);648            }649        }650 651        /// <summary>652        /// <para>Deletes the specified value from this key.653        /// Utilizes Transaction.Current for its transaction.</para>654        /// </summary>655        /// <param name="name">Name of the value to delete.</param>656        public void DeleteValue(string name)657        {658            DeleteValue(name, true);659        }660 661        /// <summary>662        /// <para>Deletes the specified value from this key.663        /// Utilizes Transaction.Current for its transaction.</para>664        /// </summary>665        /// <param name="name">Name of the value to delete.</param>666        /// <param name="throwOnMissingValue">Specify true if an ArgumentException should be thrown if667        /// the specified value does not exist. If false is specified, a missing value does not throw668        /// an exception.</param>669        public void DeleteValue(string name, bool throwOnMissingValue)670        {671            EnsureWriteable();672            CheckValueWritePermission(name);673            // Require a transaction. This will throw for "Base" keys because they aren't associated with a transaction.674            VerifyTransaction();675            int errorCode = Win32Native.RegDeleteValue(_hkey, name);676 677            //678            // From windows 2003 server, if the name is too long we will get error code ERROR_FILENAME_EXCED_RANGE679            // This still means the name doesn't exist. We need to be consistent with previous OS.680            //681            if (errorCode == Win32Native.ERROR_FILE_NOT_FOUND || errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE)682            {683                if (throwOnMissingValue)684                {685                    throw new ArgumentException(RegistryProviderStrings.Arg_RegSubKeyValueAbsent);686                }687                else688                {689                    errorCode = Win32Native.ERROR_SUCCESS;690                }691            }692 693            if (Win32Native.ERROR_SUCCESS != errorCode)694            {695                Win32Error(errorCode, null);696            }697        }698 699        /**700         * Retrieves a new TransactedRegistryKey that represents the requested key. Valid701         * values are:702         *703         * HKEY_CLASSES_ROOT,704         * HKEY_CURRENT_USER,705         * HKEY_LOCAL_MACHINE,706         * HKEY_USERS,707         * HKEY_PERFORMANCE_DATA,708         * HKEY_CURRENT_CONFIG,709         * HKEY_DYN_DATA.710         *711         * @param hKey HKEY_* to open.712         *713         * @return the TransactedRegistryKey requested.714         */715        internal static TransactedRegistryKey GetBaseKey(IntPtr hKey)716        {717            int index = ((int)hKey) & 0x0FFFFFFF;718            BCLDebug.Assert(index >= 0 && index < s_hkeyNames.Length, "index is out of range!");719            BCLDebug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");720 721            SafeRegistryHandle srh = new SafeRegistryHandle(hKey, false);722 723            // For Base keys, there is no transaction associated with the HKEY.724            TransactedRegistryKey key = new TransactedRegistryKey(srh, true, true, null, null);725            key._checkMode = RegistryKeyPermissionCheck.Default;726            key._keyName = s_hkeyNames[index];727            return key;728        }729 730        /// <summary>731        /// <para>Retrieves a subkey. If readonly is true, then the subkey is opened with732        /// read-only access.733        /// Utilizes Transaction.Current for its transaction.</para>734        /// </summary>735        /// <returns>The subkey requested or null if the operation failed.</returns>736        /// <param name="name">Name or path of the subkey to open.</param>737        /// <param name="writable">Set to true of you only need readonly access.</param>738        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey739        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]740        public TransactedRegistryKey OpenSubKey(string name, bool writable)741        {742            ValidateKeyName(name);743            EnsureNotDisposed();744            name = FixupName(name); // Fixup multiple slashes to a single slash745 746            CheckOpenSubKeyPermission(name, writable);747            SafeRegistryHandle result = null;748            int ret = 0;749            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();750 751            ret = RegOpenKeyTransactedWrapper(_hkey, name, 0, GetRegistryKeyAccess(writable), out result, safeTransactionHandle, IntPtr.Zero);752 753            if (ret == 0 && !result.IsInvalid)754            {755                TransactedRegistryKey key = new TransactedRegistryKey(result, writable, false, Transaction.Current, safeTransactionHandle);756                key._checkMode = GetSubKeyPermissionCheck(writable);757                key._keyName = _keyName + "\\" + name;758                return key;759            }760 761            // Return null if we didn't find the key.762            if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL)763            {764                // We need to throw SecurityException here for compatibility reasons,765                // although UnauthorizedAccessException will make more sense.766                throw new SecurityException(RegistryProviderStrings.Security_RegistryPermission);767            }768 769            return null;770        }771 772        /// <summary>773        /// <para>Retrieves a subkey.774        /// Utilizes Transaction.Current for its transaction.</para>775        /// </summary>776        /// <returns>The subkey requested or null if the operation failed.</returns>777        /// <param name="name">Name or path of the subkey to open.</param>778        /// <param name="permissionCheck">One of the Microsoft.Win32.RegistryKeyPermissionCheck values that specifies779        /// whether the key is opened for read or read/write access.</param>780        [ComVisible(false)]781        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey782        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]783        public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck)784        {785            ValidateKeyMode(permissionCheck);786            return InternalOpenSubKey(name, permissionCheck, GetRegistryKeyAccess(permissionCheck));787        }788 789        /// <summary>790        /// <para>Retrieves a subkey.791        /// Utilizes Transaction.Current for its transaction.</para>792        /// </summary>793        /// <returns>The subkey requested or null if the operation failed.</returns>794        /// <param name="name">Name or path of the subkey to open.</param>795        /// <param name="permissionCheck">One of the Microsoft.Win32.RegistryKeyPermissionCheck values that specifies796        /// whether the key is opened for read or read/write access.</param>797        /// <param name="rights">A bitwise combination of Microsoft.Win32.RegistryRights values that specifies the desired security access.</param>798        [ComVisible(false)]799        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey800        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]801        public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)802        {803            return InternalOpenSubKey(name, permissionCheck, (int)rights);804        }805 806        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey807        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]808        private TransactedRegistryKey InternalOpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, int rights)809        {810            ValidateKeyName(name);811            ValidateKeyMode(permissionCheck);812            ValidateKeyRights(rights);813            EnsureNotDisposed();814            name = FixupName(name); // Fixup multiple slashes to a single slash815 816            CheckOpenSubKeyPermission(name, permissionCheck);817            SafeRegistryHandle result = null;818            int ret = 0;819 820            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();821 822            ret = RegOpenKeyTransactedWrapper(_hkey, name, 0, rights, out result, safeTransactionHandle, IntPtr.Zero);823 824            if (ret == 0 && !result.IsInvalid)825            {826                TransactedRegistryKey key = new TransactedRegistryKey(result, (permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree), false,827                                                                      Transaction.Current, safeTransactionHandle);828                key._keyName = _keyName + "\\" + name;829                key._checkMode = permissionCheck;830                return key;831            }832 833            // Return null if we didn't find the key.834            if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL)835            {836                // We need to throw SecurityException here for compatibility reason,837                // although UnauthorizedAccessException will make more sense.838                throw new SecurityException(RegistryProviderStrings.Security_RegistryPermission);839            }840 841            return null;842        }843 844        // This required no security checks. This is to get around the Deleting SubKeys which only require845        // write permission. They call OpenSubKey which required read. Now instead call this function w/o security checks846        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey847        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]848        internal TransactedRegistryKey InternalOpenSubKey(string name, bool writable)849        {850            ValidateKeyName(name);851            EnsureNotDisposed();852 853            int winAccess = GetRegistryKeyAccess(writable);854            SafeRegistryHandle result = null;855            int ret = 0;856            SafeTransactionHandle safeTransactionHandle = GetTransactionHandle();857 858            ret = RegOpenKeyTransactedWrapper(_hkey, name, 0, winAccess, out result, safeTransactionHandle, IntPtr.Zero);859 860            if (ret == 0 && !result.IsInvalid)861            {862                TransactedRegistryKey key = new TransactedRegistryKey(result, writable, false, Transaction.Current, safeTransactionHandle);863                key._keyName = _keyName + "\\" + name;864                return key;865            }866 867            return null;868        }869 870        /// <summary>871        /// <para>Retrieves a subkey for readonly access.872        /// Utilizes Transaction.Current for its transaction.</para>873        /// </summary>874        /// <returns>The subkey requested or null if the operation failed.</returns>875        /// <param name="name">Name or path of the subkey to open.</param>876        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey877        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]878        public TransactedRegistryKey OpenSubKey(string name)879        {880            return OpenSubKey(name, false);881        }882 883        /// <summary>884        /// <para>Retrieves the count of subkeys.885        /// Utilizes Transaction.Current for its transaction.</para>886        /// </summary>887        /// <returns>The count of subkeys.</returns>888        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey889        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]890        public int SubKeyCount891        {892            get893            {894                CheckKeyReadPermission();895                return InternalSubKeyCount();896            }897        }898 899        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey900        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]901        internal int InternalSubKeyCount()902        {903            EnsureNotDisposed();904            // Don't require a transaction. We don't want to throw for "Base" keys.905 906            int subkeys = 0;907            int junk = 0;908            int ret = Win32Native.RegQueryInfoKey(_hkey,909                                      null,910                                      null,911                                      Win32Native.NULL,912                                      ref subkeys,  // subkeys913                                      null,914                                      null,915                                      ref junk,     // values916                                      null,917                                      null,918                                      null,919                                      null);920 921            if (ret != 0)922                Win32Error(ret, null);923            return subkeys;924        }925 926        /// <summary>927        /// <para>Retrieves an array of strings containing all the subkey names.928        /// Utilizes Transaction.Current for its transaction.</para>929        /// </summary>930        /// <returns>A string array containing all the subkey names.</returns>931        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey932        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]933        public string[] GetSubKeyNames()934        {935            CheckKeyReadPermission();936            return InternalGetSubKeyNames();937        }938 939        // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey940        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]941        internal string[] InternalGetSubKeyNames()942        {943            EnsureNotDisposed();944            // Don't require a transaction. We don't want to throw for "Base" keys.945            int subkeys = InternalSubKeyCount();946            string[] names = new string[subkeys];  // Returns 0-length array if empty.947 948            if (subkeys > 0)949            {950                StringBuilder name = new StringBuilder(256);951                int namelen;952 953                for (int i = 0; i < subkeys; i++)954                {955                    namelen = name.Capacity; // Don't remove this. The API's doesn't work if this is not properly initialised.956                    int ret = Win32Native.RegEnumKeyEx(_hkey,957                        i,958                        name,959                        out namelen,960                        null,961                        null,962                        null,963                        null);964                    if (ret != 0)965                        Win32Error(ret, null);966                    names[i] = name.ToString();967                }968            }969 970            return names;971        }972 973        /// <summary>974        /// <para>Retrieves the count of values.975        /// Utilizes Transaction.Current for its transaction.</para>976        /// </summary>977        /// <returns>A count of values.</returns>978        public int ValueCount979        {980            get981            {982                CheckKeyReadPermission();983                return InternalValueCount();984            }985        }986 987        internal int InternalValueCount()988        {989            EnsureNotDisposed();990            // Don't require a transaction. We don't want to throw for "Base" keys.991            int values = 0;992            int junk = 0;993            int ret = Win32Native.RegQueryInfoKey(_hkey,994                                      null,995                                      null,996                                      Win32Native.NULL,997                                      ref junk,     // subkeys998                                      null,999                                      null,1000                                      ref values,   // values1001                                      null,1002                                      null,1003                                      null,1004                                      null);1005            if (ret != 0)1006                Win32Error(ret, null);1007            return values;1008        }1009 1010        /// <summary>1011        /// <para>Retrieves an array of strings containing all the value names.1012        /// Utilizes Transaction.Current for its transaction.</para>1013        /// </summary>1014        /// <returns>All the value names.</returns>1015        public string[] GetValueNames()1016        {1017            CheckKeyReadPermission();1018            EnsureNotDisposed();1019            // Don't require a transaction. We don't want to throw for "Base" keys.1020 1021            int values = InternalValueCount();1022            string[] names = new string[values];1023 1024            if (values > 0)1025            {1026                StringBuilder name = new StringBuilder(256);1027                int namelen;1028                int currentlen;1029                int ret;1030 1031                for (int i = 0; i < values; i++)1032                {1033                    currentlen = name.Capacity;1034                    ret = Win32Native.ERROR_MORE_DATA;1035 1036                    // loop while we get error_more_data or until we have exceeded1037                    // the max name length.1038                    while (Win32Native.ERROR_MORE_DATA == ret)1039                    {1040                        namelen = currentlen;1041                        ret = Win32Native.RegEnumValue(_hkey,1042                            i,1043                            name,1044                            ref namelen,1045                            Win32Native.NULL,1046                            null,1047                            null,1048                            null);1049 1050                        if (ret != 0)1051                        {1052                            if (ret != Win32Native.ERROR_MORE_DATA)1053                                Win32Error(ret, null);1054 1055                            // We got ERROR_MORE_DATA. Let's see if we can make the buffer1056                            // bigger.1057                            if (MaxValueNameLength == currentlen)1058                                Win32Error(ret, null);1059 1060                            currentlen = currentlen * 2;1061                            if (MaxValueNameLength < currentlen)1062                                currentlen = MaxValueNameLength;1063 1064                            // Allocate a new buffer.1065                            name = new StringBuilder(currentlen);1066                        }1067                    }1068 1069                    names[i] = name.ToString();1070                }1071            }1072 1073            return names;1074        }1075 1076        /// <summary>1077        /// <para>Retrieves the specified value. null is returned if the value1078        /// doesn't exist. Utilizes Transaction.Current for its transaction.</para>1079        /// <para>Note that name can be null or "", at which point the1080        /// unnamed or default value of this Registry key is returned, if any.</para>1081        /// </summary>1082        /// <returns>The data associated with the value.</returns>1083        /// <param name="name">Name of value to retrieve.</param>1084        public object GetValue(string name)1085        {1086            CheckValueReadPermission(name);1087            return InternalGetValue(name, null, false, true);1088        }1089 1090        /// <summary>1091        /// <para>Retrieves the specified value. null is returned if the value1092        /// doesn't exist. Utilizes Transaction.Current for its transaction.</para>1093        /// <para>Note that name can be null or "", at which point the1094        /// unnamed or default value of this Registry key is returned, if any.</para>1095        /// </summary>1096        /// <returns>The data associated with the value.</returns>1097        /// <param name="name">Name of value to retrieve.</param>1098        /// <param name="defaultValue">Value to return if name doesn't exist.</param>1099        public object GetValue(string name, object defaultValue)1100        {1101            CheckValueReadPermission(name);1102            return InternalGetValue(name, defaultValue, false, true);1103        }1104 1105        /// <summary>1106        /// <para>Retrieves the specified value. null is returned if the value1107        /// doesn't exist. Utilizes Transaction.Current for its transaction.</para>1108        /// <para>Note that name can be null or "", at which point the1109        /// unnamed or default value of this Registry key is returned, if any.</para>1110        /// </summary>1111        /// <returns>The data associated with the value.</returns>1112        /// <param name="name">Name of value to retrieve.</param>1113        /// <param name="defaultValue">Value to return if name doesn't exist.</param>1114        /// <param name="options">One of the Microsoft.Win32.RegistryValueOptions values that specifies1115        /// optional processing of the retrieved value.</param>1116        [ComVisible(false)]1117        public object GetValue(string name, object defaultValue, RegistryValueOptions options)1118        {1119            if (options < RegistryValueOptions.None || options > RegistryValueOptions.DoNotExpandEnvironmentNames)1120            {1121                string resourceTemplate = RegistryProviderStrings.Arg_EnumIllegalVal;1122                string resource = string.Format(CultureInfo.CurrentCulture, resourceTemplate, options.ToString());1123                throw new ArgumentException(resource);1124            }1125 1126            bool doNotExpand = (options == RegistryValueOptions.DoNotExpandEnvironmentNames);1127            CheckValueReadPermission(name);1128            return InternalGetValue(name, defaultValue, doNotExpand, true);1129        }1130 1131        internal object InternalGetValue(string name, object defaultValue, bool doNotExpand, bool checkSecurity)1132        {1133            if (checkSecurity)1134            {1135                // Name can be null!  It's the most common use of RegQueryValueEx1136                EnsureNotDisposed();1137            }1138 1139            // Don't require a transaction. We don't want to throw for "Base" keys.1140 1141            object data = defaultValue;1142            int type = 0;1143            int datasize = 0;1144 1145            int ret = Win32Native.RegQueryValueEx(_hkey, name, null, ref type, (byte[])null, ref datasize);1146 1147            if (ret != 0)1148            {1149                // For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).1150                // Some OS's returned ERROR_MORE_DATA even in success cases, so we1151                // want to continue on through the function.1152                if (ret != Win32Native.ERROR_MORE_DATA)1153                    return data;1154            }1155 1156            switch (type)1157            {1158                case Win32Native.REG_DWORD_BIG_ENDIAN:1159                case Win32Native.REG_BINARY:1160                    {1161                        byte[] blob = new byte[datasize];1162                        ret = Win32Native.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);1163                        data = blob;1164                    }1165 1166                    break;1167                case Win32Native.REG_QWORD:1168                    {    // also REG_QWORD_LITTLE_ENDIAN1169                        if (datasize > 8)1170                        {1171                            // prevent an AV in the edge case that datasize is larger than sizeof(long)1172                            goto case Win32Native.REG_BINARY;1173                        }1174 1175                        long blob = 0;1176                        BCLDebug.Assert(datasize == 8, "datasize==8");1177                        // Here, datasize must be 8 when calling this1178                        ret = Win32Native.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);1179 1180                        data = blob;1181                    }1182 1183                    break;1184                case Win32Native.REG_DWORD:1185                    {    // also REG_DWORD_LITTLE_ENDIAN1186                        if (datasize > 4)1187                        {1188                            // prevent an AV in the edge case that datasize is larger than sizeof(int)1189                            goto case Win32Native.REG_QWORD;1190                        }1191 1192                        int blob = 0;1193                        BCLDebug.Assert(datasize == 4, "datasize==4");1194                        // Here, datasize must be four when calling this1195                        ret = Win32Native.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);1196 1197                        data = blob;1198                    }1199 1200                    break;

Showing the first 1,200 of 2058 lines. Download the file for the rest.