最近由于项目需求,需要编写一个监控本机共享文件夹的变化的模块,经过查询资料,找到并实现了一个较为稳定的方式
项目实现是使用 Win32 C++的,测试平台是 Win 7 64 和 Win 10 64,XP 测试也是好使的。下面是具体实现
首先要获取并监控系统共享文件夹的路径,相关注册表路径为 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanmanServer\Share , 他的值的格式为如图所示,
0x01 C++ 获取共享文件夹目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| BOOL GetSharedFoldersList(map <CString, HANDLE> &theList) { BOOL bFlag = FALSE; HKEY hKey = NULL; do { theList.clear(); HKEY rootKey = REG_SHARE_KEY; CString szRegPath = REG_SHARE_PATH; int ErrCode; if (ERROR_SUCCESS != (ErrCode = RegOpenKeyEx(rootKey, szRegPath, 0, KEY_READ | KEY_WOW64_64KEY, &hKey))) { break; } TCHAR szValue [MAX_VALUE_NAME] = { 0 }; DWORD dwValueSize = MAX_VALUE_NAME; int index = 0; DWORD dwBufferSize = 255; DWORD dwType; TCHAR *szValBuffer = NULL; DWORD dwSize; while (ERROR_NO_MORE_ITEMS != RegEnumValue ( hKey, index, szValue, &dwValueSize, NULL, &dwType, NULL, &dwBufferSize)) { switch(dwType) { case REG_MULTI_SZ: { dwSize = dwBufferSize + 1; szValBuffer = new TCHAR [dwSize]; ZeroMemory(szValBuffer, dwSize); if (ERROR_SUCCESS != RegQueryValueEx(hKey, szValue, 0, &dwType, (LPBYTE)szValBuffer, &dwBufferSize)) { break; } int j = 0; CString TmpValue; for(int i = 0; szValBuffer [i] != '\0' ; i += j + 1) { for (j = 0; szValBuffer [i + j] != '\0'; j ++) { TmpValue += szValBuffer [i + j]; } if (TmpValue.Find(_T("Path =")) == 0) { CString Tmp = TmpValue.Right(TmpValue.GetLength() - 5); CString szTmp = Tmp; Tmp.MakeLower(); break; } TmpValue = _T(""); } delete szValBuffer; szValBuffer = NULL; break; } default: { break; } } dwValueSize = MAX_VALUE_NAME; dwBufferSize = 255; index ++; } bFlag = TRUE; }while(FALSE); if (hKey != NULL) { RegCloseKey(hKey); } return bFlag; }
|
0x02 C++监控共享注册表变化
方式一 创建线程,调用 RegNotifyChangeKeyValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| DWORD WINAPI SharedMonitor:: RefreshThread(LPVOID lpParam) { SharedMonitor *pThis = (SharedMonitor *)lpParam; DWORD dwFilter = REG_NOTIFY_CHANGE_LAST_SET; HKEY hKey; HKEY rootKey = REG_SHARE_KEY; CString szRegPath = REG_SHARE_PATH; int iWaitTime = 10 * 60 * 1000; while (TRUE) { HANDLE hEvent; BOOL bFlag = FALSE; do { if (ERROR_SUCCESS != RegOpenKeyEx(rootKey, szRegPath, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey)) { MyDebugA ("RegMonitorThread--- RegOpenKeyEx ERR!"); break; } if (NULL == (hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { MyDebugA ("CreateEvent ERR"); break; } if (ERROR_SUCCESS != RegNotifyChangeKeyValue (hKey, TRUE, dwFilter, hEvent, TRUE)) { MyDebugA ("RegNotifyChangeKeyValue ERR"); break; } if (WAIT_FAILED == WaitForSingleObject (hEvent, INFINITE)) { MyDebugA ("WaitForSingleObject ERR"); break; } bFlag = TRUE; }while(FALSE); RegCloseKey (hKey); CloseHandle (hEvent); if (! bFlag) { continue; } Sleep(200); map <CString, HANDLE> theNewList; pThis-> GetSharedFoldersList(theNewList); map <CString, HANDLE> &theOldList = pThis-> GetListInstance(); BOOL bFindNew = FALSE; for (map <CString, HANDLE>:: iterator it = theNewList.begin(); it != theNewList.end(); ++it) { if (theOldList.find(it-> first) == theOldList.end()) { MyDebug(_T("----------Find New Share----------")); MyDebug(it-> first); theOldList [it-> first] = 0; bFindNew = TRUE; } } vector <CString> theDeleteList; for (map <CString, HANDLE>:: iterator it = theOldList.begin(); it != theOldList.end(); ++it) { if (theNewList.find(it-> first) == theNewList.end()) { if (! TerminateThread(it-> second, 0)) { MyDebug(_T("TerminateThread ERR")); MyDebug(it-> first); } if (gs_mpDirHandleList [it-> first]) { CloseHandle(gs_mpDirHandleList [it-> first]); } CloseHandle(it-> second); theDeleteList.push_back(it-> first); } } MyDebug(_T("-----------DeleteList-------------")); for (vector <CString>:: iterator it = theDeleteList.begin(); it != theDeleteList.end(); ++it) { theOldList.erase(*it); MyDebug(*it); } if (bFindNew) { pThis-> SetSharedMonitor(); } } return 0; }
|
共享文件夹内文件监控
最后就是最终的目的,对共享文件夹内文件的变化进行监控操作。这里使用的是 WIN32 API ReadDirectoryChangesW
,这个的具体使用在我之前的一篇文章里有介绍,这里就不多说了,需要注意的一点是 ReadDirectoryChangesW
函数的第一个参数所需的句柄需要 CreateFile
去创建,而且创建后需要一直占用着不能释放,而创建时所需的权限(第三个参数) 必须设置为 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
,因为如果少任意一个就有可能导致某些第三方软件的使用出现异常,例如迅雷下载,浏览器下载之类的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| DWORD WINAPI ATSharedMonitor:: MonitorThread(LPVOID lpParam) { CString szRootPath = *(CString *)lpParam; HANDLE hRootHandle = CreateFile( szRootPath, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if(FAILED_HANDLE(hRootHandle)) { MyDebug(_T("CreateFile Fail")); return 0; } gs_mpDirHandleList [szRootPath] = hRootHandle; szRootPath += _T("\\"); wchar_t notify [1024]; ZeroMemory(notify, 1024); DWORD dwBytes; FILE_NOTIFY_INFORMATION *pNotify = (FILE_NOTIFY_INFORMATION *)notify; CString szLastFile = _T(""); while (TRUE) { if (ReadDirectoryChangesW (hRootHandle, ¬ify, sizeof(notify), TRUE, FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytes, NULL, NULL)) { MyDebug(_T("---------Change Happened!------------")); pNotify-> FileName [pNotify-> FileNameLength / 2] = '\0'; CString TmpPath = szRootPath + pNotify-> FileName; switch(pNotify-> Action) { case FILE_ACTION_RENAMED_OLD_NAME: { MyDebug (TEXT("文件更名 :") + TmpPath); PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify-> NextEntryOffset); p-> FileName [p-> FileNameLength/2] = '\0'; CString newName = szRootPath + p-> FileName; MyDebug(newName); break; }
case FILE_ACTION_MODIFIED: { if (! PathIsDirectory(TmpPath) ) { MyDebug (TEXT("文件修改 :") + TmpPath); } break; } case FILE_ACTION_ADDED: { if (! PathIsDirectory(TmpPath) ) { MyDebug (TEXT("文件添加 :") + TmpPath); } break; } default: { break; } } } } return 0; }
|