2013-04-16 5 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

Я вижу 'delete observer' и' free (filePath) ', но не код, который выделяет память для этого, это, кроме того, что вы смешиваете выделение стиля стиля и распределение стиля C++ вместе. –

+0

@Haroogan Я хочу изменить каталог часов, могу ли я использовать этот код? любое изменение в папке: удалить папку, новую папку, переименовать ... Я не знаю, как их поймать. – user2284783

ответ

1

В вашем деструкторе у вас есть:

delete observer; 
free(filePath); 

но вы не проверить, чтобы убедиться, что ни один выделяются заранее, который явно проблема, тем более, что ваш конструктор по умолчанию не инициализирует любого из этих переменных. Это не зависит от того, что вы смешиваете выделение стиля C с распределением стилей на C++.

+0

Я не знаю, как вызвать функцию, чтобы наблюдать изменение папки в главном. Я нахожу его в: [link] (https://github.com/kzmkv/SumatraPDF/tree/master/src). Я хочу после нажатия кнопки «Справка»/«О нас» мы можем наблюдать за любыми изменениями в C: drives – 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 Вы должны изменить свой конструктор, чтобы инициализировать ** все ** переменные-члены, которые были бы недействительны, если неинициализированы. Что обычно означает * все из них *. –

+0

@ user2284783 Например, похоже, что ваш код сломается, если 'curBuffer' не' 0' или '1'. Поэтому примите меры, чтобы убедиться, что это один из них. –