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 MSVCP_bool (__cdecl
*p_Current_get
)(WCHAR
*);
169 static MSVCP_bool (__cdecl
*p_Current_set
)(WCHAR
const *);
170 static ULONGLONG (__cdecl
*p_File_size
)(WCHAR
const *);
171 static enum file_type (__cdecl
*p_Lstat
)(WCHAR
const *, int *);
172 static enum file_type (__cdecl
*p_Stat
)(WCHAR
const *, int *);
173 static int (__cdecl
*p_To_byte
)(const WCHAR
*src
, char *dst
);
174 static int (__cdecl
*p_To_wide
)(const char *src
, WCHAR
*dst
);
176 static BOOLEAN (WINAPI
*pCreateSymbolicLinkW
)(const WCHAR
*, const WCHAR
*, DWORD
);
178 static HMODULE msvcp
;
179 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
180 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
181 static BOOL
init(void)
185 msvcp
= LoadLibraryA("msvcp140.dll");
188 win_skip("msvcp140.dll not installed\n");
192 SET(p__Thrd_id
, "_Thrd_id");
193 SET(p__ContextCallback__IsCurrentOriginSTA
, "?_IsCurrentOriginSTA@_ContextCallback@details@Concurrency@@CA_NXZ");
195 if(sizeof(void*) == 8) { /* 64-bit initialization */
196 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AEAA@XZ");
197 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AEAAXPEAX@Z");
198 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QEBAXV?$function@$$A6AXXZ@std@@_N@Z");
199 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AEAAXXZ");
200 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AEAAXXZ");
201 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
202 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QEAAX_N@Z");
203 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
204 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
205 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
206 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
207 SET(p__Schedule_chore
, "?_Schedule_chore@details@Concurrency@@YAHPEAU_Threadpool_chore@12@@Z");
208 SET(p__Reschedule_chore
, "?_Reschedule_chore@details@Concurrency@@YAHPEBU_Threadpool_chore@12@@Z");
209 SET(p__Release_chore
, "?_Release_chore@details@Concurrency@@YAXPEAU_Threadpool_chore@12@@Z");
212 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AAA@XZ");
213 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AAAXPAX@Z");
214 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QBAXV?$function@$$A6AXXZ@std@@_N@Z");
215 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AAAXXZ");
216 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AAAXXZ");
217 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAAXXZ");
218 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
219 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
220 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
221 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
222 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
224 SET(p_task_continuation_context_ctor
, "??0task_continuation_context@Concurrency@@AAE@XZ");
225 SET(p__ContextCallback__Assign
, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z");
226 SET(p__ContextCallback__CallInContext
, "?_CallInContext@_ContextCallback@details@Concurrency@@QBEXV?$function@$$A6AXXZ@std@@_N@Z");
227 SET(p__ContextCallback__Capture
, "?_Capture@_ContextCallback@details@Concurrency@@AAEXXZ");
228 SET(p__ContextCallback__Reset
, "?_Reset@_ContextCallback@details@Concurrency@@AAEXXZ");
229 SET(p__TaskEventLogger__LogCancelTask
, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAEXXZ");
230 SET(p__TaskEventLogger__LogScheduleTask
, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
231 SET(p__TaskEventLogger__LogTaskCompleted
, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
232 SET(p__TaskEventLogger__LogTaskExecutionCompleted
, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
233 SET(p__TaskEventLogger__LogWorkItemCompleted
, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
234 SET(p__TaskEventLogger__LogWorkItemStarted
, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
236 SET(p__Schedule_chore
, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z");
237 SET(p__Reschedule_chore
, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z");
238 SET(p__Release_chore
, "?_Release_chore@details@Concurrency@@YAXPAU_Threadpool_chore@12@@Z");
241 SET(p_Current_get
, "_Current_get");
242 SET(p_Current_set
, "_Current_set");
243 SET(p_File_size
, "_File_size");
244 SET(p_Lstat
, "_Lstat");
245 SET(p_Stat
, "_Stat");
246 SET(p_To_byte
, "_To_byte");
247 SET(p_To_wide
, "_To_wide");
249 hdll
= GetModuleHandleA("kernel32.dll");
250 pCreateSymbolicLinkW
= (void*)GetProcAddress(hdll
, "CreateSymbolicLinkW");
252 init_thiscall_thunk();
256 static void test_thrd(void)
258 ok(p__Thrd_id() == GetCurrentThreadId(),
259 "expected same id, got _Thrd_id %u GetCurrentThreadId %u\n",
260 p__Thrd_id(), GetCurrentThreadId());
265 const char* export_name
;
266 } vbtable_size_exports_list
[] = {
267 {{0x20, 0x20}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_istream@DU?$char_traits@D@std@@@1@@"},
268 {{0x10, 0x10}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@"},
269 {{0x20, 0x20}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@"},
270 {{0x10, 0x10}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@"},
271 {{0x20, 0x20}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_istream@_WU?$char_traits@_W@std@@@1@@"},
272 {{0x10, 0x10}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_ostream@_WU?$char_traits@_W@std@@@1@@"},
273 {{0x18, 0x18}, "??_8?$basic_istream@DU?$char_traits@D@std@@@std@@7B@"},
274 {{0x18, 0x18}, "??_8?$basic_istream@GU?$char_traits@G@std@@@std@@7B@"},
275 {{0x18, 0x18}, "??_8?$basic_istream@_WU?$char_traits@_W@std@@@std@@7B@"},
276 {{ 0x8, 0x10}, "??_8?$basic_ostream@DU?$char_traits@D@std@@@std@@7B@"},
277 {{ 0x8, 0x10}, "??_8?$basic_ostream@GU?$char_traits@G@std@@@std@@7B@"},
278 {{ 0x8, 0x10}, "??_8?$basic_ostream@_WU?$char_traits@_W@std@@@std@@7B@"},
282 static void test_vbtable_size_exports(void)
285 const int *p_vbtable
;
286 int arch_idx
= (sizeof(void*) == 8);
288 for (i
= 0; vbtable_size_exports_list
[i
].export_name
; i
++)
290 SET(p_vbtable
, vbtable_size_exports_list
[i
].export_name
);
292 ok(p_vbtable
[0] == 0, "vbtable[0] wrong, got 0x%x\n", p_vbtable
[0]);
293 ok(p_vbtable
[1] == vbtable_size_exports_list
[i
].value
[arch_idx
],
294 "%d: %s[1] wrong, got 0x%x\n", i
, vbtable_size_exports_list
[i
].export_name
, p_vbtable
[1]);
298 static void test_task_continuation_context(void)
300 task_continuation_context tcc
;
302 memset(&tcc
, 0xff, sizeof(tcc
));
303 call_func1(p_task_continuation_context_ctor
, &tcc
);
304 ok(!tcc
.unk0
, "tcc.unk0 != NULL (%p)\n", tcc
.unk0
);
305 ok(!tcc
.unk1
, "tcc.unk1 != 0 (%x)\n", tcc
.unk1
);
309 static void __cdecl
function_do_call(void *this)
311 CHECK_EXPECT(function_do_call
);
314 static void __cdecl
function_do_clean(void *this, MSVCP_bool b
)
316 CHECK_EXPECT(function_do_clean
);
317 ok(b
, "b == FALSE\n");
321 static void test__ContextCallback(void)
323 _ContextCallback cc
= {0};
324 void *v
= (void*)0xdeadbeef;
326 void* function_vtbl
[] = {
329 (void*)function_do_call
,
331 (void*)function_do_clean
,
334 function_void_cdecl_void function
= { function_vtbl
, NULL
, {0}, {NULL
}, &function
};
335 function_void_cdecl_void function2
= { NULL
, NULL
, {0}, {NULL
}, &function
};
338 call_func2(p__ContextCallback__Assign
, &cc
, v
);
339 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
340 call_func1(p__ContextCallback__Reset
, &cc
);
341 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
342 call_func1(p__ContextCallback__Capture
, &cc
);
343 ok(!cc
.unused
, "cc.unused = %p\n", cc
.unused
);
344 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc
), "IsCurrentOriginSTA returned TRUE\n");
347 call_func2(p__ContextCallback__Assign
, &cc
, NULL
);
348 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
349 call_func1(p__ContextCallback__Reset
, &cc
);
350 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
351 call_func1(p__ContextCallback__Capture
, &cc
);
352 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
353 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc
), "IsCurrentOriginSTA returned TRUE\n");
354 ok(cc
.unused
== v
, "cc.unused = %p\n", cc
.unused
);
357 SET_EXPECT(function_do_call
);
358 SET_EXPECT(function_do_clean
);
359 p__ContextCallback__CallInContext(&cc
, function
, FALSE
);
360 CHECK_CALLED(function_do_call
);
361 CHECK_CALLED(function_do_clean
);
363 SET_EXPECT(function_do_call
);
364 SET_EXPECT(function_do_clean
);
365 p__ContextCallback__CallInContext(&cc
, function
, TRUE
);
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
, function2
, FALSE
);
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
, TRUE
);
378 CHECK_CALLED(function_do_call
);
379 CHECK_CALLED(function_do_clean
);
383 static void test__TaskEventLogger(void)
385 _TaskEventLogger logger
;
386 memset(&logger
, 0, sizeof(logger
));
388 call_func1(p__TaskEventLogger__LogCancelTask
, &logger
);
389 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
390 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
391 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
393 call_func2(p__TaskEventLogger__LogScheduleTask
, &logger
, FALSE
);
394 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
395 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
396 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
398 call_func1(p__TaskEventLogger__LogTaskCompleted
, &logger
);
399 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
400 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
401 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
403 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted
, &logger
);
404 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
405 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
406 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
408 call_func1(p__TaskEventLogger__LogWorkItemCompleted
, &logger
);
409 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
410 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
411 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
413 call_func1(p__TaskEventLogger__LogWorkItemStarted
, &logger
);
414 ok(!logger
.task
, "logger.task = %p\n", logger
.task
);
415 ok(!logger
.scheduled
, "logger.scheduled = %x\n", logger
.scheduled
);
416 ok(!logger
.started
, "logger.started = %x\n", logger
.started
);
418 logger
.task
= (void*)0xdeadbeef;
419 logger
.scheduled
= TRUE
;
420 logger
.started
= TRUE
;
422 call_func1(p__TaskEventLogger__LogCancelTask
, &logger
);
423 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
424 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
425 ok(logger
.started
, "logger.started = FALSE\n");
427 call_func2(p__TaskEventLogger__LogScheduleTask
, &logger
, FALSE
);
428 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
429 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
430 ok(logger
.started
, "logger.started = FALSE\n");
432 call_func1(p__TaskEventLogger__LogTaskCompleted
, &logger
);
433 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
434 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
435 ok(logger
.started
, "logger.started = FALSE\n");
437 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted
, &logger
);
438 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
439 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
440 ok(logger
.started
, "logger.started = FALSE\n");
442 call_func1(p__TaskEventLogger__LogWorkItemCompleted
, &logger
);
443 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
444 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
445 ok(logger
.started
, "logger.started = FALSE\n");
447 call_func1(p__TaskEventLogger__LogWorkItemStarted
, &logger
);
448 ok(logger
.task
== (void*)0xdeadbeef, "logger.task = %p\n", logger
.task
);
449 ok(logger
.scheduled
, "logger.scheduled = FALSE\n");
450 ok(logger
.started
, "logger.started = FALSE\n");
453 static void __cdecl
chore_callback(void *arg
)
459 static void test_chore(void)
461 HANDLE event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
462 _Threadpool_chore chore
, old_chore
;
466 memset(&chore
, 0, sizeof(chore
));
467 ret
= p__Schedule_chore(&chore
);
468 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
469 ok(chore
.work
!= NULL
, "chore.work == NULL\n");
470 ok(!chore
.callback
, "chore.callback != NULL\n");
471 p__Release_chore(&chore
);
474 chore
.callback
= chore_callback
;
476 ret
= p__Schedule_chore(&chore
);
477 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
478 ok(chore
.work
!= NULL
, "chore.work == NULL\n");
479 ok(chore
.callback
== chore_callback
, "chore.callback = %p, expected %p\n", chore
.callback
, chore_callback
);
480 ok(chore
.arg
== event
, "chore.arg = %p, expected %p\n", chore
.arg
, event
);
481 wait
= WaitForSingleObject(event
, 500);
482 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
485 ret
= p__Schedule_chore(&chore
);
486 ok(!ret
, "_Schedule_chore returned %d\n", ret
);
487 ok(old_chore
.work
!= chore
.work
, "new threadpool work was not created\n");
488 p__Release_chore(&old_chore
);
489 wait
= WaitForSingleObject(event
, 500);
490 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
492 ret
= p__Reschedule_chore(&chore
);
493 ok(!ret
, "_Reschedule_chore returned %d\n", ret
);
494 wait
= WaitForSingleObject(event
, 500);
495 ok(wait
== WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait
);
497 p__Release_chore(&chore
);
498 ok(!chore
.work
, "chore.work != NULL\n");
499 ok(chore
.callback
== chore_callback
, "chore.callback = %p, expected %p\n", chore
.callback
, chore_callback
);
500 ok(chore
.arg
== event
, "chore.arg = %p, expected %p\n", chore
.arg
, event
);
501 p__Release_chore(&chore
);
504 static void test_to_byte(void)
506 static const WCHAR test_1
[] = {'T', 'E', 'S', 'T', 0};
507 static const WCHAR test_2
[] = {0x9580, 0x9581, 0x9582, 0x9583, 0}; /* some CJK characters */
508 static const WCHAR
*tests
[] = {test_1
, test_2
};
510 char dst
[MAX_PATH
+ 4] = "ABC\0XXXXXXX";
511 char compare
[MAX_PATH
+ 4] = "ABC\0XXXXXXX";
514 WCHAR longstr
[MAX_PATH
+ 3];
516 ret
= p_To_byte(NULL
, NULL
);
517 ok(!ret
, "Got unexpected result %d\n", ret
);
518 ret
= p_To_byte(tests
[0], NULL
);
519 ok(!ret
, "Got unexpected result %d\n", ret
);
520 ret
= p_To_byte(NULL
, dst
);
521 ok(!ret
, "Got unexpected result %d\n", ret
);
523 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Destination was modified: %s\n", dst
);
525 for (i
= 0; i
< sizeof(tests
) / sizeof(*tests
); ++i
)
527 ret
= p_To_byte(tests
[i
], dst
);
528 expected
= WideCharToMultiByte(CP_ACP
, 0, tests
[i
], -1, compare
, sizeof(compare
) / sizeof(*compare
),
530 ok(ret
== expected
, "Got unexpected result %d, expected %d, test case %u\n", ret
, expected
, i
);
531 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, test case %u\n", dst
, i
);
534 /* Output length is limited to MAX_PATH.*/
535 for (i
= MAX_PATH
- 2; i
< MAX_PATH
+ 2; ++i
)
537 for (j
= 0; j
< i
; j
++)
540 memset(dst
, 0xff, sizeof(dst
));
541 memset(compare
, 0xff, sizeof(compare
));
543 ret
= p_To_byte(longstr
, dst
);
544 expected
= WideCharToMultiByte(CP_ACP
, 0, longstr
, -1, compare
, MAX_PATH
, NULL
, NULL
);
545 ok(ret
== expected
, "Got unexpected result %d, expected %d, length %u\n", ret
, expected
, i
);
546 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, length %u\n", dst
, i
);
550 static void test_to_wide(void)
552 /* öäü߀Ÿ.A.B in cp1252, the two . are an undefined value and delete.
553 * With a different system codepage it will produce different results, so do not hardcode the
554 * expected output but convert it with MultiByteToWideChar. */
555 static const char special_input
[] = {0xf6, 0xe4, 0xfc, 0xdf, 0x80, 0x9f, 0x81, 0x41, 0x7f, 0x42, 0};
556 static const char *tests
[] = {"Testtest", special_input
};
557 WCHAR dst
[MAX_PATH
+ 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
558 WCHAR compare
[MAX_PATH
+ 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
561 char longstr
[MAX_PATH
+ 3];
563 ret
= p_To_wide(NULL
, NULL
);
564 ok(!ret
, "Got unexpected result %d\n", ret
);
565 ret
= p_To_wide(tests
[0], NULL
);
566 ok(!ret
, "Got unexpected result %d\n", ret
);
567 ret
= p_To_wide(NULL
, dst
);
568 ok(!ret
, "Got unexpected result %d\n", ret
);
569 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Destination was modified: %s\n", wine_dbgstr_w(dst
));
571 for (i
= 0; i
< sizeof(tests
) / sizeof(*tests
); ++i
)
573 ret
= p_To_wide(tests
[i
], dst
);
574 expected
= MultiByteToWideChar(CP_ACP
, 0, tests
[i
], -1, compare
, sizeof(compare
) / sizeof(*compare
));
575 ok(ret
== expected
, "Got unexpected result %d, expected %d, test case %u\n", ret
, expected
, i
);
576 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, test case %u\n",
577 wine_dbgstr_w(dst
), i
);
580 /* Output length is limited to MAX_PATH.*/
581 for (i
= MAX_PATH
- 2; i
< MAX_PATH
+ 2; ++i
)
583 memset(longstr
, 'A', sizeof(longstr
));
585 memset(dst
, 0xff, sizeof(dst
));
586 memset(compare
, 0xff, sizeof(compare
));
588 ret
= p_To_wide(longstr
, dst
);
589 expected
= MultiByteToWideChar(CP_ACP
, 0, longstr
, -1, compare
, MAX_PATH
);
590 ok(ret
== expected
, "Got unexpected result %d, expected %d, length %u\n", ret
, expected
, i
);
591 ok(!memcmp(dst
, compare
, sizeof(compare
)), "Got unexpected output %s, length %u\n",
592 wine_dbgstr_w(dst
), i
);
596 static void test_File_size(void)
600 LARGE_INTEGER file_size
;
601 WCHAR test_f1_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
602 WCHAR test_f2_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
603 WCHAR test_dir_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
604 WCHAR test_ne_W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
605 WCHAR temp_path
[MAX_PATH
], origin_path
[MAX_PATH
];
607 memset(origin_path
, 0, sizeof(origin_path
));
608 memset(origin_path
, 0, sizeof(temp_path
));
609 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
610 GetTempPathW(MAX_PATH
, temp_path
);
611 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
613 CreateDirectoryW(test_dir_W
, NULL
);
615 file
= CreateFileW(test_f1_W
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
616 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
617 file_size
.QuadPart
= 7;
618 ok(SetFilePointerEx(file
, file_size
, NULL
, FILE_BEGIN
), "SetFilePointerEx failed\n");
619 ok(SetEndOfFile(file
), "SetEndOfFile failed\n");
621 val
= p_File_size(test_f1_W
);
622 ok(val
== 7, "file_size is %s\n", wine_dbgstr_longlong(val
));
624 file
= CreateFileW(test_f2_W
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
625 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
627 val
= p_File_size(test_f2_W
);
628 ok(val
== 0, "file_size is %s\n", wine_dbgstr_longlong(val
));
630 val
= p_File_size(test_dir_W
);
631 ok(val
== 0, "file_size is %s\n", wine_dbgstr_longlong(val
));
634 val
= p_File_size(test_ne_W
);
635 ok(val
== ~(ULONGLONG
)0, "file_size is %s\n", wine_dbgstr_longlong(val
));
636 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
639 val
= p_File_size(NULL
);
640 ok(val
== ~(ULONGLONG
)0, "file_size is %s\n", wine_dbgstr_longlong(val
));
641 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
643 ok(DeleteFileW(test_f1_W
), "expect wine_test_dir/f1 to exist\n");
644 ok(DeleteFileW(test_f2_W
), "expect wine_test_dir/f2 to exist\n");
645 ok(RemoveDirectoryW(test_dir_W
), "expect wine_test_dir to exist\n");
646 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
649 static void test_Current_get(void)
651 WCHAR temp_path
[MAX_PATH
], current_path
[MAX_PATH
], origin_path
[MAX_PATH
];
653 memset(origin_path
, 0, sizeof(origin_path
));
654 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
655 memset(temp_path
, 0, sizeof(temp_path
));
656 GetTempPathW(MAX_PATH
, temp_path
);
658 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
659 memset(current_path
, 0, sizeof(current_path
));
660 ret
= p_Current_get(current_path
);
661 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
662 current_path
[wcslen(current_path
)] = '\\';
663 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
664 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
666 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
667 memset(current_path
, 0, sizeof(current_path
));
668 ret
= p_Current_get(current_path
);
669 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
670 ok(!wcscmp(origin_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
671 wine_dbgstr_w(origin_path
), wine_dbgstr_w(current_path
));
674 static void test_Current_set(void)
676 WCHAR temp_path
[MAX_PATH
], current_path
[MAX_PATH
], origin_path
[MAX_PATH
];
678 WCHAR testW
[] = {'.','/',0};
679 WCHAR not_exit_dirW
[] = {'n', 'o', 't', '_', 'e', 'x', 'i', 's', 't', '_', 'd', 'i', 'r', 0};
680 WCHAR invalid_nameW
[] = {'?', '?', 'i', 'n', 'v', 'a', 'l', 'i', 'd', '_', 'n', 'a', 'm', 'e', '>', '>', 0};
681 memset(temp_path
, 0, sizeof(temp_path
));
682 GetTempPathW(MAX_PATH
, temp_path
);
683 memset(origin_path
, 0, sizeof(origin_path
));
684 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
686 ok(p_Current_set(temp_path
), "p_Current_set to temp_path failed\n");
687 memset(current_path
, 0, sizeof(current_path
));
688 ret
= p_Current_get(current_path
);
689 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
690 current_path
[wcslen(current_path
)] = '\\';
691 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
692 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
694 ok(p_Current_set(testW
), "p_Current_set to temp_path failed\n");
695 memset(current_path
, 0, sizeof(current_path
));
696 ret
= p_Current_get(current_path
);
697 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
698 current_path
[wcslen(current_path
)] = '\\';
699 ok(!wcscmp(temp_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
700 wine_dbgstr_w(temp_path
), wine_dbgstr_w(current_path
));
703 ok(!p_Current_set(not_exit_dirW
), "p_Current_set to not_exist_dir succeed\n");
704 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
707 ok(!p_Current_set(invalid_nameW
), "p_Current_set to ??invalid_name>> succeed\n");
708 ok(errno
== 0xdeadbeef, "errno = %d\n", errno
);
710 ok(p_Current_set(origin_path
), "p_Current_set to origin_path failed\n");
711 memset(current_path
, 0, sizeof(current_path
));
712 ret
= p_Current_get(current_path
);
713 ok(ret
== TRUE
, "p_Current_get returned %u\n", ret
);
714 ok(!wcscmp(origin_path
, current_path
), "p_Current_get(): expect: %s, got %s\n",
715 wine_dbgstr_w(origin_path
), wine_dbgstr_w(current_path
));
718 static void test_Stat(void)
723 WCHAR test_dirW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
724 WCHAR test_f1W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
725 WCHAR test_f2W
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
726 WCHAR pipeW
[] = {'\\','\\','.','\\','P','i','P','e','\\','t','e','s','t','s','_','p','i','p','e','.','c', 0};
727 WCHAR test_neW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
728 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};
729 WCHAR test_f1_linkW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','f','1','_','l','i','n','k',0};
730 WCHAR test_dir_linkW
[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','d','i','r','_','l','i','n','k',0};
731 WCHAR sys_path
[MAX_PATH
], origin_path
[MAX_PATH
], temp_path
[MAX_PATH
];
738 { NULL
, file_not_found
, 0xdeadbeef, FALSE
},
739 { test_dirW
, directory_file
, 0777, FALSE
},
740 { test_f1W
, regular_file
, 0777, FALSE
},
741 { test_f2W
, regular_file
, 0555, FALSE
},
742 { test_neW
, file_not_found
, 0xdeadbeef, FALSE
},
743 { test_invW
, file_not_found
, 0xdeadbeef, FALSE
},
744 { test_f1_linkW
, regular_file
, 0777, TRUE
},
745 { test_dir_linkW
, directory_file
, 0777, TRUE
},
748 memset(origin_path
, 0, sizeof(origin_path
));
749 memset(origin_path
, 0, sizeof(temp_path
));
750 GetCurrentDirectoryW(MAX_PATH
, origin_path
);
751 GetTempPathW(MAX_PATH
, temp_path
);
752 ok(SetCurrentDirectoryW(temp_path
), "SetCurrentDirectoryW to temp_path failed\n");
754 CreateDirectoryW(test_dirW
, NULL
);
756 file
= CreateFileW(test_f1W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
757 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
758 ok(CloseHandle(file
), "CloseHandle\n");
760 file
= CreateFileW(test_f2W
, 0, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
761 ok(file
!= INVALID_HANDLE_VALUE
, "create file failed: INVALID_HANDLE_VALUE\n");
762 ok(CloseHandle(file
), "CloseHandle\n");
763 SetFileAttributesW(test_f2W
, FILE_ATTRIBUTE_READONLY
);
765 SetLastError(0xdeadbeef);
766 ret
= pCreateSymbolicLinkW
&& pCreateSymbolicLinkW(test_f1_linkW
, test_f1W
, 0);
767 if(!ret
&& (!pCreateSymbolicLinkW
|| GetLastError()==ERROR_PRIVILEGE_NOT_HELD
||GetLastError()==ERROR_INVALID_FUNCTION
)) {
768 tests
[6].ret
= tests
[7].ret
= file_not_found
;
769 tests
[6].perms
= tests
[7].perms
= 0xdeadbeef;
770 win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n");
772 ok(ret
, "CreateSymbolicLinkW failed\n");
773 ok(pCreateSymbolicLinkW(test_dir_linkW
, test_dirW
, 1), "CreateSymbolicLinkW failed\n");
776 file
= CreateNamedPipeW(pipeW
,
777 PIPE_ACCESS_DUPLEX
, PIPE_TYPE_BYTE
| PIPE_WAIT
, 2, 1024, 1024,
778 NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
779 ok(file
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed\n");
781 val
= p_Stat(pipeW
, &perms
);
782 todo_wine
ok(regular_file
== val
, "_Stat(): expect: regular, got %d\n", val
);
783 todo_wine
ok(0777 == perms
, "_Stat(): perms expect: 0777, got 0%o\n", perms
);
785 val
= p_Lstat(pipeW
, &perms
);
786 ok(status_unknown
== val
, "_Lstat(): expect: unknown, got %d\n", val
);
787 ok(0xdeadbeef == perms
, "_Lstat(): perms expect: 0xdeadbeef, got %x\n", perms
);
788 ok(CloseHandle(file
), "CloseHandle\n");
789 file
= CreateNamedPipeW(pipeW
,
790 PIPE_ACCESS_DUPLEX
, PIPE_TYPE_BYTE
| PIPE_WAIT
, 2, 1024, 1024,
791 NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
792 ok(file
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed\n");
794 val
= p_Lstat(pipeW
, &perms
);
795 todo_wine
ok(regular_file
== val
, "_Lstat(): expect: regular, got %d\n", val
);
796 todo_wine
ok(0777 == perms
, "_Lstat(): perms expect: 0777, got 0%o\n", perms
);
797 ok(CloseHandle(file
), "CloseHandle\n");
799 for(i
=0; i
<sizeof(tests
)/sizeof(tests
[0]); i
++) {
801 val
= p_Stat(tests
[i
].path
, &perms
);
802 todo_wine_if(tests
[i
].is_todo
) {
803 ok(tests
[i
].ret
== val
, "_Stat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
804 ok(tests
[i
].perms
== perms
, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
805 i
+1, tests
[i
].perms
, perms
);
807 val
= p_Stat(tests
[i
].path
, NULL
);
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
);
813 val
= p_Lstat(tests
[i
].path
, &perms
);
814 todo_wine_if(tests
[i
].is_todo
) {
815 ok(tests
[i
].ret
== val
, "_Lstat(): test %d expect: %d, got %d\n", i
+1, tests
[i
].ret
, val
);
816 ok(tests
[i
].perms
== perms
, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
817 i
+1, tests
[i
].perms
, perms
);
819 val
= p_Lstat(tests
[i
].path
, NULL
);
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
);
824 GetSystemDirectoryW(sys_path
, MAX_PATH
);
826 val
= p_Stat(sys_path
, &perms
);
827 ok(directory_file
== val
, "_Stat(): expect: regular, got %d\n", val
);
828 ok(0777 == perms
, "_Stat(): perms expect: 0777, got 0%o\n", perms
);
831 todo_wine
ok(DeleteFileW(test_f1_linkW
), "expect tr2_test_dir/f1_link to exist\n");
832 todo_wine
ok(RemoveDirectoryW(test_dir_linkW
), "expect tr2_test_dir/dir_link to exist\n");
834 ok(DeleteFileW(test_f1W
), "expect tr2_test_dir/f1 to exist\n");
835 SetFileAttributesW(test_f2W
, FILE_ATTRIBUTE_NORMAL
);
836 ok(DeleteFileW(test_f2W
), "expect tr2_test_dir/f2 to exist\n");
837 ok(RemoveDirectoryW(test_dirW
), "expect tr2_test_dir to exist\n");
839 ok(SetCurrentDirectoryW(origin_path
), "SetCurrentDirectoryW to origin_path failed\n");
846 test_vbtable_size_exports();
847 test_task_continuation_context();
848 test__ContextCallback();
849 test__TaskEventLogger();