2 * Copyright 2016 Daniel Lehman
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/test.h"
28 #define DEFINE_EXPECT(func) \
29 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
31 #define SET_EXPECT(func) \
33 expect_ ## func = TRUE; \
37 #define CHECK_EXPECT2(func) \
39 ok(expect_ ##func, "unexpected call " #func "\n"); \
40 called_ ## func = TRUE; \
43 #define CHECK_EXPECT(func) \
45 CHECK_EXPECT2(func); \
46 expect_ ## func = FALSE; \
49 #define CHECK_CALLED(func) \
51 ok(called_ ## func, "expected " #func "\n"); \
52 expect_ ## func = called_ ## func = FALSE; \
56 DEFINE_EXPECT(function_do_call
);
57 DEFINE_EXPECT(function_do_clean
);
62 #define __thiscall __stdcall
64 #define __thiscall __cdecl
67 /* Emulate a __thiscall */
73 BYTE pop_eax
; /* popl %eax (ret addr) */
74 BYTE pop_edx
; /* popl %edx (func) */
75 BYTE pop_ecx
; /* popl %ecx (this) */
76 BYTE push_eax
; /* pushl %eax */
77 WORD jmp_edx
; /* jmp *%edx */
81 static void * (WINAPI
*call_thiscall_func1
)( void *func
, void *this );
82 static void * (WINAPI
*call_thiscall_func2
)( void *func
, void *this, const void *a
);
84 static void init_thiscall_thunk(void)
86 struct thiscall_thunk
*thunk
= VirtualAlloc( NULL
, sizeof(*thunk
),
87 MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
88 thunk
->pop_eax
= 0x58; /* popl %eax */
89 thunk
->pop_edx
= 0x5a; /* popl %edx */
90 thunk
->pop_ecx
= 0x59; /* popl %ecx */
91 thunk
->push_eax
= 0x50; /* pushl %eax */
92 thunk
->jmp_edx
= 0xe2ff; /* jmp *%edx */
93 call_thiscall_func1
= (void *)thunk
;
94 call_thiscall_func2
= (void *)thunk
;
97 #define call_func1(func,_this) call_thiscall_func1(func,_this)
98 #define call_func2(func,_this,a) call_thiscall_func2(func,_this,a)
102 #define init_thiscall_thunk()
103 #define call_func1(func,_this) func(_this)
104 #define call_func2(func,_this,a) func(_this,a)
106 #endif /* __i386__ */
107 typedef unsigned char MSVCP_bool
;
112 } task_continuation_context
;
120 void (__cdecl
*func
)(void);
124 } function_void_cdecl_void
;
128 MSVCP_bool scheduled
;
134 void (__cdecl
*callback
)(void*);
151 static unsigned int (__cdecl
*p__Thrd_id
)(void);
152 static task_continuation_context
* (__thiscall
*p_task_continuation_context_ctor
)(task_continuation_context
*);
153 static void (__thiscall
*p__ContextCallback__Assign
)(_ContextCallback
*, void*);
154 static void (__thiscall
*p__ContextCallback__CallInContext
)(const _ContextCallback
*, function_void_cdecl_void
, MSVCP_bool
);
155 static void (__thiscall
*p__ContextCallback__Capture
)(_ContextCallback
*);
156 static void (__thiscall
*p__ContextCallback__Reset
)(_ContextCallback
*);
157 static MSVCP_bool (__cdecl
*p__ContextCallback__IsCurrentOriginSTA
)(_ContextCallback
*);
158 static void (__thiscall
*p__TaskEventLogger__LogCancelTask
)(_TaskEventLogger
*);
159 static void (__thiscall
*p__TaskEventLogger__LogScheduleTask
)(_TaskEventLogger
*, MSVCP_bool
);
160 static void (__thiscall
*p__TaskEventLogger__LogTaskCompleted
)(_TaskEventLogger
*);
161 static void (__thiscall
*p__TaskEventLogger__LogTaskExecutionCompleted
)(_TaskEventLogger
*);
162 static void (__thiscall
*p__TaskEventLogger__LogWorkItemCompleted
)(_TaskEventLogger
*);
163 static void (__thiscall
*p__TaskEventLogger__LogWorkItemStarted
)(_TaskEventLogger
*);
164 static int (__cdecl
*p__Schedule_chore
)(_Threadpool_chore
*);
165 static int (__cdecl
*p__Reschedule_chore
)(const _Threadpool_chore
*);
166 static void (__cdecl
*p__Release_chore
)(_Threadpool_chore
*);
168 static void (__cdecl
*p_Close_dir
)(void*);
169 static MSVCP_bool (__cdecl
*p_Current_get
)(WCHAR
*);
170 static MSVCP_bool (__cdecl
*p_Current_set
)(WCHAR
const *);
171 static ULONGLONG (__cdecl
*p_File_size
)(WCHAR
const *);
172 static enum file_type (__cdecl
*p_Lstat
)(WCHAR
const *, int *);
173 static void* (__cdecl
*p_Open_dir
)(WCHAR
*, WCHAR
const*, int *, enum file_type
*);
174 static WCHAR
* (__cdecl
*p_Read_dir
)(WCHAR
*, void*, enum file_type
*);
175 static enum file_type (__cdecl
*p_Stat
)(WCHAR
const *, int *);
176 static int (__cdecl
*p_To_byte
)(const WCHAR
*src
, char *dst
);
177 static int (__cdecl
*p_To_wide
)(const char *src
, WCHAR
*dst
);
179 static BOOLEAN (WINAPI
*pCreateSymbolicLinkW
)(const WCHAR
*, const WCHAR
*, DWORD
);
181 static HMODULE msvcp
;
182 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
183 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
184 static BOOL
init(void)
188 msvcp
= LoadLibraryA("msvcp140.dll");
191 win_skip("msvcp140.dll not installed\n");
195 SET(p__Thrd_id
, "_Thrd_id");
196 SET(p__ContextCallback__IsCurrentOriginSTA
, "?_IsCurrentOriginSTA@_ContextCallback@details@Concurrency@@CA_NXZ");
198 if(sizeof(void*) == 8) { /* 64-bit initialization */
199 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AEAA@XZ");
200 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AEAAXPEAX@Z");
201 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QEBAXV?$function@$$A6AXXZ@std@@_N@Z");
202 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AEAAXXZ");
203 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AEAAXXZ");
204 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
205 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QEAAX_N@Z");
206 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
207 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
208 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
209 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
210 SET(p__Schedule_chore
, "?_Schedule_chore@details@Concurrency@@YAHPEAU_Threadpool_chore@12@@Z");
211 SET(p__Reschedule_chore
, "?_Reschedule_chore@details@Concurrency@@YAHPEBU_Threadpool_chore@12@@Z");
212 SET(p__Release_chore
, "?_Release_chore@details@Concurrency@@YAXPEAU_Threadpool_chore@12@@Z");
215 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AAA@XZ");
216 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AAAXPAX@Z");
217 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QBAXV?$function@$$A6AXXZ@std@@_N@Z");
218 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AAAXXZ");
219 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AAAXXZ");
220 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAAXXZ");
221 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
222 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
223 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
224 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
225 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
227 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AAE@XZ");
228 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z");
229 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QBEXV?$function@$$A6AXXZ@std@@_N@Z");
230 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AAEXXZ");
231 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AAEXXZ");
232 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAEXXZ");
233 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
234 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
235 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
236 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
237 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
239 SET(p__Schedule_chore
, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z");
240 SET(p__Reschedule_chore
, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z");
241 SET(p__Release_chore
, "?_Release_chore@details@Concurrency@@YAXPAU_Threadpool_chore@12@@Z");
244 SET(p_Close_dir
, "_Close_dir");
245 SET(p_Current_get
, "_Current_get");
246 SET(p_Current_set
, "_Current_set");
247 SET(p_File_size
, "_File_size");
248 SET(p_Lstat
, "_Lstat");
249 SET(p_Open_dir
, "_Open_dir");
250 SET(p_Read_dir
, "_Read_dir");
251 SET(p_Stat
, "_Stat");
252 SET(p_To_byte
, "_To_byte");
253 SET(p_To_wide
, "_To_wide");
255 hdll
= GetModuleHandleA("kernel32.dll");
256 pCreateSymbolicLinkW
= (void*)GetProcAddress(hdll
, "CreateSymbolicLinkW");
258 init_thiscall_thunk();
262 static void test_thrd(void)
264 ok(p__Thrd_id() == GetCurrentThreadId(),
265 "expected same id, got _Thrd_id %u GetCurrentThreadId %u\n",
266 p__Thrd_id(), GetCurrentThreadId());
271 const char* export_name
;
272 } vbtable_size_exports_list
[] = {
273 {{0x20, 0x20}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_istream@DU?$char_traits@D@std@@@1@@"},
274 {{0x10, 0x10}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@"},
275 {{0x20, 0x20}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@"},
276 {{0x10, 0x10}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@"},
277 {{0x20, 0x20}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_istream@_WU?$char_traits@_W@std@@@1@@"},
278 {{0x10, 0x10}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_ostream@_WU?$char_traits@_W@std@@@1@@"},
279 {{0x18, 0x18}, "??_8?$basic_istream@DU?$char_traits@D@std@@@std@@7B@"},
280 {{0x18, 0x18}, "??_8?$basic_istream@GU?$char_traits@G@std@@@std@@7B@"},
281 {{0x18, 0x18}, "??_8?$basic_istream@_WU?$char_traits@_W@std@@@std@@7B@"},
282 {{ 0x8, 0x10}, "??_8?$basic_ostream@DU?$char_traits@D@std@@@std@@7B@"},
283 {{ 0x8, 0x10}, "??_8?$basic_ostream@GU?$char_traits@G@std@@@std@@7B@"},
284 {{ 0x8, 0x10}, "??_8?$basic_ostream@_WU?$char_traits@_W@std@@@std@@7B@"},
288 static void test_vbtable_size_exports(void)
291 const int *p_vbtable
;
292 int arch_idx
= (sizeof(void*) == 8);
294 for (i
= 0; vbtable_size_exports_list
[i
].export_name
; i
++)
296 SET(p_vbtable
, vbtable_size_exports_list
[i
].export_name
);
298 ok(p_vbtable
[0] == 0, "vbtable[0] wrong, got 0x%x\n", p_vbtable
[0]);
299 ok(p_vbtable
[1] == vbtable_size_exports_list
[i
].value
[arch_idx
],
300 "%d: %s[1] wrong, got 0x%x\n", i
, vbtable_size_exports_list
[i
].export_name
, p_vbtable
[1]);
304 static void test_task_continuation_context(void)
306 task_continuation_context tcc
;
308 memset(&tcc
, 0xff, sizeof(tcc
));
309 call_func1(p_task_continuation_context_ctor
, &tcc
);
310 ok(!tcc
.unk0
, "tcc.unk0 != NULL (%p)\n", tcc
.unk0
);
311 ok(!tcc
.unk1
, "tcc.unk1 != 0 (%x)\n", tcc
.unk1
);
315 static void __cdecl
function_do_call(void *this)
317 CHECK_EXPECT(function_do_call
);
320 static void __cdecl
function_do_clean(void *this, MSVCP_bool b
)
322 CHECK_EXPECT(function_do_clean
);
323 ok(b
, "b == FALSE\n");
327 static void test__ContextCallback(void)
329 _ContextCallback cc
= {0};
330 void *v
= (void*)0xdeadbeef;
332 void* function_vtbl
[] = {
335 (void*)function_do_call
,
337 (void*)function_do_clean
,
340 function_void_cdecl_void function
= { function_vtbl
, NULL
, {0}, {NULL
}, &function
};
341 function_void_cdecl_void function2
= { NULL
, NULL
, {0}, {NULL
}, &function
};
344 call_func2(p__ContextCallback__Assign
, &cc
, v
);
345 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
346 call_func1(p__ContextCallback__Reset
, &cc
);
347 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
348 call_func1(p__ContextCallback__Capture
, &cc
);
349 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
350 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc
), "IsCurrentOriginSTA returned TRUE\n");
353 call_func2(p__ContextCallback__Assign
, &cc
, NULL
);
354 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
355 call_func1(p__ContextCallback__Reset
, &cc
);
356 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
357 call_func1(p__ContextCallback__Capture
, &cc
);
358 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
359 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc
), "IsCurrentOriginSTA returned TRUE\n");
360 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
363 SET_EXPECT(function_do_call
);
364 SET_EXPECT(function_do_clean
);
365 p__ContextCallback__CallInContext(&cc
, function
, FALSE
);
366 CHECK_CALLED(function_do_call
);
367 CHECK_CALLED(function_do_clean
);
369 SET_EXPECT(function_do_call
);
370 SET_EXPECT(function_do_clean
);
371 p__ContextCallback__CallInContext(&cc
, function
, TRUE
);
372 CHECK_CALLED(function_do_call
);
373 CHECK_CALLED(function_do_clean
);
375 SET_EXPECT(function_do_call
);
376 SET_EXPECT(function_do_clean
);
377 p__ContextCallback__CallInContext(&cc
, function2
, FALSE
);
378 CHECK_CALLED(function_do_call
);
379 CHECK_CALLED(function_do_clean
);
381 SET_EXPECT(function_do_call
);
382 SET_EXPECT(function_do_clean
);
383 p__ContextCallback__CallInContext(&cc
, function2
, TRUE
);
384 CHECK_CALLED(function_do_call
);
385 CHECK_CALLED(function_do_clean
);
389 static void test__TaskEventLogger(void)
391 _TaskEventLogger logger
;
392 memset(&logger
, 0, sizeof(logger
));
394 call_func1(p__TaskEventLogger__LogCancelTask
, &logger
);
395 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
396 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
397 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
399 call_func2(p__TaskEventLogger__LogScheduleTask
, &logger
, FALSE
);
400 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
401 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
402 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
404 call_func1(p__TaskEventLogger__LogTaskCompleted
, &logger
);
405 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
406 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
407 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
409 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted
, &logger
);
410 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
411 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
412 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
414 call_func1(p__TaskEventLogger__LogWorkItemCompleted
, &logger
);
415 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
416 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
417 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
419 call_func1(p__TaskEventLogger__LogWorkItemStarted
, &logger
);
420 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
421 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
422 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
424 logger
.task
= (void*)0xdeadbeef;
425 logger
.scheduled
= TRUE
;
426 logger
.started
= TRUE
;
428 call_func1(p__TaskEventLogger__LogCancelTask
, &logger
);
429 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
430 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
431 ok(logger
.started
, "logger.started = FALSE\n");
433 call_func2(p__TaskEventLogger__LogScheduleTask
, &logger
, FALSE
);
434 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
435 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
436 ok(logger
.started
, "logger.started = FALSE\n");
438 call_func1(p__TaskEventLogger__LogTaskCompleted
, &logger
);
439 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
440 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
441 ok(logger
.started
, "logger.started = FALSE\n");
443 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted
, &logger
);
444 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
445 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
446 ok(logger
.started
, "logger.started = FALSE\n");
448 call_func1(p__TaskEventLogger__LogWorkItemCompleted
, &logger
);
449 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
450 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
451 ok(logger
.started
, "logger.started = FALSE\n");
453 call_func1(p__TaskEventLogger__LogWorkItemStarted
, &logger
);
454 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
455 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
456 ok(logger
.started
, "logger.started = FALSE\n");
459 static void __cdecl
chore_callback(void *arg
)
465 static void test_chore(void)
467 HANDLE event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
468 _Threadpool_chore chore
, old_chore
;
472 memset(&chore
, 0, sizeof(chore
));
473 ret
= p__Schedule_chore(&chore
);
474 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
475 ok(chore
.work
!= NULL
, "chore.work == NULL\n");
476 ok(!chore
.callback
, "chore.callback != NULL\n");
477 p__Release_chore(&chore
);
480 chore
.callback
= chore_callback
;
482 ret
= p__Schedule_chore(&chore
);
483 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
484 ok(chore
.work
!= NULL
, "chore.work == NULL\n");
485 ok(chore
.callback
== chore_callback
, "chore.callback = %p, expected %p\n", chore
.callback
, chore_callback
);
486 ok(chore
.arg
== event
, "chore.arg = %p, expected %p\n", chore
.arg
, event
);
487 wait
= WaitForSingleObject(event
, 500);
488 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
491 ret
= p__Schedule_chore(&chore
);
492 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
493 ok(old_chore
.work
!= chore
.work
, "new threadpool work was not created\n");
494 p__Release_chore(&old_chore
);
495 wait
= WaitForSingleObject(event
, 500);
496 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
498 ret
= p__Reschedule_chore(&chore
);
499 ok(!ret
, "_Reschedule_chore returned %d\n", ret
);
500 wait
= WaitForSingleObject(event
, 500);
501 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
503 p__Release_chore(&chore
);
504 ok(!chore
.work
, "chore.work != NULL\n");
505 ok(chore
.callback
== chore_callback
, "chore.callback = %p, expected %p\n", chore
.callback
, chore_callback
);
506 ok(chore
.arg
== event
, "chore.arg = %p, expected %p\n", chore
.arg
, event
);
507 p__Release_chore(&chore
);
510 static void test_to_byte(void)
512 static const WCHAR test_1
[] = {'T', 'E', 'S', 'T', 0};
513 static const WCHAR test_2
[] = {0x9580, 0x9581, 0x9582, 0x9583, 0}; /* some CJK characters */
514 static const WCHAR
*tests
[] = {test_1
, test_2
};
516 char dst
[MAX_PATH
+ 4] = "ABC\0XXXXXXX";
517 char compare
[MAX_PATH
+ 4] = "ABC\0XXXXXXX";
520 WCHAR longstr
[MAX_PATH
+ 3];
522 ret
= p_To_byte(NULL
, NULL
);
523 ok(!ret
, "Got unexpected result %d\n", ret
);
524 ret
= p_To_byte(tests
[0], NULL
);
525 ok(!ret
, "Got unexpected result %d\n", ret
);
526 ret
= p_To_byte(NULL
, dst
);
527 ok(!ret
, "Got unexpected result %d\n", ret
);
529 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Destination was modified: %s\n", dst
);
531 for (i
= 0; i
< sizeof(tests
) / sizeof(*tests
); ++i
)
533 ret
= p_To_byte(tests
[i
], dst
);
534 expected
= WideCharToMultiByte(CP_ACP
, 0, tests
[i
], -1, compare
, sizeof(compare
) / sizeof(*compare
),
536 ok(ret
== expected
, "Got unexpected result %d, expected %d, test case %u\n", ret
, expected
, i
);
537 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, test case %u\n", dst
, i
);
540 /* Output length is limited to MAX_PATH.*/
541 for (i
= MAX_PATH
- 2; i
< MAX_PATH
+ 2; ++i
)
543 for (j
= 0; j
< i
; j
++)
546 memset(dst
, 0xff, sizeof(dst
));
547 memset(compare
, 0xff, sizeof(compare
));
549 ret
= p_To_byte(longstr
, dst
);
550 expected
= WideCharToMultiByte(CP_ACP
, 0, longstr
, -1, compare
, MAX_PATH
, NULL
, NULL
);
551 ok(ret
== expected
, "Got unexpected result %d, expected %d, length %u\n", ret
, expected
, i
);
552 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, length %u\n", dst
, i
);
556 static void test_to_wide(void)
558 /* öäü߀Ÿ.A.B in cp1252, the two . are an undefined value and delete.
559 * With a different system codepage it will produce different results, so do not hardcode the
560 * expected output but convert it with MultiByteToWideChar. */
561 static const char special_input
[] = {0xf6, 0xe4, 0xfc, 0xdf, 0x80, 0x9f, 0x81, 0x41, 0x7f, 0x42, 0};
562 static const char *tests
[] = {"Testtest", special_input
};
563 WCHAR dst
[MAX_PATH
+ 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
564 WCHAR compare
[MAX_PATH
+ 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
567 char longstr
[MAX_PATH
+ 3];
569 ret
= p_To_wide(NULL
, NULL
);
570 ok(!ret
, "Got unexpected result %d\n", ret
);
571 ret
= p_To_wide(tests
[0], NULL
);
572 ok(!ret
, "Got unexpected result %d\n", ret
);
573 ret
= p_To_wide(NULL
, dst
);
574 ok(!ret
, "Got unexpected result %d\n", ret
);
575 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Destination was modified: %s\n", wine_dbgstr_w(dst
));
577 for (i
= 0; i
< sizeof(tests
) / sizeof(*tests
); ++i
)
579 ret
= p_To_wide(tests
[i
], dst
);
580 expected
= MultiByteToWideChar(CP_ACP
, 0, tests
[i
], -1, compare
, sizeof(compare
) / sizeof(*compare
));
581 ok(ret
== expected
, "Got unexpected result %d, expected %d, test case %u\n", ret
, expected
, i
);
582 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, test case %u\n",
583 wine_dbgstr_w(dst
), i
);
586 /* Output length is limited to MAX_PATH.*/
587 for (i
= MAX_PATH
- 2; i
< MAX_PATH
+ 2; ++i
)
589 memset(longstr
, 'A', sizeof(longstr
));
591 memset(dst
, 0xff, sizeof(dst
));
592 memset(compare
, 0xff, sizeof(compare
));
594 ret
= p_To_wide(longstr
, dst
);
595 expected
= MultiByteToWideChar(CP_ACP
, 0, longstr
, -1, compare
, MAX_PATH
);
596 ok(ret
== expected
, "Got unexpected result %d, expected %d, length %u\n", ret
, expected
, i
);
597 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, length %u\n",
598 wine_dbgstr_w(dst
), i
);
602 static void test_File_size(void)
606 LARGE_INTEGER file_size
;
607 WCHAR test_f1_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
608 WCHAR test_f2_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
609 WCHAR test_dir_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
610 WCHAR test_ne_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
611 WCHAR temp_path
[MAX_PATH
], origin_path
[MAX_PATH
];
613 memset(origin_path
, 0, sizeof(origin_path
));
614 memset(origin_path
, 0, sizeof(temp_path
));
615 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
616 GetTempPathW(MAX_PATH
, temp_path
);
617 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
619 CreateDirectoryW(test_dir_W
, NULL
);
621 file
= CreateFileW(test_f1_W
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
622 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
623 file_size
.QuadPart
= 7;
624 ok(SetFilePointerEx(file
, file_size
, NULL
, FILE_BEGIN
), "SetFilePointerEx failed\n");
625 ok(SetEndOfFile(file
), "SetEndOfFile failed\n");
627 val
= p_File_size(test_f1_W
);
628 ok(val
== 7, "file_size is %s\n", wine_dbgstr_longlong(val
));
630 file
= CreateFileW(test_f2_W
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
631 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
633 val
= p_File_size(test_f2_W
);
634 ok(val
== 0, "file_size is %s\n", wine_dbgstr_longlong(val
));
636 val
= p_File_size(test_dir_W
);
637 ok(val
== 0, "file_size is %s\n", wine_dbgstr_longlong(val
));
640 val
= p_File_size(test_ne_W
);
641 ok(val
== ~(ULONGLONG
)0, "file_size is %s\n", wine_dbgstr_longlong(val
));
642 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
645 val
= p_File_size(NULL
);
646 ok(val
== ~(ULONGLONG
)0, "file_size is %s\n", wine_dbgstr_longlong(val
));
647 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
649 ok(DeleteFileW(test_f1_W
), "expect wine_test_dir/f1 to exist\n");
650 ok(DeleteFileW(test_f2_W
), "expect wine_test_dir/f2 to exist\n");
651 ok(RemoveDirectoryW(test_dir_W
), "expect wine_test_dir to exist\n");
652 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
655 static void test_Current_get(void)
657 WCHAR temp_path
[MAX_PATH
], current_path
[MAX_PATH
], origin_path
[MAX_PATH
];
659 memset(origin_path
, 0, sizeof(origin_path
));
660 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
661 memset(temp_path
, 0, sizeof(temp_path
));
662 GetTempPathW(MAX_PATH
, temp_path
);
664 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
665 memset(current_path
, 0, sizeof(current_path
));
666 ret
= p_Current_get(current_path
);
667 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
668 current_path
[wcslen(current_path
)] = '\\';
669 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
670 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
672 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
673 memset(current_path
, 0, sizeof(current_path
));
674 ret
= p_Current_get(current_path
);
675 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
676 ok(!wcscmp(origin_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
677 wine_dbgstr_w(origin_path
), wine_dbgstr_w(current_path
));
680 static void test_Current_set(void)
682 WCHAR temp_path
[MAX_PATH
], current_path
[MAX_PATH
], origin_path
[MAX_PATH
];
684 WCHAR testW
[] = {'.','/',0};
685 WCHAR not_exit_dirW
[] = {'n', 'o', 't', '_', 'e', 'x', 'i', 's', 't', '_', 'd', 'i', 'r', 0};
686 WCHAR invalid_nameW
[] = {'?', '?', 'i', 'n', 'v', 'a', 'l', 'i', 'd', '_', 'n', 'a', 'm', 'e', '>', '>', 0};
687 memset(temp_path
, 0, sizeof(temp_path
));
688 GetTempPathW(MAX_PATH
, temp_path
);
689 memset(origin_path
, 0, sizeof(origin_path
));
690 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
692 ok(p_Current_set(temp_path
), "p_Current_set to temp_path failed\n");
693 memset(current_path
, 0, sizeof(current_path
));
694 ret
= p_Current_get(current_path
);
695 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
696 current_path
[wcslen(current_path
)] = '\\';
697 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
698 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
700 ok(p_Current_set(testW
), "p_Current_set to temp_path failed\n");
701 memset(current_path
, 0, sizeof(current_path
));
702 ret
= p_Current_get(current_path
);
703 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
704 current_path
[wcslen(current_path
)] = '\\';
705 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
706 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
709 ok(!p_Current_set(not_exit_dirW
), "p_Current_set to not_exist_dir succeed\n");
710 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
713 ok(!p_Current_set(invalid_nameW
), "p_Current_set to ??invalid_name>> succeed\n");
714 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
716 ok(p_Current_set(origin_path
), "p_Current_set to origin_path failed\n");
717 memset(current_path
, 0, sizeof(current_path
));
718 ret
= p_Current_get(current_path
);
719 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
720 ok(!wcscmp(origin_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
721 wine_dbgstr_w(origin_path
), wine_dbgstr_w(current_path
));
724 static void test_Stat(void)
729 WCHAR test_dirW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
730 WCHAR test_f1W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
731 WCHAR test_f2W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
732 WCHAR pipeW
[] = {'\\','\\','.','\\','P','i','P','e','\\','t','e','s','t','s','_','p','i','p','e','.','c', 0};
733 WCHAR test_neW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
734 WCHAR test_invW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','?','?','i','n','v','a','l','i','d','_','n','a','m','e','>','>',0};
735 WCHAR test_f1_linkW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','f','1','_','l','i','n','k',0};
736 WCHAR test_dir_linkW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','d','i','r','_','l','i','n','k',0};
737 WCHAR sys_path
[MAX_PATH
], origin_path
[MAX_PATH
], temp_path
[MAX_PATH
];
744 { NULL
, file_not_found
, 0xdeadbeef, FALSE
},
745 { test_dirW
, directory_file
, 0777, FALSE
},
746 { test_f1W
, regular_file
, 0777, FALSE
},
747 { test_f2W
, regular_file
, 0555, FALSE
},
748 { test_neW
, file_not_found
, 0xdeadbeef, FALSE
},
749 { test_invW
, file_not_found
, 0xdeadbeef, FALSE
},
750 { test_f1_linkW
, regular_file
, 0777, TRUE
},
751 { test_dir_linkW
, directory_file
, 0777, TRUE
},
754 memset(origin_path
, 0, sizeof(origin_path
));
755 memset(origin_path
, 0, sizeof(temp_path
));
756 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
757 GetTempPathW(MAX_PATH
, temp_path
);
758 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
760 CreateDirectoryW(test_dirW
, NULL
);
762 file
= CreateFileW(test_f1W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
763 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
764 ok(CloseHandle(file
), "CloseHandle\n");
766 file
= CreateFileW(test_f2W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
767 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
768 ok(CloseHandle(file
), "CloseHandle\n");
769 SetFileAttributesW(test_f2W
, FILE_ATTRIBUTE_READONLY
);
771 SetLastError(0xdeadbeef);
772 ret
= pCreateSymbolicLinkW
&& pCreateSymbolicLinkW(test_f1_linkW
, test_f1W
, 0);
773 if(!ret
&& (!pCreateSymbolicLinkW
|| GetLastError()==ERROR_PRIVILEGE_NOT_HELD
||GetLastError()==ERROR_INVALID_FUNCTION
)) {
774 tests
[6].ret
= tests
[7].ret
= file_not_found
;
775 tests
[6].perms
= tests
[7].perms
= 0xdeadbeef;
776 win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n");
778 ok(ret
, "CreateSymbolicLinkW failed\n");
779 ok(pCreateSymbolicLinkW(test_dir_linkW
, test_dirW
, 1), "CreateSymbolicLinkW failed\n");
782 file
= CreateNamedPipeW(pipeW
,
783 PIPE_ACCESS_DUPLEX
, PIPE_TYPE_BYTE
| PIPE_WAIT
, 2, 1024, 1024,
784 NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
785 ok(file
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed\n");
787 val
= p_Stat(pipeW
, &perms
);
788 todo_wine
ok(regular_file
== val
, "_Stat(): expect: regular, got %d\n", val
);
789 todo_wine
ok(0777 == perms
, "_Stat(): perms expect: 0777, got 0%o\n", perms
);
791 val
= p_Lstat(pipeW
, &perms
);
792 ok(status_unknown
== val
, "_Lstat(): expect: unknown, got %d\n", val
);
793 ok(0xdeadbeef == perms
, "_Lstat(): perms expect: 0xdeadbeef, got %x\n", perms
);
794 ok(CloseHandle(file
), "CloseHandle\n");
795 file
= CreateNamedPipeW(pipeW
,
796 PIPE_ACCESS_DUPLEX
, PIPE_TYPE_BYTE
| PIPE_WAIT
, 2, 1024, 1024,
797 NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
798 ok(file
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed\n");
800 val
= p_Lstat(pipeW
, &perms
);
801 todo_wine
ok(regular_file
== val
, "_Lstat(): expect: regular, got %d\n", val
);
802 todo_wine
ok(0777 == perms
, "_Lstat(): perms expect: 0777, got 0%o\n", perms
);
803 ok(CloseHandle(file
), "CloseHandle\n");
805 for(i
=0; i
<sizeof(tests
)/sizeof(tests
[0]); i
++) {
807 val
= p_Stat(tests
[i
].path
, &perms
);
808 todo_wine_if(tests
[i
].is_todo
) {
809 ok(tests
[i
].ret
== val
, "_Stat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
810 ok(tests
[i
].perms
== perms
, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
811 i
+1, tests
[i
].perms
, perms
);
813 val
= p_Stat(tests
[i
].path
, NULL
);
814 todo_wine_if(tests
[i
].is_todo
)
815 ok(tests
[i
].ret
== val
, "_Stat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
819 val
= p_Lstat(tests
[i
].path
, &perms
);
820 todo_wine_if(tests
[i
].is_todo
) {
821 ok(tests
[i
].ret
== val
, "_Lstat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
822 ok(tests
[i
].perms
== perms
, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
823 i
+1, tests
[i
].perms
, perms
);
825 val
= p_Lstat(tests
[i
].path
, NULL
);
826 todo_wine_if(tests
[i
].is_todo
)
827 ok(tests
[i
].ret
== val
, "_Lstat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
830 GetSystemDirectoryW(sys_path
, MAX_PATH
);
832 val
= p_Stat(sys_path
, &perms
);
833 ok(directory_file
== val
, "_Stat(): expect: regular, got %d\n", val
);
834 ok(0777 == perms
, "_Stat(): perms expect: 0777, got 0%o\n", perms
);
837 todo_wine
ok(DeleteFileW(test_f1_linkW
), "expect tr2_test_dir/f1_link to exist\n");
838 todo_wine
ok(RemoveDirectoryW(test_dir_linkW
), "expect tr2_test_dir/dir_link to exist\n");
840 ok(DeleteFileW(test_f1W
), "expect tr2_test_dir/f1 to exist\n");
841 SetFileAttributesW(test_f2W
, FILE_ATTRIBUTE_NORMAL
);
842 ok(DeleteFileW(test_f2W
), "expect tr2_test_dir/f2 to exist\n");
843 ok(RemoveDirectoryW(test_dirW
), "expect tr2_test_dir to exist\n");
845 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
848 static void test_dir_operation(void)
850 WCHAR
*file_name
, first_file_name
[MAX_PATH
], dest
[MAX_PATH
], longer_path
[MAX_PATH
];
851 WCHAR origin_path
[MAX_PATH
], temp_path
[MAX_PATH
];
852 HANDLE file
, result_handle
;
854 int err
, num_of_f1
= 0, num_of_f2
= 0, num_of_sub_dir
= 0, num_of_other_files
= 0;
855 WCHAR test_dirW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
856 WCHAR test_f1W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
857 WCHAR test_f2W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
858 WCHAR test_sub_dirW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','s','u','b','_','d','i','r',0};
859 WCHAR test_sub_dir_f1W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',
860 '/','s','u','b','_','d','i','r','/','f','1',0};
861 WCHAR backslashW
[] = {'\\',0};
862 WCHAR sW
[] = {'s',0};
863 WCHAR f1W
[] = {'f','1',0};
864 WCHAR f2W
[] = {'f','2',0};
865 WCHAR sub_dirW
[] = {'s','u','b','_','d','i','r',0};
866 WCHAR not_existW
[] = {'n','o','t','_','e','x','i','s','t',0};
867 WCHAR emtpy_dirW
[] = {'e','m','p','t','y','_','d','i','r',0};
869 memset(origin_path
, 0, sizeof(origin_path
));
870 memset(origin_path
, 0, sizeof(temp_path
));
871 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
872 GetTempPathW(MAX_PATH
, temp_path
);
873 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
875 CreateDirectoryW(test_dirW
, NULL
);
876 file
= CreateFileW(test_f1W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
877 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
879 file
= CreateFileW(test_f2W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
880 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
882 CreateDirectoryW(test_sub_dirW
, NULL
);
883 file
= CreateFileW(test_sub_dir_f1W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
884 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
887 memcpy(longer_path
, temp_path
, sizeof(longer_path
));
888 wcscat(longer_path
, backslashW
);
889 wcscat(longer_path
, test_dirW
);
890 wcscat(longer_path
, backslashW
);
891 while(lstrlenW(longer_path
) < MAX_PATH
-1)
892 wcscat(longer_path
, sW
);
893 memset(first_file_name
, 0, sizeof(first_file_name
));
894 type
= err
= 0xdeadbeef;
895 result_handle
= NULL
;
896 result_handle
= p_Open_dir(first_file_name
, longer_path
, &err
, &type
);
897 ok(result_handle
== NULL
, "_Open_dir(): expect NULL, got %p\n", result_handle
);
898 ok(!*first_file_name
, "_Open_dir(): expect: 0, got %s\n", wine_dbgstr_w(first_file_name
));
899 ok(err
== ERROR_BAD_PATHNAME
, "_Open_dir(): expect: ERROR_BAD_PATHNAME, got %d\n", err
);
900 ok((int)type
== 0xdeadbeef, "_Open_dir(): expect 0xdeadbeef, got %d\n", type
);
902 memset(first_file_name
, 0, sizeof(first_file_name
));
903 memset(dest
, 0, sizeof(dest
));
904 err
= type
= 0xdeadbeef;
905 result_handle
= NULL
;
906 result_handle
= p_Open_dir(first_file_name
, test_dirW
, &err
, &type
);
907 ok(result_handle
!= NULL
, "_Open_dir(): expect: not NULL, got %p\n", result_handle
);
908 ok(err
== ERROR_SUCCESS
, "_Open_dir(): expect: ERROR_SUCCESS, got %d\n", err
);
909 file_name
= first_file_name
;
911 if (!wcscmp(file_name
, f1W
)) {
913 ok(type
== regular_file
, "expect regular_file, got %d\n", type
);
914 }else if(!wcscmp(file_name
, f2W
)) {
916 ok(type
== regular_file
, "expect regular_file, got %d\n", type
);
917 }else if(!wcscmp(file_name
, sub_dirW
)) {
919 ok(type
== directory_file
, "expect directory_file, got %d\n", type
);
921 ++num_of_other_files
;
923 file_name
= p_Read_dir(dest
, result_handle
, &type
);
925 ok(type
== status_unknown
, "_Read_dir(): expect: status_unknown, got %d\n", type
);
926 p_Close_dir(result_handle
);
927 ok(result_handle
!= NULL
, "_Open_dir(): expect: not NULL, got %p\n", result_handle
);
928 ok(num_of_f1
== 1, "found f1 %d times\n", num_of_f1
);
929 ok(num_of_f2
== 1, "found f2 %d times\n", num_of_f2
);
930 ok(num_of_sub_dir
== 1, "found sub_dir %d times\n", num_of_sub_dir
);
931 ok(num_of_other_files
== 0, "found %d other files\n", num_of_other_files
);
933 memset(first_file_name
, 0, sizeof(first_file_name
));
934 err
= type
= 0xdeadbeef;
935 result_handle
= file
;
936 result_handle
= p_Open_dir(first_file_name
, not_existW
, &err
, &type
);
937 ok(result_handle
== NULL
, "_Open_dir(): expect: NULL, got %p\n", result_handle
);
938 todo_wine
ok(err
== ERROR_BAD_PATHNAME
, "_Open_dir(): expect: ERROR_BAD_PATHNAME, got %d\n", err
);
939 ok((int)type
== 0xdeadbeef, "_Open_dir(): expect: 0xdeadbeef, got %d\n", type
);
940 ok(!*first_file_name
, "_Open_dir(): expect: 0, got %s\n", wine_dbgstr_w(first_file_name
));
942 CreateDirectoryW(emtpy_dirW
, NULL
);
943 memset(first_file_name
, 0, sizeof(first_file_name
));
944 err
= type
= 0xdeadbeef;
945 result_handle
= file
;
946 result_handle
= p_Open_dir(first_file_name
, emtpy_dirW
, &err
, &type
);
947 ok(result_handle
== NULL
, "_Open_dir(): expect: NULL, got %p\n", result_handle
);
948 ok(err
== ERROR_SUCCESS
, "_Open_dir(): expect: ERROR_SUCCESS, got %d\n", err
);
949 ok(type
== status_unknown
, "_Open_dir(): expect: status_unknown, got %d\n", type
);
950 ok(!*first_file_name
, "_Open_dir(): expect: 0, got %s\n", wine_dbgstr_w(first_file_name
));
951 p_Close_dir(result_handle
);
952 ok(result_handle
== NULL
, "_Open_dir(): expect: NULL, got %p\n", result_handle
);
954 ok(RemoveDirectoryW(emtpy_dirW
), "expect empty_dir to exist\n");
955 ok(DeleteFileW(test_sub_dir_f1W
), "expect wine_test_dir/sub_dir/sub_f1 to exist\n");
956 ok(RemoveDirectoryW(test_sub_dirW
), "expect wine_test_dir/sub_dir to exist\n");
957 ok(DeleteFileW(test_f1W
), "expect wine_test_dir/f1 to exist\n");
958 ok(DeleteFileW(test_f2W
), "expect wine_test_dir/f2 to exist\n");
959 ok(RemoveDirectoryW(test_dirW
), "expect wine_test_dir to exist\n");
961 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
968 test_vbtable_size_exports();
969 test_task_continuation_context();
970 test__ContextCallback();
971 test__TaskEventLogger();
979 test_dir_operation();