| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | 
							- /////////////////////////////////////////////////////////////////////////////
 
- // Name:        wx/msw/private/fswatcher.h
 
- // Purpose:     File system watcher impl classes
 
- // Author:      Bartosz Bekier
 
- // Created:     2009-05-26
 
- // Copyright:   (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
 
- // Licence:     wxWindows licence
 
- /////////////////////////////////////////////////////////////////////////////
 
- #ifndef WX_MSW_PRIVATE_FSWATCHER_H_
 
- #define WX_MSW_PRIVATE_FSWATCHER_H_
 
- #include "wx/filename.h"
 
- #include "wx/vector.h"
 
- #include "wx/msw/private.h"
 
- // ============================================================================
 
- // wxFSWatcherEntry implementation & helper declarations
 
- // ============================================================================
 
- class wxFSWatcherImplMSW;
 
- class wxFSWatchEntryMSW : public wxFSWatchInfo
 
- {
 
- public:
 
-     enum
 
-     {
 
-         BUFFER_SIZE = 4096   // TODO parametrize
 
-     };
 
-     wxFSWatchEntryMSW(const wxFSWatchInfo& winfo) :
 
-         wxFSWatchInfo(winfo)
 
-     {
 
-         // get handle for this path
 
-         m_handle = OpenDir(m_path);
 
-         m_overlapped = (OVERLAPPED*)calloc(1, sizeof(OVERLAPPED));
 
-         wxZeroMemory(m_buffer);
 
-     }
 
-     virtual ~wxFSWatchEntryMSW()
 
-     {
 
-         wxLogTrace(wxTRACE_FSWATCHER, "Deleting entry '%s'", m_path);
 
-         if (m_handle != INVALID_HANDLE_VALUE)
 
-         {
 
-             if (!CloseHandle(m_handle))
 
-             {
 
-                 wxLogSysError(_("Unable to close the handle for '%s'"),
 
-                                 m_path);
 
-             }
 
-         }
 
-         free(m_overlapped);
 
-     }
 
-     bool IsOk() const
 
-     {
 
-         return m_handle != INVALID_HANDLE_VALUE;
 
-     }
 
-     HANDLE GetHandle() const
 
-     {
 
-         return m_handle;
 
-     }
 
-     void* GetBuffer()
 
-     {
 
-         return m_buffer;
 
-     }
 
-     OVERLAPPED* GetOverlapped() const
 
-     {
 
-         return m_overlapped;
 
-     }
 
- private:
 
-     // opens dir with all flags, attributes etc. necessary to be later
 
-     // asynchronous watched with ReadDirectoryChangesW
 
-     static HANDLE OpenDir(const wxString& path)
 
-     {
 
-         HANDLE handle = CreateFile(path.t_str(),
 
-                                    FILE_LIST_DIRECTORY,
 
-                                    FILE_SHARE_READ |
 
-                                    FILE_SHARE_WRITE |
 
-                                    FILE_SHARE_DELETE,
 
-                                    NULL,
 
-                                    OPEN_EXISTING,
 
-                                    FILE_FLAG_BACKUP_SEMANTICS |
 
-                                    FILE_FLAG_OVERLAPPED,
 
-                                    NULL);
 
-         if (handle == INVALID_HANDLE_VALUE)
 
-         {
 
-             wxLogSysError(_("Failed to open directory \"%s\" for monitoring."),
 
-                             path);
 
-         }
 
-         return handle;
 
-     }
 
-     HANDLE m_handle;             // handle to opened directory
 
-     char m_buffer[BUFFER_SIZE];  // buffer for fs events
 
-     OVERLAPPED* m_overlapped;
 
-     wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryMSW);
 
- };
 
- // ============================================================================
 
- // wxFSWatcherImplMSW helper classes implementations
 
- // ============================================================================
 
- class wxIOCPService
 
- {
 
- public:
 
-     wxIOCPService() :
 
-         m_iocp(INVALID_HANDLE_VALUE)
 
-     {
 
-         Init();
 
-     }
 
-     ~wxIOCPService()
 
-     {
 
-         if (m_iocp != INVALID_HANDLE_VALUE)
 
-         {
 
-             if (!CloseHandle(m_iocp))
 
-             {
 
-                 wxLogSysError(_("Unable to close I/O completion port handle"));
 
-             }
 
-         }
 
-         m_watches.clear();
 
-     }
 
-     // associates a wxFSWatchEntryMSW with completion port
 
-     bool Add(wxSharedPtr<wxFSWatchEntryMSW> watch)
 
-     {
 
-         wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
 
-         wxCHECK_MSG( watch->IsOk(), false, "Invalid watch" );
 
-         // associate with IOCP
 
-         HANDLE ret = CreateIoCompletionPort(watch->GetHandle(), m_iocp,
 
-                                             (ULONG_PTR)watch.get(), 0);
 
-         if (ret == NULL)
 
-         {
 
-             wxLogSysError(_("Unable to associate handle with "
 
-                             "I/O completion port"));
 
-             return false;
 
-         }
 
-         else if (ret != m_iocp)
 
-         {
 
-             wxFAIL_MSG(_("Unexpectedly new I/O completion port was created"));
 
-             return false;
 
-         }
 
-         // add to watch map
 
-         wxFSWatchEntries::value_type val(watch->GetPath(), watch);
 
-         return m_watches.insert(val).second;
 
-     }
 
-     // Removes a watch we're currently using. Notice that this doesn't happen
 
-     // immediately, CompleteRemoval() must be called later when it's really
 
-     // safe to delete the watch, i.e. after completion of the IO operation
 
-     // using it.
 
-     bool ScheduleForRemoval(const wxSharedPtr<wxFSWatchEntryMSW>& watch)
 
-     {
 
-         wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
 
-         wxCHECK_MSG( watch->IsOk(), false, "Invalid watch" );
 
-         const wxString path = watch->GetPath();
 
-         wxFSWatchEntries::iterator it = m_watches.find(path);
 
-         wxCHECK_MSG( it != m_watches.end(), false,
 
-                      "Can't remove a watch we don't use" );
 
-         // We can't just delete the watch here as we can have pending events
 
-         // for it and if we destroyed it now, we could get a dangling (or,
 
-         // worse, reused to point to another object) pointer in ReadEvents() so
 
-         // just remember that this one should be removed when CompleteRemoval()
 
-         // is called later.
 
-         m_removedWatches.push_back(watch);
 
-         m_watches.erase(it);
 
-         return true;
 
-     }
 
-     // Really remove the watch previously passed to ScheduleForRemoval().
 
-     //
 
-     // It's ok to call this for a watch that hadn't been removed before, in
 
-     // this case we'll just return false and do nothing.
 
-     bool CompleteRemoval(wxFSWatchEntryMSW* watch)
 
-     {
 
-         for ( Watches::iterator it = m_removedWatches.begin();
 
-               it != m_removedWatches.end();
 
-               ++it )
 
-         {
 
-             if ( (*it).get() == watch )
 
-             {
 
-                 // Removing the object from here will result in deleting the
 
-                 // watch itself as it's not referenced from anywhere else now.
 
-                 m_removedWatches.erase(it);
 
-                 return true;
 
-             }
 
-         }
 
-         return false;
 
-     }
 
-     // post completion packet
 
-     bool PostEmptyStatus()
 
-     {
 
-         wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, false, "IOCP not init" );
 
-         // The special values of 0 will make GetStatus() return Status_Exit.
 
-         int ret = PostQueuedCompletionStatus(m_iocp, 0, 0, NULL);
 
-         if (!ret)
 
-         {
 
-             wxLogSysError(_("Unable to post completion status"));
 
-         }
 
-         return ret != 0;
 
-     }
 
-     // Possible return values of GetStatus()
 
-     enum Status
 
-     {
 
-         // Status successfully retrieved into the provided arguments.
 
-         Status_OK,
 
-         // Special status indicating that we should exit retrieved.
 
-         Status_Exit,
 
-         // An error occurred because the watched directory was deleted.
 
-         Status_Deleted,
 
-         // Some other error occurred.
 
-         Status_Error
 
-     };
 
-     // Wait for completion status to arrive.
 
-     // This function can block forever in it's wait for completion status.
 
-     // Use PostEmptyStatus() to wake it up (and end the worker thread)
 
-     Status
 
-     GetStatus(DWORD* count, wxFSWatchEntryMSW** watch,
 
-               OVERLAPPED** overlapped)
 
-     {
 
-         wxCHECK_MSG( m_iocp != INVALID_HANDLE_VALUE, Status_Error,
 
-                      "Invalid IOCP object" );
 
-         wxCHECK_MSG( count && watch && overlapped, Status_Error,
 
-                      "Output parameters can't be NULL" );
 
-         int ret = GetQueuedCompletionStatus(m_iocp, count, (ULONG_PTR *)watch,
 
-                                             overlapped, INFINITE);
 
-         if ( ret != 0 )
 
-         {
 
-             return *count || *watch || *overlapped ? Status_OK : Status_Exit;
 
-         }
 
-         // An error is returned if the underlying directory has been deleted,
 
-         // but this is not really an unexpected failure, so handle it
 
-         // specially.
 
-         if ( wxSysErrorCode() == ERROR_ACCESS_DENIED &&
 
-                 *watch && !wxFileName::DirExists((*watch)->GetPath()) )
 
-             return Status_Deleted;
 
-         // Some other error, at least log it.
 
-         wxLogSysError(_("Unable to dequeue completion packet"));
 
-         return Status_Error;
 
-     }
 
- protected:
 
-     bool Init()
 
-     {
 
-         m_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
 
-         if (m_iocp == NULL)
 
-         {
 
-             wxLogSysError(_("Unable to create I/O completion port"));
 
-         }
 
-         return m_iocp != NULL;
 
-     }
 
-     HANDLE m_iocp;
 
-     // The hash containing all the wxFSWatchEntryMSW objects currently being
 
-     // watched keyed by their paths.
 
-     wxFSWatchEntries m_watches;
 
-     // Contains the watches which had been removed but are still pending.
 
-     typedef wxVector< wxSharedPtr<wxFSWatchEntryMSW> > Watches;
 
-     Watches m_removedWatches;
 
- };
 
- class wxIOCPThread : public wxThread
 
- {
 
- public:
 
-     wxIOCPThread(wxFSWatcherImplMSW* service, wxIOCPService* iocp);
 
-     // finishes this thread
 
-     bool Finish();
 
- protected:
 
-     // structure to hold information needed to process one native event
 
-     // this is just a dummy holder, so it doesn't take ownership of it's data
 
-     struct wxEventProcessingData
 
-     {
 
-         wxEventProcessingData(const FILE_NOTIFY_INFORMATION* ne,
 
-                               const wxFSWatchEntryMSW* watch) :
 
-             nativeEvent(ne), watch(watch)
 
-         {}
 
-         const FILE_NOTIFY_INFORMATION* nativeEvent;
 
-         const wxFSWatchEntryMSW* watch;
 
-     };
 
-     virtual ExitCode Entry();
 
-     // wait for events to occur, read them and send to interested parties
 
-     // returns false it empty status was read, which means we whould exit
 
-     //         true otherwise
 
-     bool ReadEvents();
 
-     void ProcessNativeEvents(wxVector<wxEventProcessingData>& events);
 
-     void SendEvent(wxFileSystemWatcherEvent& evt);
 
-     static int Native2WatcherFlags(int flags);
 
-     static wxString FileNotifyInformationToString(
 
-                                             const FILE_NOTIFY_INFORMATION& e);
 
-     static wxFileName GetEventPath(const wxFSWatchEntryMSW& watch,
 
-                                    const FILE_NOTIFY_INFORMATION& e);
 
-     wxFSWatcherImplMSW* m_service;
 
-     wxIOCPService* m_iocp;
 
- };
 
- #endif /* WX_MSW_PRIVATE_FSWATCHER_H_ */
 
 
  |