Click to See Complete Forum and Search --> : Unable to track all changes in a directory using FindNextChangeNotification


ganga
June 19th, 2006, 12:53 PM
Platform : Windows2000, XP,
Microsoft Visual C++ .NET (Version 7.1),

Hello,

I need to process the files in a directory immediately the moment it gets
deposited in a directory.
I am trying to achieve this by using WaitForMultipleObjects ,
FindFirstChangeNotification, FindNextChangeNotification in a While loop
in the Run() of one of my worker threads of my multithread application.
I get the events for the files that were deposited after the
WaitForMultipleObjects was invoked in the while loop.
However those files that get deposited in the folder in the split of second
before the WaitForMultipleObjects is invoked are not getting reported i.e. I
am not getting their handles.
Is there any other API or code that can help me achieve the same without
losing the notification of the files deposited in between?
Any evident problem that you see as to why this should happen?

Any pointers would be of great help
Thanks and Regards
Ganga

(Please see excerpts of code below:)
int CABIEventWorkThread::Run()

{

ASSERT_VALID(GetWork());

CDirEventReceiverWork* dirWrk =
dynamic_cast<CDirEventReceiverWork*>(GetWork());


try

{

COMMINFOCON con;

dirWrk->GetEventDirectoryList(con);

dirWrk->RunOnce();

HANDLE* dwChangeHandles;


DWORD timeout = GetCycleTime();

BOOL waitAll = FALSE;

DWORD dwWaitStatus;

while (TRUE)

{

try

{

dirWrk->GetEventDirectoryList(con);

m_pDirEventServer.WatchDirectories(con);

dwChangeHandles = GetHandleList();


int nHandles = m_pDirEventServer.GetHandleMap().size()+ 2;

dwWaitStatus = WaitForMultipleObjects(nHandles, dwChangeHandles,

waitAll, timeout);

if(dwWaitStatus == WAIT_TIMEOUT )

{

//Refresh receiver list

continue;

}

if((dwWaitStatus == WAIT_OBJECT_0 + 0) || (dwWaitStatus == WAIT_OBJECT_0 +
1) )

{

//signalled kill event

break;

}

if((dwWaitStatus <= (WAIT_OBJECT_0 +1)) || (dwWaitStatus >= nHandles))

{

ASSERT(false);

ostringstream ost;

ost << "Invalid wait return value [" << dwWaitStatus << "]";

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

continue;

}


if(dwWaitStatus == m_pDirEventServer.GetHandleMap().size())

{

//signalled kill event

break;

}


try

{

CCommInfo ci = m_pDirEventServer.SetNextChangeNotification

(dwWaitStatus , dwChangeHandles);

dirWrk->SetCommInfo(ci);

//Process the directory

dirWrk->DoWork(GetWork());

}

catch(CABIException e)

{

ostringstream ost;

ost << e.ReportError();

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

continue;

}

}

catch(CABIException e)

{

ostringstream ost;

ost << e.ReportError();

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

continue;

}

}

}

catch(...)

{

ostringstream ost;

ost << "Caught Unknown Exception while doing Directory receiver Work";

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

}

try

{

//signalled externally for killing myself

EndWork(); //do derived shutdown

}

catch(CABIException& e)

{

ASSERT(false);

}

catch(CException* e)

{

ASSERT(false);

char szErr[1024];

e->GetErrorMessage(szErr, 1024);

e->Delete();

ostringstream ost;

ost << "Caught CException while executing EndWork(), with error [" << szErr
<< "]. Rebulidng ABI Exception";

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

}

catch(exception& e)

{

ASSERT(false);

ostringstream ost;

ost << "Caught exception while executing EndWork(), with error [" <<
e.what() << "]. Rebulidng ABI Exception";

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

}

catch(...)

{

//this should never happen unless there is problem destroying

//work object (bad pointer)

ASSERT(false);

ostringstream ost;

ost << "Caught unknown exception while executing EndWork(). Rebulidng ABI
Exception";

CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

}

SetEvent(GetEventDead()); //signal to calling thread that i am done

SetEvent(GetEventAnotherDead()); //signal to calling thread that i am done

AfxEndThread(0,m_bAutoDelete);

return 0;

}

void CDirEventServer::WatchDirectories(const COMMINFOCON& con)

{

HANDLE dwChangeHandle;

TCHAR lpDrive[4];

TCHAR lpFile[_MAX_FNAME];

TCHAR lpExt[_MAX_EXT];

StopWatch();

for(COMMINFOCON::const_iterator It = con.begin(); It != con.end(); It++)

{

const CCommInfo& ci =(*It);


string strPath = ci.GetRemoteDir();

const TCHAR* lpDir = strPath.c_str();

bool subDirState = ci.IsSubDirectory();

_tsplitpath(lpDir, lpDrive, NULL, lpFile, lpExt);

lpDrive[2] = (TCHAR)'\\';

lpDrive[3] = (TCHAR)'\0';


// Watch the directory for file creation and deletion.


dwChangeHandle= FindFirstChangeNotification(

lpDir, // directory to watch

subDirState, // do not watch subtree

FILE_NOTIFY_CHANGE_CREATION |

FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes


if (dwChangeHandle == INVALID_HANDLE_VALUE)

{

ostringstream ost;

ost << "FindFirstChangeNotification returned an INVALID_HANDLE_VALUE";

throw CABIException(PROGRAM_ERROR,ost.str(),__FILE__,__LINE__);

}


AddToHandleMap(dwChangeHandle, &ci);

}

}

CCommInfo CDirEventServer::SetNextChangeNotification(long lWait, HANDLE*
dwChangeHandles)

{


HANDLECOMMINFOMAP::iterator It =
GetHandleMap().find(dwChangeHandles[lWait]);

if (lWait >= 0 && It != GetHandleMap().end())

{

const CCommInfo* ci = (*It).second;


ASSERT(lWait < GetHandleMap().size()+2);

if (FindNextChangeNotification(

dwChangeHandles[lWait]) == FALSE)

{

ostringstream ost;

ost << "FindNextChangeNotification returned an INVALID_HANDLE_VALUE";

throw CABIException(PROGRAM_ERROR,ost.str(),__FILE__,__LINE__);

}

return *ci;

}

else

{

ostringstream ost;

ost << "Invalid Handle Wait state";

throw CABIException(PROGRAM_ERROR, ost.str(), __FILE__, __LINE__);

}

}

humptydumpty
June 20th, 2006, 01:13 AM
Here is a Sample code from MSDN .have a look on this.

DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];

// Watch the C:\WINDOWS directory for file creation and
// deletion.

dwChangeHandles[0] = FindFirstChangeNotification(
"C:\\WINDOWS", // directory to watch
FALSE, // do not watch the subtree
FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes

if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

// Watch the C:\ subtree for directory creation and
// deletion.

dwChangeHandles[1] = FindFirstChangeNotification(
"C:\\", // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir. name changes

if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

// Change notification is set. Now wait on both notification
// handles and refresh accordingly.

while (TRUE)
{

// Wait for notification.

dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);

switch (dwWaitStatus)
{
case WAIT_OBJECT_0:

// A file was created or deleted in C:\WINDOWS.
// Refresh this directory and restart the
// change notification. RefreshDirectory is an
// application-defined function.

RefreshDirectory("C:\\WINDOWS")
if ( FindNextChangeNotification(
dwChangeHandles[0]) == FALSE )
ExitProcess(GetLastError());
break;

case WAIT_OBJECT_0 + 1:

// A directory was created or deleted in C:\.
// Refresh the directory tree and restart the
// change notification. RefreshTree is an
// application-defined function.

RefreshTree("C:\\");
if (FindNextChangeNotification(
dwChangeHandles[1]) == FALSE)
ExitProcess(GetLastError());
break;

default:
ExitProcess(GetLastError());
}
}


Thanx