Example #1
0
        /// <devdoc>
        ///     Callback from thread pool.
        /// </devdoc>
        /// <internalonly/>
        private unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped *overlappedPointer)
        {
            Overlapped     overlapped  = Overlapped.Unpack(overlappedPointer);
            FSWAsyncResult asyncResult = (FSWAsyncResult)overlapped.AsyncResult;

            try {
                if (stopListening)
                {
                    return;
                }

                lock (this) {
                    if (errorCode != 0)
                    {
                        if (errorCode == 995 /* ERROR_OPERATION_ABORTED */)
                        {
                            //Win2000 inside a service the first completion status is false
                            //cannot return without monitoring again.
                            //Because this return statement is inside a try/finally block,
                            //the finally block will execute. It does restart the monitoring.
                            return;
                        }
                        else
                        {
                            OnError(new ErrorEventArgs(new Win32Exception((int)errorCode)));
                            EnableRaisingEvents = false;
                            return;
                        }
                    }

                    // Ignore any events that occurred before this "session",
                    // so we don't get changed or error events after we
                    // told FSW to stop.
                    if (asyncResult.session != currentSession)
                    {
                        return;
                    }


                    if (numBytes == 0)
                    {
                        NotifyInternalBufferOverflowEvent();
                    }
                    else    // Else, parse each of them and notify appropriate delegates

                    /******
                     *  Format for the buffer is the following C struct:
                     *
                     *  typedef struct _FILE_NOTIFY_INFORMATION {
                     *     DWORD NextEntryOffset;
                     *     DWORD Action;
                     *     DWORD FileNameLength;
                     *     WCHAR FileName[1];
                     *  } FILE_NOTIFY_INFORMATION;
                     *
                     *  NOTE1: FileNameLength is length in bytes.
                     *  NOTE2: The Filename is a Unicode string that's NOT NULL terminated.
                     *  NOTE3: A NextEntryOffset of zero means that it's the last entry
                     *******/

                    // Parse the file notify buffer:
                    {
                        int    offset = 0;
                        int    nextOffset, action, nameLength;
                        string oldName = null;
                        string name    = null;

                        do
                        {
                            fixed(byte *buffPtr = asyncResult.buffer)
                            {
                                // Get next offset:
                                nextOffset = *((int *)(buffPtr + offset));

                                // Get change flag:
                                action = *((int *)(buffPtr + offset + 4));

                                // Get filename length (in bytes):
                                nameLength = *((int *)(buffPtr + offset + 8));
                                name       = new String((char *)(buffPtr + offset + 12), 0, nameLength / 2);
                            }


                            /* A slightly convoluted piece of code follows.  Here's what's happening:
                             *
                             * We wish to collapse the poorly done rename notifications from the
                             * ReadDirectoryChangesW API into a nice rename event. So to do that,
                             * it's assumed that a FILE_ACTION_RENAMED_OLD_NAME will be followed
                             * immediately by a FILE_ACTION_RENAMED_NEW_NAME in the buffer, which is
                             * all that the following code is doing.
                             *
                             * On a FILE_ACTION_RENAMED_OLD_NAME, it asserts that no previous one existed
                             * and saves its name.  If there are no more events in the buffer, it'll
                             * assert and fire a RenameEventArgs with the Name field null.
                             *
                             * If a NEW_NAME action comes in with no previous OLD_NAME, we assert and fire
                             * a rename event with the OldName field null.
                             *
                             * If the OLD_NAME and NEW_NAME actions are indeed there one after the other,
                             * we'll fire the RenamedEventArgs normally and clear oldName.
                             *
                             * If the OLD_NAME is followed by another action, we assert and then fire the
                             * rename event with the Name field null and then fire the next action.
                             *
                             * In case it's not a OLD_NAME or NEW_NAME action, we just fire the event normally.
                             *
                             * (Phew!)
                             */

                            // If the action is RENAMED_FROM, save the name of the file
                            if (action == Direct.FILE_ACTION_RENAMED_OLD_NAME)
                            {
                                Debug.Assert(oldName == null, "FileSystemWatcher: Two FILE_ACTION_RENAMED_OLD_NAME " +
                                             "in a row!  [" + oldName + "], [ " + name + "]");

                                oldName = name;
                            }
                            else if (action == Direct.FILE_ACTION_RENAMED_NEW_NAME)
                            {
                                if (oldName != null)
                                {
                                    NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                                    oldName = null;
                                }
                                else
                                {
                                    Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_NEW_NAME with no" +
                                                 "old name! [ " + name + "]");

                                    NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                                    oldName = null;
                                }
                            }
                            else
                            {
                                if (oldName != null)
                                {
                                    NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                                    oldName = null;
                                }

                                // Notify each file of change
                                NotifyFileSystemEventArgs(action, name);
                            }

                            offset += nextOffset;
                        } while (nextOffset != 0);

                        if (oldName != null)
                        {
                            Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" +
                                         "new name!  [" + oldName + "]");

                            NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                            oldName = null;
                        }
                    }
                }
            }
            finally {
                Overlapped.Free(overlappedPointer);
                if (!stopListening && !runOnce)
                {
                    Monitor(asyncResult.buffer);
                }
            }
        }
Example #2
0
        private unsafe void Monitor(byte[] buffer)
        {
            if (!enabled || IsHandleInvalid)
            {
                return;
            }

            Overlapped overlapped = new Overlapped();

            if (buffer == null)
            {
                try {
                    buffer = new byte[internalBufferSize];
                }
                catch (OutOfMemoryException) {
                    throw new OutOfMemoryException(SR.GetString(SR.BufferSizeTooLarge, internalBufferSize.ToString(CultureInfo.CurrentCulture)));
                }
            }

            // Pass "session" counter to callback:
            FSWAsyncResult asyncResult = new FSWAsyncResult();

            asyncResult.session = currentSession;
            asyncResult.buffer  = buffer;

            // Pack overlapped. The buffer will be pinned by Overlapped:
            overlapped.AsyncResult = asyncResult;
            NativeOverlapped *overlappedPointer = overlapped.Pack(new IOCompletionCallback(this.CompletionStatusChanged), buffer);

            // Can now call OS:
            int  size;
            bool ok = false;

            try {
                // There could be a ---- in user code between calling StopRaisingEvents (where we close the handle)
                // and when we get here from CompletionStatusChanged.
                // We might need to take a lock to prevent ---- absolutely, instead just catch
                // ObjectDisposedException from SafeHandle in case it is disposed
                if (!IsHandleInvalid)
                {
                    // An interrupt is possible here
                    fixed(byte *buffPtr = buffer)
                    {
                        ok = UnsafeNativeMethods.ReadDirectoryChangesW(directoryHandle,
                                                                       new HandleRef(this, (IntPtr)buffPtr),
                                                                       internalBufferSize,
                                                                       includeSubdirectories ? 1 : 0,
                                                                       (int)notifyFilters,
                                                                       out size,
                                                                       overlappedPointer,
                                                                       NativeMethods.NullHandleRef);
                    }
                }
            } catch (ObjectDisposedException) { //Ignore
                Debug.Assert(IsHandleInvalid, "ObjectDisposedException from something other than SafeHandle?");
            } catch (ArgumentNullException) {   //Ignore
                Debug.Assert(IsHandleInvalid, "ArgumentNullException from something other than SafeHandle?");
            } finally {
                if (!ok)
                {
                    Overlapped.Free(overlappedPointer);

                    // If the handle was for some reason changed or closed during this call, then don't throw an
                    // exception.  Else, it's a valid error.
                    if (!IsHandleInvalid)
                    {
                        OnError(new ErrorEventArgs(new Win32Exception()));
                    }
                }
            }
        }
        private unsafe void Monitor(byte[] buffer) {
            if (!enabled || IsHandleInvalid) {
                return;
            }

            Overlapped overlapped = new Overlapped();            
            if (buffer == null) {
                try {
                    buffer = new byte[internalBufferSize];
                }
                catch (OutOfMemoryException) {
                        throw new OutOfMemoryException(SR.GetString(SR.BufferSizeTooLarge, internalBufferSize.ToString(CultureInfo.CurrentCulture)));
                }
            }
                        
            // Pass "session" counter to callback:
            FSWAsyncResult asyncResult = new FSWAsyncResult();
            asyncResult.session = currentSession;
            asyncResult.buffer = buffer;

            // Pack overlapped. The buffer will be pinned by Overlapped:
            overlapped.AsyncResult = asyncResult;
            NativeOverlapped* overlappedPointer = overlapped.Pack(new IOCompletionCallback(this.CompletionStatusChanged), buffer);

            // Can now call OS:
            int size;
            bool ok = false;

            try {
                // There could be a ---- in user code between calling StopRaisingEvents (where we close the handle) 
                // and when we get here from CompletionStatusChanged. 
                // We might need to take a lock to prevent ---- absolutely, instead just catch 
                // ObjectDisposedException from SafeHandle in case it is disposed
                if (!IsHandleInvalid) {
                    // An interrupt is possible here
                    fixed (byte * buffPtr = buffer) {
                        ok = UnsafeNativeMethods.ReadDirectoryChangesW(directoryHandle,
                                                           new HandleRef(this, (IntPtr) buffPtr),
                                                           internalBufferSize,
                                                           includeSubdirectories ? 1 : 0,
                                                           (int) notifyFilters,
                                                           out size,
                                                           overlappedPointer,
                                                           NativeMethods.NullHandleRef);
                    }
                }
            } catch (ObjectDisposedException ) { //Ignore
                Debug.Assert(IsHandleInvalid, "ObjectDisposedException from something other than SafeHandle?");
            } catch (ArgumentNullException ) { //Ignore
                Debug.Assert(IsHandleInvalid, "ArgumentNullException from something other than SafeHandle?");
            } finally {
                if (! ok) {
                    Overlapped.Free(overlappedPointer);

                    // If the handle was for some reason changed or closed during this call, then don't throw an
                    // exception.  Else, it's a valid error.
                    if (!IsHandleInvalid) {
                        OnError(new ErrorEventArgs(new Win32Exception()));
                    }
                }
            }
        }                            
        /// <devdoc>
        ///     Calls native API and sets up handle with the directory change API.
        /// </devdoc>
        /// <internalonly/>
        private unsafe void Monitor(byte[] buffer)
        {
            if (!_enabled || IsHandleInvalid)
            {
                return;
            }

            if (buffer == null)
            {
                buffer = AllocateBuffer();
            }

            // Pass "session" counter to callback:
            FSWAsyncResult asyncResult = new FSWAsyncResult();
            asyncResult.session = _currentSession;
            asyncResult.buffer = buffer;

            NativeOverlapped* overlappedPointer = _threadPoolBinding.AllocateNativeOverlapped(new IOCompletionCallback(this.CompletionStatusChanged), asyncResult, buffer);

            // Can now call OS:
            int size;
            bool ok = false;

            try
            {
                // There could be a race in user code between calling StopRaisingEvents (where we close the handle)
                // and when we get here from CompletionStatusChanged.
                // We might need to take a lock to prevent race absolutely, instead just catch
                // ObjectDisposedException from SafeHandle in case it is disposed
                if (!IsHandleInvalid)
                {
                    // An interrupt is possible here
                    fixed (byte* buffPtr = buffer)
                    {
                        ok = UnsafeNativeMethods.ReadDirectoryChangesW(_directoryHandle,
                                                           buffPtr,
                                                           _internalBufferSize,
                                                           _includeSubdirectories ? 1 : 0,
                                                           (int)_notifyFilters,
                                                           out size,
                                                           overlappedPointer,
                                                           IntPtr.Zero);
                    }
                }
            }
            catch (ObjectDisposedException)
            { //Ignore
            }
            catch (ArgumentNullException)
            { //Ignore
                Debug.Assert(IsHandleInvalid, "ArgumentNullException from something other than SafeHandle?");
            }
            finally
            {
                if (!ok)
                {
                    _threadPoolBinding.FreeNativeOverlapped(overlappedPointer);

                    // If the handle was for some reason changed or closed during this call, then don't throw an
                    // exception.  Else, it's a valid error.
                    if (!IsHandleInvalid)
                    {
                        OnError(new ErrorEventArgs(new Win32Exception()));
                    }
                }
            }
        }
        /// <devdoc>
        ///     Calls native API and sets up handle with the directory change API.
        /// </devdoc>
        /// <internalonly/>
        private unsafe void Monitor(byte[] buffer)
        {
            if (!_enabled || IsHandleInvalid)
            {
                return;
            }

            if (buffer == null)
            {
                buffer = AllocateBuffer();
            }

            // Pass "session" counter to callback:
            FSWAsyncResult asyncResult = new FSWAsyncResult();

            asyncResult.session = _currentSession;
            asyncResult.buffer  = buffer;

            NativeOverlapped *overlappedPointer = _threadPoolBinding.AllocateNativeOverlapped(new IOCompletionCallback(this.CompletionStatusChanged), asyncResult, buffer);

            // Can now call OS:
            int  size;
            bool ok = false;

            try
            {
                // There could be a race in user code between calling StopRaisingEvents (where we close the handle)
                // and when we get here from CompletionStatusChanged.
                // We might need to take a lock to prevent race absolutely, instead just catch
                // ObjectDisposedException from SafeHandle in case it is disposed
                if (!IsHandleInvalid)
                {
                    // An interrupt is possible here
                    fixed(byte *buffPtr = buffer)
                    {
                        ok = UnsafeNativeMethods.ReadDirectoryChangesW(_directoryHandle,
                                                                       buffPtr,
                                                                       _internalBufferSize,
                                                                       _includeSubdirectories ? 1 : 0,
                                                                       (int)_notifyFilters,
                                                                       out size,
                                                                       overlappedPointer,
                                                                       IntPtr.Zero);
                    }
                }
            }
            catch (ObjectDisposedException)
            { //Ignore
            }
            catch (ArgumentNullException)
            { //Ignore
                Debug.Assert(IsHandleInvalid, "ArgumentNullException from something other than SafeHandle?");
            }
            finally
            {
                if (!ok)
                {
                    _threadPoolBinding.FreeNativeOverlapped(overlappedPointer);

                    // If the handle was for some reason changed or closed during this call, then don't throw an
                    // exception.  Else, it's a valid error.
                    if (!IsHandleInvalid)
                    {
                        OnError(new ErrorEventArgs(new Win32Exception()));
                    }
                }
            }
        }
Example #6
0
        private unsafe void Monitor(byte[] buffer)
        {
            if (this.enabled && !this.IsHandleInvalid)
            {
                Overlapped overlapped = new Overlapped();
                if (buffer == null)
                {
                    try
                    {
                        buffer = new byte[this.internalBufferSize];
                    }
                    catch (OutOfMemoryException)
                    {
                        throw new OutOfMemoryException(SR.GetString("BufferSizeTooLarge", new object[] { this.internalBufferSize.ToString(CultureInfo.CurrentCulture) }));
                    }
                }
                FSWAsyncResult result = new FSWAsyncResult {
                    session = this.currentSession,
                    buffer  = buffer
                };
                overlapped.AsyncResult = result;
                NativeOverlapped *overlappedPointer = overlapped.Pack(new IOCompletionCallback(this.CompletionStatusChanged), buffer);
                bool flag = false;
                try
                {
                    if (!this.IsHandleInvalid)
                    {
                        try
                        {
                            byte[] buffer2;
                            if (((buffer2 = buffer) == null) || (buffer2.Length == 0))
                            {
                                numRef = null;
                                goto Label_00B3;
                            }
                            fixed(byte *numRef = buffer2)
                            {
                                int num;

Label_00B3:
                                flag = Microsoft.Win32.UnsafeNativeMethods.ReadDirectoryChangesW(this.directoryHandle, new HandleRef(this, (IntPtr)numRef), this.internalBufferSize, this.includeSubdirectories ? 1 : 0, (int)this.notifyFilters, out num, overlappedPointer, Microsoft.Win32.NativeMethods.NullHandleRef);
                            }
                        }
                        finally
                        {
                            numRef = null;
                        }
                    }
                }
                catch (ObjectDisposedException)
                {
                }
                catch (ArgumentNullException)
                {
                }
                finally
                {
                    if (!flag)
                    {
                        Overlapped.Free(overlappedPointer);
                        if (!this.IsHandleInvalid)
                        {
                            this.OnError(new ErrorEventArgs(new Win32Exception()));
                        }
                    }
                }
            }
        }
Example #7
0
        private unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped *overlappedPointer)
        {
            FSWAsyncResult asyncResult = (FSWAsyncResult)Overlapped.Unpack(overlappedPointer).AsyncResult;

            try
            {
                if (!this.stopListening)
                {
                    lock (this)
                    {
                        if (errorCode != 0)
                        {
                            if (errorCode != 0x3e3)
                            {
                                this.OnError(new ErrorEventArgs(new Win32Exception((int)errorCode)));
                                this.EnableRaisingEvents = false;
                            }
                        }
                        else if (asyncResult.session == this.currentSession)
                        {
                            if (numBytes == 0)
                            {
                                this.NotifyInternalBufferOverflowEvent();
                            }
                            else
                            {
                                int    num2;
                                int    index   = 0;
                                string oldName = null;
                                string name    = null;
                                do
                                {
                                    int num3;
                                    try
                                    {
                                        fixed(byte *numRef = asyncResult.buffer)
                                        {
                                            num2 = numRef[index];
                                            num3 = (numRef + index)[4];
                                            int num4 = (numRef + index)[8];

                                            name = new string((char *)((numRef + index) + 12), 0, num4 / 2);
                                        }
                                    }
                                    finally
                                    {
                                        numRef = null;
                                    }
                                    switch (num3)
                                    {
                                    case 4:
                                        oldName = name;
                                        break;

                                    case 5:
                                        if (oldName != null)
                                        {
                                            this.NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                                            oldName = null;
                                        }
                                        else
                                        {
                                            this.NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                                            oldName = null;
                                        }
                                        break;

                                    default:
                                        if (oldName != null)
                                        {
                                            this.NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                                            oldName = null;
                                        }
                                        this.NotifyFileSystemEventArgs(num3, name);
                                        break;
                                    }
                                    index += num2;
                                }while (num2 != 0);
                                if (oldName != null)
                                {
                                    this.NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                                    oldName = null;
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                Overlapped.Free(overlappedPointer);
                if (!this.stopListening && !this.runOnce)
                {
                    this.Monitor(asyncResult.buffer);
                }
            }
        }