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