// ====================================================================== // DirectoryWatcher.cpp // ====================================================================== #include "stdafx.h" #include "DirectoryWatcher.h" #include "PerforceClientService.h" #include "FileSystemEvent.h" #include <windows.h> #include <process.h> #include <stdio.h> #include <stdarg.h> // ====================================================================== unsigned int __stdcall DirectoryWatcher::beginThread(void * object) { return reinterpret_cast<DirectoryWatcher *>(object)->threadRoutine(); } // ---------------------------------------------------------------------- char * DirectoryWatcher::duplicateString(char const * source) { int const length = strlen(source) + 1; char * copy = new char[length]; memcpy(copy, source, length); return copy; } // ---------------------------------------------------------------------- void DirectoryWatcher::convertToChar(wchar_t const * source, int fileNameLength, char * dest) { for (int i = 0; i < fileNameLength; ++i) dest[i] = static_cast<char>(source[i]); dest[fileNameLength/2] = '\0'; } // ====================================================================== DirectoryWatcher::DirectoryWatcher(char const * directory) : m_directory(duplicateString(directory)), m_stopThread(false) { _beginthreadex(NULL, 0, &DirectoryWatcher::beginThread, this, 0, NULL); } // ---------------------------------------------------------------------- DirectoryWatcher::~DirectoryWatcher() { m_stopThread = true; char buffer[MAX_PATH]; _snprintf_s(buffer, sizeof(buffer), _TRUNCATE, "%s/%s", m_directory, "stopThread.tmp"); HANDLE handle = CreateFile(buffer, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL); if (handle == INVALID_HANDLE_VALUE) { MessageBox(NULL, buffer, "StopThread failed", MB_ICONERROR); abort(); } CloseHandle(handle); DeleteFile(buffer); delete [] m_directory; } // ---------------------------------------------------------------------- unsigned int DirectoryWatcher::threadRoutine() { HANDLE directory = CreateFile(m_directory, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (directory == INVALID_HANDLE_VALUE) return 1; // build a spot for the full-path 'from' file name char path[MAX_PATH]; int basePathLength = strlen(m_directory); strcpy_s(path, sizeof(path), m_directory); if (path[basePathLength-1] != '\\') { path[basePathLength] = '\\'; path[basePathLength+1] = '\0'; ++basePathLength; } // reserve some storage for the filename for rename options char rename[MAX_PATH]; // watch for changes until the application wants to quite for (;;) { // get the directory changes DWORD bytesReturned = 0; char buffer[16 * 1024]; BOOL result = ReadDirectoryChangesW(directory, buffer, sizeof(buffer), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &bytesReturned, NULL, NULL); if (!result) return 2; // parse all the records returned for (FILE_NOTIFY_INFORMATION * f = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(buffer); f; f = (f->NextEntryOffset ? reinterpret_cast<FILE_NOTIFY_INFORMATION *>(reinterpret_cast<char *>(f) + f->NextEntryOffset) : NULL)) { convertToChar(f->FileName, f->FileNameLength, path+basePathLength); switch (f->Action) { // handle file adds case FILE_ACTION_ADDED: { if (strstr(path, "stopThread.tmp") != 0 && m_stopThread) { CloseHandle(directory); return 0; } static_cast<CPerforceClientServiceApp*>(AfxGetApp())->enqueueFileSystemEvent(new FileSystemEvent(FileSystemEvent::T_add, path)); } break; // handle file deletes case FILE_ACTION_REMOVED: static_cast<CPerforceClientServiceApp*>(AfxGetApp())->enqueueFileSystemEvent(new FileSystemEvent(FileSystemEvent::T_delete, path)); break; // handle file changes case FILE_ACTION_MODIFIED: static_cast<CPerforceClientServiceApp*>(AfxGetApp())->enqueueFileSystemEvent(new FileSystemEvent(FileSystemEvent::T_modify, path)); break; // handle the first half of a rename case FILE_ACTION_RENAMED_OLD_NAME: strcpy_s(rename, sizeof(rename), path); break; // complete handling a rename case FILE_ACTION_RENAMED_NEW_NAME: static_cast<CPerforceClientServiceApp*>(AfxGetApp())->enqueueFileSystemEvent(new FileSystemEvent(FileSystemEvent::T_rename, rename, path)); break; } } } } // ======================================================================
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 7201 | Jeff Grills | Upgrade to VS2005 and the 2008.2 p4api | ||
#1 | 4896 | Jeff Grills |
First drop of the PerforceClientService. This version is only barely functional, supporting adds, edits, and deletes. It does not handle multiple operations on the same file gracefully. |