0

我正在编写一个程序来监视文件夹。我使用FileWatch.h图书馆。这是我的FileWatch.h

#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;
            }

我有一条错误消息:访问冲突读取位置 0xba2f1498。有什么解决办法?

4

2 回答 2

3

您有一个默认构造函数,它使您的所有变量都未初始化。

FileWatcher()
{
}

你在这里使用的。

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

Init还会留下几个未初始化的变量,例如curBuffer在这一行中。

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

这可能就是你得到的原因Access violation reading location 0xba2f1498

一个好的做法是确保您的对象在构造函数完成之前始终完全有效。

于 2013-04-16T03:25:29.270 回答
1

在你的析构函数中,你有:

delete observer;
free(filePath);

但是您没有检查以确保事先分配了任何一个,这显然是一个问题,特别是因为您的默认构造函数没有初始化任何这些变量。这超出了您将 C 样式分配与 C++ 样式分配混合的事实。

于 2013-04-16T03:20:45.457 回答