?
Solved

Problem to terminate thread when using ReadDirectoryChangesW

Posted on 2005-03-15
10
Medium Priority
?
1,112 Views
Last Modified: 2013-11-20
Hi

I am working in MFC. In my application, I wrote a thread function which continouly checks for a update in a file in one particular directory. This thread should stop when clicked on a button. I have used ReadDirectoryChangesW for getting notification of the file change. To end the thread I waited on a STOP event i.e checking for it to end the thread.
But the m_StopEvent event is not caught because the control is stuck at while( ReadDirectoryChangesW) i.e it is not going inside the while loop unless ReadDirectoryChangesW returns true.


UINT CheckFileUpdates(LPVOID lp)
{
//Get the document pointer
CLogViewerAppView* pView = (CLogViewerAppView*)lp;
CLogViewerAppDoc* pDoc = pView->GetDocument();

CFileException err;
CFileStatus st;
CFile::GetStatus(pView->m_LogFilePath,st);
LONG l1,l2;

CFile file;
if( !file.Open(pView->m_LogFilePath, CFile::modeRead|CFile::shareDenyNone, &err ) )
{
TCHAR szCause[255];
err.GetErrorMessage(szCause, 255);
AfxMessageBox(szCause);
return 0;
}
l1 = (LONG)file.GetLength();
file.Close();
CFile file1;
LONG size_1 = (LONG)st.m_size;
int len = pView->m_LogFilePath.GetLength()-pView->m_LogFileName.GetLength()-1;
CString dir = pView->m_LogFilePath.Left(len);
HANDLE hDir = CreateFile( dir, // pointer to the file name
FILE_LIST_DIRECTORY, // access (read/write) mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
NULL, // security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS, // file attributes
NULL // file with attributes to copy
);

FILE_NOTIFY_INFORMATION Buffer[1024];
DWORD BytesReturned;

while( ReadDirectoryChangesW(
hDir,
&Buffer,
sizeof(Buffer),
TRUE,
FILE_NOTIFY_CHANGE_SIZE, conditions
&BytesReturned, // bytes returned
NULL, // overlapped buffer
NULL// completion routine
))
{
if ( WaitForSingleObject(pView->m_StopEvent, 1) == WAIT_OBJECT_0 )
{
OutputDebugString(_T("\n KILL THE THREAD\n"));
return 0; //end the thread

}

CString fileName(Buffer[0].FileName);
fileName = fileName.Left(Buffer[0].FileNameLength / 2);

if(fileName.CompareNoCase(pView->m_LogFileName) == 0)
{
//Do the work
}
}

return 0;
}


Can anyone please help me to proceed further. I do not want to end the thraed from outside the function as it may cause memory leaks.

Thanks
Madhavi
0
Comment
Question by:osi-sys
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
10 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 13542776
You need to use ReadDirectoryChangesW in overlapped mode. Create OVERLAPPED structure and fill it's event. When ReadDirectoryChangesW is called in overlapped mode, it returns immidiately and program must wait for overlapped event. Replace WaitForSingleObject with WaitForMultipleObjects and wait for two events - overlapped and stop.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 13542823
You can learn more about asynchronous calls to ReadDirectoryChangesW from this article:
http://www.codeproject.com/file/directorychangewatcher.asp

or you can use CDirectoryChangeWatcher class directly.
0
 

Author Comment

by:osi-sys
ID: 13542875
Hi AlexFM

Thanks for the inputs.

Yes, I tried using ReadDirectoryChangesW in overlapped mode as shown below.
But when my file gets updated I am getting an assertion at this statement
  bResult = GetOverlappedResult(hDir,&overlapped,NULL,TRUE); when I update the log file.

Can you please help me further..

UINT CheckFileUpdates(LPVOID lp)
{
   CLogViewerAppView* pView = (CLogViewerAppView*)lp;
   //Create a critical section object
   //
   CSingleLock csl(&pView->m_UpdateCSect);

   CFileException err;
   CFileStatus st;
   CFile::GetStatus(pView->m_LogFilePath,st);
   LONG l1,l2;      
   CFile file;
   if( !file.Open(pView->m_LogFilePath, CFile::modeRead|CFile::shareDenyNone, &err ) )
   {
      TCHAR   szCause[255];      
      err.GetErrorMessage(szCause, 255);      
      AfxMessageBox(szCause);      
      return 0;
   }
   l1 = (LONG)file.GetLength();
   file.Close();
   CFile file1;
   LONG size_1 = (LONG)st.m_size;
   int len = pView->m_LogFilePath.GetLength()-pView->m_LogFileName.GetLength()-1;
   CString dir = pView->m_LogFilePath.Left(len);

   HANDLE hDir = CreateFile( dir, // pointer to the file name
      FILE_LIST_DIRECTORY,                // access (read/write) mode
      FILE_SHARE_READ|FILE_SHARE_WRITE,  // share mode
      NULL,                               // security descriptor
      OPEN_EXISTING,                      // how to create
      FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,         // file attributes
      NULL                                // file with attributes to copy
      );

   FILE_NOTIFY_INFORMATION Buffer[1024];
   OVERLAPPED overlapped;
   overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

   DWORD BytesReturned;
   while( 1)
   {
      if(ReadDirectoryChangesW(
         hDir,                                  // handle to directory
         &Buffer,                                    // read results buffer
         sizeof(Buffer),                                // length of buffer
         TRUE,                                // monitoring option
         FILE_NOTIFY_CHANGE_SIZE|//to check if file is modified
         FILE_NOTIFY_CHANGE_LAST_ACCESS|//used to end thread
         FILE_NOTIFY_CHANGE_FILE_NAME,// if file is  deleted, used to end thread
         &BytesReturned,              // bytes returned
         &overlapped,                          // overlapped buffer
         NULL// completion routine
         ))
   
      {
         BOOL bResult;
         bResult = GetOverlappedResult(hDir,&overlapped,NULL,TRUE);
         if ( bResult )
         {
           
         }
         else
         {
            if ( GetLastError() == ERROR_IO_PENDING )
            {
               // wait for overlapped and stop events
               HANDLE handles[1];
               handles[0] = overlapped.hEvent;
               handles[1] = pView->m_Stop;
               DWORD dwResult = WaitForMultipleObjects(2, handles, FALSE, INFINITE);

               switch ( dwResult )
               {
               case WAIT_OBJECT_0 + 0:
                  AfxMessageBox(_T(" Fired"));
                  break;

               case WAIT_OBJECT_0 +1:                  
                  AfxMessageBox(_T(" m_StopEvent Fired"));
                  return 0;
                  break;
               default:
                  break;
                  // handle error
               }
            }
         }
      }

    }
}

Thanks
Madhavi
0
Moving data to the cloud? Find out if you’re ready

Before moving to the cloud, it is important to carefully define your db needs, plan for the migration & understand prod. environment. This wp explains how to define what you need from a cloud provider, plan for the migration & what putting a cloud solution into practice entails.

 
LVL 48

Expert Comment

by:AlexFM
ID: 13542892
What assertion exactly?
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 13542924
You need to wait for overlapped event first. Only when event is signaled, call GetOverlappedResult.
0
 

Author Comment

by:osi-sys
ID: 13542944
Unhandled exception at 0x7c81fd0b in LogViewerApp_d.exe: 0xC0000005: Access violation writing location 0x00000000.
0
 

Author Comment

by:osi-sys
ID: 13542968
Can you please tell me where to modify my code above. I am a bit confused with these events.
0
 

Author Comment

by:osi-sys
ID: 13543007
Can you please tell me where to modify my code above. I am a bit confused with these events.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 13543257
Code fragments from my project which works with ReadFile in overlapped mode. I change it to ReadDirectoryChangesW, this can give an idea how to work with overlapped input:

    HANDLE hEvents[2];

    // Fill OVERLAPPED structure
    OVERLAPPED ov;
    memset(&ov,0,sizeof(ov));

    ov.hEvent = CreateEvent(
        NULL,                   // security attributes
        TRUE,                   // manually reset
        FALSE,                  // unsignaled
        NULL);                  // name

    hEvents[0] = m_StopEvent;  // stop thread event
    hEvents[1] = ov.hEvent;

    BOOL bResult;
    DWORD dwError;

    while ( TRUE )    // thread loop
    {
        bResult = ReadDirectoryChangesW(...);

        dwError = dwError = GetLastError();

        if ( bResult )          // operation succeded immidiately
        {
            // handle results here
        }
        else    // error or pending I/O
        {
            if ( dwError != ERROR_IO_PENDING )          // error
            {
                    // handle error here and exit
            }
            else
            {
                // Wait for overlapped result and for stop event
                dwResult = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
                dwError = GetLastError();

                switch ( dwResult )
                {
                case WAIT_OBJECT_0:
                    // stop thread
                    // ... add code here to exit the thread
                    break;

                case WAIT_OBJECT_0 + 1:
                    // overlapped operation finished
                    bResult = GetOverlappedResult(...);
                    dwError = GetLastError();

                    if ( ! bResult )
                    {
                         // handle error here
                    }
                    else
                    {
                         // handle results of asynchronous operation here
                    }
                    break;

                default:
                    // handle error here
                    break;
                }
            }
        }
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 500 total points
ID: 13543263
Correction.
dwError = dwError = GetLastError();
should be
dwError = GetLastError();
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Suggested Courses
Course of the Month15 days, 10 hours left to enroll

741 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question