监控文件的变化 (异步模式)

DectoryWatch.cpp

#pragma once
#pragma execution_character_set("utf-8")


// DectoryWatch.cpp
#include "stdafx.h"
#include "DirectoryWatch.h"

#include <process.h>
#include <strsafe.h>
#include <Shlwapi.h>

#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shlwapi.lib")

#define MAX_BUFFER_SIZE	(1024)

typedef enum _MyMSG
{
	MSG_SUCCESS = (WM_USER)+0x100,
	MSG_STARTWATCH,
	MSG_STOPWATCH,
	MSG_EXIT
};


//目录监控的构造函数
CDirectoryWatch::CDirectoryWatch(): m_dwMSGTID(0), m_hMSG(NULL)
{
	m_hMutex = CreateMutexW(NULL, FALSE, NULL);

	m_hMSG = (HANDLE)_beginthreadex(NULL, NULL, MSGThred, this, NULL, (unsigned int *)&m_dwMSGTID);
	//创建消息线程 接收消息 此线程必须先于发送消息函数之前运行 否则消息将发送失败
	if (NULL == m_hMSG)
		TRACE("<ERR> CDirectoryWatch()->Create MSGThred fail! ErrorCode:0x%X\r\n", GetLastError());

	TRACE("<DBG> CDirectoryWatch() success! Open the MSGThred...\r\n");
}


CDirectoryWatch::~CDirectoryWatch()
{
	// 释放资源
	if (!m_vWatchList.empty())
	{
		std::list<WATCH_PARAM*>::iterator iBegin = m_vWatchList.begin();
		std::list<WATCH_PARAM*>::iterator iEnd = m_vWatchList.end();
		while (iBegin != iEnd)
		{
			StopWatch((*iBegin++)->wzPath); // 停止监控
		}
	}

	PostThreadMessageW(m_dwMSGTID, MSG_EXIT, NULL, NULL); // 退出 MSGThred 线程
	WaitForSingleObject(m_hMSG, INFINITE);
	CloseHandle(m_hMSG);
	CloseHandle(m_hMutex);

	TRACE("<DBG> ~CDirectoryWatch() success! Close the MSGThred...\r\n");
}

void CDirectoryWatch::Lock()
{
	WaitForSingleObject(m_hMutex, INFINITE);
}

void CDirectoryWatch::UnLock()
{
	ReleaseMutex(m_hMutex);
}

BOOL CDirectoryWatch::StartWatch(LPWSTR wzPath, funNotifyAction lpfunNotifyAction)
{
	if (wzPath == NULL && wzPath[0] == 0 && lpfunNotifyAction == NULL && !PathFileExistsW(wzPath))
		return FALSE;

	// 排除重复
	Lock();
	std::list<WATCH_PARAM*>::iterator iBegin = m_vWatchList.begin();
	std::list<WATCH_PARAM*>::iterator iEnd = m_vWatchList.end();
	while (iBegin != iEnd)
	{
		if (wcscmp((*iBegin)->wzPath, wzPath) == 0)
		{
			TRACE("<ERR> StartWatch() fail! %S 已经被监控!\r\n", wzPath);
			UnLock();
			return FALSE;
		}
		++iBegin;
	}
	UnLock();

	if (!PostThreadMessageW(m_dwMSGTID, MSG_STARTWATCH, (WPARAM)wzPath, (LPARAM)lpfunNotifyAction))
	{
		TRACE("<ERR> StartWatch()->PostThreadMessageW() fail! ErrorCode:0x%X\r\n", GetLastError());
		return FALSE;
	}

	return TRUE;
}


BOOL CDirectoryWatch::StopWatch(LPWSTR wzPath)
{
	if (wzPath == NULL && wzPath[0] == 0 && !PathFileExistsW(wzPath))
		return FALSE;

	BOOL bIsExist = FALSE;
	std::list<WATCH_PARAM*>::iterator iBegin = m_vWatchList.begin();
	std::list<WATCH_PARAM*>::iterator iEnd = m_vWatchList.end();
	while (iBegin != iEnd)
	{
		if (wcscmp((*iBegin)->wzPath, wzPath) == 0)
		{
			bIsExist = TRUE;
			break;
		}
		++iBegin;
	}

	if (!bIsExist)
	{
		TRACE("<ERR> StopWatch() fail! %S 没有监控...\r\n", wzPath);
		return FALSE;
	}

	if (!PostThreadMessageW(m_dwMSGTID, MSG_STOPWATCH, (WPARAM)wzPath, NULL))
	{
		TRACE("<ERR> StopWatch()->PostThreadMessageW() fail! ErrorCode:0x%X\r\n", GetLastError());
		return FALSE;
	}

	return TRUE;
}

unsigned __stdcall CDirectoryWatch::MSGThred( LPVOID lpParam )
{         
    CDirectoryWatch* This = (CDirectoryWatch*)lpParam;
    MSG msg;
    while( GetMessageW(&msg, NULL, 0, 0) ){
      switch ( msg.message ){
        default:
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        break;
        //开启监控
        case MSG_STARTWATCH: 
        {  
          WATCH_PARAM* SwatchParam = new(std::nothrow) WATCH_PARAM;
          if( SwatchParam == 0 ){
              TRACE("<ERR> MSGThred()->New buffer fail!\r\n");
              break;
          }
          ZeroMemory(SwatchParam, sizeof(WATCH_PARAM));
          StringCchCopyW(SwatchParam->wzPath, MAX_PATH, (LPCWSTR)msg.wParam);
          SwatchParam->hFile = CreateFileW( 
              SwatchParam->wzPath,
              FILE_LIST_DIRECTORY,
              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
              NULL,
              OPEN_EXISTING,
              FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // 注意这里的 异步标志
              NULL
          );
          if( SwatchParam->hFile == INVALID_HANDLE_VALUE ){
              TRACE("<ERR> MSGThred()->CreateFileW fail! ErrorCode:0x%X\r\n", GetLastError());
              delete[] SwatchParam;
              break;
          }
          SwatchParam->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
          if( SwatchParam->hEvent == NULL ){
              TRACE("<ERR> MSGThred()->CreateEventW fail! ErrorCode:0x%X\r\n", GetLastError());
              CloseHandle(SwatchParam->hFile);
              delete[] SwatchParam;
              break;
          }
          SwatchParam->ol.hEvent = SwatchParam->hEvent;
          // 接收通知信息的缓存区
          SwatchParam->pBuffer = new(std::nothrow) BYTE[MAX_BUFFER_SIZE];
          if( SwatchParam->pBuffer == 0 ){                      
              SwatchParam->pBuffer = new(std::nothrow) BYTE[MAX_BUFFER_SIZE];
              if( SwatchParam->pBuffer == 0 ){
                  TRACE("<ERR> MSGThred()->New buffer fail!\r\n");
                  CloseHandle(SwatchParam->hEvent);
                  CloseHandle(SwatchParam->hFile);
                  delete[] SwatchParam;
                  break;
              }
          }
          ZeroMemory(SwatchParam->pBuffer, MAX_BUFFER_SIZE);
          SwatchParam->dwBufferSize = MAX_BUFFER_SIZE;
          SwatchParam->NotifyAction = (funNotifyAction)msg.lParam;
          // 开启监控线程 每个文件都有一个
          SwatchParam->hWatch = (HANDLE)_beginthreadex(NULL, NULL, WatchThred, (LPVOID)SwatchParam, NULL, NULL);
          This->Lock();
          This->m_vWatchList.push_back(SwatchParam); // 添加到监控列表 便于控制
          This->UnLock();
          TRACE("<DBG> StartWatch success!-> %S\r\n", SwatchParam->wzPath);
          break;
        }
        // 停止监控
        case MSG_STOPWATCH:
        {   
          WCHAR *wzPath = (WCHAR *)msg.wParam;
          This->Lock();
          std::list<WATCH_PARAM*>::iterator iBegin = This->m_vWatchList.begin();
          std::list<WATCH_PARAM*>::iterator iEnd = This->m_vWatchList.end();
          while (iBegin != iEnd){
            if( wcscmp((*iBegin)->wzPath, wzPath) == 0 ){
                break;
            }
            ++iBegin;
          }
          (*iBegin)->bIsExit = TRUE;
          SetEvent((*iBegin)->hEvent); //设置状态 不让 监控函数堵塞住
          WaitForSingleObject((*iBegin)->hWatch, INFINITE);
          CloseHandle((*iBegin)->hFile);
          CloseHandle((*iBegin)->hEvent);
          delete[](*iBegin)->pBuffer;
          TRACE("<DBG> StopWatch success!-> %S\r\n", (*iBegin)->wzPath);
          delete[](*iBegin);
          This->m_vWatchList.erase(iBegin);
          This->UnLock();
          break;
        }
        case MSG_EXIT:
        {  
          _endthreadex(0);
        }
      }
    }
    return 0;
}




















unsigned __stdcall CDirectoryWatch::WatchThred( LPVOID lpParam )
{         
    WATCH_PARAM* pSwatchParam = (WATCH_PARAM*)lpParam;
    DWORD dwByteRet = 0;
	FILE_NOTIFY_INFORMATION* pNextFileNotify;
    while( true ){
      if( pSwatchParam->bIsExit ){
          break; 
          //退出标记
      }
      if( !ReadDirectoryChangesW(pSwatchParam->hFile,
          pSwatchParam->pBuffer,
          pSwatchParam->dwBufferSize,
          TRUE,
          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,
          &dwByteRet,
          &pSwatchParam->ol, //异步结构
          NULL) ){
          TRACE("<ERR> WatchThred()->ReadDirectoryChangesW() fail! ErrorCode:0x%X path:%S\r\n", GetLastError(), pSwatchParam->wzPath);
          continue;
      }

	  //TRACE("WatchThred.0\n");
      if( !GetOverlappedResult(pSwatchParam->hFile, &pSwatchParam->ol, &dwByteRet, TRUE)){
          TRACE("<ERR> WatchThred()->GetOverlappedResult() fail! ErrorCode:0x%X path:%S\r\n", GetLastError(), pSwatchParam->wzPath);
          continue;
      }

	  Sleep(100);
	  
	  //TRACE("WatchThred.1\n");
      FILE_NOTIFY_INFORMATION* pFileNotify = (FILE_NOTIFY_INFORMATION*)pSwatchParam->pBuffer;

	  next_frame:
      if( !pFileNotify->Action ){
          continue;
      }
	  //TRACE("WatchThred.2\n");
      //这里要注意的就是 FILE_NOTIFY_INFORMATION.FileName 不是以'\0'结尾
      WCHAR wzSrcFile[MAX_PATH]  = { 0 };
	  WCHAR wzDestFile[MAX_PATH] = { 0 };
      memcpy(wzSrcFile, pFileNotify->FileName, pFileNotify->FileNameLength);
      //用wmemcpy 会有乱码 多拷贝数据了 应该用memcpy





      //如果是重命名会将新的信息存储到下一个结构
      if( pFileNotify->Action == FILE_ACTION_RENAMED_OLD_NAME ){
          pNextFileNotify = (FILE_NOTIFY_INFORMATION*)((BYTE*)pFileNotify + pFileNotify->NextEntryOffset);
          memcpy(wzDestFile, pNextFileNotify->FileName, pNextFileNotify->FileNameLength);
		  
      }
      //通用处理函数
      pSwatchParam->NotifyAction(pFileNotify->Action, wzSrcFile, wzDestFile);

      if( pFileNotify->Action == FILE_ACTION_RENAMED_OLD_NAME ){
	      pFileNotify = pNextFileNotify;
      }

	  
	  if( pFileNotify->NextEntryOffset ){
          pFileNotify = PFILE_NOTIFY_INFORMATION((BYTE*)pFileNotify + pFileNotify->NextEntryOffset);
          goto next_frame;
      }else{
          ZeroMemory(pSwatchParam->pBuffer, MAX_BUFFER_SIZE);
      }	
    }
    _endthreadex(0);
    return 0;
}





DirectoryWatch.h

#pragma once
#pragma execution_character_set("utf-8")


// DirectoryWatch.h
#pragma once
#include <windows.h>
#include <list>

// 通用的通知处理函数
typedef void(*funNotifyAction)(DWORD dwAction, LPWSTR wzSrcFile, LPWSTR wzDestFile);

// 要监控的目录的信息
typedef struct _WATCH_PARAM
{
	_WATCH_PARAM()
	{
		hFile = INVALID_HANDLE_VALUE;
		hEvent = NULL;
		hWatch = NULL;
		pBuffer = NULL;
		bIsExit = FALSE;
		dwBufferSize = 0;
		NotifyAction = NULL;
		ZeroMemory(&wzPath, sizeof(WCHAR)*MAX_PATH);
		ZeroMemory(&ol, sizeof(OVERLAPPED));
	}
	WCHAR  wzPath[MAX_PATH]; // 路径
	HANDLE hFile;            // 文件句柄
	HANDLE hEvent;           // 事件句柄
	BYTE  *pBuffer;          // 缓存区
	DWORD  dwBufferSize;     // 缓存区大小
	OVERLAPPED ol;           // 异步结构

	HANDLE hWatch;           // 监控线程句柄
	BOOL   bIsExit;          // 监控线程是否退出

	funNotifyAction NotifyAction;

}WATCH_PARAM, *PWATCH_PARAM;

// 监控类
class CDirectoryWatch
{
public:
	CDirectoryWatch();
	virtual ~CDirectoryWatch();

public:
	BOOL StartWatch(LPWSTR wzPath, funNotifyAction lpfunNotifyAction);
	BOOL StopWatch(LPWSTR wzPath);

private:
	static unsigned __stdcall MSGThred(LPVOID lpParam);   // 消息线程
	static unsigned __stdcall WatchThred(LPVOID lpParam); // 监控线程

	void Lock();
	void UnLock();

private:
	std::list<WATCH_PARAM*> m_vWatchList; // 监控的列表
	HANDLE m_hMSG;                        // 消息线程句柄
	DWORD  m_dwMSGTID;                    // 消息线程ID
	HANDLE m_hMutex;                      // 互斥锁(list保护)
};

 

 

测试函数  main.cpp



// 测试函数  main.cpp

#include "stdafx.h"
#include "DirectoryWatch.h"

#include <locale.h>

void NotifyAction(DWORD dwAction, LPWSTR wzSrcFile, LPWSTR wzDestFile)
{
	switch (dwAction)
	{
	case FILE_ACTION_ADDED:
		TRACE("FILE_ACTION_ADDED:%S \r\n", wzSrcFile);
		break;

	case FILE_ACTION_REMOVED:
		TRACE("FILE_ACTION_REMOVED:%S \r\n", wzSrcFile);
		break;

	case FILE_ACTION_MODIFIED:
		TRACE("FILE_ACTION_MODIFIED:%S \r\n", wzSrcFile);
		break;

	case FILE_ACTION_RENAMED_OLD_NAME:
		TRACE("FILE_ACTION_RENAMED:%S to %S \r\n", wzSrcFile, wzDestFile);
		break;

	case FILE_ACTION_RENAMED_NEW_NAME:
		TRACE("FILE_ACTION_RENAMED new:%S to %S \r\n", wzSrcFile, wzDestFile);

		break;

	default:
		TRACE("FILE_ACTION_RENAMED default:%S to %S \r\n", wzSrcFile, wzDestFile);
		break;
	}
}

int test_main(void)
{
	//setlocale(LC_ALL, "chs");

	CDirectoryWatch watch;
	Sleep(100);
	TRACE("Start Directory Watch ...\r\n");
	watch.StartWatch(L"F:\\A50\\java\\doip\\uart\\libs\\armeabi\\", NotifyAction);
	//watch.StartWatch(L"F:\\22", NotifyAction);
	//watch.StartWatch(L"F:\\33", NotifyAction);
	system("pause");

	watch.StopWatch(L"F:\\A50\\java\\doip\\uart\\libs\\armeabi\\");
	//watch.StopWatch(L"F:\\22");
	//watch.StopWatch(L"F:\\33");

	system("pause");
	TRACE("Stop Directory Watch ...\r\n");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值