Применение Windows API - страница 20

Шрифт
Интервал

стр.

>class FolderWatcher : public ActiveObject {

>public: FolderWatcher(char const* folder, HWND hwnd) : _notifySource (folder), _hwndNotifySink (hwnd) {

> strcpy(_folder, folder);

>  _thread.Resume();

> }

> ~FolderWatcher() {

>  Kill();

> }

>private:

> void InitThread() {}

> void Loop();

> void FlushThread() {}

> FolderChangeEvent _notifySource;

> HWND _hwndNotifySink;

> char _folder[MAX_PATH];

>};

Все действия в ActiveObject происходят внутри метода Loop. Здесь мы устанавливаем "бесконечный" цикл, в котором поток должен ожидать событие. Когда событие происходит, мы проверяем флажок _isDying (как обычно) и посылаем специальное сообщение WM_FOLDER_CHANGE окну, которое имеет дело с уведомлениями. Это — не предопределенное сообщение Windows. Оно специально определено нами для передачи уведомления о папке от одного потока другому.

Происходит следующее: удерживаемый поток делает другой вызов API, чтобы позволить файловой системе, узнать, что она нуждается в большем количестве уведомлений. Затем управление возвращается к ожидающему потоку, находящемуся в состоянии сна. Одновременно Windows получает наше сообщение WM_FOLDER_CHANGE из очереди сообщений и посылает его оконной процедуре принимающего окна. Подробности чуть позже.

>UINT const WM_FOLDER_CHANGE = WM_USER;


>void FolderWatcher::Loop() {

> for (;;) {

>  // Wait for change notification

>  DWORD waitStatus = WaitForSingleObject(_notifySource, INFINITE);

>  if (WAIT_OBJECT_0 == waitStatus) {

>   // If folder changed

>   if (_isDying) return;

>   PostMessage(_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM)_folder);

>   // Continue change notification

>   if (!_notifySource.ContinueNotification()) {

>    // Error: Continuation failed

>    return;

>   }

>  } else {

>   // Error: Wait failed

>   return;

>  }

> }

>}

Рассмотрим, что происходит в оконной процедуре в ответ на наше специальное сообщение. Мы вызываем метод Контроллера OnFolderChange. Этот метод может делать все, что мы захотим. В Проводнике (Explorer) он регенерирует отображение содержимого папки, которую мы наблюдаем. В нашем примере он только вызывает простое окно сообщения. Обратите внимание, что мы передаем имя измененной папки как LPARAM. Совершенно неважно, как определить WPARAM и LPARAM, в сообщении, определяемом пользователем.

Между прочим, Наблюдатель Папки — только часть Контроллера.

>case WM_FOLDER_CHANGE:

> pCtrl->OnFolderChange(hwnd, (char const *)lParam);

> return 0;


>void Controller::OnFolderChange(HWND hwnd, char const * folder) {

> MessageBox(hwnd, "Change Detected, "Folder Watcher", MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);

>}


>class Controller {

>public:

> Controller(HWND hwnd, CREATESTRUCT * pCreate);

> ~Controller();

> void OnFolderChange(HWND hwnd, char const *folder);

>private:

> FolderWatcher _folderWatcher;

>};

Теперь, когда мы знаем, как иметь дело с уведомлением, давайте взглянем на их источники, События изменяющие файлы. Объект события создан файловой системой в ответ на FindFirstChangeNotification. Дескриптор этого события возвращен из вызова. Мы запоминаем этот дескриптор и используем его позже, чтобы или осуществить восстанавление или отказаться от нашего интереса к дальнейшим уведомлениям. Обратите внимание, что мы можем устанавливать наблююдение рекурсивно, то есть, наблюдать данную папку и все ее подпапки и подподпапки. Мы можем также выражать интерес к специфическим изменениям, передавая поразрядное ИЛИ для любой комбинации следующих флажков:

• FILE_NOTIFY_CHANGE_FILE_NAME (переименование, создание или удаление файла)

• FILE_NOTIFY_CHANGE_DIR_NAME (создание или удаление каталога (папки))

• FILE_NOTIFY_CHANGE_ATTRIBUTES

• FILE_NOTIFY_CHANGE_SIZE

• FILE_NOTIFY_CHANGE_LAST_WRITE (сохранение файла)

• FILE_NOTIFY_CHANGE_SECURITY

Для удобства мы определили несколько подклассов от FileChangeEvent, которые соответствуют к некоторым полезным комбинациям этих флажков. Один из них — FolderChangeEvent, который мы использовали в нашем FolderWatcher.

>class FileChangeEvent {

>public:

> FileChangeEvent(char const *folder, BOOL recursive, DWORD notifyFlags) {

>  _handle = FindFirstChangeNotification(folder, recursive, notifyFlags);


стр.

Похожие книги