1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/msw/private/fswatcher.h
3 // Purpose: File system watcher impl classes
4 // Author: Bartosz Bekier
7 // Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #ifndef WX_MSW_PRIVATE_FSWATCHER_H_
12 #define WX_MSW_PRIVATE_FSWATCHER_H_
14 #include "wx/filename.h"
15 #include "wx/vector.h"
16 #include "wx/msw/private.h"
18 // ============================================================================
19 // wxFSWatcherEntry implementation & helper declarations
20 // ============================================================================
22 class wxFSWatcherImplMSW
;
24 class wxFSWatchEntryMSW
: public wxFSWatchInfo
29 BUFFER_SIZE
= 4096 // TODO parametrize
32 wxFSWatchEntryMSW(const wxFSWatchInfo
& winfo
) :
35 // get handle for this path
36 m_handle
= OpenDir(m_path
);
37 m_overlapped
= (OVERLAPPED
*)calloc(1, sizeof(OVERLAPPED
));
38 wxZeroMemory(m_buffer
);
41 virtual ~wxFSWatchEntryMSW()
43 wxLogTrace(wxTRACE_FSWATCHER
, "Deleting entry '%s'", m_path
);
45 if (m_handle
!= INVALID_HANDLE_VALUE
)
47 if (!CloseHandle(m_handle
))
49 wxLogSysError(_("Unable to close the handle for '%s'"),
58 return m_handle
!= INVALID_HANDLE_VALUE
;
61 HANDLE
GetHandle() const
71 OVERLAPPED
* GetOverlapped() const
77 // opens dir with all flags, attributes etc. necessary to be later
78 // asynchronous watched with ReadDirectoryChangesW
79 static HANDLE
OpenDir(const wxString
& path
)
81 HANDLE handle
= CreateFile(path
, FILE_LIST_DIRECTORY
,
82 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
85 FILE_FLAG_BACKUP_SEMANTICS
|
88 if (handle
== INVALID_HANDLE_VALUE
)
90 wxLogSysError(_("Failed to open directory \"%s\" for monitoring."),
97 HANDLE m_handle
; // handle to opened directory
98 char m_buffer
[BUFFER_SIZE
]; // buffer for fs events
99 OVERLAPPED
* m_overlapped
;
101 wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryMSW
);
105 // ============================================================================
106 // wxFSWatcherImplMSW helper classes implementations
107 // ============================================================================
113 m_iocp(INVALID_HANDLE_VALUE
)
120 if (m_iocp
!= INVALID_HANDLE_VALUE
)
122 if (!CloseHandle(m_iocp
))
124 wxLogSysError(_("Unable to close I/O completion port handle"));
130 // associates a wxFSWatchEntryMSW with completion port
131 bool Add(wxSharedPtr
<wxFSWatchEntryMSW
> watch
)
133 wxCHECK_MSG( m_iocp
!= INVALID_HANDLE_VALUE
, false, "IOCP not init" );
134 wxCHECK_MSG( watch
->IsOk(), false, "Invalid watch" );
136 // associate with IOCP
137 HANDLE ret
= CreateIoCompletionPort(watch
->GetHandle(), m_iocp
,
138 (ULONG_PTR
)watch
.get(), 0);
141 wxLogSysError(_("Unable to associate handle with "
142 "I/O completion port"));
145 else if (ret
!= m_iocp
)
147 wxFAIL_MSG(_("Unexpectedly new I/O completion port was created"));
152 wxFSWatchEntries::value_type
val(watch
->GetPath(), watch
);
153 return m_watches
.insert(val
).second
;
156 // post completion packet
157 bool PostEmptyStatus()
159 wxCHECK_MSG( m_iocp
!= INVALID_HANDLE_VALUE
, false, "IOCP not init" );
161 int ret
= PostQueuedCompletionStatus(m_iocp
, 0, NULL
, NULL
);
164 wxLogSysError(_("Unable to post completion status"));
170 // Wait for completion status to arrive.
171 // This function can block forever in it's wait for completion status.
172 // Use PostEmptyStatus() to wake it up (and end the worker thread)
173 bool GetStatus(unsigned long* count
, wxFSWatchEntryMSW
** watch
,
174 OVERLAPPED
** overlapped
)
176 wxCHECK_MSG( m_iocp
!= INVALID_HANDLE_VALUE
, false, "IOCP not init" );
177 wxCHECK_MSG( count
!= NULL
, false, "Null out parameter 'count'");
178 wxCHECK_MSG( watch
!= NULL
, false, "Null out parameter 'watch'");
179 wxCHECK_MSG( overlapped
!= NULL
, false,
180 "Null out parameter 'overlapped'");
182 int ret
= GetQueuedCompletionStatus(m_iocp
, count
, (PULONG_PTR
)watch
,
183 overlapped
, INFINITE
);
186 wxLogSysError(_("Unable to dequeue completion packet"));
194 m_iocp
= CreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 0);
197 wxLogSysError(_("Unable to create I/O completion port"));
199 return m_iocp
!= NULL
;
203 wxFSWatchEntries m_watches
;
207 class wxIOCPThread
: public wxThread
210 wxIOCPThread(wxFSWatcherImplMSW
* service
, wxIOCPService
* iocp
);
212 // finishes this thread
216 // structure to hold information needed to process one native event
217 // this is just a dummy holder, so it doesn't take ownership of it's data
218 struct wxEventProcessingData
220 wxEventProcessingData(const FILE_NOTIFY_INFORMATION
* ne
,
221 const wxFSWatchEntryMSW
* watch
) :
222 nativeEvent(ne
), watch(watch
)
225 const FILE_NOTIFY_INFORMATION
* nativeEvent
;
226 const wxFSWatchEntryMSW
* watch
;
229 virtual ExitCode
Entry();
231 // wait for events to occur, read them and send to interested parties
232 // returns false it empty status was read, which means we whould exit
236 void ProcessNativeEvents(wxVector
<wxEventProcessingData
>& events
);
238 void SendEvent(wxFileSystemWatcherEvent
& evt
);
240 static int Native2WatcherFlags(int flags
);
242 static wxString
FileNotifyInformationToString(
243 const FILE_NOTIFY_INFORMATION
& e
);
245 static wxFileName
GetEventPath(const wxFSWatchEntryMSW
& watch
,
246 const FILE_NOTIFY_INFORMATION
& e
);
248 wxFSWatcherImplMSW
* m_service
;
249 wxIOCPService
* m_iocp
;
252 #endif /* WX_MSW_PRIVATE_FSWATCHER_H_ */