This class maintains its own internal buffer and extends it, if the it is too small to fit the desired data.
The main reason of using this class is to avoid unnecessary memory allocations.
For example, the same memory can be used for getting the driver notification and then storing the reply message into, so there's no need to allocate two separate memory blocks.
Inheritance: IDisposable
コード例 #1
0
        /// <summary>
        /// Gets the name of the user for the <paramref name="process"/> given.
        /// </summary>
        /// <param name="process">Process to get username for.</param>
        /// <returns>Name of the user for the <paramref name="process"/> in the <c>DOMAIN\username</c> format.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="process"/> is <see langword="null"/>.</exception>
        /// <exception cref="InvalidOperationException">
        /// Process token cannot be obtained.
        ///     <para>-or-</para>
        /// Process token information cannot be retrieved.
        ///     <para>-or-</para>
        /// Account information cannot be found.
        /// </exception>
        public static string GetUserNameForProcess(Process process)
        {
            if (process == null)
            {
                throw new ArgumentNullException(nameof(process));
            }

            SafeTokenHandle tokenHandle;

            if (!NativeMethods.OpenProcessToken(process.Handle, TokenAccessRights.TokenQuery, out tokenHandle))
            {
                int hr = Marshal.GetHRForLastWin32Error();
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open process token: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
            }

            using (tokenHandle)
                using (ResizableBuffer buffer = new ResizableBuffer(ProcessHelper.DefaultBufferSize))
                {
                    int actualSize;
                    if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize))
                    {
                        int hr = Marshal.GetHRForLastWin32Error();
                        if (hr != NativeMethods.ErrorInsufficientBuffer)
                        {
                            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
                        }

                        // Resize and retry.
                        buffer.Resize(actualSize);

                        if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize))
                        {
                            hr = Marshal.GetHRForLastWin32Error();
                            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
                        }
                    }

                    TokenUser tokenUser = (TokenUser)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(TokenUser));

                    return(ProcessHelper.GetUserNameForSid(tokenUser.User.Sid));
                }
        }
コード例 #2
0
        private void ProcessNotification(ResizableBuffer resizableBuffer)
        {
            IntPtr bufferPointer = resizableBuffer.DangerousGetPointer();

            // Marshal the notification received.
            DriverNotificationHeader header = (DriverNotificationHeader)Marshal.PtrToStructure(bufferPointer, typeof(DriverNotificationHeader));
            DriverNotification notification = new DriverNotification { Type = header.Type, DataLength = header.DataLength, Data = bufferPointer + this.notificationHeaderSize };

            // Get the reply object from the user-defined handler.
            object reply = null;
            int handlerResult = (int)NativeMethods.Ok;

            try
            {
                reply = this.handler(notification);
            }
            catch (Exception e)
            {
                handlerResult = Marshal.GetHRForException(e);
                NotificationsMonitor.Logger.Error(e, "Notification handler threw an exception.");
            }

            // Driver is not expecting any reply.
            if (header.ReplyLength == 0)
            {
                if (reply != null)
                {
                    NotificationsMonitor.Logger.Warn(CultureInfo.InvariantCulture, "Driver is not expecting any reply, but reply object is returned from handler: {0}", reply.GetType());
                }

                return;
            }

            int replySize = this.replyHeaderSize + MarshalingHelper.GetObjectSize(reply);
            if (replySize > header.ReplyLength)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Reply ({0} bytes) is bigger than the one expected by the driver ({1} bytes).", replySize, header.ReplyLength));
            }

            DriverReplyHeader replyHeader = new DriverReplyHeader
            {
                MessageId = header.MessageId,

                // Notify driver about the exception thrown, if any.
                Status    = handlerResult
            };

            // Adjust the buffer to fit the reply.
            resizableBuffer.Resize(replySize);
            bufferPointer = resizableBuffer.DangerousGetPointer();

            // Marshal reply to the output buffer.
            MarshalingHelper.MarshalObjectsToPointer(bufferPointer, replySize, replyHeader, reply);

            // And send it to the driver.
            uint hr = NativeMethods.FilterReplyMessage(this.filterPortHandle, bufferPointer, (uint)replySize);
            if (hr != NativeMethods.Ok)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to send reply: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr)));
            }
        }
コード例 #3
0
        private bool GetNextNotification(ResizableBuffer resizableBuffer, ManualResetEvent resetEvent, NativeOverlapped overlapped)
        {
            uint numberOfBytesTransferred;
            IntPtr completionKey;
            NativeOverlapped nativeOverlapped;

            // Buffer to marshal the notification into.
            IntPtr notificationBuffer = resizableBuffer.DangerousGetPointer();
            resetEvent.Reset();

            //
            // 'Asynchronously' request and get a message from the driver.
            //

            // FilterGetMessage returns ERROR_IO_PENDING, if it's set to operate in the asynchronous mode.
            uint hr = NativeMethods.FilterGetMessage(this.filterPortHandle, notificationBuffer, this.bufferSize, ref overlapped);
            if (hr != NativeMethods.Ok && hr != NativeMethods.ErrorIoPending)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to request for a message: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr)));
            }

            // If we don't specify timeout, this method will wait forever, but we want to be able to react on the task cancellation.
            while (!NativeMethods.GetQueuedCompletionStatus(this.completionPortHandle.DangerousGetHandle(), out numberOfBytesTransferred, out completionKey, out nativeOverlapped, NotificationsMonitor.QueueTimeout))
            {
                hr = unchecked((uint)Marshal.GetHRForLastWin32Error());

                // Break on the task cancellation.
                if (this.token.IsCancellationRequested)
                {
                    break;
                }

                // If the WAIT_TIMEOUT is returned, there was no notification available and we want to wait again.
                if (hr == NativeMethods.WaitTimeout)
                {
                    continue;
                }

                // If the I/O was cancelled on the completion port, or the completion port was closed.
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid completion status: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr)));
            }

            // If the current task was cancelled, the token wait handle will be set.
            // The 'resetEvent' will be set via the overlapped' structure, when the driver finishes writing notification to the buffer.
            return WaitHandle.WaitAny(new[] { this.token.WaitHandle, resetEvent }) == 1;
        }
コード例 #4
0
        public void DoWork()
        {
            // Notification buffer must also include a message header. This also validates the 'this.bufferSize' parameter.
            // The 'resetEvent' will be set by the I/O completion port via the OVERLAPPED structure when notification is available.
            using (ResizableBuffer resizableBuffer = new ResizableBuffer(this.notificationHeaderSize + this.bufferSize))
            using (ManualResetEvent resetEvent     = new ManualResetEvent(false))
            {
                // This OVERLAPPED structure will be passed to the 'FilterGetMessage' method, so it'll operate in the asynchronous mode.
                NativeOverlapped overlapped = new NativeOverlapped { EventHandle = resetEvent.SafeWaitHandle.DangerousGetHandle() };

                try
                {
                    // Get the next notification and store it into the 'resizableBuffer'.
                    while (this.GetNextNotification(resizableBuffer, resetEvent, overlapped))
                    {
                        // Get the reply and send it back to the driver.
                        this.ProcessNotification(resizableBuffer);
                    }
                }
                finally
                {
                    this.CancelIo(overlapped);
                }
            }
        }
コード例 #5
0
ファイル: ProcessHelper.cs プロジェクト: aleksk/LazyCopy
        /// <summary>
        /// Gets the name of the user for the <paramref name="process"/> given.
        /// </summary>
        /// <param name="process">Process to get username for.</param>
        /// <returns>Name of the user for the <paramref name="process"/> in the <c>DOMAIN\username</c> format.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="process"/> is <see langword="null"/>.</exception>
        /// <exception cref="InvalidOperationException">
        /// Process token cannot be obtained.
        ///     <para>-or-</para>
        /// Process token information cannot be retrieved.
        ///     <para>-or-</para>
        /// Account information cannot be found.
        /// </exception>
        public static string GetUserNameForProcess(Process process)
        {
            if (process == null)
            {
                throw new ArgumentNullException(nameof(process));
            }

            SafeTokenHandle tokenHandle;
            if (!NativeMethods.OpenProcessToken(process.Handle, TokenAccessRights.TokenQuery, out tokenHandle))
            {
                int hr = Marshal.GetHRForLastWin32Error();
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open process token: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
            }

            using (tokenHandle)
            using (ResizableBuffer buffer = new ResizableBuffer(ProcessHelper.DefaultBufferSize))
            {
                int actualSize;
                if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize))
                {
                    int hr = Marshal.GetHRForLastWin32Error();
                    if (hr != NativeMethods.ErrorInsufficientBuffer)
                    {
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
                    }

                    // Resize and retry.
                    buffer.Resize(actualSize);

                    if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize))
                    {
                        hr = Marshal.GetHRForLastWin32Error();
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr));
                    }
                }

                TokenUser tokenUser = (TokenUser)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(TokenUser));

                return ProcessHelper.GetUserNameForSid(tokenUser.User.Sid);
            }
        }
コード例 #6
0
        /// <summary>
        /// Sets the reparse point data for the <paramref name="path"/> given.
        /// </summary>
        /// <param name="path">File or directory to set the reparse point data for.</param>
        /// <param name="data">
        /// Reparse point data to be set.
        /// It should be a value type, or an <see cref="IEnumerable"/>, and it should not contain
        /// reparse point data header information, because this function handles it separately.
        /// </param>
        /// <param name="reparseTag">Reparse point tag.</param>
        /// <param name="reparseGuid">Reparse point <see cref="Guid"/>. Must be specified, if the <paramref name="reparseTag"/> is a non-Microsoft tag.</param>
        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="data"/> is not a collection or a value type.
        ///     <para>-or-</para>
        /// <paramref name="reparseTag"/> is a Microsoft tag, but the <paramref name="reparseGuid"/> is not <see langword="null"/>.
        ///     <para>-or-</para>
        /// <paramref name="reparseTag"/> is a non-Microsoft tag, but the <paramref name="reparseGuid"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Reparse point <paramref name="data"/> cannot be set for the <paramref name="path"/>.
        /// </exception>
        /// <exception cref="IOException">
        /// <paramref name="path"/> cannot be accessed.
        /// </exception>
        /// <remarks>
        /// This method will <i>NOT</i> update file attributes.<br/>
        /// For example, the <see cref="FileAttributes.ReparsePoint"/> will not be set.
        /// </remarks>
        public static void SetReparsePointData(string path, object data, int reparseTag, Guid?reparseGuid)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            ReparsePointHelper.ValidateTagAndGuid(reparseTag, reparseGuid);

            bool   isMicrosoftTag = ReparsePointHelper.IsMicrosoftTag(reparseTag);
            string normalizedPath = LongPathCommon.NormalizePath(path);

            if (!LongPathCommon.Exists(normalizedPath))
            {
                throw new IOException(string.Format(CultureInfo.InvariantCulture, "{0} cannot be found.", path));
            }

            using (SafeFileHandle handle = NativeMethods.CreateFile(
                       normalizedPath,
                       AccessRights.GenericWrite,
                       FileShare.None,
                       IntPtr.Zero,
                       FileMode.Open,
                       EFileAttributes.OpenReparsePoint | EFileAttributes.BackupSemantics,
                       IntPtr.Zero))
            {
                if (handle.IsInvalid)
                {
                    Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
                    throw new IOException(string.Format(CultureInfo.InvariantCulture, "Unable to open: {0}", path), nativeException);
                }

                int dataSize = MarshalingHelper.GetObjectSize(data);

                object header = isMicrosoftTag
                                ? (object)new ReparseDataBufferHeader {
                    ReparseDataLength = unchecked ((ushort)dataSize), ReparseTag = reparseTag
                }
                                : new ReparseGuidDataBufferHeader     {
                    ReparseDataLength = unchecked ((ushort)dataSize), ReparseTag = reparseTag, ReparseGuid = reparseGuid.Value
                };

                int headerSize    = Marshal.SizeOf(header);
                int tagDataLength = headerSize + dataSize;

                using (ResizableBuffer buffer = new ResizableBuffer(Math.Max(ReparsePointHelper.BufferSize, tagDataLength)))
                {
                    MarshalingHelper.MarshalObjectToPointer(new[] { header, data }, buffer.DangerousGetPointer());

                    // Set the reparse point data.
                    int  bytesReturned;
                    bool success = NativeMethods.DeviceIoControl(
                        handle,
                        ReparsePointHelper.SetReparsePointControlCode,
                        buffer.DangerousGetPointer(),
                        tagDataLength,
                        IntPtr.Zero,
                        0,
                        out bytesReturned,
                        IntPtr.Zero);

                    if (!success)
                    {
                        Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to set the reparse point data: {0}", path), nativeException);
                    }
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Gets the reparse point data from the <paramref name="path"/> given.
        /// </summary>
        /// <typeparam name="T">
        /// Reparse point buffer data type.
        /// It should not contain reparse point data header information, because this function handles it separately.
        /// </typeparam>
        /// <param name="path">Path to the reparse point to get data from.</param>
        /// <param name="reparseTag">Reparse point tag.</param>
        /// <param name="reparseGuid">Reparse point <see cref="Guid"/>. Must be specified, if the <paramref name="reparseTag"/> is a non-Microsoft tag.</param>
        /// <returns>Reparse point data found.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="reparseTag"/> is a Microsoft tag, but the <paramref name="reparseGuid"/> is not <see langword="null"/>.
        ///     <para>-or-</para>
        /// <paramref name="reparseTag"/> is a non-Microsoft tag, but the <paramref name="reparseGuid"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// <paramref name="path"/> cannot be found.
        ///     <para>-or-</para>
        /// <paramref name="path"/> is not a reparse point.
        ///     <para>-or-</para>
        /// <paramref name="path"/> reparse point cannot be opened.
        ///     <para>-or-</para>
        /// <paramref name="path"/> reparse point data cannot be retrieved.
        ///     <para>-or-</para>
        /// <paramref name="path"/> reparse point tag or GUID is invalid.
        /// </exception>
        /// <remarks>
        /// See <c>http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511(v=vs.85).aspx</c> for more details about reparse point tags.
        /// </remarks>
        public static T GetReparsePointData <T>(string path, int reparseTag, Guid?reparseGuid)
            where T : struct
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            ReparsePointHelper.ValidateTagAndGuid(reparseTag, reparseGuid);

            bool   isMicrosoftTag = ReparsePointHelper.IsMicrosoftTag(reparseTag);
            string normalizedPath = LongPathCommon.NormalizePath(path);

            bool isDirectory;

            if (!LongPathCommon.Exists(normalizedPath, out isDirectory))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Path does not exist: {0}", path));
            }

            // Check, whether the path given is a reparse point.
            FileAttributes attributes = isDirectory ? new LongPathDirectoryInfo(normalizedPath).Attributes : LongPathFile.GetAttributes(normalizedPath);

            if (!attributes.HasFlag(FileAttributes.ReparsePoint))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Path given is not a reparse point: {0}", path));
            }

            using (SafeFileHandle handle = NativeMethods.CreateFile(
                       normalizedPath,
                       AccessRights.GenericRead,
                       FileShare.Read,
                       IntPtr.Zero,
                       FileMode.Open,
                       EFileAttributes.OpenReparsePoint | EFileAttributes.BackupSemantics,
                       IntPtr.Zero))
            {
                if (handle.IsInvalid)
                {
                    Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open reparse point: {0}", path), nativeException);
                }

                // Make sure that the buffer will be large enough to hold reparse point data.
                int initialBufferSize = Math.Max(ReparsePointHelper.BufferSize, Marshal.SizeOf(typeof(ReparseGuidDataBufferHeader)) + Marshal.SizeOf(typeof(T)));

                using (ResizableBuffer buffer = new ResizableBuffer(initialBufferSize))
                {
                    // Query the reparse point data.
                    int  bytesReturned;
                    bool success = NativeMethods.DeviceIoControl(
                        handle,
                        ReparsePointHelper.GetReparsePointControlCode,
                        IntPtr.Zero,
                        0,
                        buffer.DangerousGetPointer(),
                        buffer.ByteLength,
                        out bytesReturned,
                        IntPtr.Zero);

                    int headerSize = isMicrosoftTag ? Marshal.SizeOf(typeof(ReparseDataBufferHeader)) : Marshal.SizeOf(typeof(ReparseGuidDataBufferHeader));

                    if (!success)
                    {
                        int hr = Marshal.GetHRForLastWin32Error();
                        if (hr != NativeMethods.ErrorMoreData)
                        {
                            Exception nativeException = Marshal.GetExceptionForHR(hr);
                            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get the reparse point data: {0}", path), nativeException);
                        }

                        // Read the ReparseDataLength value, and resize buffer to fit the data.
                        int dataSize = headerSize + Marshal.ReadInt16(buffer.DangerousGetPointer(), 4 /* sizeof(uint) */);

                        buffer.Resize(dataSize);

                        success = NativeMethods.DeviceIoControl(
                            handle,
                            ReparsePointHelper.GetReparsePointControlCode,
                            IntPtr.Zero,
                            0,
                            buffer.DangerousGetPointer(),
                            buffer.ByteLength,
                            out bytesReturned,
                            IntPtr.Zero);

                        if (!success)
                        {
                            Exception nativeException = Marshal.GetExceptionForHR(hr);
                            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get the reparse point data: {0}", path), nativeException);
                        }
                    }

                    // Make sure that the reparse tag is correct.
                    uint tag = unchecked ((uint)Marshal.ReadInt32(buffer.DangerousGetPointer()));
                    if (tag != unchecked ((uint)reparseTag))
                    {
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Reparse point tag is invalid. Path has 0x{0:X8}, but 0x{1:X8} is specified.", tag, reparseTag));
                    }

                    // Make sure that the reparse point GUID is correct, if needed.
                    if (!isMicrosoftTag)
                    {
                        ReparseGuidDataBufferHeader header = (ReparseGuidDataBufferHeader)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(ReparseGuidDataBufferHeader));
                        if (header.ReparseGuid != reparseGuid)
                        {
                            throw new InvalidOperationException(string.Format(
                                                                    CultureInfo.InvariantCulture,
                                                                    "Reparse point GUID is invalid. Path has {0}, but {1} is specified.",
                                                                    header.ReparseGuid.ToString("N"),
                                                                    reparseGuid.Value.ToString("N")));
                        }
                    }

                    return((T)Marshal.PtrToStructure(buffer.DangerousGetPointer() + headerSize, typeof(T)));
                }
            }
        }
コード例 #8
0
ファイル: FltmcManager.cs プロジェクト: aleksk/LazyCopy
        public IEnumerable<FilterInfo> GetFiltersInformation()
        {
            List<FilterInfo> result = new List<FilterInfo>();

            lock (this.syncRoot)
            {
                using (ResizableBuffer buffer = new ResizableBuffer(1024))
                {
                    IntPtr filterFindHandle = IntPtr.Zero;
                    uint hr = 0;

                    try
                    {
                        uint bytesReturned;

                        hr = NativeMethods.FilterFindFirst(NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned, out filterFindHandle);

                        // If the buffer allocated is not large enough to hold all data returned, resize it and try again.
                        if (hr == NativeMethods.ErrorInsufficientBuffer)
                        {
                            buffer.Resize(unchecked((int)bytesReturned));
                            hr = NativeMethods.FilterFindFirst(NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned, out filterFindHandle);
                        }

                        if (hr != NativeMethods.Ok)
                        {
                            // There are no filters available.
                            if (hr == NativeMethods.ErrorNoMoreItems)
                            {
                                return result;
                            }

                            throw Marshal.GetExceptionForHR(unchecked((int)hr));
                        }

                        result.AddRange(FltmcManager.MarshalFilterInfo(buffer.DangerousGetPointer()));

                        while (true)
                        {
                            hr = NativeMethods.FilterFindNext(filterFindHandle, NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned);
                            if (hr == NativeMethods.ErrorInsufficientBuffer)
                            {
                                buffer.Resize(unchecked((int)bytesReturned));
                                hr = NativeMethods.FilterFindNext(filterFindHandle, NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned);
                            }

                            if (hr != NativeMethods.Ok)
                            {
                                if (hr == NativeMethods.ErrorNoMoreItems)
                                {
                                    break;
                                }

                                throw Marshal.GetExceptionForHR(unchecked((int)hr));
                            }

                            result.AddRange(FltmcManager.MarshalFilterInfo(buffer.DangerousGetPointer()));
                        }
                    }
                    catch (Exception e)
                    {
                        string message = string.Format(CultureInfo.InvariantCulture, "Unable to get the filter driver information: 0x{0:X8}", hr);

                        FltmcManager.Logger.Error(e, message);
                        throw new InvalidOperationException(message, e);
                    }
                    finally
                    {
                        if (filterFindHandle != IntPtr.Zero)
                        {
                            NativeMethods.FilterFindClose(filterFindHandle);
                        }
                    }
                }
            }

            return result;
        }