Snapshot of commit d5ec1d5018ed24f1b4f32b1d09df6dbd7e2fc425
from branch master of git://git.jetbrains.org/idea/community.git
diff --git a/native/fileWatcher/fileWatcher3.cpp b/native/fileWatcher/fileWatcher3.cpp
new file mode 100644
index 0000000..9a0b3d8
--- /dev/null
+++ b/native/fileWatcher/fileWatcher3.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+
+struct WatchRootInfo {
+ char driveLetter;
+ HANDLE hThread;
+ HANDLE hStopEvent;
+ bool bInitialized;
+ bool bUsed;
+ bool bFailed;
+};
+
+struct WatchRoot {
+ char *path;
+ WatchRoot *next;
+};
+
+const int ROOT_COUNT = 26;
+
+WatchRootInfo watchRootInfos[ROOT_COUNT];
+
+WatchRoot *firstWatchRoot = NULL;
+
+CRITICAL_SECTION csOutput;
+
+void NormalizeSlashes(char *path, char slash)
+{
+ for(char *p=path; *p; p++)
+ if (*p == '\\' || *p == '/')
+ *p = slash;
+}
+
+// -- Watchable root checks ---------------------------------------------------
+
+bool IsNetworkDrive(const char *name)
+{
+ const int BUF_SIZE = 1024;
+ char buffer[BUF_SIZE];
+ UNIVERSAL_NAME_INFO* uni = (UNIVERSAL_NAME_INFO*) buffer;
+ DWORD size = BUF_SIZE;
+
+ DWORD result = WNetGetUniversalNameA(
+ name, // path for network resource
+ UNIVERSAL_NAME_INFO_LEVEL, // level of information
+ buffer, // name buffer
+ &size // size of buffer
+ );
+
+ return result == NO_ERROR;
+}
+
+bool IsUnwatchableFS(const char *path)
+{
+ char volumeName[MAX_PATH];
+ char fsName[MAX_PATH];
+ DWORD fsFlags;
+ DWORD maxComponentLength;
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+ if (!GetVolumeInformationA(path, volumeName, MAX_PATH-1, NULL, &maxComponentLength, &fsFlags, fsName, MAX_PATH-1))
+ return false;
+ if (strcmp(fsName, "NTFS") && strcmp(fsName, "FAT") && strcmp(fsName, "FAT32"))
+ return true;
+
+ if (!strcmp(fsName, "NTFS") && maxComponentLength != 255 && !(fsFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ // SAMBA reports itself as NTFS
+ return true;
+ }
+
+ return false;
+}
+
+bool IsWatchable(const char *path)
+{
+ if (IsNetworkDrive(path))
+ return false;
+ if (IsUnwatchableFS(path))
+ return false;
+ return true;
+}
+
+// -- Substed drive checks ----------------------------------------------------
+
+void PrintRemapForSubstDrive(char driveLetter)
+{
+ const int BUF_SIZE = 1024;
+ char targetPath[BUF_SIZE];
+
+ char rootPath[8];
+ sprintf_s(rootPath, 8, "%c:", driveLetter);
+
+ DWORD result = QueryDosDeviceA(rootPath, targetPath, BUF_SIZE);
+ if (result == 0) {
+ return;
+ }
+ else
+ {
+ if (targetPath[0] == '\\' && targetPath[1] == '?' && targetPath[2] == '?' && targetPath[3] == '\\')
+ {
+ // example path: \??\C:\jetbrains\idea
+ NormalizeSlashes(targetPath, '/');
+ printf("%c:\n%s\n", driveLetter, targetPath+4);
+ }
+ }
+}
+
+void PrintRemapForSubstDrives()
+{
+ for(int i=0; i<ROOT_COUNT; i++)
+ {
+ if (watchRootInfos [i].bUsed)
+ {
+ PrintRemapForSubstDrive(watchRootInfos [i].driveLetter);
+ }
+ }
+}
+
+// -- Mount point enumeration -------------------------------------------------
+
+const int BUFSIZE = 1024;
+
+void PrintDirectoryReparsePoint(const char *path)
+{
+ int size = strlen(path)+2;
+ char *directory = (char *) malloc(size);
+ strcpy_s(directory, size, path);
+ NormalizeSlashes(directory, '\\');
+ if (directory [strlen(directory)-1] != '\\')
+ strcat_s(directory, size, "\\");
+
+ char volumeName[_MAX_PATH];
+ int rc = GetVolumeNameForVolumeMountPointA(directory, volumeName, sizeof(volumeName));
+ if (rc)
+ {
+ char volumePathNames[_MAX_PATH];
+ DWORD returnLength;
+ rc = GetVolumePathNamesForVolumeNameA(volumeName, volumePathNames, sizeof(volumePathNames), &returnLength);
+ if (rc)
+ {
+ char *p = volumePathNames;
+ while(*p)
+ {
+ if (_stricmp(p, directory)) // if it's not the path we've already found
+ {
+ NormalizeSlashes(directory, '/');
+ NormalizeSlashes(p, '/');
+ puts(directory);
+ puts(p);
+ }
+ p += strlen(p)+1;
+ }
+ }
+ }
+ free(directory);
+}
+
+bool PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
+{
+ HANDLE hPt; // handle for mount point scan
+ char Path[BUFSIZE]; // string buffer for mount points
+ DWORD dwSysFlags; // flags that describe the file system
+ char FileSysNameBuf[BUFSIZE];
+
+ // Is this volume NTFS?
+ GetVolumeInformationA(Buf, NULL, 0, NULL, NULL, &dwSysFlags, FileSysNameBuf, BUFSIZE);
+
+ // Detect support for reparse points, and therefore for volume
+ // mount points, which are implemented using reparse points.
+
+ if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS)) {
+ return true;
+ }
+
+ // Start processing mount points on this volume.
+ hPt = FindFirstVolumeMountPointA(
+ Buf, // root path of volume to be scanned
+ Path, // pointer to output string
+ BUFSIZE // size of output buffer
+ );
+
+ // Shall we error out?
+ if (hPt == INVALID_HANDLE_VALUE) {
+ return GetLastError() != ERROR_ACCESS_DENIED;
+ }
+
+ // Process the volume mount point.
+ char *buf = new char[MAX_PATH];
+ do {
+ strcpy_s(buf, MAX_PATH, volumePath);
+ strcat_s(buf, MAX_PATH, Path);
+ PrintDirectoryReparsePoint(buf);
+ } while (FindNextVolumeMountPointA(hPt, Path, BUFSIZE));
+
+ FindVolumeMountPointClose(hPt);
+ return true;
+}
+
+bool PrintMountPoints(const char *path)
+{
+ char volumeUniqueName[128];
+ BOOL res = GetVolumeNameForVolumeMountPointA(path, volumeUniqueName, 128);
+ if (!res) {
+ return false;
+ }
+
+ char buf[BUFSIZE]; // buffer for unique volume identifiers
+ HANDLE hVol; // handle for the volume scan
+
+ // Open a scan for volumes.
+ hVol = FindFirstVolumeA(buf, BUFSIZE );
+
+ // Shall we error out?
+ if (hVol == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ bool success = true;
+ do {
+ if (!strcmp(buf, volumeUniqueName)) {
+ success = PrintMountPointsForVolume(hVol, path, buf);
+ if (!success) break;
+ }
+ } while (FindNextVolumeA(hVol, buf, BUFSIZE));
+
+ FindVolumeClose(hVol);
+ return success;
+}
+
+// -- Searching for mount points in watch roots (fallback) --------------------
+
+void PrintDirectoryReparsePoints(const char *path)
+{
+ char *const buf = _strdup(path);
+ while(strchr(buf, '/'))
+ {
+ DWORD attributes = GetFileAttributesA(buf);
+ if (attributes == INVALID_FILE_ATTRIBUTES)
+ break;
+ if (attributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ PrintDirectoryReparsePoint(buf);
+ }
+ char *pSlash = strrchr(buf, '/');
+ if (pSlash)
+ {
+ *pSlash = '\0';
+ }
+ }
+ free(buf);
+}
+
+// This is called if we got an ERROR_ACCESS_DENIED when trying to enumerate all mount points for volume.
+// In this case, we walk the directory tree up from each watch root, and look at each parent directory
+// to check whether it's a reparse point.
+void PrintWatchRootReparsePoints()
+{
+ WatchRoot *pWatchRoot = firstWatchRoot;
+ while(pWatchRoot)
+ {
+ PrintDirectoryReparsePoints(pWatchRoot->path);
+ pWatchRoot = pWatchRoot->next;
+ }
+}
+
+// -- Watcher thread ----------------------------------------------------------
+
+void PrintChangeInfo(char *rootPath, FILE_NOTIFY_INFORMATION *info)
+{
+ char FileNameBuffer[_MAX_PATH];
+ int converted = WideCharToMultiByte(CP_ACP, 0, info->FileName, info->FileNameLength/sizeof(WCHAR), FileNameBuffer, _MAX_PATH-1, NULL, NULL);
+ FileNameBuffer[converted] = '\0';
+ char *command;
+ if (info->Action == FILE_ACTION_ADDED || info->Action == FILE_ACTION_RENAMED_OLD_NAME)
+ {
+ command = "CREATE";
+ }
+ else if (info->Action == FILE_ACTION_REMOVED || info->Action == FILE_ACTION_RENAMED_OLD_NAME)
+ {
+ command = "DELETE";
+ }
+ else if (info->Action == FILE_ACTION_MODIFIED)
+ {
+ command = "CHANGE";
+ }
+ else
+ {
+ return; // unknown command
+ }
+
+ EnterCriticalSection(&csOutput);
+ puts(command);
+ printf("%s", rootPath);
+ puts(FileNameBuffer);
+ fflush(stdout);
+ LeaveCriticalSection(&csOutput);
+}
+
+void PrintEverythingChangedUnderRoot(char *rootPath)
+{
+ EnterCriticalSection(&csOutput);
+ puts("RECDIRTY");
+ puts(rootPath);
+ fflush(stdout);
+ LeaveCriticalSection(&csOutput);
+}
+
+DWORD WINAPI WatcherThread(void *param)
+{
+ WatchRootInfo *info = (WatchRootInfo *) param;
+
+ OVERLAPPED overlapped;
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ char rootPath[8];
+ sprintf_s(rootPath, 8, "%c:\\", info->driveLetter);
+ HANDLE hRootDir = CreateFileA(rootPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
+
+ int buffer_size = 10240;
+ char *buffer = new char[buffer_size];
+
+ HANDLE handles [2];
+ handles [0] = info->hStopEvent;
+ handles [1] = overlapped.hEvent;
+ while(true)
+ {
+ int rcDir = ReadDirectoryChangesW(hRootDir, buffer, buffer_size, TRUE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE,
+ NULL,
+ &overlapped,
+ NULL);
+ if (rcDir == 0)
+ {
+ info->bFailed = true;
+ break;
+ }
+
+ int rc = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ if (rc == WAIT_OBJECT_0)
+ {
+ break;
+ }
+ if (rc == WAIT_OBJECT_0+1)
+ {
+ DWORD dwBytesReturned;
+ if(!GetOverlappedResult(hRootDir, &overlapped, &dwBytesReturned, FALSE))
+ {
+ info->bFailed = true;
+ break;
+ }
+
+ if (dwBytesReturned == 0)
+ {
+ // don't send dirty too much, everything is changed anyway
+ if (WaitForSingleObject(info->hStopEvent, 500) == WAIT_OBJECT_0)
+ break;
+
+ // Got a buffer overflow => current changes lost => send RECDIRTY on root
+ PrintEverythingChangedUnderRoot(rootPath);
+ } else {
+ FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *) buffer;
+ while(true)
+ {
+ PrintChangeInfo(rootPath, info);
+ if (!info->NextEntryOffset)
+ break;
+ info = (FILE_NOTIFY_INFORMATION *) ((char *) info + info->NextEntryOffset);
+ }
+ }
+ }
+ }
+ CloseHandle(overlapped.hEvent);
+ CloseHandle(hRootDir);
+ delete[] buffer;
+ return 0;
+}
+
+// -- Roots update ------------------------------------------------------------
+
+void MarkAllRootsUnused()
+{
+ for(int i=0; i<ROOT_COUNT; i++)
+ {
+ watchRootInfos [i].bUsed = false;
+ }
+}
+
+void StartRoot(WatchRootInfo *info)
+{
+ info->hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ info->hThread = CreateThread(NULL, 0, &WatcherThread, info, 0, NULL);
+ info->bInitialized = true;
+}
+
+void StopRoot(WatchRootInfo *info)
+{
+ SetEvent(info->hStopEvent);
+ WaitForSingleObject(info->hThread, INFINITE);
+ CloseHandle(info->hThread);
+ CloseHandle(info->hStopEvent);
+ info->bInitialized = false;
+}
+
+void UpdateRoots()
+{
+ char infoBuffer [256];
+ strcpy_s(infoBuffer, "UNWATCHEABLE\n");
+ for(int i=0; i<ROOT_COUNT; i++)
+ {
+ if (watchRootInfos [i].bInitialized && (!watchRootInfos [i].bUsed || watchRootInfos [i].bFailed))
+ {
+ StopRoot(&watchRootInfos [i]);
+ watchRootInfos [i].bFailed = false;
+ }
+ if (watchRootInfos [i].bUsed)
+ {
+ char rootPath[8];
+ sprintf_s(rootPath, 8, "%c:\\", watchRootInfos [i].driveLetter);
+ if (!IsWatchable(rootPath))
+ {
+ strcat_s(infoBuffer, rootPath);
+ strcat_s(infoBuffer, "\n");
+ continue;
+ }
+ if (!watchRootInfos [i].bInitialized)
+ {
+ StartRoot(&watchRootInfos [i]);
+ }
+ }
+ }
+ EnterCriticalSection(&csOutput);
+ fprintf(stdout, "%s", infoBuffer);
+ puts("#\nREMAP");
+ PrintRemapForSubstDrives();
+ bool printedMountPoints = true;
+ for(int i=0; i<ROOT_COUNT; i++)
+ {
+ if (watchRootInfos [i].bUsed)
+ {
+ char rootPath[8];
+ sprintf_s(rootPath, 8, "%c:\\", watchRootInfos [i].driveLetter);
+ if (!PrintMountPoints(rootPath))
+ printedMountPoints = false;
+ }
+ }
+ if (!printedMountPoints)
+ {
+ PrintWatchRootReparsePoints();
+ }
+ puts("#");
+ fflush(stdout);
+ LeaveCriticalSection(&csOutput);
+}
+
+void AddWatchRoot(const char *path)
+{
+ WatchRoot *watchRoot = (WatchRoot *) malloc(sizeof(WatchRoot));
+ watchRoot->next = NULL;
+ watchRoot->path = _strdup(path);
+ watchRoot->next = firstWatchRoot;
+ firstWatchRoot = watchRoot;
+}
+
+void FreeWatchRootsList()
+{
+ WatchRoot *pWatchRoot = firstWatchRoot;
+ WatchRoot *pNext;
+ while(pWatchRoot)
+ {
+ pNext = pWatchRoot->next;
+ free(pWatchRoot->path);
+ free(pWatchRoot);
+ pWatchRoot=pNext;
+ }
+ firstWatchRoot = NULL;
+}
+
+// -- Main - filewatcher protocol ---------------------------------------------
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ InitializeCriticalSection(&csOutput);
+
+ for(int i=0; i<26; i++)
+ {
+ watchRootInfos [i].driveLetter = 'A' + i;
+ watchRootInfos [i].bInitialized = false;
+ watchRootInfos [i].bUsed = false;
+ }
+
+ char buffer[8192];
+ while(true)
+ {
+ if (!gets_s(buffer, sizeof(buffer)-1))
+ break;
+
+ if (!strcmp(buffer, "ROOTS"))
+ {
+ MarkAllRootsUnused();
+ FreeWatchRootsList();
+ bool failed = false;
+ while(true)
+ {
+ if (!gets_s(buffer, sizeof(buffer)-1))
+ {
+ failed = true;
+ break;
+ }
+ if (buffer [0] == '#')
+ break;
+ int driveLetterPos = 0;
+ char *pDriveLetter = buffer;
+ if (*pDriveLetter == '|')
+ pDriveLetter++;
+
+ AddWatchRoot(pDriveLetter);
+
+ _strupr_s(buffer, sizeof(buffer)-1);
+ char driveLetter = *pDriveLetter;
+ if (driveLetter >= 'A' && driveLetter <= 'Z')
+ {
+ watchRootInfos [driveLetter-'A'].bUsed = true;
+ }
+ }
+ if (failed)
+ break;
+
+ UpdateRoots();
+ }
+ if (!strcmp(buffer, "EXIT"))
+ break;
+ }
+
+ MarkAllRootsUnused();
+ UpdateRoots();
+
+ DeleteCriticalSection(&csOutput);
+}
diff --git a/native/fileWatcher/fileWatcher3.rc b/native/fileWatcher/fileWatcher3.rc
new file mode 100644
index 0000000..a2ed61e
--- /dev/null
+++ b/native/fileWatcher/fileWatcher3.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "041904b0"
+ BEGIN
+ VALUE "CompanyName", "JetBrains, Inc."
+ VALUE "FileDescription", "File System Notification Processor"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "fsnotifier"
+ VALUE "LegalCopyright", "Copyright (C) 2008-09 JetBrains, Inc."
+ VALUE "OriginalFilename", "fsnotifier.exe"
+ VALUE "ProductName", "IntelliJ IDEA"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x419, 1200
+ END
+END
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/native/fileWatcher/fileWatcher3.sln b/native/fileWatcher/fileWatcher3.sln
new file mode 100644
index 0000000..821f143
--- /dev/null
+++ b/native/fileWatcher/fileWatcher3.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fileWatcher3", "fileWatcher3.vcproj", "{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|Win32.Build.0 = Debug|Win32
+ {0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|Win32.ActiveCfg = Release|Win32
+ {0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/native/fileWatcher/fileWatcher3.vcproj b/native/fileWatcher/fileWatcher3.vcproj
new file mode 100644
index 0000000..14ec211
--- /dev/null
+++ b/native/fileWatcher/fileWatcher3.vcproj
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="fileWatcher3"
+ ProjectGUID="{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}"
+ RootNamespace="fileWatcher3"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="mpr.lib"
+ OutputFile="$(OutDir)\fsnotifier.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="mpr.lib"
+ OutputFile="$(OutDir)\fsnotifier.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\fileWatcher3.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\targetver.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\fileWatcher3.rc"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/native/fileWatcher/resource.h b/native/fileWatcher/resource.h
new file mode 100644
index 0000000..08209cb
--- /dev/null
+++ b/native/fileWatcher/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by fileWatcher3.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/native/fileWatcher/stdafx.cpp b/native/fileWatcher/stdafx.cpp
new file mode 100644
index 0000000..4303745
--- /dev/null
+++ b/native/fileWatcher/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// fileWatcher3.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/native/fileWatcher/stdafx.h b/native/fileWatcher/stdafx.h
new file mode 100644
index 0000000..624e518
--- /dev/null
+++ b/native/fileWatcher/stdafx.h
@@ -0,0 +1,15 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+#include <process.h>
+
+// TODO: reference additional headers your program requires here
diff --git a/native/fileWatcher/targetver.h b/native/fileWatcher/targetver.h
new file mode 100644
index 0000000..7021c2a
--- /dev/null
+++ b/native/fileWatcher/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+