Introduction
This article is about how we can notify our application that a file has been changed by another application.
I've created the CFileChangeEvent
-class for it. It has the following methods:
void addFile(const std::string &sFileName)
Use this method when you want to be notified of changes of a file. When the notification thread is running, it will be stopped and restarted.
void removeFile(const std::string &sFileName)
Use this method when you don't want to be notified anymore. When the notification thread is running, it will be stopped and restarted.
void startWatch(void)
This method starts the notification thread.
void stopWatch(void)
This method stops the notification thread. It's also called in the destructor, so you know the thread will always stop.
virtual void OnFileAlarm(FileAlarm nAlarm, const std::string &sFileName)
Override this method. This method is called when a file is changed or deleted. FileAlarm
is an enum
with following attributes: FA_CHANGED
, FA_REMOVED
, FA_CREATED
.
How to use this class ?
Derive a class (for example your CDocument
-class) from CFileChangeEvent
and override the OnFileAlarm
. That's all.
Warning: You can't call the method UpdateAllViews
in the OnFileAlarm
. This is why:
A thread can access only MFC objects that it created. This is because temporary and permanent Windows handle maps are kept in thread local storage to ensure protection from simultaneous access from multiple threads.
How can we solve this?
- Pass the individual handles (like
HWND
) rather than C++ objects, to the worker thread. The thread then adds these objects to its temporary map by calling the appropriate FromHandle
member function.
- You can use a new user-defined message corresponding to the different tasks your worker threads will be performing and post these messages to the application's windows/views using
PostMessage
.
- Create a user-defined message with
::RegisterWindowMessage
like this: const UINT msgFileChange = ::RegisterWindowMessage("FILECHANGE");
Put this in the application's header file so that you can use this everywhere in your application
- In your document-class, create a member-variable to hold a pointer to the window you want to process the message.
CView *m_pView;
- In the method called by the thread, post the message to the processing window.
m_pView->PostMessage(msgFileChange);
- In the processing view header file, add the following in the message map functions:
afx_msg void OnFileChange();
- In the processing view source file, add the following in the message map:
ON_REGISTERED_MESSAGE(msgFileChange, OnFileChange)
- Add the source code for
OnFileChange
in the processing view source file. void CProcessView::OnFileChange()
{
CMyDocument *pDoc = GetDocument();
pDoc->UpdateAllViews();
}