最近由于项目需求,需要编写一个监控本机共享文件夹的变化的模块,经过查询资料,找到并实现了一个较为稳定的方式
项目实现是使用 Win32 C++的,测试平台是 Win 7 64 和 Win 10 64,XP 测试也是好使的。下面是具体实现
首先要获取并监控系统共享文件夹的路径,相关注册表路径为 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanmanServer\Share , 他的值的格式为如图所示,

 0x01 C++ 获取共享文件夹目录
| 12
 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
| 12
 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,因为如果少任意一个就有可能导致某些第三方软件的使用出现异常,例如迅雷下载,浏览器下载之类的。
| 12
 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;
 }
 
 |