2 * Synchronization tests
4 * Copyright 2005 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define _WIN32_WINNT 0x500
28 #include "wine/test.h"
30 static BOOL (WINAPI *pChangeTimerQueueTimer)(HANDLE, HANDLE, ULONG, ULONG);
31 static HANDLE (WINAPI *pCreateTimerQueue)(void);
32 static BOOL (WINAPI *pCreateTimerQueueTimer)(PHANDLE, HANDLE, WAITORTIMERCALLBACK,
33 PVOID, DWORD, DWORD, ULONG);
34 static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*,BOOL,LPCSTR);
35 static BOOL (WINAPI *pDeleteTimerQueueEx)(HANDLE, HANDLE);
36 static BOOL (WINAPI *pDeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE);
37 static HANDLE (WINAPI *pOpenWaitableTimerA)(DWORD,BOOL,LPCSTR);
38 static HANDLE (WINAPI *pCreateMemoryResourceNotification)(MEMORY_RESOURCE_NOTIFICATION_TYPE);
39 static BOOL (WINAPI *pQueryMemoryResourceNotification)(HANDLE, PBOOL);
41 static void test_signalandwait(void)
43 DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
46 HANDLE event[2], semaphore[2], file;
48 kernel32 = GetModuleHandle("kernel32");
49 pSignalObjectAndWait = (void*) GetProcAddress(kernel32, "SignalObjectAndWait");
51 if (!pSignalObjectAndWait)
54 /* invalid parameters */
55 r = pSignalObjectAndWait(NULL, NULL, 0, 0);
56 if (r == ERROR_INVALID_FUNCTION)
58 win_skip("SignalObjectAndWait is not implemented\n");
59 return; /* Win98/ME */
61 ok( r == WAIT_FAILED, "should fail\n");
63 event[0] = CreateEvent(NULL, 0, 0, NULL);
64 event[1] = CreateEvent(NULL, 1, 1, NULL);
66 ok( event[0] && event[1], "failed to create event flags\n");
68 r = pSignalObjectAndWait(event[0], NULL, 0, FALSE);
69 ok( r == WAIT_FAILED, "should fail\n");
71 r = pSignalObjectAndWait(NULL, event[0], 0, FALSE);
72 ok( r == WAIT_FAILED, "should fail\n");
75 /* valid parameters */
76 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
77 ok( r == WAIT_OBJECT_0, "should succeed\n");
79 /* event[0] is now signalled */
80 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
81 ok( r == WAIT_OBJECT_0, "should succeed\n");
83 /* event[0] is not signalled */
84 r = WaitForSingleObject(event[0], 0);
85 ok( r == WAIT_TIMEOUT, "event was signalled\n");
87 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
88 ok( r == WAIT_OBJECT_0, "should succeed\n");
90 /* clear event[1] and check for a timeout */
91 ok(ResetEvent(event[1]), "failed to clear event[1]\n");
92 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
93 ok( r == WAIT_TIMEOUT, "should timeout\n");
95 CloseHandle(event[0]);
96 CloseHandle(event[1]);
99 semaphore[0] = CreateSemaphore( NULL, 0, 1, NULL );
100 semaphore[1] = CreateSemaphore( NULL, 1, 1, NULL );
101 ok( semaphore[0] && semaphore[1], "failed to create semaphore\n");
103 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
104 ok( r == WAIT_OBJECT_0, "should succeed\n");
106 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
107 ok( r == WAIT_FAILED, "should fail\n");
109 r = ReleaseSemaphore(semaphore[0],1,NULL);
110 ok( r == FALSE, "should fail\n");
112 r = ReleaseSemaphore(semaphore[1],1,NULL);
113 ok( r == TRUE, "should succeed\n");
115 CloseHandle(semaphore[0]);
116 CloseHandle(semaphore[1]);
118 /* try a registry key */
119 file = CreateFile("x", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
120 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
121 r = pSignalObjectAndWait(file, file, 0, FALSE);
122 ok( r == WAIT_FAILED, "should fail\n");
123 ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n");
127 static void test_mutex(void)
136 hCreated = CreateMutex(NULL, FALSE, "WineTestMutex");
137 ok(hCreated != NULL, "CreateMutex failed with error %d\n", GetLastError());
139 hOpened = OpenMutex(0, FALSE, "WineTestMutex");
140 ok(hOpened == NULL, "OpenMutex succeeded\n");
142 hOpened = OpenMutex(GENERIC_EXECUTE, FALSE, "WineTestMutex");
143 ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
144 wait_ret = WaitForSingleObject(hOpened, INFINITE);
145 ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error %d\n", GetLastError());
146 CloseHandle(hOpened);
148 for(i=0; i < 31; i++)
150 wait_ret = WaitForSingleObject(hCreated, INFINITE);
151 ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08x\n", wait_ret);
154 hOpened = OpenMutex(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex");
155 ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
156 wait_ret = WaitForSingleObject(hOpened, INFINITE);
157 ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n");
158 CloseHandle(hOpened);
160 for (i = 0; i < 32; i++)
162 hOpened = OpenMutex(0x1 << i, FALSE, "WineTestMutex");
165 ret = ReleaseMutex(hOpened);
166 ok(ret, "ReleaseMutex failed with error %d, access %x\n", GetLastError(), 1 << i);
167 CloseHandle(hOpened);
171 ReleaseMutex(hCreated);
176 ok( failed == 0x0de0fffe, "open succeeded when it shouldn't: %x\n", failed);
178 ret = ReleaseMutex(hCreated);
179 ok(!ret && (GetLastError() == ERROR_NOT_OWNER),
180 "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError());
182 /* test case sensitivity */
184 SetLastError(0xdeadbeef);
185 hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX");
186 ok(!hOpened, "OpenMutex succeeded\n");
187 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
189 SetLastError(0xdeadbeef);
190 hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex");
191 ok(!hOpened, "OpenMutex succeeded\n");
192 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
194 SetLastError(0xdeadbeef);
195 hOpened = CreateMutex(NULL, FALSE, "WineTestMutex");
196 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
197 ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
198 CloseHandle(hOpened);
200 SetLastError(0xdeadbeef);
201 hOpened = CreateMutex(NULL, FALSE, "WINETESTMUTEX");
202 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
203 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
204 CloseHandle(hOpened);
206 CloseHandle(hCreated);
209 static void test_slist(void)
215 } item1, item2, item3, *pitem;
217 SLIST_HEADER slist_header;
221 VOID (WINAPI *pInitializeSListHead)(PSLIST_HEADER);
222 USHORT (WINAPI *pQueryDepthSList)(PSLIST_HEADER);
223 PSLIST_ENTRY (WINAPI *pInterlockedFlushSList)(PSLIST_HEADER);
224 PSLIST_ENTRY (WINAPI *pInterlockedPopEntrySList)(PSLIST_HEADER);
225 PSLIST_ENTRY (WINAPI *pInterlockedPushEntrySList)(PSLIST_HEADER,PSLIST_ENTRY);
228 kernel32 = GetModuleHandle("KERNEL32.DLL");
229 pInitializeSListHead = (void*) GetProcAddress(kernel32, "InitializeSListHead");
230 pQueryDepthSList = (void*) GetProcAddress(kernel32, "QueryDepthSList");
231 pInterlockedFlushSList = (void*) GetProcAddress(kernel32, "InterlockedFlushSList");
232 pInterlockedPopEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPopEntrySList");
233 pInterlockedPushEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPushEntrySList");
234 if (pInitializeSListHead == NULL ||
235 pQueryDepthSList == NULL ||
236 pInterlockedFlushSList == NULL ||
237 pInterlockedPopEntrySList == NULL ||
238 pInterlockedPushEntrySList == NULL)
240 win_skip("some required slist entrypoints were not found, skipping tests\n");
244 memset(&slist_header, 0xFF, sizeof(slist_header));
245 pInitializeSListHead(&slist_header);
246 size = pQueryDepthSList(&slist_header);
247 ok(size == 0, "initially created slist has size %d, expected 0\n", size);
250 ok(pInterlockedPushEntrySList(&slist_header, &item1.entry) == NULL,
251 "previous entry in empty slist wasn't NULL\n");
252 size = pQueryDepthSList(&slist_header);
253 ok(size == 1, "slist with 1 item has size %d\n", size);
256 entry = pInterlockedPushEntrySList(&slist_header, &item2.entry);
257 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
260 pitem = (struct item*) entry;
261 ok(pitem->value == 1, "previous entry in slist wasn't the one added\n");
263 size = pQueryDepthSList(&slist_header);
264 ok(size == 2, "slist with 2 items has size %d\n", size);
267 entry = pInterlockedPushEntrySList(&slist_header, &item3.entry);
268 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
271 pitem = (struct item*) entry;
272 ok(pitem->value == 2, "previous entry in slist wasn't the one added\n");
274 size = pQueryDepthSList(&slist_header);
275 ok(size == 3, "slist with 3 items has size %d\n", size);
277 entry = pInterlockedPopEntrySList(&slist_header);
278 ok(entry != NULL, "entry shouldn't be NULL\n");
281 pitem = (struct item*) entry;
282 ok(pitem->value == 3, "unexpected entry removed\n");
284 size = pQueryDepthSList(&slist_header);
285 ok(size == 2, "slist with 2 items has size %d\n", size);
287 entry = pInterlockedFlushSList(&slist_header);
288 size = pQueryDepthSList(&slist_header);
289 ok(size == 0, "flushed slist should be empty, size is %d\n", size);
292 ok(pInterlockedPopEntrySList(&slist_header) == NULL,
293 "popping empty slist didn't return NULL\n");
295 ok(((struct item*)entry)->value == 2, "item 2 not in front of list\n");
296 ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n");
299 static void test_event(void)
301 HANDLE handle, handle2;
302 SECURITY_ATTRIBUTES sa;
303 SECURITY_DESCRIPTOR sd;
309 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
310 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
313 sa.nLength = sizeof(sa);
314 sa.lpSecurityDescriptor = &sd;
315 sa.bInheritHandle = FALSE;
317 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
320 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
321 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
324 /* sd with NULL dacl */
325 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
326 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
327 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
330 /* sd with empty dacl */
331 InitializeAcl(&acl, sizeof(acl), ACL_REVISION);
332 SetSecurityDescriptorDacl(&sd, TRUE, &acl, FALSE);
333 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
334 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
337 /* test case sensitivity */
339 SetLastError(0xdeadbeef);
340 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
341 ok( handle != NULL, "CreateEvent failed with error %u\n", GetLastError());
342 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
344 SetLastError(0xdeadbeef);
345 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
346 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
347 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
348 CloseHandle( handle2 );
350 SetLastError(0xdeadbeef);
351 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT");
352 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
353 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
354 CloseHandle( handle2 );
356 SetLastError(0xdeadbeef);
357 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event");
358 ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError());
359 CloseHandle( handle2 );
361 SetLastError(0xdeadbeef);
362 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT");
363 ok( !handle2, "OpenEvent succeeded\n");
364 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
366 CloseHandle( handle );
368 /* resource notifications are events too */
370 if (!pCreateMemoryResourceNotification || !pQueryMemoryResourceNotification)
372 trace( "memory resource notifications not supported\n" );
375 handle = pCreateMemoryResourceNotification( HighMemoryResourceNotification + 1 );
376 ok( !handle, "CreateMemoryResourceNotification succeeded\n" );
377 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
378 ret = pQueryMemoryResourceNotification( handle, &val );
379 ok( !ret, "QueryMemoryResourceNotification succeeded\n" );
380 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
382 handle = pCreateMemoryResourceNotification( LowMemoryResourceNotification );
383 ok( handle != 0, "CreateMemoryResourceNotification failed err %u\n", GetLastError() );
384 ret = WaitForSingleObject( handle, 10 );
385 ok( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT, "WaitForSingleObject wrong ret %u\n", ret );
388 ret = pQueryMemoryResourceNotification( handle, &val );
389 ok( ret, "QueryMemoryResourceNotification failed err %u\n", GetLastError() );
390 ok( val == FALSE || val == TRUE, "wrong value %u\n", val );
391 ret = CloseHandle( handle );
392 ok( ret, "CloseHandle failed err %u\n", GetLastError() );
394 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
396 ret = pQueryMemoryResourceNotification( handle, &val );
397 ok( ret, "QueryMemoryResourceNotification failed err %u\n", GetLastError() );
398 ok( val == FALSE || val == TRUE, "wrong value %u\n", val );
399 CloseHandle( handle );
402 static void test_semaphore(void)
404 HANDLE handle, handle2;
406 /* test case sensitivity */
408 SetLastError(0xdeadbeef);
409 handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
410 ok(handle != NULL, "CreateSemaphore failed with error %u\n", GetLastError());
411 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
413 SetLastError(0xdeadbeef);
414 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
415 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
416 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
417 CloseHandle( handle2 );
419 SetLastError(0xdeadbeef);
420 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE");
421 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
422 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
423 CloseHandle( handle2 );
425 SetLastError(0xdeadbeef);
426 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore");
427 ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError());
428 CloseHandle( handle2 );
430 SetLastError(0xdeadbeef);
431 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE");
432 ok( !handle2, "OpenSemaphore succeeded\n");
433 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
435 CloseHandle( handle );
438 static void test_waitable_timer(void)
440 HANDLE handle, handle2;
442 if (!pCreateWaitableTimerA || !pOpenWaitableTimerA)
444 win_skip("{Create,Open}WaitableTimerA() is not available\n");
448 /* test case sensitivity */
450 SetLastError(0xdeadbeef);
451 handle = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
452 ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError());
453 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
455 SetLastError(0xdeadbeef);
456 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
457 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
458 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
459 CloseHandle( handle2 );
461 SetLastError(0xdeadbeef);
462 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER");
463 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
464 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
465 CloseHandle( handle2 );
467 SetLastError(0xdeadbeef);
468 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer");
469 ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError());
470 CloseHandle( handle2 );
472 SetLastError(0xdeadbeef);
473 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER");
474 ok( !handle2, "OpenWaitableTimer succeeded\n");
475 ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
476 GetLastError() == ERROR_INVALID_NAME, /* win98 */
477 "wrong error %u\n", GetLastError());
479 CloseHandle( handle );
482 static HANDLE sem = 0;
484 static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
486 ReleaseSemaphore(sem, 1, NULL);
489 static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL;
491 static void test_iocp_callback(void)
493 char temp_path[MAX_PATH];
494 char filename[MAX_PATH];
497 static const char prefix[] = "pfx";
499 HMODULE hmod = GetModuleHandleA("kernel32.dll");
501 const char *buffer = "12345678123456781234567812345678";
502 OVERLAPPED overlapped;
504 p_BindIoCompletionCallback = (void*)GetProcAddress(hmod, "BindIoCompletionCallback");
505 if(!p_BindIoCompletionCallback) {
506 win_skip("BindIoCompletionCallback not found in this DLL\n");
510 sem = CreateSemaphore(NULL, 0, 1, NULL);
511 ok(sem != INVALID_HANDLE_VALUE, "Creating a semaphore failed\n");
513 ret = GetTempPathA(MAX_PATH, temp_path);
514 ok(ret != 0, "GetTempPathA error %d\n", GetLastError());
515 ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
517 ret = GetTempFileNameA(temp_path, prefix, 0, filename);
518 ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError());
520 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
521 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0);
522 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
524 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
525 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n");
526 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
528 ret = CloseHandle(hFile);
529 ok( ret, "CloseHandle: error %d\n", GetLastError());
530 ret = DeleteFileA(filename);
531 ok( ret, "DeleteFileA: error %d\n", GetLastError());
533 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
534 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
535 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
537 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
538 ok(retb == TRUE, "BindIoCompletionCallback failed\n");
540 memset(&overlapped, 0, sizeof(overlapped));
541 retb = WriteFile(hFile, buffer, 4, &bytesWritten, &overlapped);
542 ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %d\n", GetLastError());
544 ret = WaitForSingleObject(sem, 5000);
545 ok(ret == WAIT_OBJECT_0, "Wait for the IO completion callback failed\n");
548 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
549 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the same callback on the file again\n");
550 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
551 retb = p_BindIoCompletionCallback(hFile, NULL, 0);
552 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the callback to NULL\n");
553 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
555 ret = CloseHandle(hFile);
556 ok( ret, "CloseHandle: error %d\n", GetLastError());
557 ret = DeleteFileA(filename);
558 ok( ret, "DeleteFileA: error %d\n", GetLastError());
560 /* win2k3 requires the Flags parameter to be zero */
561 SetLastError(0xdeadbeef);
562 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
563 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
564 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
565 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 12345);
567 ok(GetLastError() == ERROR_INVALID_PARAMETER,
568 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
570 ok(retb == TRUE, "BindIoCompletionCallback failed with Flags != 0\n");
571 ret = CloseHandle(hFile);
572 ok( ret, "CloseHandle: error %d\n", GetLastError());
573 ret = DeleteFileA(filename);
574 ok( ret, "DeleteFileA: error %d\n", GetLastError());
576 retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0);
577 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n");
578 ok(GetLastError() == ERROR_INVALID_HANDLE ||
579 GetLastError() == ERROR_INVALID_PARAMETER, /* vista */
580 "Last error is %d\n", GetLastError());
583 static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut)
586 ok(timedOut, "Timer callbacks should always time out\n");
590 struct timer_queue_data1
597 static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut)
599 struct timer_queue_data1 *d = p;
600 ok(timedOut, "Timer callbacks should always time out\n");
601 if (d->t && ++d->num_calls == d->max_calls)
604 SetLastError(0xdeadbeef);
605 /* Note, XP SP2 does *not* do any deadlock checking, so passing
606 INVALID_HANDLE_VALUE here will just hang. */
607 ret = pDeleteTimerQueueTimer(d->q, d->t, NULL);
608 ok(!ret, "DeleteTimerQueueTimer\n");
609 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
613 static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut)
615 struct timer_queue_data1 *d = p;
616 ok(timedOut, "Timer callbacks should always time out\n");
617 if (d->t && ++d->num_calls == d->max_calls)
619 /* Basically kill the timer since it won't have time to run
621 BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 10000, 0);
622 ok(ret, "ChangeTimerQueueTimer\n");
626 static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut)
628 struct timer_queue_data1 *d = p;
629 ok(timedOut, "Timer callbacks should always time out\n");
632 /* This tests whether a timer gets flagged for deletion before
633 or after the callback runs. If we start this timer with a
634 period of zero (run once), then ChangeTimerQueueTimer will
635 fail if the timer is already flagged. Hence we really run
636 only once. Otherwise we will run multiple times. */
637 BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 50, 50);
638 ok(ret, "ChangeTimerQueueTimer\n");
643 static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut)
645 DWORD_PTR delay = (DWORD_PTR) p;
646 ok(timedOut, "Timer callbacks should always time out\n");
651 static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut)
653 struct timer_queue_data1 *d = p;
654 ok(timedOut, "Timer callbacks should always time out\n");
655 /* This tests an original implementation bug where a deleted timer may get
656 to run, but it is tricky to set up. */
657 if (d->q && d->num_calls++ == 0)
659 /* First run: delete ourselves, then insert and remove a timer
660 that goes in front of us in the sorted timeout list. Once
661 removed, we will still timeout at the faster timer's due time,
662 but this should be a no-op if we are bug-free. There should
663 not be a second run. We can test the value of num_calls later. */
667 /* The delete will pend while we are in this callback. */
668 SetLastError(0xdeadbeef);
669 ret = pDeleteTimerQueueTimer(d->q, d->t, NULL);
670 ok(!ret, "DeleteTimerQueueTimer\n");
671 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
673 ret = pCreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0);
674 ok(ret, "CreateTimerQueueTimer\n");
675 ok(t != NULL, "CreateTimerQueueTimer\n");
677 ret = pDeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE);
678 ok(ret, "DeleteTimerQueueTimer\n");
680 /* Now we stay alive by hanging around in the callback. */
685 static void test_timer_queue(void)
687 HANDLE q, t1, t2, t3, t4, t5;
688 int n1, n2, n3, n4, n5;
689 struct timer_queue_data1 d1, d2, d3, d4;
693 if (!pChangeTimerQueueTimer || !pCreateTimerQueue || !pCreateTimerQueueTimer
694 || !pDeleteTimerQueueEx || !pDeleteTimerQueueTimer)
696 win_skip("TimerQueue API not present\n");
700 /* Test asynchronous deletion of the queue. */
701 q = pCreateTimerQueue();
702 ok(q != NULL, "CreateTimerQueue\n");
704 SetLastError(0xdeadbeef);
705 ret = pDeleteTimerQueueEx(q, NULL);
706 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
707 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
710 /* Test synchronous deletion of the queue and running timers. */
711 q = pCreateTimerQueue();
712 ok(q != NULL, "CreateTimerQueue\n");
717 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0,
719 ok(ret, "CreateTimerQueueTimer\n");
720 ok(t1 != NULL, "CreateTimerQueueTimer\n");
725 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0,
727 ok(ret, "CreateTimerQueueTimer\n");
728 ok(t2 != NULL, "CreateTimerQueueTimer\n");
733 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0,
735 ok(ret, "CreateTimerQueueTimer\n");
736 ok(t3 != NULL, "CreateTimerQueueTimer\n");
738 /* Start really late (it won't start). */
741 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000,
743 ok(ret, "CreateTimerQueueTimer\n");
744 ok(t4 != NULL, "CreateTimerQueueTimer\n");
746 /* Start soon, but delay so long it won't run again. */
749 ret = pCreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0,
751 ok(ret, "CreateTimerQueueTimer\n");
752 ok(t5 != NULL, "CreateTimerQueueTimer\n");
754 /* Give them a chance to do some work. */
757 /* Test deleting a once-only timer. */
758 ret = pDeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE);
759 ok(ret, "DeleteTimerQueueTimer\n");
761 /* A periodic timer. */
762 ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE);
763 ok(ret, "DeleteTimerQueueTimer\n");
765 ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE);
766 ok(ret, "DeleteTimerQueueEx\n");
767 ok(n1 == 1, "Timer callback 1\n");
768 ok(n2 < n3, "Timer callback 2 should be much slower than 3\n");
769 ok(n4 == 0, "Timer callback 4\n");
770 ok(n5 == 1, "Timer callback 5\n");
772 /* Test synchronous deletion of the timer/queue with event trigger. */
773 e = CreateEvent(NULL, TRUE, FALSE, NULL);
774 et1 = CreateEvent(NULL, TRUE, FALSE, NULL);
775 et2 = CreateEvent(NULL, TRUE, FALSE, NULL);
776 if (!e || !et1 || !et2)
778 skip("Failed to create timer queue descruction event\n");
782 q = pCreateTimerQueue();
783 ok(q != NULL, "CreateTimerQueue\n");
785 /* Run once and finish quickly (should be done when we delete it). */
787 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb5, NULL, 0, 0, 0);
788 ok(ret, "CreateTimerQueueTimer\n");
789 ok(t1 != NULL, "CreateTimerQueueTimer\n");
791 /* Run once and finish slowly (shouldn't be done when we delete it). */
793 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb5, (PVOID) 1000, 0,
795 ok(ret, "CreateTimerQueueTimer\n");
796 ok(t2 != NULL, "CreateTimerQueueTimer\n");
798 /* Run once and finish quickly (should be done when we delete it). */
800 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb5, NULL, 0, 0, 0);
801 ok(ret, "CreateTimerQueueTimer\n");
802 ok(t3 != NULL, "CreateTimerQueueTimer\n");
804 /* Run once and finish slowly (shouldn't be done when we delete it). */
806 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0,
808 ok(ret, "CreateTimerQueueTimer\n");
809 ok(t4 != NULL, "CreateTimerQueueTimer\n");
811 /* Give them a chance to start. */
814 /* DeleteTimerQueueTimer always returns PENDING with a NULL event,
815 even if the timer is finished. */
816 SetLastError(0xdeadbeef);
817 ret = pDeleteTimerQueueTimer(q, t1, NULL);
818 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
819 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
822 SetLastError(0xdeadbeef);
823 ret = pDeleteTimerQueueTimer(q, t2, NULL);
824 ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n");
825 ok(GetLastError() == ERROR_IO_PENDING,
826 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
829 SetLastError(0xdeadbeef);
830 ret = pDeleteTimerQueueTimer(q, t3, et1);
831 ok(ret, "DeleteTimerQueueTimer call was expected to fail\n");
832 ok(GetLastError() == 0xdeadbeef,
833 "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d\n",
835 ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0,
836 "Timer destruction event not triggered\n");
838 SetLastError(0xdeadbeef);
839 ret = pDeleteTimerQueueTimer(q, t4, et2);
840 ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n");
841 ok(GetLastError() == ERROR_IO_PENDING,
842 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
844 ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0,
845 "Timer destruction event not triggered\n");
847 SetLastError(0xdeadbeef);
848 ret = pDeleteTimerQueueEx(q, e);
849 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
850 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
852 ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0,
853 "Queue destruction event not triggered\n");
856 /* Test deleting/changing a timer in execution. */
857 q = pCreateTimerQueue();
858 ok(q != NULL, "CreateTimerQueue\n");
860 /* Test changing a once-only timer before it fires (this is allowed,
861 whereas after it fires you cannot). */
863 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000,
865 ok(ret, "CreateTimerQueueTimer\n");
866 ok(t1 != NULL, "CreateTimerQueueTimer\n");
867 ret = pChangeTimerQueueTimer(q, t1, 0, 0);
868 ok(ret, "ChangeTimerQueueTimer\n");
874 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb2, &d2, 10,
877 ok(ret, "CreateTimerQueueTimer\n");
878 ok(t2 != NULL, "CreateTimerQueueTimer\n");
884 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb3, &d3, 10,
887 ok(ret, "CreateTimerQueueTimer\n");
888 ok(t3 != NULL, "CreateTimerQueueTimer\n");
893 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb4, &d4, 10,
896 ok(ret, "CreateTimerQueueTimer\n");
897 ok(t4 != NULL, "CreateTimerQueueTimer\n");
901 ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE);
902 ok(ret, "DeleteTimerQueueEx\n");
903 ok(n1 == 1, "ChangeTimerQueueTimer\n");
904 ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n");
905 ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n");
906 ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n");
908 /* Test an obscure bug that was in the original implementation. */
909 q = pCreateTimerQueue();
910 ok(q != NULL, "CreateTimerQueue\n");
912 /* All the work is done in the callback. */
916 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb6, &d1, 100,
917 100, WT_EXECUTELONGFUNCTION);
919 ok(ret, "CreateTimerQueueTimer\n");
920 ok(t1 != NULL, "CreateTimerQueueTimer\n");
924 SetLastError(0xdeadbeef);
925 ret = pDeleteTimerQueueEx(q, NULL);
926 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
927 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
929 ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n");
931 /* Test functions on the default timer queue. */
934 ret = pCreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000,
936 ok(ret, "CreateTimerQueueTimer, default queue\n");
937 ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n");
939 ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000);
940 ok(ret, "ChangeTimerQueueTimer, default queue\n");
942 ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE);
943 ok(ret, "DeleteTimerQueueTimer, default queue\n");
945 /* Try mixing default and non-default queues. Apparently this works. */
946 q = pCreateTimerQueue();
947 ok(q != NULL, "CreateTimerQueue\n");
951 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 1000,
953 ok(ret, "CreateTimerQueueTimer\n");
954 ok(t1 != NULL, "CreateTimerQueueTimer\n");
958 ret = pCreateTimerQueueTimer(&t2, NULL, timer_queue_cb1, &n2, 1000,
960 ok(ret, "CreateTimerQueueTimer\n");
961 ok(t2 != NULL, "CreateTimerQueueTimer\n");
963 ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000);
964 ok(ret, "ChangeTimerQueueTimer\n");
966 ret = pChangeTimerQueueTimer(q, t2, 2000, 2000);
967 ok(ret, "ChangeTimerQueueTimer\n");
969 ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE);
970 ok(ret, "DeleteTimerQueueTimer\n");
972 ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE);
973 ok(ret, "DeleteTimerQueueTimer\n");
975 /* Try to delete the default queue? In any case: not allowed. */
976 SetLastError(0xdeadbeef);
977 ret = pDeleteTimerQueueEx(NULL, NULL);
978 ok(!ret, "DeleteTimerQueueEx call was expected to fail\n");
979 ok(GetLastError() == ERROR_INVALID_HANDLE,
980 "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %d\n",
983 SetLastError(0xdeadbeef);
984 ret = pDeleteTimerQueueEx(q, NULL);
985 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
986 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
990 static HANDLE modify_handle(HANDLE handle, DWORD modify)
992 DWORD tmp = HandleToULong(handle);
994 return ULongToHandle(tmp);
997 static void test_WaitForSingleObject(void)
999 HANDLE signaled, nonsignaled, invalid;
1002 signaled = CreateEventW(NULL, TRUE, TRUE, NULL);
1003 nonsignaled = CreateEventW(NULL, TRUE, FALSE, NULL);
1004 invalid = (HANDLE) 0xdeadbee0;
1006 /* invalid handle with different values for lower 2 bits */
1007 SetLastError(0xdeadbeef);
1008 ret = WaitForSingleObject(invalid, 0);
1009 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
1010 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1012 SetLastError(0xdeadbeef);
1013 ret = WaitForSingleObject(modify_handle(invalid, 1), 0);
1014 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
1015 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1017 SetLastError(0xdeadbeef);
1018 ret = WaitForSingleObject(modify_handle(invalid, 2), 0);
1019 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
1020 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1022 SetLastError(0xdeadbeef);
1023 ret = WaitForSingleObject(modify_handle(invalid, 3), 0);
1024 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
1025 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1027 /* valid handle with different values for lower 2 bits */
1028 SetLastError(0xdeadbeef);
1029 ret = WaitForSingleObject(nonsignaled, 0);
1030 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1031 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1033 SetLastError(0xdeadbeef);
1034 ret = WaitForSingleObject(modify_handle(nonsignaled, 1), 0);
1035 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1036 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1038 SetLastError(0xdeadbeef);
1039 ret = WaitForSingleObject(modify_handle(nonsignaled, 2), 0);
1040 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1041 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1043 SetLastError(0xdeadbeef);
1044 ret = WaitForSingleObject(modify_handle(nonsignaled, 3), 0);
1045 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1046 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1048 /* valid handle with different values for lower 2 bits */
1049 SetLastError(0xdeadbeef);
1050 ret = WaitForSingleObject(signaled, 0);
1051 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1052 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1054 SetLastError(0xdeadbeef);
1055 ret = WaitForSingleObject(modify_handle(signaled, 1), 0);
1056 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1057 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1059 SetLastError(0xdeadbeef);
1060 ret = WaitForSingleObject(modify_handle(signaled, 2), 0);
1061 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1062 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1064 SetLastError(0xdeadbeef);
1065 ret = WaitForSingleObject(modify_handle(signaled, 3), 0);
1066 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1067 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1069 CloseHandle(signaled);
1070 CloseHandle(nonsignaled);
1073 static void test_WaitForMultipleObjects(void)
1077 HANDLE maxevents[MAXIMUM_WAIT_OBJECTS];
1079 /* create the maximum number of events and make sure
1080 * we can wait on that many */
1081 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
1083 maxevents[i] = CreateEvent(NULL, i==0, TRUE, NULL);
1084 ok( maxevents[i] != 0, "should create enough events\n");
1087 /* a manual-reset event remains signaled, an auto-reset event is cleared */
1088 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1089 ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r);
1090 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1091 ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %d\n", r);
1092 ok(ResetEvent(maxevents[0]), "ResetEvent\n");
1093 for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++)
1095 /* the lowest index is checked first and remaining events are untouched */
1096 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1097 ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %d\n", i, r);
1100 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
1101 if (maxevents[i]) CloseHandle(maxevents[i]);
1106 HMODULE hdll = GetModuleHandle("kernel32");
1107 pChangeTimerQueueTimer = (void*)GetProcAddress(hdll, "ChangeTimerQueueTimer");
1108 pCreateTimerQueue = (void*)GetProcAddress(hdll, "CreateTimerQueue");
1109 pCreateTimerQueueTimer = (void*)GetProcAddress(hdll, "CreateTimerQueueTimer");
1110 pCreateWaitableTimerA = (void*)GetProcAddress(hdll, "CreateWaitableTimerA");
1111 pDeleteTimerQueueEx = (void*)GetProcAddress(hdll, "DeleteTimerQueueEx");
1112 pDeleteTimerQueueTimer = (void*)GetProcAddress(hdll, "DeleteTimerQueueTimer");
1113 pOpenWaitableTimerA = (void*)GetProcAddress(hdll, "OpenWaitableTimerA");
1114 pCreateMemoryResourceNotification = (void *)GetProcAddress(hdll, "CreateMemoryResourceNotification");
1115 pQueryMemoryResourceNotification = (void *)GetProcAddress(hdll, "QueryMemoryResourceNotification");
1117 test_signalandwait();
1122 test_waitable_timer();
1123 test_iocp_callback();
1125 test_WaitForSingleObject();
1126 test_WaitForMultipleObjects();