1 /*
2  * FILE:            notificationtest.c
3  * PURPOSE:         Files notifications testing
4  * NOTES:           MSDN code from: https://learn.microsoft.com/en-us/windows/win32/fileio/obtaining-directory-change-notifications
5  */
6 
7 #include <windows.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <tchar.h>
11 
12 #if defined(_tsplitpath) && !defined(_tsplitpath_s)
13 #define _tsplitpath_s(f, d,dl, p,pl, n,nl, e,el) _tsplitpath(f, d, p, n, e)
14 #else
15 #define _wsplitpath_s(f, d,dl, p,pl, n,nl, e,el) _wsplitpath(f, d, p, n, e)
16 #define _splitpath_s(f, d,dl, p,pl, n,nl, e,el) _splitpath(f, d, p, n, e)
17 #endif
18 
19 void RefreshDirectory(LPTSTR);
20 void RefreshTree(LPTSTR);
21 void WatchDirectory(LPTSTR);
22 
_tmain(int argc,TCHAR * argv[])23 int _tmain(int argc, TCHAR *argv[])
24 {
25     if(argc != 2)
26     {
27         _tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
28         return -1;
29     }
30 
31     WatchDirectory(argv[1]);
32 
33     return 0;
34 }
35 
WatchDirectory(LPTSTR lpDir)36 void WatchDirectory(LPTSTR lpDir)
37 {
38    DWORD dwWaitStatus;
39    HANDLE dwChangeHandles[2];
40    TCHAR lpDrive[4];
41    TCHAR lpFile[_MAX_FNAME];
42    TCHAR lpExt[_MAX_EXT];
43 
44    _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
45 
46    lpDrive[2] = (TCHAR)'\\';
47    lpDrive[3] = (TCHAR)'\0';
48 
49 // Watch the directory for file creation and deletion.
50 
51    dwChangeHandles[0] = FindFirstChangeNotification(
52       lpDir,                         // directory to watch
53       FALSE,                         // do not watch subtree
54       FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes
55 
56    if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
57    {
58      printf("\n ERROR: FindFirstChangeNotification function failed.\n");
59      ExitProcess(GetLastError());
60    }
61 
62 // Watch the subtree for directory creation and deletion.
63 
64    dwChangeHandles[1] = FindFirstChangeNotification(
65       lpDrive,                       // directory to watch
66       TRUE,                          // watch the subtree
67       FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes
68 
69    if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
70    {
71      printf("\n ERROR: FindFirstChangeNotification function failed.\n");
72      ExitProcess(GetLastError());
73    }
74 
75 
76 // Make a final validation check on our handles.
77 
78    if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
79    {
80      printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
81      ExitProcess(GetLastError());
82    }
83 
84 // Change notification is set. Now wait on both notification
85 // handles and refresh accordingly.
86 
87    while (TRUE)
88    {
89    // Wait for notification.
90 
91       printf("\nWaiting for notification...\n");
92 
93       dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
94          FALSE, INFINITE);
95 
96       switch (dwWaitStatus)
97       {
98          case WAIT_OBJECT_0:
99 
100          // A file was created, renamed, or deleted in the directory.
101          // Refresh this directory and restart the notification.
102 
103              RefreshDirectory(lpDir);
104              if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
105              {
106                printf("\n ERROR: FindNextChangeNotification function failed.\n");
107                ExitProcess(GetLastError());
108              }
109              break;
110 
111          case WAIT_OBJECT_0 + 1:
112 
113          // A directory was created, renamed, or deleted.
114          // Refresh the tree and restart the notification.
115 
116              RefreshTree(lpDrive);
117              if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
118              {
119                printf("\n ERROR: FindNextChangeNotification function failed.\n");
120                ExitProcess(GetLastError());
121              }
122              break;
123 
124          case WAIT_TIMEOUT:
125 
126          // A timeout occurred, this would happen if some value other
127          // than INFINITE is used in the Wait call and no changes occur.
128          // In a single-threaded environment you might not want an
129          // INFINITE wait.
130 
131             printf("\nNo changes in the timeout period.\n");
132             break;
133 
134          default:
135             printf("\n ERROR: Unhandled dwWaitStatus.\n");
136             ExitProcess(GetLastError());
137             break;
138       }
139    }
140 }
141 
RefreshDirectory(LPTSTR lpDir)142 void RefreshDirectory(LPTSTR lpDir)
143 {
144    // This is where you might place code to refresh your
145    // directory listing, but not the subtree because it
146    // would not be necessary.
147 
148    _tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
149 }
150 
RefreshTree(LPTSTR lpDrive)151 void RefreshTree(LPTSTR lpDrive)
152 {
153    // This is where you might place code to refresh your
154    // directory listing, including the subtree.
155 
156    _tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
157 }
158