Jump to content

Filesystem Notification


Recommended Posts

Guest vivekian
Posted

Hi,

 

Writing a small application which requires the application to be

informed when the content / filename / location of a particular file

changes. Is there a Win32 class available which does this ?

 

Thanks in advance,

vivekian

Guest Kellie Fitton
Posted

Re: Filesystem Notification

 

On Apr 7, 3:48 pm, vivekian <vivekase...@gmail.com> wrote:

> Hi,

>

> Writing a small application which requires the application to be

> informed when the  content / filename / location of a particular file

> changes. Is there a Win32 class available which does this ?

>

> Thanks in advance,

> vivekian

 

 

Hi,

 

You can use the following API to retrieve information that

describes the changes within the specified directory:

 

ReadDirectoryChangesW()

 

http://msdn2.microsoft.com/en-us/library/aa365465(VS.85).aspx

 

Kellie.

Guest Michael D. Ober
Posted

Re: Filesystem Notification

 

"Kellie Fitton" <KELLIEFITTON@yahoo.com> wrote in message

news:60ab34b1-ef43-4c37-b1bb-9579e052bbe3@a5g2000prg.googlegroups.com...

On Apr 7, 3:48 pm, vivekian <vivekase...@gmail.com> wrote:

> Hi,

>

> Writing a small application which requires the application to be

> informed when the content / filename / location of a particular file

> changes. Is there a Win32 class available which does this ?

>

> Thanks in advance,

> vivekian

 

 

Take a look at the FindFirstChangeNotification API. In the MSDN library,

the path is Win32 and COM Development -> System Services -> File Services ->

File Systems ->Directory Management -> Using Directory Management ->

Obtaining Directory Change Notifications. If you are coding in dotNet, take

a look at the System.IO.FileSystemWatcher class which is a wrapper for the

FindFirstChangeNotification API functions.

 

Mike.

Guest Eugene Mayevski
Posted

Re: Filesystem Notification

 

Hello!

You wrote on Mon, 7 Apr 2008 15:48:19 -0700 (PDT):

 

v> Writing a small application which requires the application to be

v> informed when the content / filename / location of a particular file

v> changes. Is there a Win32 class available which does this ?

 

You can try FindFirstChangeNotification API as mentioned, but it seems that

it won't be enough for your task as it won't give you information that your

file has been moved or renamed.

You can check CallbackFilter ( http://www.eldos.com/cbflt/ ) that would let

you track file system events in real-time and give complete control over the

events.

 

With best regards,

Eugene Mayevski

http://mayevski.blogspot.com/

Guest vivekian
Posted

Re: Filesystem Notification

 

On Apr 8, 9:52 am, "Eugene Mayevski" <mayev...@eldos.com> wrote:

> Hello!

> You wrote  on Mon, 7 Apr 2008 15:48:19 -0700 (PDT):

>

>  v> Writing a small application which requires the application to be

>  v> informed when the  content / filename / location of a particular file

>  v> changes. Is there aWin32class available which does this ?

>

> You can try FindFirstChangeNotification API as mentioned, but it seems that

> it won't be enough for your task as it won't give you information that your

> file has been moved or renamed.

> You can check CallbackFilter (http://www.eldos.com/cbflt/) that would let

> you track file system events in real-time and give complete control over the

> events.

>

> With best regards,

> Eugene Mayevskihttp://mayevski.blogspot.com/

 

Thanks a bunch for all the pointers !!

Guest Christian ASTOR
Posted

Re: Filesystem Notification

 

On 8 avr, 16:52, "Eugene Mayevski" <mayev...@eldos.com> wrote:

> You can try FindFirstChangeNotification API as mentioned, but it seems that

> it won't be enough for your task as it won't give you information that your

> file has been moved or renamed.

> You can check CallbackFilter (http://www.eldos.com/cbflt/) that would let

> you track file system events in real-time and give complete control over the

> events.

 

SHChangeNotifyRegister() does this...

Guest Eugene Mayevski
Posted

Re: Filesystem Notification

 

Hello!

You wrote on Tue, 8 Apr 2008 08:10:24 -0700 (PDT):

 

CA> SHChangeNotifyRegister() does this...

 

"This function is available through Microsoft Windows XP Service Pack 2

(SP2) and Windows Server 2003"

 

Also, this gives only notification and not control.

 

With best regards,

Eugene Mayevski

http://mayevski.blogspot.com/

Guest Christian ASTOR
Posted

Re: Filesystem Notification

 

On 8 avr, 17:35, "Eugene Mayevski" <mayev...@eldos.com> wrote:

> Hello!

> You wrote  on Tue, 8 Apr 2008 08:10:24 -0700 (PDT):

>

>  CA> SHChangeNotifyRegister() does this...

>

> "This function is available through Microsoft Windows XP Service Pack 2

> (SP2) and Windows Server 2003"

 

It's available since NT4 (dynamic call), but was not documented

before...

Guest vivekian
Posted

Re: Filesystem Notification

 

On Apr 7, 7:45 pm, "Michael D. Ober" <obermd.@.alum.mit.edu.nospam.>

wrote:

> "Kellie Fitton" <KELLIEFIT...@yahoo.com> wrote in message

>

> news:60ab34b1-ef43-4c37-b1bb-9579e052bbe3@a5g2000prg.googlegroups.com...

> On Apr 7, 3:48 pm, vivekian <vivekase...@gmail.com> wrote:

>

> > Hi,

>

> > Writing a small application which requires the application to be

> > informed when the content / filename / location of a particular file

> > changes. Is there a Win32 class available which does this ?

>

> > Thanks in advance,

> > vivekian

>

> Take a look at the FindFirstChangeNotification API. In the MSDN library,

> the path is Win32 and COM Development -> System Services -> File Services ->

> File Systems ->Directory Management -> Using Directory Management ->

> Obtaining Directory Change Notifications. If you are coding in dotNet, take

> a look at the System.IO.FileSystemWatcher class which is a wrapper for the

> FindFirstChangeNotification API functions.

>

> Mike.

 

I imagine coding in dotNet would require the .NET platform to become a

prerequisite for the application ?

 

~vivekian

Guest Michael D. Ober
Posted

Re: Filesystem Notification

 

"vivekian" <vivekaseeja@gmail.com> wrote in message

news:f4e4bced-805c-4dc4-a00e-4e8e533b04a4@u36g2000prf.googlegroups.com...

> On Apr 7, 7:45 pm, "Michael D. Ober" <obermd.@.alum.mit.edu.nospam.>

> wrote:

>> "Kellie Fitton" <KELLIEFIT...@yahoo.com> wrote in message

>>

>> news:60ab34b1-ef43-4c37-b1bb-9579e052bbe3@a5g2000prg.googlegroups.com...

>> On Apr 7, 3:48 pm, vivekian <vivekase...@gmail.com> wrote:

>>

>> > Hi,

>>

>> > Writing a small application which requires the application to be

>> > informed when the content / filename / location of a particular file

>> > changes. Is there a Win32 class available which does this ?

>>

>> > Thanks in advance,

>> > vivekian

>>

>> Take a look at the FindFirstChangeNotification API. In the MSDN library,

>> the path is Win32 and COM Development -> System Services -> File

>> Services ->

>> File Systems ->Directory Management -> Using Directory Management ->

>> Obtaining Directory Change Notifications. If you are coding in dotNet,

>> take

>> a look at the System.IO.FileSystemWatcher class which is a wrapper for

>> the

>> FindFirstChangeNotification API functions.

>>

>> Mike.

>

> I imagine coding in dotNet would require the .NET platform to become a

> prerequisite for the application ?

>

 

 

True, which is why I listed both methods. The question of monitoring the

file system appears periodically in the dotnet programming groups as well.

Your post wasn't clear what your development environment was. Also, the

FindFirstChangeNotification supports renames, creates, closes, changes, and

deletes. The one drawback is that the file system must be on an NT4 or

Windows 95 or later system. Samba doesn't support this API.

 

Mike.

 

Mike.

Guest Uwe Kotyczka
Posted

Re: Filesystem Notification

 

On 8 Apr., 00:48, vivekian <vivekase...@gmail.com> wrote:

> Hi,

>

> Writing a small application which requires the application to be

> informed when the  content / filename / location of a particular file

> changes. Is there a Win32 class available which does this ?

 

I wrote my own which tells me that a file was modified,

moved or deleted. However, if the file was moved, it

does not find out the new location and does not monitor

the file with it's new filename.

 

Here is my code:

 

 

/////////////////////////////////////////////////////////////////////////////

// Copyright:

// Uwe Kotyczka <uwe.kotyczka@web.de>

// created: February 2000

//

/////////////////////////////////////////////////////////////////////////////

// WatchInThreadBase.h : Schnittstelle der Klasse CWatchInThreadBase

//

/////////////////////////////////////////////////////////////////////////////

 

#if !

defined(AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_)

#define

AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_

 

#if defined(_MSC_VER) && (_MSC_VER >= 1020)

#pragma once

#endif

 

 

class AFX_EXT_CLASS_GENERAL CWatchInThreadBase

{

public:

CWatchInThreadBase();

 

// Attribute

public:

HANDLE m_hEventStartWatch;

HANDLE m_hEventWatchDone;

HANDLE m_hEventKillWatchThread;

HANDLE m_hEventWatchThreadKilled;

 

HWND m_hwndNotifyFileChanged;

CString m_strPathNameWatch;

 

protected:

CWinThread* m_pWatchWorkerThread;

 

BOOL m_bFileLost;

 

// Überladungen

// Vom Klassenassistenten generierte Überladungen virtueller

Funktionen

//{{AFX_VIRTUAL(CWatchInThreadBase)

public:

virtual void SetFileLostFlag(BOOL bFileLost = TRUE);

virtual BOOL IsFileLost();

protected:

virtual BOOL DoFileAlarm(int nCause, LPCTSTR szPathName);

virtual BOOL PostFileAlarmMsg(UINT message, int nCause) = 0;

//}}AFX_VIRTUAL

 

// Implementierung

public:

virtual ~CWatchInThreadBase();

 

void ShutDownWatchThreadSafely();

protected:

BOOL FileWatch(LPCTSTR szPathName);

};

 

inline void CWatchInThreadBase::SetFileLostFlag(BOOL bFileLost)

{ ASSERT(this != NULL); m_bFileLost = bFileLost; }

inline BOOL CWatchInThreadBase::IsFileLost()

{ ASSERT(this != NULL); return m_bFileLost; }

inline BOOL CWatchInThreadBase::PostFileAlarmMsg(UINT message, int

nCause)

{ ASSERT(FALSE); UNREFERENCED_PARAMETER(message);

UNREFERENCED_PARAMETER(nCause); return FALSE; }

 

/////////////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ fügt unmittelbar vor der vorhergehenden Zeile

zusätzliche Deklarationen ein.

 

#endif // !

defined(AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_)

 

 

 

/////////////////////////////////////////////////////////////////////////////

// Copyright:

// Uwe Kotyczka <uwe.kotyczka@web.de>

// created: February 2000

//

/////////////////////////////////////////////////////////////////////////////

// WatchInThreadBase.cpp : Implementierung der Klasse

CWatchInThreadBase

//

 

#include "StdAfx.h"

#include "GlWinApp.h"

#include "WatchInThreadBase.h"

#include "Helper.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CWatchInThreadBase

 

CWatchInThreadBase::CWatchInThreadBase()

{

m_hEventStartWatch = CreateEvent(NULL, FALSE, FALSE, NULL); // auto

reset, initially reset

m_hEventWatchDone = CreateEvent(NULL, TRUE, TRUE, NULL); // manual

reset, initially set

m_hEventKillWatchThread = CreateEvent(NULL, FALSE, FALSE, NULL); //

auto reset, initially reset

m_hEventWatchThreadKilled = CreateEvent(NULL, FALSE, FALSE, NULL); //

auto reset, initially reset

 

m_hwndNotifyFileChanged = NULL;

 

m_pWatchWorkerThread = NULL;

m_bFileLost = FALSE;

}

 

CWatchInThreadBase::~CWatchInThreadBase()

{

ShutDownWatchThreadSafely();

 

CloseHandle(m_hEventStartWatch);

CloseHandle(m_hEventWatchDone);

CloseHandle(m_hEventKillWatchThread);

CloseHandle(m_hEventWatchThreadKilled);

}

 

void CWatchInThreadBase::ShutDownWatchThreadSafely()

{

// It's a good idea to wait for the worker thread to notify via a

// "thread killed" event that it has killed itself. Otherwise, in the

case

// where the app is terminating, is possible (even if unlikely) that

it

// will detect a memory leak of the CWinThread object before the

// CWinThread object has had a chance to auto-delete itself.

 

DWORD dwExitCode;

HANDLE hThread = m_pWatchWorkerThread ? m_pWatchWorkerThread-

>m_hThread : NULL;

if (m_pWatchWorkerThread != NULL &&

GetExitCodeThread(hThread, &dwExitCode) &&

dwExitCode == STILL_ACTIVE)

{

// Kill the worker thread by setting the "watch done" and "kill

thread" events.

SetEvent(m_hEventKillWatchThread);

SetEvent(m_hEventWatchDone);

SetEvent(m_hEventStartWatch);

//WaitForSingleObject(m_hEventWatchThreadKilled, INFINITE);

while (WaitForSingleObject(m_hEventWatchThreadKilled, 1) !=

WAIT_OBJECT_0)

{

// Allow the calling thread to handle messages. This might be

useful e.g. if

// the worker thread pops up a MessageBox, which must be closed

before it can

// finish itself.

if (!RunExtraLoop())

return;

}

 

// Next lines seems to be nessesary.

// When exiting the app it happens that the main thread is finshed

// before the worker thread has ended itself. To avoid a memory

// leak we give the worker thread some more time to end itself.

while (GetExitCodeThread(hThread, &dwExitCode) &&

dwExitCode == STILL_ACTIVE)

{

WaitForSingleObject(m_hEventWatchThreadKilled, 1);

}

 

// Reset it to be able to start a new worker thread by

"WatchInThread"

m_pWatchWorkerThread = NULL;

}

}

 

BOOL CWatchInThreadBase::FileWatch(LPCTSTR szPathName)

{

// Note: In order to get a correct behaviour in a SDI environment

// we start file watching in OnOpenDocument *BEFORE* the path name is

set

// correctly. This is due to the fact that an overwritten

OnOpenDocument in

// a derived class may return FALSE.

// So when the path name has changed a short time after file watching

has been started

// we stop this FileWatch procedure and restart a new one.

DWORD dwResult = WAIT_TIMEOUT, dwLastError;

 

// open the docfile

CFile file;

BOOL bRet = file.Open(szPathName, CFile::modeRead |

CFile::shareDenyNone);

 

if (bRet)

{

// save the last write time

FILETIME ftLastWriteTime;

BY_HANDLE_FILE_INFORMATION fileinfo;

 

if (!GetFileInformationByHandle((HANDLE)file.m_hFile, &fileinfo))

{

file.Abort();

return FALSE;

}

 

ftLastWriteTime = fileinfo.ftLastWriteTime;

file.Close();

 

// determine the path

CString strPath = szPathName;

strPath = strPath.Left(strPath.ReverseFind('\\'));

ASSERT(!strPath.IsEmpty());

 

// endless loop

while (TRUE)

{

// get file notify event

HANDLE hFileChanged = FindFirstChangeNotification(strPath, FALSE,

FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE |

FILE_NOTIFY_CHANGE_FILE_NAME);

 

// wait for request to abort watching or for file change event

HANDLE hWaitEvents[] = { m_hEventWatchDone, hFileChanged };

//DWORD dwResult = WaitForMultipleObjects(2, hWaitEvents, FALSE,

INFINITE);

while (TRUE)

{

// some devices seem to NOT support FindFirstChangeNotification

// so we take only the first handle into account then

dwResult = WaitForMultipleObjects(hFileChanged ==

INVALID_HANDLE_VALUE ? 1 : 2, hWaitEvents, FALSE, 10);

 

if (dwResult == WAIT_OBJECT_0 + 0 || dwResult == WAIT_OBJECT_0 +

1)

{

break;

}

}

FindCloseChangeNotification(hFileChanged);

 

// some file in the directory changed

if (dwResult == WAIT_OBJECT_0 + 1)

{

// retrieve docfile's write time

BOOL bSuccess = file.Open(szPathName, CFile::modeRead |

CFile::shareDenyNone);

dwLastError = GetLastError();

if (!bSuccess && dwLastError == ERROR_FILE_NOT_FOUND)

{

// Try it a second time, some network devices report

ERROR_FILE_NOT_FOUND

// even if the file was just written.

bSuccess = file.Open(szPathName, CFile::modeRead |

CFile::shareDenyNone);

dwLastError = GetLastError();

}

if (bSuccess)

{

if (!GetFileInformationByHandle((HANDLE)file.m_hFile, &fileinfo))

{

file.Abort();

}

else

{

// detect if changes made

BOOL bAlarm = (ftLastWriteTime.dwHighDateTime !=

fileinfo.ftLastWriteTime.dwHighDateTime ||

ftLastWriteTime.dwLowDateTime !=

fileinfo.ftLastWriteTime.dwLowDateTime ||

IsFileLost());

 

// resave last time

ftLastWriteTime = fileinfo.ftLastWriteTime;

file.Close();

SetFileLostFlag(FALSE);

 

if (bAlarm)

{

if (!DoFileAlarm(FA_FILE_WRITTEN, szPathName))

{

// leave the outer loop if watching was

// aborted while being in DoFileAlarm.

break;

}

}

}

}

else if (!IsFileLost() && dwLastError == ERROR_FILE_NOT_FOUND)

{

SetFileLostFlag(TRUE);

if (!DoFileAlarm(FA_FILE_LOST, szPathName))

{

// leave the outer loop if watching was

// aborted while being in DoFileAlarm.

break;

}

}

else

{

TRACE1("FileWatch: An error occured (%d).\n", dwLastError);

}

}

else

break;

}

}

return bRet;

}

 

BOOL CWatchInThreadBase::DoFileAlarm(int nCause, LPCTSTR szPathName)

{

BOOL bInvert = FALSE;

 

// alarm

MessageBeep(MB_ICONEXCLAMATION);

 

while (TRUE)

{

if (WaitForSingleObject(m_hEventWatchDone, 500) == WAIT_OBJECT_0)

{

if (bInvert)

FlashWindow(m_hwndNotifyFileChanged, FALSE);

 

return FALSE;

}

else if (!IsIconic(m_hwndNotifyFileChanged) &&

IsWindowEnabled(m_hwndNotifyFileChanged))

{

if (bInvert)

FlashWindow(m_hwndNotifyFileChanged, FALSE);

 

if (GetForegroundWindow() == m_hwndNotifyFileChanged)

{

// Note: We don't call OnFileAlarm in the watching worker thread.

In order to

// reopen the document it will be necessary to update the views,

which can only

// be done by the creating thread. So we have to post a message to

the main thread.

// If the main thread is blocked by a MessageBox, then this

message might get lost.

// To avoid that we make sure that the main window is enabled

before posting the

// message.

m_strPathNameWatch = szPathName;

PostFileAlarmMsg(WM_FILE_ALARM, nCause);

break;

}

}

else

{

bInvert = !bInvert;

FlashWindow(m_hwndNotifyFileChanged, bInvert);

}

}

return TRUE;

}

 

It is just an abstract class, so you have to derive

from it. I usually use by deriving from both CDocument

and CWatchInThreadBase.

 

HTH

Guest vivekian
Posted

Re: Filesystem Notification

 

On Apr 9, 3:52 am, Uwe Kotyczka <uwe.kotyc...@web.de> wrote:

> On 8 Apr., 00:48, vivekian <vivekase...@gmail.com> wrote:

>

> > Hi,

>

> > Writing a small application which requires the application to be

> > informed when the  content / filename / location of a particular file

> > changes. Is there a Win32 class available which does this ?

>

> I wrote my own which tells me that a file was modified,

> moved or deleted. However, if the file was moved, it

> does not find out the new location and does not monitor

> the file with it's new filename.

>

> Here is my code:

>

> /////////////////////////////////////////////////////////////////////////////

> // Copyright:

> // Uwe Kotyczka <uwe.kotyc...@web.de>

> // created: February 2000

> //

> /////////////////////////////////////////////////////////////////////////////

> // WatchInThreadBase.h : Schnittstelle der Klasse CWatchInThreadBase

> //

> /////////////////////////////////////////////////////////////////////////////

>

> #if !

> defined(AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_)

> #define

> AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_

>

> #if defined(_MSC_VER) && (_MSC_VER >= 1020)

> #pragma once

> #endif

>

> class AFX_EXT_CLASS_GENERAL CWatchInThreadBase

> {

> public:

>         CWatchInThreadBase();

>

> // Attribute

> public:

>         HANDLE m_hEventStartWatch;

>         HANDLE m_hEventWatchDone;

>         HANDLE m_hEventKillWatchThread;

>         HANDLE m_hEventWatchThreadKilled;

>

>         HWND m_hwndNotifyFileChanged;

>         CString m_strPathNameWatch;

>

> protected:

>         CWinThread* m_pWatchWorkerThread;

>

>         BOOL m_bFileLost;

>

> // Überladungen

>         // Vom Klassenassistenten generierte Überladungen virtueller

> Funktionen

>         //{{AFX_VIRTUAL(CWatchInThreadBase)

>         public:

>         virtual void SetFileLostFlag(BOOL bFileLost = TRUE);

>         virtual BOOL IsFileLost();

>         protected:

>         virtual BOOL DoFileAlarm(int nCause, LPCTSTR szPathName);

>         virtual BOOL PostFileAlarmMsg(UINT message, int nCause) = 0;

>         //}}AFX_VIRTUAL

>

> // Implementierung

> public:

>         virtual ~CWatchInThreadBase();

>

>         void ShutDownWatchThreadSafely();

> protected:

>         BOOL FileWatch(LPCTSTR szPathName);

>

> };

>

> inline void CWatchInThreadBase::SetFileLostFlag(BOOL bFileLost)

>         { ASSERT(this != NULL); m_bFileLost = bFileLost; }

> inline BOOL CWatchInThreadBase::IsFileLost()

>         { ASSERT(this != NULL); return m_bFileLost; }

> inline BOOL CWatchInThreadBase::PostFileAlarmMsg(UINT message, int

> nCause)

>         { ASSERT(FALSE); UNREFERENCED_PARAMETER(message);

> UNREFERENCED_PARAMETER(nCause); return FALSE; }

>

> /////////////////////////////////////////////////////////////////////////////

>

> //{{AFX_INSERT_LOCATION}}

> // Microsoft Visual C++ fügt unmittelbar vor der vorhergehenden Zeile

> zusätzliche Deklarationen ein.

>

> #endif // !

> defined(AFX_WATCHINTHREADBASE_H__7C0A94EE_0665_11D5_8CB4_00001CD5E4D1__INCLUDED_)

>

> /////////////////////////////////////////////////////////////////////////////

> // Copyright:

> // Uwe Kotyczka <uwe.kotyc...@web.de>

> // created: February 2000

> //

> /////////////////////////////////////////////////////////////////////////////

> // WatchInThreadBase.cpp : Implementierung der Klasse

> CWatchInThreadBase

> //

>

> #include "StdAfx.h"

> #include "GlWinApp.h"

> #include "WatchInThreadBase.h"

> #include "Helper.h"

>

> #ifdef _DEBUG

> #define new DEBUG_NEW

> #undef THIS_FILE

> static char THIS_FILE[] = __FILE__;

> #endif

>

> /////////////////////////////////////////////////////////////////////////////

> // CWatchInThreadBase

>

> CWatchInThreadBase::CWatchInThreadBase()

> {

>         m_hEventStartWatch = CreateEvent(NULL, FALSE, FALSE, NULL);                     // auto

> reset, initially reset

>         m_hEventWatchDone = CreateEvent(NULL, TRUE, TRUE, NULL);                        // manual

> reset, initially set

>         m_hEventKillWatchThread = CreateEvent(NULL, FALSE, FALSE, NULL);        //

> auto reset, initially reset

>         m_hEventWatchThreadKilled = CreateEvent(NULL, FALSE, FALSE, NULL);      //

> auto reset, initially reset

>

>         m_hwndNotifyFileChanged = NULL;

>

>         m_pWatchWorkerThread = NULL;

>         m_bFileLost = FALSE;

>

> }

>

> CWatchInThreadBase::~CWatchInThreadBase()

> {

>         ShutDownWatchThreadSafely();

>

>         CloseHandle(m_hEventStartWatch);

>         CloseHandle(m_hEventWatchDone);

>         CloseHandle(m_hEventKillWatchThread);

>         CloseHandle(m_hEventWatchThreadKilled);

>

> }

>

> void CWatchInThreadBase::ShutDownWatchThreadSafely()

> {

>         // It's a good idea to wait for the worker thread to notify via a

>         // "thread killed" event that it has killed itself. Otherwise, in the

> case

>         // where the app is terminating, is possible (even if unlikely) that

> it

>         // will detect a memory leak of the CWinThread object before the

>         // CWinThread object has had a chance to auto-delete itself.

>

>         DWORD dwExitCode;

>         HANDLE hThread = m_pWatchWorkerThread ? m_pWatchWorkerThread->m_hThread : NULL;

>

>         if (m_pWatchWorkerThread != NULL &&

>                 GetExitCodeThread(hThread, &dwExitCode) &&

>                 dwExitCode == STILL_ACTIVE)

>         {

>                 // Kill the worker thread by setting the "watch done" and "kill

> thread" events.

>                 SetEvent(m_hEventKillWatchThread);

>                 SetEvent(m_hEventWatchDone);

>                 SetEvent(m_hEventStartWatch);

>                 //WaitForSingleObject(m_hEventWatchThreadKilled, INFINITE);

>                 while (WaitForSingleObject(m_hEventWatchThreadKilled, 1) !=

> WAIT_OBJECT_0)

>                 {

>                         // Allow the calling thread to handle messages. This might be

> useful e.g. if

>                         // the worker thread pops up a MessageBox, which must be closed

> before it can

>                         // finish itself.

>                         if (!RunExtraLoop())

>                                 return;

>                 }

>

>                 // Next lines seems to be nessesary.

>                 // When exiting the app it happens that the main thread is finshed

>                 // before the worker thread has ended itself. To avoid a memory

>                 // leak we give the worker thread some more time to end itself.

>                 while (GetExitCodeThread(hThread, &dwExitCode) &&

>                         dwExitCode == STILL_ACTIVE)

>                 {

>                         WaitForSingleObject(m_hEventWatchThreadKilled, 1);

>                 }

>

>                 // Reset it to be able to start a new worker thread by

> "WatchInThread"

>                 m_pWatchWorkerThread = NULL;

>         }

>

> }

>

> BOOL CWatchInThreadBase::FileWatch(LPCTSTR szPathName)

> {

>         // Note: In order to get a correct behaviour in a SDI environment

>         //      we start file watching in OnOpenDocument *BEFORE* the path name is

> set

>         //      correctly. This is due to the fact that an overwritten

> OnOpenDocument in

>         //      a derived class may return FALSE.

>         //      So when the path name has changed a short time after file watching

> has been started

>         //      we stop this FileWatch procedure and restart a new one.

>         DWORD dwResult = WAIT_TIMEOUT, dwLastError;

>

>         // open the docfile

>         CFile file;

>         BOOL bRet = file.Open(szPathName, CFile::modeRead |

> CFile::shareDenyNone);

>

>         if (bRet)

>         {

>                 // save the last write time

>                 FILETIME ftLastWriteTime;

>                 BY_HANDLE_FILE_INFORMATION fileinfo;

>

>                 if (!GetFileInformationByHandle((HANDLE)file.m_hFile, &fileinfo))

>                 {

>                         file.Abort();

>                         return FALSE;

>                 }

>

>                 ftLastWriteTime = fileinfo.ftLastWriteTime;

>                 file.Close();

>

>                 // determine the path

>                 CString strPath = szPathName;

>                 strPath = strPath.Left(strPath.ReverseFind('\\'));

>                 ASSERT(!strPath.IsEmpty());

>

>                 // endless loop

>                 while (TRUE)

>                 {

>                         // get file notify event

>                         HANDLE hFileChanged = FindFirstChangeNotification(strPath, FALSE,

> FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE |

> FILE_NOTIFY_CHANGE_FILE_NAME);

>

>                         // wait for request to abort watching or for file change event

>                         HANDLE hWaitEvents[] = { m_hEventWatchDone, hFileChanged };

>                         //DWORD dwResult = WaitForMultipleObjects(2, hWaitEvents, FALSE,

> INFINITE);

>                         while (TRUE)

>                         {

>                                 // some devices seem to NOT support FindFirstChangeNotification

>                                 // so we take only the first handle into account then

>                                 dwResult = WaitForMultipleObjects(hFileChanged ==

> INVALID_HANDLE_VALUE ? 1 : 2, hWaitEvents, FALSE, 10);

>

>                                 if (dwResult == WAIT_OBJECT_0 + 0 || dwResult == WAIT_OBJECT_0 +

> 1)

>                                 {

>                                         break;

>                                 }

>                         }

>                         FindCloseChangeNotification(hFileChanged);

>

>                         // some file in the directory changed

>                         if (dwResult == WAIT_OBJECT_0 + 1)

>                         {

>                                 // retrieve docfile's write time

>                                 BOOL bSuccess = file.Open(szPathName, CFile::modeRead |

> CFile::shareDenyNone);

>                                 dwLastError = GetLastError();

>                                 if (!bSuccess && dwLastError == ERROR_FILE_NOT_FOUND)

>                                 {

>                                         // Try it a second time, some network devices report

> ERROR_FILE_NOT_FOUND

>                                         // even if the file was just written.

>                                         bSuccess = file.Open(szPathName, CFile::modeRead |

> CFile::shareDenyNone);

>                                         dwLastError = GetLastError();

>                                 }

>                                 if (bSuccess)

>                                 {

>                                         if (!GetFileInformationByHandle((HANDLE)file.m_hFile, &fileinfo))

>                                         {

>                                                 file.Abort();

>                                         }

>                                         else

>                                         {

>                                                 // detect if changes made

>                                                 BOOL bAlarm = (ftLastWriteTime.dwHighDateTime !=

> fileinfo.ftLastWriteTime.dwHighDateTime ||

>                                                                                 ftLastWriteTime.dwLowDateTime !=

> fileinfo.ftLastWriteTime.dwLowDateTime ||

>                                                                                 IsFileLost());

>

>                                                 // resave last time

>                                                 ftLastWriteTime = fileinfo.ftLastWriteTime;

>                                                 file.Close();

>                                                 SetFileLostFlag(FALSE);

>

>                                                 if (bAlarm)

>                                                 {

>                                                         if (!DoFileAlarm(FA_FILE_WRITTEN, szPathName))

>                                                         {

>                                                                 // leave the outer loop if watching was

>                                                                 // aborted while being in DoFileAlarm.

>                                                                 break;

>                                                         }

>                                                 }

>                                         }

>                                 }

>                                 else if (!IsFileLost() && dwLastError == ERROR_FILE_NOT_FOUND)

>                                 {

>                                         SetFileLostFlag(TRUE);

>                                         if (!DoFileAlarm(FA_FILE_LOST, szPathName))

>                                         {

>                                                 // leave the outer loop if watching was

>                                                 // aborted while being in DoFileAlarm.

>                                                 break;

>                                         }

>                                 }

>                                 else

>                                 {

>                                         TRACE1("FileWatch: An error occured (%d).\n", dwLastError);

>                                 }

>                         }

>                         else

>                                 break;

>                 }

>         }

>         return bRet;

>

> }

>

> BOOL CWatchInThreadBase::DoFileAlarm(int nCause, LPCTSTR szPathName)

> {

>         BOOL bInvert = FALSE;

>

>         // alarm

>         MessageBeep(MB_ICONEXCLAMATION);

>

>         while (TRUE)

>         {

>                 if (WaitForSingleObject(m_hEventWatchDone, 500) == WAIT_OBJECT_0)

>                 {

>                         if (bInvert)

>                                 FlashWindow(m_hwndNotifyFileChanged, FALSE);

>

>                         return FALSE;

>                 }

>                 else if (!IsIconic(m_hwndNotifyFileChanged) &&

>                         IsWindowEnabled(m_hwndNotifyFileChanged))

>                 {

>                         if (bInvert)

>                                 FlashWindow(m_hwndNotifyFileChanged, FALSE);

>

>                         if (GetForegroundWindow() == m_hwndNotifyFileChanged)

>                         {

>                                 // Note: We don't call OnFileAlarm in the watching worker thread.

> In order to

>                                 //  reopen the document it will be necessary to update the views,

> which can only

>                                 //      be done by the creating thread.

> ...

>

> read more »

 

Thanks for the code and thanks to everyone for all the pointers !!

Great help.

×
×
  • Create New...