我正在编写一个程序来监视文件夹。我使用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。有什么解决办法?