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__);
}
}
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__);
}
}