2013-04-16 184 views
0

我正在編程監視文件夾。我使用FileWatch.h庫。這是我的FileWatch.h訪問衝突讀取位置0xba2f1498

#ifndef FILEWATCH_H 
#define FILEWATCH_H 

class FileChangeObserver 
{ 
public: 
    virtual ~FileChangeObserver() 
    { 

    } 
    virtual void OnFileChanged() = 0; 
}; 
// information concerning a directory being watched 
class FileWatcher 
{ 
public: 
    // Watching file modifications using a loop 
    void Init(LPCTSTR filefullpath); 
    bool CheckForChanges(DWORD waittime=0); 
    // Watching file modification via a thread 
    void StartWatchThread(); 
    bool IsThreadRunning(); 
    void SynchronousAbort(); 
    FileWatcher(FileChangeObserver *observer) : hDir(NULL), curBuffer(0), 
     filePath(NULL), hWatchingThread(NULL), observer(observer) 
    { 
     ZeroMemory(&this->overl, sizeof(this->overl)); 
     // create the event used to abort the "watching" thread 
     hEvtStopWatching = CreateEvent(NULL, TRUE, FALSE, NULL); 
    } 
    FileWatcher() 
    { 
    } 
    ~FileWatcher() 
    { 
     SynchronousAbort(); 
     delete observer; 
     free(filePath); 
     CloseHandle(hEvtStopWatching); 
    } 
public: 
    HANDLE   hDir;  // handle of the directory to watch 
    FileChangeObserver *observer; // function called when a file change is detected 
    TCHAR *   filePath; // path to the file watched 
    FILE_NOTIFY_INFORMATION buffer[2][512]; 
     // a double buffer where the Windows API ReadDirectory will store the list 
     // of files that have been modified. 
    int curBuffer; // current buffer used (alternate between 0 and 1) 
    bool NotifyChange(); 
public: 
    // fields for use by the WathingThread 
    OVERLAPPED overl; // object used for asynchronous API calls 
    HANDLE hWatchingThread; // handle of the watching thread 
    HANDLE hEvtStopWatching; // this event is fired when the watching thread needs to be aborted 
}; 
static DWORD WINAPI WatchingThread(void *param); 
#endif 

這是我FileWatch.cpp

#include "stdafx.h" 
#include "FileWatch.h" 
#include "assert.h" 
#if _MSC_VER > 1600 
extern "C" { 
WINBASEAPI BOOL WINAPI 
GetOverlappedResult(_In_ HANDLE hFile, _In_ LPOVERLAPPED lpOverlapped, _Out_ LPDWORD lpNumberOfBytesTransferred, _In_ BOOL bWait); 
} 
#endif 
bool FileWatcher::IsThreadRunning() 
{ 
    return hWatchingThread && (WaitForSingleObject(hWatchingThread, 0) == WAIT_TIMEOUT); 
} 
// Ask for the thread to stop and waith until it ends 
void FileWatcher::SynchronousAbort() 
{ 
    SetEvent(hEvtStopWatching); 
    if (hWatchingThread) 
    { 
     WaitForSingleObject(hWatchingThread, INFINITE); 
     CloseHandle(hWatchingThread); 
     Sleep(500); 
     hWatchingThread = NULL; 
    } 
    CloseHandle(overl.hEvent); 
    overl.hEvent = NULL; 
    CloseHandle(hDir); 
    hDir = NULL; 
} 
// Start watching a file for changes 
void FileWatcher::StartWatchThread() 
{ 
    // if the thread already exists then stop it 
    if (IsThreadRunning()) 
     SynchronousAbort(); 
    assert(hDir); 
    if (!hDir) 
    { 
     return; 
    } 
    // reset the hEvtStopWatching event so that it can be set if 
    // some thread requires the watching thread to stop 
    ResetEvent(hEvtStopWatching); 
    DWORD watchingthreadID; 
    hWatchingThread = CreateThread(NULL, 0, WatchingThread, this, 0, &watchingthreadID); 
} 
void FileWatcher::Init(const TCHAR* fileFullPath) 
{ 
    // if the thread already exists then stop it 
    if (IsThreadRunning()) 
     SynchronousAbort(); 
    // str::ReplacePtr(&filePath, fileFullPath); 
    //TCHAR *dirPath = path::GetDir(filePath); 
    hDir = CreateFile(
     L"C:\\", // pointer to the directory containing the tex files 
     FILE_LIST_DIRECTORY,    // access (read-write) mode 
     FILE_SHARE_READ|FILE_SHARE_DELETE|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 
    // free(dirPath); 
    ZeroMemory(&overl, sizeof(overl)); 
    ZeroMemory(buffer, sizeof(buffer)); 
    overl.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 
    // watch the directory 
    ReadDirectoryChangesW(
     hDir, /* handle to directory */ 
     &buffer[curBuffer], /* read results buffer */ 
     sizeof(buffer[curBuffer]), /* length of buffer */ 
     FALSE, /* monitoring option */ 
     //FILE_NOTIFY_CHANGE_CREATION| 
     FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */ 
     NULL, /* bytes returned */ 
     &overl, /* overlapped buffer */ 
     NULL); /* completion routine */ 
} 
// Thread responsible of watching the directory containg the file to be watched for modifications 
DWORD WINAPI WatchingThread(void *param) 
{ 
    //qDebug()<<"in WatchingThread"; 
    FileWatcher *fw = (FileWatcher *)param; 
    HANDLE hp[2] = { fw->hEvtStopWatching, fw->overl.hEvent }; 
    for (;;) 
    { 
     DWORD dwObj = WaitForMultipleObjects((sizeof(hp)/(sizeof(hp[0]))) 
              , hp, FALSE, INFINITE); 
     if (dwObj == WAIT_OBJECT_0) // the user asked to quit the program 
     { 
      //qDebug()<<"in WatchingThread the user asked to quit the program"; 
      //exit(-1); 
      break; 
     } 
     if (dwObj != WAIT_OBJECT_0 + 1) 
     { 
      // BUG! 
      //assert(0); 
      // qDebug()<<"dwObj "<<dwObj<<" last error "<<GetLastError(); 
      break; 
     } 
     //qDebug()<<"WatchingThread fw->NotifyChange() "; 
     //if (fw->wakeup) 
     fw->NotifyChange(); 
    } 
    return 0; 
} 
// Call ReadDirectoryChangesW to check if the file has changed since the last call. 
bool FileWatcher::CheckForChanges(DWORD waittime) 
{ 
    if (!overl.hEvent) 
    { 
     return false; 
    } 
    DWORD dwObj = WaitForSingleObject(overl.hEvent, waittime); 
    if (dwObj != WAIT_OBJECT_0) 
    { 
     return false; 
    } 
    return NotifyChange(); 
} 
// Call the ReadDirectory API and determine if the file being watched has been modified since the last call. 
// Returns true if it is the case. 
bool FileWatcher::NotifyChange() 
{ 
    //qDebug()<<"in NotifyChange"; 
    DWORD dwNumberbytes; 
    GetOverlappedResult(hDir, &overl, &dwNumberbytes, FALSE); 
    FILE_NOTIFY_INFORMATION *pFileNotify = (FILE_NOTIFY_INFORMATION *)buffer[curBuffer]; 
    // Switch the 2 buffers 
    curBuffer = (curBuffer + 1) % (sizeof(buffer)/(sizeof(buffer[0]))); 
    SecureZeroMemory(buffer[curBuffer], sizeof(buffer[curBuffer])); 
    // start a new asynchronous call to ReadDirectory in the alternate buffer 
    ReadDirectoryChangesW(
     hDir, /* handle to directory */ 
     &buffer[curBuffer], /* read results buffer */ 
     sizeof(buffer[curBuffer]), /* length of buffer */ 
     TRUE, /* monitoring option */ 
     FILE_NOTIFY_CHANGE_FILE_NAME | 
      FILE_NOTIFY_CHANGE_DIR_NAME | 
      FILE_NOTIFY_CHANGE_ATTRIBUTES | 
      FILE_NOTIFY_CHANGE_SIZE | 
      FILE_NOTIFY_CHANGE_LAST_WRITE | 
      FILE_NOTIFY_CHANGE_LAST_ACCESS | 
      FILE_NOTIFY_CHANGE_CREATION | 
      FILE_NOTIFY_CHANGE_SECURITY, 
     //FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */ 
     NULL, /* bytes returned */ 
     &overl, /* overlapped buffer */ 
     NULL); /* completion routine */ 
    // Note: the ReadDirectoryChangesW API fills the buffer with WCHAR strings. 
    for (;;) 
    { 
     if (pFileNotify->Action == FILE_ACTION_ADDED) 
     { 
      //qDebug()<<"in NotifyChange if "; 
       char szAction[42]; 
       char szFilename[MAX_PATH] ; 
       memset(szFilename,'\0',sizeof(szFilename)); 
       strcpy(szAction,"added"); 
       wcstombs(szFilename, pFileNotify->FileName, MAX_PATH); 
       if(observer) 
        observer->OnFileChanged(); 
       return true; 
       //OnFileChanged(szFilename,szAction); 
       // qDebug()<<"in NotifyChange after OnFileChanged "; 
     } 
     // step to the next entry if there is one 
     if (!pFileNotify->NextEntryOffset) 
     { 
      return false; 
     } 
     pFileNotify = (FILE_NOTIFY_INFORMATION *)((PBYTE)pFileNotify + pFileNotify->NextEntryOffset); 
    } 
    pFileNotify=NULL; 
    return true; 
} 

在主程序中,我有:

case IDM_ABOUT: 
      //DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 
      { 
       FileWatcher *cWatcher = new FileWatcher(); 
      cWatcher->Init(L"AB"); 
      cWatcher->NotifyChange(); 
      break; 
      } 

我有messeage一個錯誤:訪問衝突讀取位置0xba2f1498。 什麼是解決方案?

+3

沒有人會解開那個爛攤子。您應該從調試器提供跟蹤。問題歸結爲訪問你不應該訪問的內存,但很難確定除非你發佈調試器跟蹤。因此,請擴展您的問題以獲得更多幫助。 –

+0

我看到一個'刪除觀察者'和'免費(filePath)',但沒有代碼分配內存,這是除了你混合c風格分配和C++風格分配的事實。 –

+0

@Haroogan我想看目錄更改,我可以使用此代碼?文件夾中的任何更改:刪除文件夾,新文件夾,重命名...我不知道如何捕捉它們。 – user2284783

回答

1

在你的析構函數中您有:

delete observer; 
free(filePath); 

但你不檢查,以確保任何一個預先分配這顯然是一個問題,尤其是因爲你的默認構造函數不初始化這些變量。這超出了您將C風格分配與C++風格分配混合的事實。

+0

我不知道如何調用函數來觀察主文件夾中的變化。我在[鏈接]找到它(https://github.com/kzmkv/SumatraPDF/tree/master/src)。我想要點擊幫助/關於我們可以看到C:驅動器的任何變化 – user2284783

3

您有一個默認的構造函數,它將保留所有未初始化的變量。

FileWatcher() 
{ 
} 

你在這裏使用。

  FileWatcher *cWatcher = new FileWatcher(); 
     cWatcher->Init(L"AB"); 

Init也留下幾個變量初始化,如curBuffer在這條線。

 &buffer[curBuffer], /* read results buffer */ 

這可能是爲什麼你正在Access violation reading location 0xba2f1498

一個很好的做法是確保你的對象始終是構造完成之前完全有效的。

+0

我該怎麼辦?謝謝 – user2284783

+0

@ user2284783您應該修改您的構造函數以初始化** all **成員變量,如果未初始化,這些變量將會失效。這通常意味着*所有這些*。 –

+0

@ user2284783例如,如果'curBuffer'不是'0'或'1',你的代碼就會中斷。所以要採取措施確保它是其中之一。 –