2 * Tests for file change notification functions
4 * Copyright (c) 2004 Hans Leidekker
5 * Copyright 2006 Mike McCormack for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* TODO: - security attribute changes
23 * - compound filter and multiple notifications
24 * - subtree notifications
25 * - non-documented flags FILE_NOTIFY_CHANGE_LAST_ACCESS and
26 * FILE_NOTIFY_CHANGE_CREATION
33 #define WIN32_NO_STATUS
34 #include "wine/test.h"
39 static DWORD CALLBACK
NotificationThread(LPVOID arg
)
41 HANDLE change
= (HANDLE
) arg
;
45 status
= WaitForSingleObject(change
, 100);
47 if (status
== WAIT_OBJECT_0
) {
48 ret
= FindNextChangeNotification(change
);
51 ret
= FindCloseChangeNotification(change
);
52 ok( ret
, "FindCloseChangeNotification error: %ld\n",
55 ExitThread((DWORD
)ret
);
58 static HANDLE
StartNotificationThread(LPCSTR path
, BOOL subtree
, DWORD flags
)
60 HANDLE change
, thread
;
63 change
= FindFirstChangeNotificationA(path
, subtree
, flags
);
64 ok(change
!= INVALID_HANDLE_VALUE
, "FindFirstChangeNotification error: %ld\n", GetLastError());
66 thread
= CreateThread(NULL
, 0, NotificationThread
, (LPVOID
)change
,
68 ok(thread
!= INVALID_HANDLE_VALUE
, "CreateThread error: %ld\n", GetLastError());
73 static DWORD
FinishNotificationThread(HANDLE thread
)
75 DWORD status
, exitcode
;
77 status
= WaitForSingleObject(thread
, 5000);
78 ok(status
== WAIT_OBJECT_0
, "WaitForSingleObject status %ld error %ld\n", status
, GetLastError());
80 ok(GetExitCodeThread(thread
, &exitcode
), "Could not retrieve thread exit code\n");
85 static void test_FindFirstChangeNotification(void)
87 HANDLE change
, file
, thread
;
88 DWORD attributes
, count
;
91 char workdir
[MAX_PATH
], dirname1
[MAX_PATH
], dirname2
[MAX_PATH
];
92 char filename1
[MAX_PATH
], filename2
[MAX_PATH
];
93 static const char prefix
[] = "FCN";
98 change
= FindFirstChangeNotificationA("not-a-file", FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
99 ok(change
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_FILE_NOT_FOUND
,
100 "FindFirstChangeNotification error: %ld\n", GetLastError());
102 if (0) /* This documents win2k behavior. It crashes on win98. */
104 change
= FindFirstChangeNotificationA(NULL
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
105 ok(change
== NULL
&& GetLastError() == ERROR_PATH_NOT_FOUND
,
106 "FindFirstChangeNotification error: %ld\n", GetLastError());
109 ret
= FindNextChangeNotification(NULL
);
110 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "FindNextChangeNotification error: %ld\n",
113 ret
= FindCloseChangeNotification(NULL
);
114 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "FindCloseChangeNotification error: %ld\n",
117 ret
= GetTempPathA(MAX_PATH
, workdir
);
118 ok(ret
, "GetTempPathA error: %ld\n", GetLastError());
120 lstrcatA(workdir
, "testFileChangeNotification");
122 ret
= CreateDirectoryA(workdir
, NULL
);
123 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
125 ret
= GetTempFileNameA(workdir
, prefix
, 0, filename1
);
126 ok(ret
, "GetTempFileNameA error: %ld\n", GetLastError());
128 file
= CreateFileA(filename1
, GENERIC_WRITE
|GENERIC_READ
, 0, NULL
, CREATE_ALWAYS
,
129 FILE_ATTRIBUTE_NORMAL
, 0);
130 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
131 ret
= CloseHandle(file
);
132 ok( ret
, "CloseHandle error: %ld\n", GetLastError());
134 /* Try to register notification for a file. win98 and win2k behave differently here */
135 change
= FindFirstChangeNotificationA(filename1
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
136 ok(change
== INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_DIRECTORY
||
137 GetLastError() == ERROR_FILE_NOT_FOUND
),
138 "FindFirstChangeNotification error: %ld\n", GetLastError());
140 lstrcpyA(dirname1
, filename1
);
141 lstrcatA(dirname1
, "dir");
143 lstrcpyA(dirname2
, dirname1
);
144 lstrcatA(dirname2
, "new");
146 ret
= CreateDirectoryA(dirname1
, NULL
);
147 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
149 /* What if we move the directory we registered notification for? */
150 thread
= StartNotificationThread(dirname1
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
151 ret
= MoveFileA(dirname1
, dirname2
);
152 ok(ret
, "MoveFileA error: %ld\n", GetLastError());
153 ok(FinishNotificationThread(thread
), "Missed notification\n");
155 /* What if we remove the directory we registered notification for? */
156 thread
= StartNotificationThread(dirname2
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
157 ret
= RemoveDirectoryA(dirname2
);
158 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
160 /* win98 and win2k behave differently here */
161 ret
= FinishNotificationThread(thread
);
162 ok(ret
|| !ret
, "You'll never read this\n");
164 /* functional checks */
166 /* Create a directory */
167 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
168 ret
= CreateDirectoryA(dirname1
, NULL
);
169 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
170 ok(FinishNotificationThread(thread
), "Missed notification\n");
172 /* Rename a directory */
173 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
174 ret
= MoveFileA(dirname1
, dirname2
);
175 ok(ret
, "MoveFileA error: %ld\n", GetLastError());
176 ok(FinishNotificationThread(thread
), "Missed notification\n");
178 /* Delete a directory */
179 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
180 ret
= RemoveDirectoryA(dirname2
);
181 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
182 ok(FinishNotificationThread(thread
), "Missed notification\n");
184 lstrcpyA(filename2
, filename1
);
185 lstrcatA(filename2
, "new");
188 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
189 ret
= MoveFileA(filename1
, filename2
);
190 ok(ret
, "MoveFileA error: %ld\n", GetLastError());
191 ok(FinishNotificationThread(thread
), "Missed notification\n");
194 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
195 ret
= DeleteFileA(filename2
);
196 ok(ret
, "DeleteFileA error: %ld\n", GetLastError());
197 ok(FinishNotificationThread(thread
), "Missed notification\n");
200 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
201 file
= CreateFileA(filename2
, GENERIC_WRITE
|GENERIC_READ
, 0, NULL
, CREATE_ALWAYS
,
202 FILE_ATTRIBUTE_NORMAL
, 0);
203 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
204 ret
= CloseHandle(file
);
205 ok( ret
, "CloseHandle error: %ld\n", GetLastError());
206 ok(FinishNotificationThread(thread
), "Missed notification\n");
208 attributes
= GetFileAttributesA(filename2
);
209 ok(attributes
!= INVALID_FILE_ATTRIBUTES
, "GetFileAttributesA error: %ld\n", GetLastError());
210 attributes
&= FILE_ATTRIBUTE_READONLY
;
212 /* Change file attributes */
213 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_ATTRIBUTES
);
214 ret
= SetFileAttributesA(filename2
, attributes
);
215 ok(ret
, "SetFileAttributesA error: %ld\n", GetLastError());
216 ok(FinishNotificationThread(thread
), "Missed notification\n");
218 /* Change last write time by writing to a file */
219 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_LAST_WRITE
);
220 file
= CreateFileA(filename2
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
221 FILE_ATTRIBUTE_NORMAL
, 0);
222 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
223 ret
= WriteFile(file
, buffer
, sizeof(buffer
), &count
, NULL
);
224 ok(ret
&& count
== sizeof(buffer
), "WriteFile error: %ld\n", GetLastError());
225 ret
= CloseHandle(file
);
226 ok( ret
, "CloseHandle error: %ld\n", GetLastError());
227 ok(FinishNotificationThread(thread
), "Missed notification\n");
229 /* Change file size by truncating a file */
230 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_SIZE
);
231 file
= CreateFileA(filename2
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
232 FILE_ATTRIBUTE_NORMAL
, 0);
233 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
234 ret
= WriteFile(file
, buffer
, sizeof(buffer
) / 2, &count
, NULL
);
235 ok(ret
&& count
== sizeof(buffer
) / 2, "WriteFileA error: %ld\n", GetLastError());
236 ret
= CloseHandle(file
);
237 ok( ret
, "CloseHandle error: %ld\n", GetLastError());
238 ok(FinishNotificationThread(thread
), "Missed notification\n");
242 ret
= DeleteFileA(filename2
);
243 ok(ret
, "DeleteFileA error: %ld\n", GetLastError());
245 ret
= RemoveDirectoryA(workdir
);
246 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
249 /* this test concentrates more on the wait behaviour of the handle */
250 static void test_ffcn(void)
255 WCHAR path
[MAX_PATH
], subdir
[MAX_PATH
];
256 static const WCHAR szBoo
[] = { '\\','b','o','o',0 };
257 static const WCHAR szHoo
[] = { '\\','h','o','o',0 };
259 r
= GetTempPathW( MAX_PATH
, path
);
260 ok( r
!= 0, "temp path failed\n");
264 lstrcatW( path
, szBoo
);
265 lstrcpyW( subdir
, path
);
266 lstrcatW( subdir
, szHoo
);
268 RemoveDirectoryW( subdir
);
269 RemoveDirectoryW( path
);
271 r
= CreateDirectoryW(path
, NULL
);
272 ok( r
== TRUE
, "failed to create directory\n");
274 filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
275 filter
|= FILE_NOTIFY_CHANGE_DIR_NAME
;
277 handle
= FindFirstChangeNotificationW( path
, 1, filter
);
278 ok( handle
!= INVALID_HANDLE_VALUE
, "invalid handle\n");
280 r
= WaitForSingleObject( handle
, 0 );
281 ok( r
== STATUS_TIMEOUT
, "should time out\n");
283 r
= CreateDirectoryW( subdir
, NULL
);
284 ok( r
== TRUE
, "failed to create subdir\n");
286 r
= WaitForSingleObject( handle
, 0 );
287 ok( r
== WAIT_OBJECT_0
, "should be ready\n");
289 r
= WaitForSingleObject( handle
, 0 );
290 ok( r
== WAIT_OBJECT_0
, "should be ready\n");
292 r
= FindNextChangeNotification(handle
);
293 ok( r
== TRUE
, "find next failed\n");
295 r
= WaitForSingleObject( handle
, 0 );
296 ok( r
== STATUS_TIMEOUT
, "should time out\n");
298 r
= RemoveDirectoryW( subdir
);
299 ok( r
== TRUE
, "failed to remove subdir\n");
301 r
= WaitForSingleObject( handle
, 0 );
302 ok( r
== WAIT_OBJECT_0
, "should be ready\n");
304 r
= WaitForSingleObject( handle
, 0 );
305 ok( r
== WAIT_OBJECT_0
, "should be ready\n");
307 r
= FindNextChangeNotification(handle
);
308 ok( r
== TRUE
, "find next failed\n");
310 r
= FindNextChangeNotification(handle
);
311 ok( r
== TRUE
, "find next failed\n");
313 r
= FindCloseChangeNotification(handle
);
314 ok( r
== TRUE
, "should succeed\n");
316 r
= RemoveDirectoryW( path
);
317 ok( r
== TRUE
, "failed to remove dir\n");
320 typedef BOOL (WINAPI
*fnReadDirectoryChangesW
)(HANDLE
,LPVOID
,DWORD
,BOOL
,DWORD
,
321 LPDWORD
,LPOVERLAPPED
,LPOVERLAPPED_COMPLETION_ROUTINE
);
322 fnReadDirectoryChangesW pReadDirectoryChangesW
;
324 static void test_readdirectorychanges(void)
328 DWORD fflags
, filter
= 0, r
, dwCount
;
330 WCHAR path
[MAX_PATH
], subdir
[MAX_PATH
];
331 static const WCHAR szBoo
[] = { '\\','b','o','o',0 };
332 static const WCHAR szHoo
[] = { '\\','h','o','o',0 };
333 PFILE_NOTIFY_INFORMATION pfni
;
335 if (!pReadDirectoryChangesW
)
338 r
= GetTempPathW( MAX_PATH
, path
);
339 ok( r
!= 0, "temp path failed\n");
343 lstrcatW( path
, szBoo
);
344 lstrcpyW( subdir
, path
);
345 lstrcatW( subdir
, szHoo
);
347 RemoveDirectoryW( subdir
);
348 RemoveDirectoryW( path
);
350 r
= CreateDirectoryW(path
, NULL
);
351 ok( r
== TRUE
, "failed to create directory\n");
353 SetLastError(0xd0b00b00);
354 r
= pReadDirectoryChangesW(NULL
,NULL
,0,FALSE
,0,NULL
,NULL
,NULL
);
355 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
356 ok(r
==FALSE
, "should return false\n");
358 fflags
= FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
;
359 hdir
= CreateFileW(path
, GENERIC_READ
|SYNCHRONIZE
|FILE_LIST_DIRECTORY
,
360 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
361 OPEN_EXISTING
, fflags
, NULL
);
362 ok( hdir
!= INVALID_HANDLE_VALUE
, "failed to open directory\n");
364 ov
.hEvent
= CreateEvent( NULL
, 1, 0, NULL
);
366 SetLastError(0xd0b00b00);
367 r
= pReadDirectoryChangesW(hdir
,NULL
,0,FALSE
,0,NULL
,NULL
,NULL
);
368 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
369 ok(r
==FALSE
, "should return false\n");
371 SetLastError(0xd0b00b00);
372 r
= pReadDirectoryChangesW(hdir
,NULL
,0,FALSE
,0,NULL
,&ov
,NULL
);
373 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
374 ok(r
==FALSE
, "should return false\n");
376 filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
377 filter
|= FILE_NOTIFY_CHANGE_DIR_NAME
;
378 filter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
379 filter
|= FILE_NOTIFY_CHANGE_SIZE
;
380 filter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
381 filter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
382 filter
|= FILE_NOTIFY_CHANGE_CREATION
;
383 filter
|= FILE_NOTIFY_CHANGE_SECURITY
;
385 SetLastError(0xd0b00b00);
388 memset( buffer
, 0, sizeof buffer
);
390 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,-1,NULL
,&ov
,NULL
);
391 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
392 ok(r
==FALSE
, "should return false\n");
394 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,0,NULL
,&ov
,NULL
);
395 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
396 ok(r
==FALSE
, "should return false\n");
398 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,filter
,NULL
,&ov
,NULL
);
399 ok(r
==TRUE
, "should return true\n");
401 r
= WaitForSingleObject( ov
.hEvent
, 10 );
402 ok( r
== STATUS_TIMEOUT
, "should timeout\n" );
404 r
= CreateDirectoryW( subdir
, NULL
);
405 ok( r
== TRUE
, "failed to create directory\n");
407 r
= WaitForSingleObject( ov
.hEvent
, INFINITE
);
408 ok( r
== WAIT_OBJECT_0
, "event should be ready\n" );
410 ok( ov
.Internal
== STATUS_SUCCESS
, "ov.Internal wrong\n");
411 ok( ov
.InternalHigh
== 0x12, "ov.InternalHigh wrong\n");
413 pfni
= (PFILE_NOTIFY_INFORMATION
) buffer
;
414 ok( pfni
->NextEntryOffset
== 0, "offset wrong\n" );
415 ok( pfni
->Action
== FILE_ACTION_ADDED
, "action wrong\n" );
416 ok( pfni
->FileNameLength
== 6, "len wrong\n" );
417 ok( !memcmp(pfni
->FileName
,&szHoo
[1],6), "name wrong\n" );
419 ResetEvent(ov
.hEvent
);
420 SetLastError(0xd0b00b00);
421 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,0,NULL
,NULL
,NULL
);
422 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
423 ok(r
==FALSE
, "should return false\n");
425 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,0,NULL
,&ov
,NULL
);
426 ok(GetLastError()==ERROR_INVALID_PARAMETER
,"last error wrong\n");
427 ok(r
==FALSE
, "should return false\n");
429 filter
= FILE_NOTIFY_CHANGE_SIZE
;
435 S(U(ov
)).OffsetHigh
= 0;
436 memset( buffer
, 0, sizeof buffer
);
437 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,filter
,NULL
,&ov
,NULL
);
438 ok(r
==TRUE
, "should return true\n");
440 ok( ov
.Internal
== STATUS_PENDING
, "ov.Internal wrong\n");
441 ok( ov
.InternalHigh
== 1, "ov.InternalHigh wrong\n");
443 r
= WaitForSingleObject( ov
.hEvent
, 0 );
444 ok( r
== STATUS_TIMEOUT
, "should timeout\n" );
446 r
= RemoveDirectoryW( subdir
);
447 ok( r
== TRUE
, "failed to remove directory\n");
449 r
= WaitForSingleObject( ov
.hEvent
, INFINITE
);
450 ok( r
== WAIT_OBJECT_0
, "should be ready\n" );
452 ok( ov
.Internal
== STATUS_SUCCESS
, "ov.Internal wrong\n");
453 ok( ov
.InternalHigh
== 0x12, "ov.InternalHigh wrong\n");
455 r
= GetOverlappedResult( hdir
, &ov
, &dwCount
, TRUE
);
456 ok( r
== TRUE
, "getoverlappedresult failed\n");
457 ok( dwCount
== 0x12, "count wrong\n");
459 pfni
= (PFILE_NOTIFY_INFORMATION
) buffer
;
460 ok( pfni
->NextEntryOffset
== 0, "offset wrong\n" );
461 ok( pfni
->Action
== FILE_ACTION_REMOVED
, "action wrong\n" );
462 ok( pfni
->FileNameLength
== 6, "len wrong\n" );
463 ok( !memcmp(pfni
->FileName
,&szHoo
[1],6), "name wrong\n" );
467 r
= RemoveDirectoryW( path
);
468 ok( r
== TRUE
, "failed to remove directory\n");
471 /* show the behaviour when a null buffer is passed */
472 static void test_readdirectorychanges_null(void)
477 DWORD fflags
, filter
= 0;
479 WCHAR path
[MAX_PATH
], subdir
[MAX_PATH
];
480 static const WCHAR szBoo
[] = { '\\','b','o','o',0 };
481 static const WCHAR szHoo
[] = { '\\','h','o','o',0 };
482 PFILE_NOTIFY_INFORMATION pfni
;
484 if (!pReadDirectoryChangesW
)
487 r
= GetTempPathW( MAX_PATH
, path
);
488 ok( r
!= 0, "temp path failed\n");
492 lstrcatW( path
, szBoo
);
493 lstrcpyW( subdir
, path
);
494 lstrcatW( subdir
, szHoo
);
496 RemoveDirectoryW( subdir
);
497 RemoveDirectoryW( path
);
499 r
= CreateDirectoryW(path
, NULL
);
500 ok( r
== TRUE
, "failed to create directory\n");
502 fflags
= FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
;
503 hdir
= CreateFileW(path
, GENERIC_READ
|SYNCHRONIZE
|FILE_LIST_DIRECTORY
,
504 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
505 OPEN_EXISTING
, fflags
, NULL
);
506 ok( hdir
!= INVALID_HANDLE_VALUE
, "failed to open directory\n");
508 ov
.hEvent
= CreateEvent( NULL
, 1, 0, NULL
);
510 filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
511 filter
|= FILE_NOTIFY_CHANGE_DIR_NAME
;
513 SetLastError(0xd0b00b00);
516 memset( buffer
, 0, sizeof buffer
);
518 r
= pReadDirectoryChangesW(hdir
,NULL
,0,FALSE
,filter
,NULL
,&ov
,NULL
);
519 ok(r
==TRUE
, "should return true\n");
521 r
= WaitForSingleObject( ov
.hEvent
, 0 );
522 ok( r
== STATUS_TIMEOUT
, "should timeout\n" );
524 r
= CreateDirectoryW( subdir
, NULL
);
525 ok( r
== TRUE
, "failed to create directory\n");
527 r
= WaitForSingleObject( ov
.hEvent
, 0 );
528 ok( r
== WAIT_OBJECT_0
, "event should be ready\n" );
530 ok( ov
.Internal
== STATUS_NOTIFY_ENUM_DIR
, "ov.Internal wrong\n");
531 ok( ov
.InternalHigh
== 0, "ov.InternalHigh wrong\n");
536 S(U(ov
)).OffsetHigh
= 0;
537 memset( buffer
, 0, sizeof buffer
);
539 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,FALSE
,filter
,NULL
,&ov
,NULL
);
540 ok(r
==TRUE
, "should return true\n");
542 r
= WaitForSingleObject( ov
.hEvent
, 0 );
543 ok( r
== STATUS_TIMEOUT
, "should timeout\n" );
545 r
= RemoveDirectoryW( subdir
);
546 ok( r
== TRUE
, "failed to remove directory\n");
548 r
= WaitForSingleObject( ov
.hEvent
, INFINITE
);
549 ok( r
== WAIT_OBJECT_0
, "should be ready\n" );
551 ok( ov
.Internal
== STATUS_NOTIFY_ENUM_DIR
, "ov.Internal wrong\n");
552 ok( ov
.InternalHigh
== 0, "ov.InternalHigh wrong\n");
554 pfni
= (PFILE_NOTIFY_INFORMATION
) buffer
;
555 ok( pfni
->NextEntryOffset
== 0, "offset wrong\n" );
559 r
= RemoveDirectoryW( path
);
560 ok( r
== TRUE
, "failed to remove directory\n");
563 static void test_readdirectorychanges_filedir(void)
568 DWORD fflags
, filter
= 0;
570 WCHAR path
[MAX_PATH
], subdir
[MAX_PATH
], file
[MAX_PATH
];
571 static const WCHAR szBoo
[] = { '\\','b','o','o',0 };
572 static const WCHAR szHoo
[] = { '\\','h','o','o',0 };
573 static const WCHAR szFoo
[] = { '\\','f','o','o',0 };
574 PFILE_NOTIFY_INFORMATION pfni
;
576 r
= GetTempPathW( MAX_PATH
, path
);
577 ok( r
!= 0, "temp path failed\n");
581 lstrcatW( path
, szBoo
);
582 lstrcpyW( subdir
, path
);
583 lstrcatW( subdir
, szHoo
);
585 lstrcpyW( file
, path
);
586 lstrcatW( file
, szFoo
);
589 RemoveDirectoryW( subdir
);
590 RemoveDirectoryW( path
);
592 r
= CreateDirectoryW(path
, NULL
);
593 ok( r
== TRUE
, "failed to create directory\n");
595 fflags
= FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
;
596 hdir
= CreateFileW(path
, GENERIC_READ
|SYNCHRONIZE
|FILE_LIST_DIRECTORY
,
597 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
598 OPEN_EXISTING
, fflags
, NULL
);
599 ok( hdir
!= INVALID_HANDLE_VALUE
, "failed to open directory\n");
601 ov
.hEvent
= CreateEvent( NULL
, 0, 0, NULL
);
603 filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
605 r
= pReadDirectoryChangesW(hdir
,buffer
,sizeof buffer
,TRUE
,filter
,NULL
,&ov
,NULL
);
606 ok(r
==TRUE
, "should return true\n");
608 r
= WaitForSingleObject( ov
.hEvent
, 10 );
609 ok( r
== WAIT_TIMEOUT
, "should timeout\n" );
611 r
= CreateDirectoryW( subdir
, NULL
);
612 ok( r
== TRUE
, "failed to create directory\n");
614 hfile
= CreateFileW( file
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
615 ok( hfile
!= INVALID_HANDLE_VALUE
, "failed to create file\n");
616 ok( CloseHandle(hfile
), "failed toc lose file\n");
618 r
= WaitForSingleObject( ov
.hEvent
, INFINITE
);
619 ok( r
== WAIT_OBJECT_0
, "event should be ready\n" );
621 ok( ov
.Internal
== STATUS_SUCCESS
, "ov.Internal wrong\n");
622 ok( ov
.InternalHigh
== 0x12, "ov.InternalHigh wrong\n");
624 pfni
= (PFILE_NOTIFY_INFORMATION
) buffer
;
625 ok( pfni
->NextEntryOffset
== 0, "offset wrong\n" );
626 ok( pfni
->Action
== FILE_ACTION_ADDED
, "action wrong\n" );
627 ok( pfni
->FileNameLength
== 6, "len wrong\n" );
628 ok( !memcmp(pfni
->FileName
,&szFoo
[1],6), "name wrong\n" );
630 r
= DeleteFileW( file
);
631 ok( r
== TRUE
, "failed to delete file\n");
633 r
= RemoveDirectoryW( subdir
);
634 ok( r
== TRUE
, "failed to remove directory\n");
638 r
= RemoveDirectoryW( path
);
639 ok( r
== TRUE
, "failed to remove directory\n");
644 HMODULE hkernel32
= GetModuleHandle("kernel32");
645 pReadDirectoryChangesW
= (fnReadDirectoryChangesW
)
646 GetProcAddress(hkernel32
, "ReadDirectoryChangesW");
648 test_FindFirstChangeNotification();
650 test_readdirectorychanges();
651 test_readdirectorychanges_null();
652 test_readdirectorychanges_filedir();