Проблема с состоянием делегата. PreAllocatedOverlapped при изменении папки мониторинга. ⇐ C#
-
Anonymous
Проблема с состоянием делегата. PreAllocatedOverlapped при изменении папки мониторинга.
Привет, сообщество Stack Overflow!
Надеюсь, это сообщение вас застанет. Мы столкнулись с проблемой при разработке приложения под названием «DC Watcher», которое отслеживает изменения локальной файловой системы и уведомляет нас. К сожалению, для папок профилей пользователей он не работает должным образом.
Проблема: После тщательного тестирования и ведения журнала мы определили, что делегат state.PreAllocatedOverlapped (см. предоставленный код) не вызывается при наличии изменений в локальной рабочей области. Похоже, это проблема обратного вызова Windows. Стоит отметить, что приложение отлично работает с непользовательскими папками. Мы используем среду VDI, и у пользователей нет прав администратора. Похоже, это не проблема с разрешениями, поскольку мы можем писать в папку пользователя.
Фрагмент кода: Ниже приведен соответствующий фрагмент кода, в котором мы разместили журналы.
Private void StartRaisingEvents() { Console.WriteLine("внутри StartRaisingEvents"); // Если мы уже работаем, ничего не делайте. если (!IsHandleInvalid(_directoryHandle)) { Console.WriteLine("уровень1 - IsHandleInvalid false"); возвращаться; } // Создаём дескриптор отслеживаемого каталога _directoryHandle = CreateFile( lpFileName: _directory, dwDesiredAccess: FileListDirectory, dwShareMode: (uint)(FileShare.Read | FileShare.Delete | FileShare.Write), lpSecurityAttributes: IntPtr.Zero, dwCreationDisposition: (uint)(FileMode.Open), dwFlagsAndAttributes: BackupSemanticsAndOverlapped, hTemplateFile: IntPtr.Zero); если (IsHandleInvalid(_directoryHandle)) { Console.WriteLine("Уровень2 - IsHandleInvalid true"); _directoryHandle = ноль; создать новое FileNotFoundException(_directory); } // Создаем состояние, связанное с операцией мониторинга направления состояние AsyncReadState; пытаться { Console.WriteLine("StartRaisingEvents 1"); // Начинаем игнорировать все события, которые были инициированы до этого, и // выделяем буфер, который нужно закрепить и использовать на время операции int session = Interlocked.Increment(ref _currentSession); байт[] буфер = AllocateBuffer(); // Сохраняем все состояние, включая предварительно выделенное перекрытие, в объект состояния, который будет // передается от итерации к итерации в течение всего времени выполнения операции. Буфер будет закреплен // с этого момента и до конца операции. состояние = новый AsyncReadState (сессия, буфер, _directoryHandle, ThreadPoolBoundHandle.BindHandle (_directoryHandle), это); Console.WriteLine("StartRaisingEvents 2"); небезопасный { Console.WriteLine("StartRaisingEvents 3"); state.PreAllocatedOverlapped = новый PreAllocatedOverlapped((errorCode, numBytes, OverlappedPointer) => { Console.WriteLine("StartRaisingEvents 4"); Состояние AsyncReadState = (AsyncReadState)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer); state.ThreadPoolBinding.FreeNativeOverlapped(overlappedPointer); если (state.WeakWatcher.TryGetTarget(out FileSystemWatcherEx? наблюдатель)) { наблюдатель.ReadDirectoryChangesCallback(errorCode, numBytes, состояние); } Console.WriteLine("StartRaisingEvents 5"); }, состояние, буфер); если (state.PreAllocatedOverlapped == null) { Console.WriteLine("(state.PreAllocatedOverlapped == null"); } еще { Console.WriteLine("(state.PreAllocatedOverlapped != null"); } Console.WriteLine("StartRaisingEvents 6"); } Console.WriteLine("StartRaisingEvents 7"); } поймать (Исключение ex) { Console.WriteLine("StartRaisingEvents: " + ex.Message); // Убедитесь, что мы не оставляем действительный дескриптор каталога, если мы не работаем _directoryHandle.Dispose(); _directoryHandle = ноль; бросать; } // Начать мониторинг _enabled = правда; Монитор(состояние); } Мы наблюдали различия в результатах при мониторинге пользовательских папок (для C:\Users\ritesh.gadodia\DC) и непользовательских папок (C:\Autodesk).
Различия в выходных данных: При мониторинге пользовательской папки мы наблюдали следующий вывод журнала: «После запуска журнала ничего не записывается при добавлении файлов:
»
Watcher создается для пути C:\Users\ritesh.gadodia\DC внутри StartRaisingEvents StartRaisingEvents 1 StartRaisingEvents 2 Монитор наконец Наблюдатель запущен! нажмите любую клавишу для выхода При мониторинге непользовательской папки вывод журнала был, и все работает правильно:
Watcher создается для пути C:\Autodesk. внутри StartRaisingEvents StartRaisingEvents 1 StartRaisingEvents 2 Монитор наконец Наблюдатель запущен! нажмите любую клавишу для выхода StartRaisingEvents 3 StartRaisingEvents 4 Внутри ReadDirectoryChangesCallback ReadDirectoryChangesCallback => ParseEventBufferAndNotifyForEach Уведомитьфилесистемевентаргс GetHandler создан обработчик != ноль NotifyFileSystemEventArgs шаг 1 ReadDirectoryChangesCallback => Монитор Монитор наконец Watcher_Created C:\Autodesk\New Text Document.txt StartRaisingEvents 3 StartRaisingEvents 4 Внутри ReadDirectoryChangesCallback ReadDirectoryChangesCallback => ParseEventBufferAndNotifyForEach УведомитьRenameEventArgs ReadDirectoryChangesCallback => Монитор Watcher_Renamed C:\Autodesk\Ganesh.txt Монитор наконец Запрос на помощь: Если у кого-то есть идеи, предложения или опыт работы с подобным сценарием, мы будем очень признательны за вашу помощь.
Привет, сообщество Stack Overflow!
Надеюсь, это сообщение вас застанет. Мы столкнулись с проблемой при разработке приложения под названием «DC Watcher», которое отслеживает изменения локальной файловой системы и уведомляет нас. К сожалению, для папок профилей пользователей он не работает должным образом.
Проблема: После тщательного тестирования и ведения журнала мы определили, что делегат state.PreAllocatedOverlapped (см. предоставленный код) не вызывается при наличии изменений в локальной рабочей области. Похоже, это проблема обратного вызова Windows. Стоит отметить, что приложение отлично работает с непользовательскими папками. Мы используем среду VDI, и у пользователей нет прав администратора. Похоже, это не проблема с разрешениями, поскольку мы можем писать в папку пользователя.
Фрагмент кода: Ниже приведен соответствующий фрагмент кода, в котором мы разместили журналы.
Private void StartRaisingEvents() { Console.WriteLine("внутри StartRaisingEvents"); // Если мы уже работаем, ничего не делайте. если (!IsHandleInvalid(_directoryHandle)) { Console.WriteLine("уровень1 - IsHandleInvalid false"); возвращаться; } // Создаём дескриптор отслеживаемого каталога _directoryHandle = CreateFile( lpFileName: _directory, dwDesiredAccess: FileListDirectory, dwShareMode: (uint)(FileShare.Read | FileShare.Delete | FileShare.Write), lpSecurityAttributes: IntPtr.Zero, dwCreationDisposition: (uint)(FileMode.Open), dwFlagsAndAttributes: BackupSemanticsAndOverlapped, hTemplateFile: IntPtr.Zero); если (IsHandleInvalid(_directoryHandle)) { Console.WriteLine("Уровень2 - IsHandleInvalid true"); _directoryHandle = ноль; создать новое FileNotFoundException(_directory); } // Создаем состояние, связанное с операцией мониторинга направления состояние AsyncReadState; пытаться { Console.WriteLine("StartRaisingEvents 1"); // Начинаем игнорировать все события, которые были инициированы до этого, и // выделяем буфер, который нужно закрепить и использовать на время операции int session = Interlocked.Increment(ref _currentSession); байт[] буфер = AllocateBuffer(); // Сохраняем все состояние, включая предварительно выделенное перекрытие, в объект состояния, который будет // передается от итерации к итерации в течение всего времени выполнения операции. Буфер будет закреплен // с этого момента и до конца операции. состояние = новый AsyncReadState (сессия, буфер, _directoryHandle, ThreadPoolBoundHandle.BindHandle (_directoryHandle), это); Console.WriteLine("StartRaisingEvents 2"); небезопасный { Console.WriteLine("StartRaisingEvents 3"); state.PreAllocatedOverlapped = новый PreAllocatedOverlapped((errorCode, numBytes, OverlappedPointer) => { Console.WriteLine("StartRaisingEvents 4"); Состояние AsyncReadState = (AsyncReadState)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer); state.ThreadPoolBinding.FreeNativeOverlapped(overlappedPointer); если (state.WeakWatcher.TryGetTarget(out FileSystemWatcherEx? наблюдатель)) { наблюдатель.ReadDirectoryChangesCallback(errorCode, numBytes, состояние); } Console.WriteLine("StartRaisingEvents 5"); }, состояние, буфер); если (state.PreAllocatedOverlapped == null) { Console.WriteLine("(state.PreAllocatedOverlapped == null"); } еще { Console.WriteLine("(state.PreAllocatedOverlapped != null"); } Console.WriteLine("StartRaisingEvents 6"); } Console.WriteLine("StartRaisingEvents 7"); } поймать (Исключение ex) { Console.WriteLine("StartRaisingEvents: " + ex.Message); // Убедитесь, что мы не оставляем действительный дескриптор каталога, если мы не работаем _directoryHandle.Dispose(); _directoryHandle = ноль; бросать; } // Начать мониторинг _enabled = правда; Монитор(состояние); } Мы наблюдали различия в результатах при мониторинге пользовательских папок (для C:\Users\ritesh.gadodia\DC) и непользовательских папок (C:\Autodesk).
Различия в выходных данных: При мониторинге пользовательской папки мы наблюдали следующий вывод журнала: «После запуска журнала ничего не записывается при добавлении файлов:
»
Watcher создается для пути C:\Users\ritesh.gadodia\DC внутри StartRaisingEvents StartRaisingEvents 1 StartRaisingEvents 2 Монитор наконец Наблюдатель запущен! нажмите любую клавишу для выхода При мониторинге непользовательской папки вывод журнала был, и все работает правильно:
Watcher создается для пути C:\Autodesk. внутри StartRaisingEvents StartRaisingEvents 1 StartRaisingEvents 2 Монитор наконец Наблюдатель запущен! нажмите любую клавишу для выхода StartRaisingEvents 3 StartRaisingEvents 4 Внутри ReadDirectoryChangesCallback ReadDirectoryChangesCallback => ParseEventBufferAndNotifyForEach Уведомитьфилесистемевентаргс GetHandler создан обработчик != ноль NotifyFileSystemEventArgs шаг 1 ReadDirectoryChangesCallback => Монитор Монитор наконец Watcher_Created C:\Autodesk\New Text Document.txt StartRaisingEvents 3 StartRaisingEvents 4 Внутри ReadDirectoryChangesCallback ReadDirectoryChangesCallback => ParseEventBufferAndNotifyForEach УведомитьRenameEventArgs ReadDirectoryChangesCallback => Монитор Watcher_Renamed C:\Autodesk\Ganesh.txt Монитор наконец Запрос на помощь: Если у кого-то есть идеи, предложения или опыт работы с подобным сценарием, мы будем очень признательны за вашу помощь.
Мобильная версия