向导生成的所有控件变量:
<code class="lang-cpp">void CFolderMonitorDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BTN_START, m_startbutton);
DDX_Control(pDX, IDC_EDIT1, m_folderedit);
DDX_Control(pDX, IDC_MFCSHELLTREE1, m_foldertree);
DDX_Control(pDX, IDC_LIST1, m_resultlist);
DDX_Control(pDX, IDC_CHECK1, m_flag_filename);
DDX_Control(pDX, IDC_CHECK2, m_flag_dirname);
DDX_Control(pDX, IDC_CHECK3, m_flag_attr);
DDX_Control(pDX, IDC_CHECK4, m_flag_size);
DDX_Control(pDX, IDC_CHECK5, m_flag_lastwrite);
DDX_Control(pDX, IDC_CHECK6, m_flag_lastaccess);
DDX_Control(pDX, IDC_CHECK7, m_flag_creation);
DDX_Control(pDX, IDC_CHECK8, m_flag_security);
}</code>
其它变量:
<code class="lang-cpp">CString m_getpath;
CString m_getopr;
CString m_gettime;
CWinThread *m_monthread;
HANDLE m_dirhandle;
CMutex m_mutex;</code>
消息映射:
<code class="lang-cpp">#define WM_TRHEADMSG (WM_USER + 8)
BEGIN_MESSAGE_MAP(CFolderMonitorDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_NOTIFY(TVN_SELCHANGED, IDC_MFCSHELLTREE1, &CFolderMonitorDlg::OnTvnSelchangedMfcshelltree1)
ON_BN_CLICKED(IDC_BTN_START, &CFolderMonitorDlg::OnBnClickedBtnStart)
ON_MESSAGE(WM_TRHEADMSG, &CFolderMonitorDlg::ThreadMsg)
ON_WM_DESTROY()
ON_COMMAND_RANGE(IDC_CHECK1, IDC_CHECK8, &CFolderMonitorDlg::OnCheckBox)
END_MESSAGE_MAP()</code>
核心代码(FolderMonitorDlg.h):
<code class="lang-cpp">//////////////////////////////////////////////////////////////////////////////////////
//BOOL CFolderMonitorDlg::OnInitDialog()
//{
// ResetComponents();
//}
void CFolderMonitorDlg::ResetComponents(void)
{
while (m_resultlist.DeleteColumn(0)); // 删除原有表列
m_resultlist.InsertColumn(0, _T("路径"), 0, 200); // 添加表列
m_resultlist.InsertColumn(1, _T("操作"), 0, 80);
m_resultlist.InsertColumn(2, _T("时间"), 0, 80);
m_resultlist.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); // 设置为列表式
DWORD exstyle = m_resultlist.GetExtendedStyle(); // 设置为全行选择、有格线
m_resultlist.SetExtendedStyle(exstyle|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
m_flag_filename.SetCheck(true); // 设置默认监控项目
m_flag_creation.SetCheck(true);
m_flag_lastwrite.SetCheck(true);
OnCheckBox(IDC_CHECK1); // 更新m_monflag
}
void CFolderMonitorDlg::OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<lpnmtreeview>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
CString path;
m_foldertree.GetItemPath(path);
m_folderedit.SetWindowText(path); // 根据文件夹树所选项目,更新文本框
}
UINT MonitorThread(LPVOID pvoid);
void CFolderMonitorDlg::OnBnClickedBtnStart()
{
// TODO: 在此添加控件通知处理程序代码
CString btntext;
m_startbutton.GetWindowText(btntext);
if (btntext == _T("开始"))
{
CString path;
m_folderedit.GetWindowText(path); // 获取文本框中的字符串
m_dirhandle = ::CreateFile( // 打开所选目录!
path, // 目录名
FILE_LIST_DIRECTORY, // 以列出目录权限打开
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, // 允许其它程序读写删除
NULL, // 没有安全选项
OPEN_EXISTING, // 存在时打开
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, // 备份存取异步存取
NULL); // 没有文件模板
if (m_dirhandle == INVALID_HANDLE_VALUE) // 如果打开失败则退出
return;
m_monthread = new CWinThread(MonitorThread, this); // 新建并启动工作线程
m_monthread->CreateThread();
m_startbutton.SetWindowText(_T("停止"));
}
else if (btntext == _T("停止"))
{
OnDestroy(); // 停止工作线程并清理资源
m_startbutton.SetWindowText(_T("清除"));
}
else if (btntext == _T("清除"))
{
m_resultlist.DeleteAllItems(); // 清空列表框
m_startbutton.SetWindowText(_T("开始"));
}
else
{
AfxMessageBox(_T("出现了不该出现的情况"));
m_startbutton.SetWindowText(_T("停止"));
}
}
void CFolderMonitorDlg::OnDestroy()
{
if (m_monthread != NULL) // 如果线程存在,则终止线程
{
if (m_monthread->m_hThread != INVALID_HANDLE_VALUE)
m_monthread->SuspendThread();
delete m_monthread;
m_monthread = NULL;
}
if (m_dirhandle != INVALID_HANDLE_VALUE) // 如果目录已打开,则关闭目录
{
CloseHandle(m_dirhandle);
m_dirhandle = INVALID_HANDLE_VALUE;
}
}
//BEGIN_MESSAGE_MAP(CFolderMonitorDlg, CDialogEx)
// ON_COMMAND_RANGE(IDC_CHECK1, IDC_CHECK8, &CFolderMonitorDlg::OnCheckBox)
//END_MESSAGE_MAP()
void CFolderMonitorDlg::OnCheckBox(UINT nID)
{
m_mutex.Lock(); // 赋值时可能会被工作线程异步读取,所以要上锁
m_monflag = 0;
if (m_flag_attr.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
if (m_flag_creation.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_CREATION;
if (m_flag_dirname.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_DIR_NAME;
if (m_flag_filename.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_FILE_NAME;
if (m_flag_lastaccess.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
if (m_flag_lastwrite.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_LAST_WRITE;
if (m_flag_security.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_SECURITY;
if (m_flag_size.GetCheck()) m_monflag |= FILE_NOTIFY_CHANGE_SIZE;
m_mutex.Unlock();
}
UINT MonitorThread(LPVOID pvoid)
{
CFolderMonitorDlg *pWnd = (CFolderMonitorDlg*)pvoid;
char notify[65536]; // 储存FILE_NOTIFY_INFORMATION链表的缓冲区
DWORD dwBytes; // 返回字节数
FILE_NOTIFY_INFORMATION *pnotify; // FILE_NOTIFY_INFORMATION指针
if (pWnd->m_dirhandle == INVALID_HANDLE_VALUE) // 如果文件夹没打开则直接结束
return 1;
while(true) // 监控循环
{
memset(notify, 0, sizeof(notify)); // 清零缓冲区
pnotify = (FILE_NOTIFY_INFORMATION*)notify; // 指向缓冲区开头的链表第一项
pWnd->m_mutex.Lock(); // 因为可能会被主线程异步赋值,所以要进行锁定
DWORD monflag = pWnd->m_monflag; // 获取flag(见OnCheckBox)
pWnd->m_mutex.Unlock();
if (::ReadDirectoryChangesW(
pWnd->m_dirhandle, // 目录句柄(见OnBnClickedBtnStart)
¬ify, sizeof(notify), // 缓冲区及大小
TRUE, // 是否监控子项目
monflag, // 监控的内容(见OnCheckBox)
&dwBytes, // 返回字节数
NULL, NULL)) // 异步调用相关,这里是同步调用,因此全填NULL
{
if (!dwBytes) // 如果缓冲区溢出
{
pWnd->m_getpath = _T("[缓冲区溢出]");
pWnd->m_getopr = _T("未知");
SYSTEMTIME st;
GetLocalTime(&st);
pWnd->m_gettime = CTime(st).Format("%H:%M:%S"); // 获取系统时间
pWnd->SendMessage(WM_TRHEADMSG, 0, 0); // 通知主线程添加列表项
}
else
while(true) // 链表迭代循环
{
LPWSTR wbuf = pWnd->m_getpath.GetBufferSetLength(pnotify->FileNameLength / 2);
memcpy(wbuf, pnotify->FileName, pnotify->FileNameLength);
pWnd->m_getpath.ReleaseBuffer(pnotify->FileNameLength / 2); // 获取文件名
pWnd->m_getopr = // 获取操作类型
pnotify->Action == FILE_ACTION_ADDED ? _T("新建") :
pnotify->Action == FILE_ACTION_MODIFIED ? _T("更改") :
pnotify->Action == FILE_ACTION_REMOVED ? _T("删除") :
pnotify->Action == FILE_ACTION_RENAMED_OLD_NAME ? _T("重命名") :
pnotify->Action == FILE_ACTION_RENAMED_NEW_NAME ? _T("新名称") :
_T("未知");
SYSTEMTIME st;
GetLocalTime(&st);
pWnd->m_gettime = CTime(st).Format("%H:%M:%S"); // 获取系统时间
pWnd->SendMessage(WM_TRHEADMSG, 0, 0); // 通知主线程添加列表项
if (pnotify->NextEntryOffset) // 如果返回了另一个项目(通常是新文件名)
{
pnotify = (FILE_NOTIFY_INFORMATION *)
((char*)pnotify + pnotify->NextEntryOffset); // 迭代链表下一项
continue; // 继续
}
break; // 退出
}
}
}
}
//#define WM_THREADMSG (WM_USER + 8)
//BEGIN_MESSAGE_MAP(CFolderMonitorDlg, CDialogEx)
// ON_MESSAGE(WM_TRHEADMSG, &CFolderMonitorDlg::ThreadMsg)
//END_MESSAGE_MAP()
LRESULT CFolderMonitorDlg::ThreadMsg(WPARAM wParam, LPARAM lParam)
{
// 工作线程调用此消息以插入列表项
m_resultlist.InsertItem(0, m_getpath); // 根据返回的字符串插入表项,设置其它列的值
m_resultlist.SetItemText(0, 1, m_getopr);
m_resultlist.SetItemText(0, 2, m_gettime);
return TRUE;
}</lpnmtreeview></code>
(完)