• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1128
  • Last Modified:

Problem to terminate thread when using ReadDirectoryChangesW

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
osi-sys
Asked:
osi-sys
  • 6
  • 4
1 Solution
 
AlexFMCommented:
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
 
AlexFMCommented:
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
 
osi-sysAuthor Commented:
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
AlexFMCommented:
What assertion exactly?
0
 
AlexFMCommented:
You need to wait for overlapped event first. Only when event is signaled, call GetOverlappedResult.
0
 
osi-sysAuthor Commented:
Unhandled exception at 0x7c81fd0b in LogViewerApp_d.exe: 0xC0000005: Access violation writing location 0x00000000.
0
 
osi-sysAuthor Commented:
Can you please tell me where to modify my code above. I am a bit confused with these events.
0
 
osi-sysAuthor Commented:
Can you please tell me where to modify my code above. I am a bit confused with these events.
0
 
AlexFMCommented:
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
 
AlexFMCommented:
Correction.
dwError = dwError = GetLastError();
should be
dwError = GetLastError();
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 6
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now