Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
Эксперт WindowsАвтор FAQ
17663 / 7507 / 887
Регистрация: 25.12.2011
Сообщений: 11,278
Записей в блоге: 16
1

Асинхронное ожидание множества событий файловых операций (пример для класса от The Trick)

09.12.2014, 00:04. Показов 2714. Ответов 31
Метки нет (Все метки)

Написал пример для использования vbWaitForMultipleObjects для мониторинга множества папок с помощью этого класса.
Видимо неправильно передаю указатель на массив хендлов событий,
ибо начинает сыпатся куча уведомлений с пустым именем файлов.

The Trick, можешь, пожалуйста, как освободишься, посмотреть?

И еще, как в Callback процедуре получить код возврата WaitForMultipleObjects,
чтобы узнать от которого из событий пришло уведомление?

Кликните здесь для просмотра всего текста

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
Option Explicit
 
Private Const MAX_PATH As Long = 260&
 
Private Type OVERLAPPED
    Internal        As Long
    InternalHigh    As Long
    offset          As Long
    OffsetHigh      As Long
    hEvent          As Long
End Type
 
Private Type FILE_NOTIFY_INFORMATION
    dwNextEntryOffset           As Long
    dwAction                    As Long
    dwFileNameLength            As Long
    wcFileName(MAX_PATH * 2)    As Byte
End Type
 
Private Type bufEvents_TYPE
    bufEvent() As Long   ' Буфер уведомлений для мониторинга файлов
End Type
 
Private Declare Function ReadDirectoryChanges Lib "kernel32.dll" Alias "ReadDirectoryChangesW" (ByVal hDirectory As Long, lpBuffer As Any, ByVal nBufferLength As Long, ByVal bWatchSubTree As Long, ByVal dwNotifyFilter As Long, ByVal lpBytesReturned As Long, lpOverlapped As Any, ByVal lpCompletionRoutine As Long) As Long
Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileW" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CancelIo Lib "kernel32" (ByVal hFile As Long) As Long
Private Declare Function CreateEvent Lib "kernel32" Alias "CreateEventW" (ByVal lpEventAttributes As Long, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As Long) As Long
Private Declare Function ResetEvent Lib "kernel32" (ByVal hEvent As Long) As Long
Private Declare Function memcpy Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (pArr() As Any) As Long
 
Private Const SYNCHRONIZE                   As Long = &H100000
Private Const INFINITE                      As Long = -1
Private Const WAIT_OBJECT_0                 As Long = 0
Private Const FILE_LIST_DIRECTORY           As Long = &H1
Private Const FILE_SHARE_DELETE             As Long = &H4
Private Const FILE_SHARE_READ               As Long = &H1
Private Const FILE_SHARE_WRITE              As Long = &H2
Private Const FILE_FLAG_BACKUP_SEMANTICS    As Long = &H2000000
Private Const FILE_FLAG_OVERLAPPED          As Long = &H40000000
Private Const OPEN_EXISTING                 As Long = &H3
Private Const INVALID_HANDLE_VALUE          As Long = -1
Private Const FILE_NOTIFY_CHANGE_FILE_NAME  As Long = 1
Private Const FILE_ACTION_ADDED             As Long = &H1
Private Const FILE_ACTION_REMOVED           As Long = &H2
Private Const FILE_ACTION_RENAMED_OLD_NAME  As Long = &H4
Private Const FILE_ACTION_RENAMED_NEW_NAME  As Long = &H5
 
Dim WithEvents mon  As clsTrickWait ' Объект событий мониторинга файлов
 
Dim hDirectory() As Long     ' Описатель мониторящейся директории
Dim hEvent()     As Long     ' Описатель события для мониторящейся директории
Dim EventIDs     As Long     ' Кол-во успешно созданных событий
Dim ovr()        As OVERLAPPED
Dim Events()     As bufEvents_TYPE
 
Private Sub Command1_Click()
    Unload Me
End Sub
 
Private Sub Form_Load()
    Dim Folders(0) As String
      
    Folders(0) = "c:\rsit"
    Folders(1) = "c:\windows"
    
    BeginMonitor Folders()
End Sub
 
Private Sub BeginMonitor(Folders() As String)
    Dim i        As Long
    Dim FCnt     As Long
    
    ' Создаем объект для уведомлений
    Set mon = New clsTrickWait
    
    FCnt = UBound(Folders)
    
    ReDim hDirectory(FCnt)
    ReDim hEvent(FCnt)
    ReDim Events(FCnt)
    ReDim ovr(FCnt)
    
    For i = 0 To FCnt
        ' Открываем директорию для мониторинга
        hDirectory(EventIDs) = CreateFile(StrPtr(Folders(i)), FILE_LIST_DIRECTORY, FILE_SHARE_READ Or FILE_SHARE_WRITE Or FILE_SHARE_DELETE, _
                        ByVal 0&, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS Or FILE_FLAG_OVERLAPPED, 0)
                        
        ' При ошибке уведомляем и выходим
        If hDirectory(EventIDs) = INVALID_HANDLE_VALUE Then
            Debug.Print "Cannot get a handle of directory: " & Folders(i)
        Else
            ' Создаем событие для уведомления
            hEvent(EventIDs) = CreateEvent(0, True, True, 0)
            ' При ошибке уведомляем и выходим
            If hEvent(EventIDs) = 0 Then
                CloseHandle hDirectory(EventIDs):   hDirectory(EventIDs) = 0
                Debug.Print "Error create notify event for: " & Folders(i)
            Else
                ' Заполняем структуру OVERLAPPED для асинхронного вызова
                ovr(EventIDs).hEvent = hEvent(EventIDs)
                
                ReDim Events(EventIDs).bufEvent(16383) As Long
                
                ' начинаем мониторить в асинхронном режиме
                If ReadDirectoryChanges(hDirectory(EventIDs), Events(EventIDs).bufEvent(0), UBound(Events(i).bufEvent) + 1, False, FILE_NOTIFY_CHANGE_FILE_NAME, 0&, ovr(EventIDs), 0&) = 0 Then
                    ' При ошибке  уведомляем и выходим
                    Debug.Print "Error start monitor of: " & Folders(i)
                    CloseHandle hEvent(EventIDs):     hEvent(EventIDs) = 0
                    CloseHandle hDirectory(EventIDs): hDirectory(EventIDs) = 0
                Else
                    ' увеличиваем счетчик успешно созданных событий
                    EventIDs = EventIDs + 1
                End If
            End If
        End If
    Next
    ' урезаем массив событий до кол-ва успешно созданных
    ReDim Preserve hEvent(EventIDs - 1)
    
    ' Если хоть одно событие было успешно создано
    If hEvent(0) Then
        ' Запускаем асинхронное уведомление для всех созданных событий
        mon.vbWaitForMultipleObjects UBound(hEvent) + 1, ArrPtr(hEvent), 0&, INFINITE
    End If
    
End Sub
 
' // Событие возникает при изменениях в директории на которые мы подписаны
Private Sub mon_OnWait(ByVal Handle As Long, ByVal Result As Long)
    Dim notify  As FILE_NOTIFY_INFORMATION
    Dim OBJ_idx As Long
    Dim idx     As Long
    Dim name    As String
    
    OBJ_idx = WAIT_OBJECT_0 'Result ' !!! <--- Должен быть индекс отслеживаемого события
    
    ' Проход по буферу уведомлений
    Do
        ' Копируем во временную структуру уведомление
        ' Здесь правильнее сделать через указатели, но для примера я оставил так (более понятно)
        memcpy notify, Events(OBJ_idx).bufEvent(idx), Len(notify)
        ' Узнаем имя файла
        name = Chr$(34) & Left$(notify.wcFileName, notify.dwFileNameLength \ 2) & Chr$(34)
        ' Проверяем тип уведомления
        Select Case notify.dwAction
        Case FILE_ACTION_ADDED:             name = "ADDED: " & name                 ' Файл добавлен
        Case FILE_ACTION_REMOVED:           name = "REMOVED: " & name               ' Файл удален
        Case FILE_ACTION_RENAMED_OLD_NAME:  name = "RENAMED (old name): " & name    ' Файл переименован - это старое имя
        Case FILE_ACTION_RENAMED_NEW_NAME:  name = "RENAMED (new name): " & name    ' Файл переименован - это новое имя
        End Select
        ' Добавить в список
        Debug.Print name
        ' Переход к следующему уведомлению
        idx = idx + notify.dwNextEntryOffset
        ' Пока есть уведомления в буфере повторяем
    Loop While notify.dwNextEntryOffset
    ' Сбрасываем событие
    ResetEvent Handle
    ' Заполняем структуру OVERLAPPED
    ovr(OBJ_idx).hEvent = Handle
    ' Запускаем мониторинг
    Call ReadDirectoryChanges(hDirectory(OBJ_idx), Events(OBJ_idx).bufEvent(0), UBound(Events(OBJ_idx).bufEvent) + 1, False, FILE_NOTIFY_CHANGE_FILE_NAME, 0&, ovr(OBJ_idx), 0&)
    ' Снимаем старое уведомление
    mon.Abort
    ' Запускаем новое
    ' !!! - handle ???
    mon.vbWaitForMultipleObjects UBound(hEvent) + 1, Handle, 0&, INFINITE
End Sub
 
Public Sub EndMonitoring()
    Dim i As Long
    ' Проверяем если директория открыта, то значит останавливаем
    If hDirectory(0) Then
        ' Завершаем ожидание
        mon.Abort
        ' Закрываем описатели события и директории
        For i = 0 To EventIDs - 1
            CloseHandle hEvent(i):     hEvent(i) = 0
            CloseHandle hDirectory(i): hDirectory(i) = 0
        Next
    End If
End Sub
 
Private Sub Form_Unload(Cancel As Integer)
    Dim i As Long
    ' Прервывание ожиданий
    mon.Abort
    ' Если мониторинг
    If hDirectory(0) Then
        For i = 0 To EventIDs - 1
            ' Остановка ожидания мониторинга
            CancelIo hDirectory(i)
            ' Закрываем описатели
            CloseHandle hDirectory(i)
            CloseHandle hEvent(i)
        Next
    End If
End Sub
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.12.2014, 00:04
Ответы с готовыми решениями:

Как создать драйвер для перехвата файловых и реестровых операций
Здравствуйте, уже давно пытаюсь осуществить перехват файловых и реестровых операций. Пришёл к...

Асинхронное ожидание ManualResetEvent
Можно ли как-то не блокируя текущий поток асинхронно ожидать сигнал от ManualResetEvent? ...

Реализация файловых операций с использованием меню
1)Тспользуя команды языка пакетных(.bat) файлов реализовать текстовое меню из 4х пунктов. При...

Программирование файловых операций средствами Windows
Помогите пожалуйста с практикой, WinAPI прослушал :) 1. Создать программу для копирования файлов с...

31
0 / 0 / 0
Регистрация: 13.10.2016
Сообщений: 15
18.06.2017, 13:07 21
Dragokas, благодарю!
Но Вы уверены, что это работает при удалении?
Проблема именно в определении при удалении того или другого...
Ваш код не работает в данном случае...
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

oh my god
1447 / 786 / 161
Регистрация: 05.01.2016
Сообщений: 2,307
Записей в блоге: 8
18.06.2017, 13:28 22
А ведь у меня тоже не все работает из предложенного, я вижу что вы уже полгода про это говорите
иногда, что греха таить проверял у себя что это..... ?
но может оно мне и не надо-было, но хотябы объясните мне почему XP не поддерживает некоторые примеры ?
а с ХП я уходить не собираюсь, если есть пример для хп то тогда сделайте его чтобы хотябы мы поняли др друга
0
Эксперт WindowsАвтор FAQ
17663 / 7507 / 887
Регистрация: 25.12.2011
Сообщений: 11,278
Записей в блоге: 16
19.06.2017, 00:04  [ТС] 23
Цитата Сообщение от LongSword Посмотреть сообщение
Dragokas, благодарю!
Но Вы уверены, что это работает при удалении?
Проблема именно в определении при удалении того или другого...
Ваш код не работает в данном случае...
Уверен.
Неужели так сложно просто скопировать и вставить указанные строчки.
Выкладывайте свой проект. Напишите какая ОС.

Добавлено через 1 минуту
fever brain, вместо того, чтобы ныть, попробовали бы сами разобраться. А то рассуждаете как бабка в программировании.
0
0 / 0 / 0
Регистрация: 13.10.2016
Сообщений: 15
21.06.2017, 21:52 24
Да нет конечно, не сложно.
Для чистоты эксперимента я взял чистый проект от The trick и добавил туда...
При удалении файла или каталога - всегда распознается как каталог.
ОС - Win 7 Prof x64

Стоит ли сюда постить этот проект?
Попробуйте у себя с чистым проектом и своим кодом...
0
Эксперт WindowsАвтор FAQ
17663 / 7507 / 887
Регистрация: 25.12.2011
Сообщений: 11,278
Записей в блоге: 16
22.06.2017, 17:02  [ТС] 25
Цитата Сообщение от LongSword Посмотреть сообщение
Попробуйте у себя с чистым проектом и своим кодом...
Ну конечно пробовал.
Не от балды же я код написал.

Добавлено через 17 часов 43 минуты
LongSword, я понял, почему распознаётся неверно. Простите, что не поверил сразу.
Дело в том, что после удаления файлового объекта проверять атрубут уже не у кого.
Так что создавайте 2 отдельных экземпляра класса с разными флагами. Один для файлов, другой для папок.
0
0 / 0 / 0
Регистрация: 13.10.2016
Сообщений: 15
24.06.2017, 20:03 26
Dragokas, я и начал разговор потому, что после совета The trick воспользовался советом по атрибутам.
У меня и свой код норм работал... до момента удаления)
И то, что проверять нечего было очевидно. Это я не до конца расписал... и Вы извините.

Я думаю,что работать не будет по атрибутам и с разными экземплярами класса т.к. папка - это тот же файл для системы.
...хотя попробовать можно...вероятность, что будет работать есть)

Где-то вскольз попадалось, что в ReadDirectoryChangesW есть биты по этому делу, но пока не раскопал вообще((
Поэтому и обратился к The trick за помощью...
0
Модератор
8671 / 3208 / 838
Регистрация: 22.02.2013
Сообщений: 4,793
Записей в блоге: 78
24.06.2017, 20:05 27
LongSword, позже отвечу.
0
0 / 0 / 0
Регистрация: 13.10.2016
Сообщений: 15
24.06.2017, 20:08 28
The trick, благодарю!
0
Модератор
8671 / 3208 / 838
Регистрация: 22.02.2013
Сообщений: 4,793
Записей в блоге: 78
24.06.2017, 21:51 29
В общем Dragokas верно написал, только 2 экземпляра класса не к чему создавать. Просто запустить 2 мониторинга с разными флагами для файлов отдельно, для папок отдельно. Потом 2 хендла передать в vbWaitForMultipleObject. В обработчике смотреть уже какой (или оба) хендла инициировать событие и обрабатывать соответствующий буфер.
0
Эксперт WindowsАвтор FAQ
17663 / 7507 / 887
Регистрация: 25.12.2011
Сообщений: 11,278
Записей в блоге: 16
24.06.2017, 23:05  [ТС] 30
Вот проект.
Вывод в консоль отладки.
Можно мониторить сразу несколько разных папок.
0
Вложения
Тип файла: zip Monitor_Folder.zip (12.5 Кб, 15 просмотров)
0 / 0 / 0
Регистрация: 13.10.2016
Сообщений: 15
01.07.2017, 19:51 31
Dragokas, благодарю!
Все норм, работает)

Добавлено через 10 минут
Dragokas, Вы пишите мониторинг нескольких каталогов...
Я так понимаю, что они находятся на разных дисках?
Потому как , если они на одном диске, то достаточно указать корень диска, а далее отлавливать только те каталоги , что нужны...
0
Эксперт WindowsАвтор FAQ
17663 / 7507 / 887
Регистрация: 25.12.2011
Сообщений: 11,278
Записей в блоге: 16
01.07.2017, 19:57  [ТС] 32
Цитата Сообщение от LongSword Посмотреть сообщение
Потому как , если они на одном диске, то достаточно указать корень диска, а далее отлавливать только те каталоги , что нужны...
Можно и так.

Вообще, изначально, мой код был ориентирован на мониторинг только 2 папок (и без подкаталогов). Незачем без необходимости нагружать событийную функцию, если можно "отфильтровать" заранее. Тем более для системного диска, где постоянно изменяются какие-то временные файлы.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.07.2017, 19:57

Ноутбук сильно тормозит во время выполнения файловых операций
Когда на ноутбуке выполняется длительная файловая операция, например, копирование большого...

Что такое синхронное и асинхронное выполнение операций
Объясните пожалуйста, что такое синхронное и асинхронное выполнение операций ? :scratch:

Приведите пример класса с методом и конструктором. Создайте экземпляр этого класса. Правильный ли пример?
class Point { int х, у; Point(int х, int у) { this.x = х; this.у = у; } }

Привести примеры профессионального кода процедур-обработчиков событий для операций с файлами
Почти в каждом оконном приложении, в котором есть пункт меню обращения к файлами, требуется...

Ожидание событий
function sq_create(){ if (sq_g_id == undefined) {var sq_g_id = this.id; alert(sq_g_id);} else...

Ожидание одного из событий
Мне надо написать функцию, которая ждет либо когда переменная count будет равна 5 либо определенное...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.