//ThreadParameter结构体的定义
/*
*整合参数为一个结构体传给子线程的原因在于创建线程时
*指定的线程入口函数只接受一个LPVOID类型的指针,具体内容可以参考msdn,
*实际上向子线程传递参数还有一种方法,全局变量,
*例如后面程序中的WriteLog就是一个文件输入流对象,我就是在程序首部定义的全局变量。
*/
typedef struct ThreadParameter
{
LPTSTR in_directory;//监控的路径
FILE_NOTIFY_INFORMATION *in_out_notification;//存储监控函数返回信息地址
DWORD in_MemorySize;//传递存储返回信息的内存的字节数
DWORD *in_out_BytesReturned;//存储监控函数返回信息的字节数
DWORD *in_out_version;//返回版本信息
FILE_NOTIFY_INFORMATION *temp_notification;//备用的一个参数
}ThreadParameter; void HexDump(char *buf, int len, int addr);
// 函数: WatchChanges(LPVOID lpParameter)
//
// 目的: 监控目录的程序
//
// 注释:主函数创建线程时制定了这个函数的入口
// 届时该子程序将自动启动执行。
// 备注:因为代码不全,看下面的代码时,主要参考红色的字体部分char * testbuff = "12345";
DWORD WINAPI WatchChanges(LPVOID lpParameter)//返回版本信息
{
ThreadParameter *parameter = (ThreadParameter*)lpParameter;
LPCTSTR WatchDirectory = parameter->in_directory;
TRACE("testbuff len = %d\n", strlen(testbuff));
//创建一个目录句柄
HANDLE handle_directory = CreateFile( WatchDirectory,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (handle_directory == INVALID_HANDLE_VALUE){
DWORD ERROR_DIR = GetLastError();
MessageBox(NULL, TEXT("打开目录错误!"), TEXT("文件监控"), 0);
}
BOOL watch_state;
int edit_flag;
edit_flag = 0x00;
//time_t ChangeTime;
char file_name[1024];
PFILE_NOTIFY_INFORMATION p_notify_information;
//HexDump((char *)parameter->in_out_notification, 0x200, 0);
while (TRUE){
watch_state = ReadDirectoryChangesW(handle_directory,
(LPVOID)parameter->in_out_notification,
parameter->in_MemorySize,
TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
(LPDWORD)parameter->in_out_BytesReturned,
NULL,
NULL);
TRACE("watch_state = %d\n", watch_state);
TRACE("watch_state123 = %d\n", *parameter->in_out_BytesReturned);
//检测结果为1,表明函数已成功执行
//time(&ChangeTime);
//记录修改时间
//TRACE(_T("文件监控,删除文件! %S\\%S\n"), file_name, file_name);
p_notify_information = parameter->in_out_notification;
HexDump((char *)p_notify_information, *parameter->in_out_BytesReturned, 0);
if (GetLastError() == ERROR_INVALID_FUNCTION){
MessageBox(NULL, TEXT("系统不支持!"), TEXT("文件监控"), 0);
}else if (watch_state == 0){
MessageBox(NULL, TEXT("监控失败!"), TEXT("文件监控"), 0);
}else if (GetLastError() == ERROR_NOTIFY_ENUM_DIR){
MessageBox(NULL, TEXT("内存溢出!"), TEXT("文件监控"), 0);
}else{
//将宽字符类型的FileName变量转换成string,便于写入log文件,否则写不进去正确的文件名
//string file_name;
//DWORD length = WideCharToMultiByte(0, 0, parameter->in_out_notification->FileName, -1, NULL, 0, NULL, NULL);
next_frame:
DWORD length;
length = p_notify_information->FileNameLength / 2;
PSTR ps = new CHAR[length+1];
ps[length] = '\0'; //TRACE("length = %d\n", length);
//TRACE("parameter->in_out_notification->FileNameLength = %d\n", p_notify_information->FileNameLength);
//HexDump((char *)p_notify_information, 0x100, 0);
if( length >= 0 ){
WideCharToMultiByte(0, 0, p_notify_information->FileName, -1, ps, length, NULL, NULL);
//HexDump((char *)ps, 0x100, 0);
strcpy(file_name, ps);
//TRACE("file_name1 = %s\n", file_name);
//TRACE("file_name2 len = %d\n", strlen(file_name) );
delete[] ps;
}
//这里主要就是检测返回的信息,需要注意FILE_NOTIFY_INFORMATION结构体的定义,以便正确调用返回信息
if( p_notify_information->Action == FILE_ACTION_ADDED ){
TRACE(_T("文件监控,新增文件: %S\n"), file_name );
}else if (p_notify_information->Action == FILE_ACTION_REMOVED){
TRACE(_T("文件监控,删除文件: %S\n"), file_name );
}else if (p_notify_information->Action == FILE_ACTION_MODIFIED){
TRACE(_T("文件监控,修改文件: %S\n"), file_name );
}else if( p_notify_information->Action == FILE_ACTION_RENAMED_OLD_NAME ){
TRACE(_T("文件监控,重命名->老名字: %S\n"), file_name );
}else if( p_notify_information->Action == FILE_ACTION_RENAMED_NEW_NAME ){
TRACE(_T("文件监控,重命名->新名字: %S\n"), file_name );
}
if( p_notify_information->NextEntryOffset ){
p_notify_information = PFILE_NOTIFY_INFORMATION((int)p_notify_information + p_notify_information->NextEntryOffset);
goto next_frame;
}else{
memset(parameter->in_out_notification, '\0', 1024);
}
}
Sleep(100);
}
return 0;
}//传递给WatchChanges函数的参数,这部分代码截自主函数
char notify[1024];FILE_NOTIFY_INFORMATION *Notification = (FILE_NOTIFY_INFORMATION *)notify;
FILE_NOTIFY_INFORMATION *TempNotification = NULL;
DWORD BytesReturned = 0;
DWORD version = 0;LPTSTR Directory = L"F:\\A50\\java\\doip\\uart\\libs\\armeabi\\";
//整合传给子线程的参数,该结构体的定义参考上面的定义
ThreadParameter ParameterToThread = { Directory, Notification, sizeof(notify), &BytesReturned, &version, TempNotification };void Cfile_extractDlg::OnBnClickedCheck2()
{
// TODO: 在此添加控件通知处理程序代码
CButton* pBtn = (CButton*)GetDlgItem(IDC_CHECK2);
int state = pBtn->GetCheck();
if (state == 1){
g_current_file_modify_monitor_enable = 0x01;
}
else{
g_current_file_modify_monitor_enable = 0x00; //::AfxBeginThread( Monitor, (LPVOID)m_hWnd );
memset(notify, '\0', 1024);
//创建一个线程专门用于监控文件变化
HANDLE TrheadWatch = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WatchChanges, &ParameterToThread, 0, NULL);
CloseHandle(TrheadWatch); }
}
这种模式有一个缺点,就是线程没法主动退出来
只有文件变化了 才能解除 ReadDirectoryChangesW函数的阻塞
做不到 主动、灵活可控的线程控制
也就是cpu资源不能随意控制
不爽
不过基本功能已经实现了 不会丢失文件的变化信息