/// <summary>
        /// Initializes a new instance of the <see cref="FileEnumerator"/> class.
        /// </summary>
        /// <param name="path">The directory to search.</param>
        /// <param name="fileExtension">The file extension to search for.</param>
        /// <param name="searchOption">
        /// One of the <see cref="SearchOption"/> values that specifies whether the search operation should include only the current directory or should include all subdirectories.
        /// </param>
        /// <param name="dereferenceLinks">If set to <c>true</c> search the target of shortcuts.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="path"/> in null.
        /// -or-
        /// <paramref name="fileExtension"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException"><paramref name="path"/> is a 0 length string, or contains only white-space, or contains one or more invalid characters as defined by <see cref="Path.GetInvalidPathChars"/>.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="searchOption"/> is not a valid <see cref="SearchOption"/> value.</exception>
        /// <exception cref="DirectoryNotFoundException">The directory specified by <paramref name="path"/> does not exist.</exception>
        /// <exception cref="IOException"><paramref name="path"/> is a file.</exception>
        /// <exception cref="PathTooLongException">The specified path, file name, or combined exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters and file names must be less than 260 characters.</exception>
        /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.</exception>
        /// <exception cref="SecurityException">The caller does not have the required permission.</exception>
        public FileEnumerator(string path, string fileExtension, SearchOption searchOption, bool dereferenceLinks)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (fileExtension == null)
            {
                throw new ArgumentNullException(nameof(fileExtension));
            }
            if (searchOption < SearchOption.TopDirectoryOnly || searchOption > SearchOption.AllDirectories)
            {
                throw new ArgumentOutOfRangeException(nameof(searchOption));
            }

            string fullPath   = Path.GetFullPath(path);
            string demandPath = GetPermissionPath(fullPath, false);

            new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand();
            needsPathDiscoveryDemand = false;

            searchData         = new SearchData(fullPath);
            this.fileExtension = fileExtension;
            this.searchOption  = searchOption;
            searchDirectories  = new Queue <SearchData>();
            if (dereferenceLinks)
            {
                shellLink             = new ShellLink();
                this.dereferenceLinks = true;
            }
            else
            {
                shellLink             = null;
                this.dereferenceLinks = false;
            }
            shellLinkTarget    = null;
            visitedDirectories = new HashSet <DirectoryIdentifier>();

            if (OS.IsWindows7OrLater)
            {
                // Suppress the querying of short filenames and use a larger buffer on Windows 7 and later.
                infoLevel       = NativeEnums.FindExInfoLevel.Basic;
                additionalFlags = NativeEnums.FindExAdditionalFlags.LargeFetch;
            }
            else
            {
                infoLevel       = NativeEnums.FindExInfoLevel.Standard;
                additionalFlags = NativeEnums.FindExAdditionalFlags.None;
            }
            oldErrorMode = SetErrorModeWrapper(NativeConstants.SEM_FAILCRITICALERRORS);
            state        = -1;
            current      = null;
            disposed     = false;
            Init();
        }
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!disposed)
            {
                disposed = true;

                if (handle != null)
                {
                    handle.Dispose();
                    handle = null;
                }

                if (shellLink != null)
                {
                    shellLink.Dispose();
                    shellLink = null;
                }
                current = null;
                state   = -1;
                SetErrorModeWrapper(oldErrorMode);
            }
        }