/* * Copyright 2014 Yifu Wang for ESRI * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wine/test.h" #include #include #ifdef __i386__ #include "pshpack1.h" struct thiscall_thunk { BYTE pop_eax; /* popl %eax (ret addr) */ BYTE pop_edx; /* popl %edx (func) */ BYTE pop_ecx; /* popl %ecx (this) */ BYTE push_eax; /* pushl %eax */ WORD jmp_edx; /* jmp *%edx */ }; #include "poppack.h" static ULONG_PTR (WINAPI *call_thiscall_func1)( void *func, void *this ); static ULONG_PTR (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a ); static ULONG_PTR (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b ); static void init_thiscall_thunk(void) { struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); thunk->pop_eax = 0x58; /* popl %eax */ thunk->pop_edx = 0x5a; /* popl %edx */ thunk->pop_ecx = 0x59; /* popl %ecx */ thunk->push_eax = 0x50; /* pushl %eax */ thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ call_thiscall_func1 = (void *)thunk; call_thiscall_func2 = (void *)thunk; call_thiscall_func3 = (void *)thunk; } #define call_func1(func,_this) call_thiscall_func1(func,_this) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)(a),(const void*)(b)) #else #define init_thiscall_thunk() #define call_func1(func,_this) func(_this) #define call_func2(func,_this,a) func(_this,a) #define call_func3(func,_this,a,b) func(_this,a,b) #endif /* __i386__ */ #undef __thiscall #ifdef __i386__ #define __thiscall __stdcall #else #define __thiscall __cdecl #endif typedef unsigned char MSVCRT_bool; typedef struct cs_queue { struct cs_queue *next; BOOL free; int unknown; } cs_queue; typedef struct { ULONG_PTR unk_thread_id; cs_queue unk_active; void *unknown[2]; cs_queue *head; void *tail; } critical_section; typedef struct { critical_section *cs; void *unknown[4]; int unknown2[2]; } critical_section_scoped_lock; typedef struct { void *chain; critical_section lock; } _Condition_variable; struct MSVCRT_lconv { char* decimal_point; char* thousands_sep; char* grouping; char* int_curr_symbol; char* currency_symbol; char* mon_decimal_point; char* mon_thousands_sep; char* mon_grouping; char* positive_sign; char* negative_sign; char int_frac_digits; char frac_digits; char p_cs_precedes; char p_sep_by_space; char n_cs_precedes; char n_sep_by_space; char p_sign_posn; char n_sign_posn; wchar_t* _W_decimal_point; wchar_t* _W_thousands_sep; wchar_t* _W_int_curr_symbol; wchar_t* _W_currency_symbol; wchar_t* _W_mon_decimal_point; wchar_t* _W_mon_thousands_sep; wchar_t* _W_positive_sign; wchar_t* _W_negative_sign; }; typedef struct { double r; double i; } _Dcomplex; typedef void (*vtable_ptr)(void); typedef struct { const vtable_ptr *vtable; } Context; typedef struct { Context *ctx; } _Context; typedef struct _StructuredTaskCollection { void *unk1; unsigned int unk2; void *unk3; Context *context; volatile LONG count; volatile LONG finished; void *unk4; void *event; } _StructuredTaskCollection; typedef struct _UnrealizedChore { const vtable_ptr *vtable; void (__cdecl *proc)(struct _UnrealizedChore*); struct _StructuredTaskCollection *task_collection; void (__cdecl *proc_wrapper)(struct _UnrealizedChore*); void *unk[6]; } _UnrealizedChore; static char* (CDECL *p_setlocale)(int category, const char* locale); static struct MSVCRT_lconv* (CDECL *p_localeconv)(void); static size_t (CDECL *p_wcstombs_s)(size_t *ret, char* dest, size_t sz, const wchar_t* src, size_t max); static int (CDECL *p__dsign)(double); static int (CDECL *p__fdsign)(float); static int (__cdecl *p__dpcomp)(double x, double y); static wchar_t** (CDECL *p____lc_locale_name_func)(void); static unsigned int (CDECL *p__GetConcurrency)(void); static void* (CDECL *p__W_Gettnames)(void); static void* (CDECL *p__Gettnames)(void); static void (CDECL *p_free)(void*); static float (CDECL *p_strtof)(const char *, char **); static int (CDECL *p__finite)(double); static float (CDECL *p_wcstof)(const wchar_t*, wchar_t**); static double (CDECL *p_remainder)(double, double); static int* (CDECL *p_errno)(void); static int (CDECL *p_fegetenv)(fenv_t*); static int (CDECL *p_fesetenv)(const fenv_t*); static int (CDECL *p_fegetround)(void); static int (CDECL *p_fesetround)(int); static int (CDECL *p_fegetexceptflag)(fexcept_t*,int); static int (CDECL *p_fesetexceptflag)(const fexcept_t*,int); static int (CDECL *p_fetestexcept)(int); static int (CDECL *p_feclearexcept)(int); static int (CDECL *p_feupdateenv)(fenv_t*); static int (CDECL *p__clearfp)(void); static _locale_t (__cdecl *p_wcreate_locale)(int, const wchar_t *); static void (__cdecl *p_free_locale)(_locale_t); static unsigned short (__cdecl *p_wctype)(const char*); static int (__cdecl *p_vsscanf)(const char*, const char *, va_list valist); static _Dcomplex* (__cdecl *p__Cbuild)(_Dcomplex*, double, double); static double (__cdecl *p_creal)(_Dcomplex); static double (__cdecl *p_nexttoward)(double, double); static float (__cdecl *p_nexttowardf)(float, double); static double (__cdecl *p_nexttowardl)(double, double); static wctrans_t (__cdecl *p_wctrans)(const char*); static wint_t (__cdecl *p_towctrans)(wint_t, wctrans_t); /* make sure we use the correct errno */ #undef errno #define errno (*p_errno()) static critical_section* (__thiscall *p_critical_section_ctor)(critical_section*); static void (__thiscall *p_critical_section_dtor)(critical_section*); static void (__thiscall *p_critical_section_lock)(critical_section*); static void (__thiscall *p_critical_section_unlock)(critical_section*); static critical_section* (__thiscall *p_critical_section_native_handle)(critical_section*); static MSVCRT_bool (__thiscall *p_critical_section_try_lock)(critical_section*); static MSVCRT_bool (__thiscall *p_critical_section_try_lock_for)(critical_section*, unsigned int); static critical_section_scoped_lock* (__thiscall *p_critical_section_scoped_lock_ctor) (critical_section_scoped_lock*, critical_section *); static void (__thiscall *p_critical_section_scoped_lock_dtor)(critical_section_scoped_lock*); static _Condition_variable* (__thiscall *p__Condition_variable_ctor)(_Condition_variable*); static void (__thiscall *p__Condition_variable_dtor)(_Condition_variable*); static void (__thiscall *p__Condition_variable_wait)(_Condition_variable*, critical_section*); static MSVCRT_bool (__thiscall *p__Condition_variable_wait_for)(_Condition_variable*, critical_section*, unsigned int); static void (__thiscall *p__Condition_variable_notify_one)(_Condition_variable*); static void (__thiscall *p__Condition_variable_notify_all)(_Condition_variable*); static Context* (__cdecl *p_Context_CurrentContext)(void); static _Context* (__cdecl *p__Context__CurrentContext)(_Context*); static _StructuredTaskCollection* (__thiscall *p__StructuredTaskCollection_ctor)(_StructuredTaskCollection*, void*); static void (__thiscall *p__StructuredTaskCollection_dtor)(_StructuredTaskCollection*); static void (__thiscall *p__StructuredTaskCollection__Schedule)(_StructuredTaskCollection*, _UnrealizedChore*); static int (__stdcall *p__StructuredTaskCollection__RunAndWait)(_StructuredTaskCollection*, _UnrealizedChore*); #define SETNOFAIL(x,y) x = (void*)GetProcAddress(module,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) static BOOL init(void) { HMODULE module; module = LoadLibraryA("msvcr120.dll"); if (!module) { win_skip("msvcr120.dll not installed\n"); return FALSE; } p_setlocale = (void*)GetProcAddress(module, "setlocale"); p_localeconv = (void*)GetProcAddress(module, "localeconv"); p_wcstombs_s = (void*)GetProcAddress(module, "wcstombs_s"); p__dsign = (void*)GetProcAddress(module, "_dsign"); p__fdsign = (void*)GetProcAddress(module, "_fdsign"); p__dpcomp = (void*)GetProcAddress(module, "_dpcomp"); p____lc_locale_name_func = (void*)GetProcAddress(module, "___lc_locale_name_func"); p__GetConcurrency = (void*)GetProcAddress(module,"?_GetConcurrency@details@Concurrency@@YAIXZ"); p__W_Gettnames = (void*)GetProcAddress(module, "_W_Gettnames"); p__Gettnames = (void*)GetProcAddress(module, "_Gettnames"); p_free = (void*)GetProcAddress(module, "free"); p_strtof = (void*)GetProcAddress(module, "strtof"); p__finite = (void*)GetProcAddress(module, "_finite"); p_wcstof = (void*)GetProcAddress(module, "wcstof"); p_remainder = (void*)GetProcAddress(module, "remainder"); p_errno = (void*)GetProcAddress(module, "_errno"); p_wcreate_locale = (void*)GetProcAddress(module, "_wcreate_locale"); p_free_locale = (void*)GetProcAddress(module, "_free_locale"); SET(p_wctype, "wctype"); SET(p_fegetenv, "fegetenv"); SET(p_fesetenv, "fesetenv"); SET(p_fegetround, "fegetround"); SET(p_fesetround, "fesetround"); SET(p_fegetexceptflag, "fegetexceptflag"); SET(p_fesetexceptflag, "fesetexceptflag"); SET(p_fetestexcept, "fetestexcept"); SET(p_feclearexcept, "feclearexcept"); SET(p_feupdateenv, "feupdateenv"); SET(p__clearfp, "_clearfp"); SET(p_vsscanf, "vsscanf"); SET(p__Cbuild, "_Cbuild"); SET(p_creal, "creal"); SET(p_nexttoward, "nexttoward"); SET(p_nexttowardf, "nexttowardf"); SET(p_nexttowardl, "nexttowardl"); SET(p_wctrans, "wctrans"); SET(p_towctrans, "towctrans"); SET(p__Context__CurrentContext, "?_CurrentContext@_Context@details@Concurrency@@SA?AV123@XZ"); if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(p__StructuredTaskCollection_ctor, "??0_StructuredTaskCollection@details@Concurrency@@QEAA@PEAV_CancellationTokenState@12@@Z"); SET(p__StructuredTaskCollection_dtor, "??1_StructuredTaskCollection@details@Concurrency@@QEAA@XZ"); SET(p__StructuredTaskCollection__Schedule, "?_Schedule@_StructuredTaskCollection@details@Concurrency@@QEAAXPEAV_UnrealizedChore@23@@Z"); SET(p__StructuredTaskCollection__RunAndWait, "?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QEAA?AW4_TaskCollectionStatus@23@PEAV_UnrealizedChore@23@@Z"); SET(p_critical_section_ctor, "??0critical_section@Concurrency@@QEAA@XZ"); SET(p_critical_section_dtor, "??1critical_section@Concurrency@@QEAA@XZ"); SET(p_critical_section_lock, "?lock@critical_section@Concurrency@@QEAAXXZ"); SET(p_critical_section_unlock, "?unlock@critical_section@Concurrency@@QEAAXXZ"); SET(p_critical_section_native_handle, "?native_handle@critical_section@Concurrency@@QEAAAEAV12@XZ"); SET(p_critical_section_try_lock, "?try_lock@critical_section@Concurrency@@QEAA_NXZ"); SET(p_critical_section_try_lock_for, "?try_lock_for@critical_section@Concurrency@@QEAA_NI@Z"); SET(p_critical_section_scoped_lock_ctor, "??0scoped_lock@critical_section@Concurrency@@QEAA@AEAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QEAA@XZ"); SET(p__Condition_variable_ctor, "??0_Condition_variable@details@Concurrency@@QEAA@XZ"); SET(p__Condition_variable_dtor, "??1_Condition_variable@details@Concurrency@@QEAA@XZ"); SET(p__Condition_variable_wait, "?wait@_Condition_variable@details@Concurrency@@QEAAXAEAVcritical_section@3@@Z"); SET(p__Condition_variable_wait_for, "?wait_for@_Condition_variable@details@Concurrency@@QEAA_NAEAVcritical_section@3@I@Z"); SET(p__Condition_variable_notify_one, "?notify_one@_Condition_variable@details@Concurrency@@QEAAXXZ"); SET(p__Condition_variable_notify_all, "?notify_all@_Condition_variable@details@Concurrency@@QEAAXXZ"); SET(p_Context_CurrentContext, "?CurrentContext@Context@Concurrency@@SAPEAV12@XZ"); } else { #ifdef __arm__ SET(p__StructuredTaskCollection_ctor, "??0_StructuredTaskCollection@details@Concurrency@@QAA@PAV_CancellationTokenState@12@@Z"); SET(p__StructuredTaskCollection_dtor, "??1_StructuredTaskCollection@details@Concurrency@@QAA@XZ"); SET(p__StructuredTaskCollection__Schedule, "?_Schedule@_StructuredTaskCollection@details@Concurrency@@QAAXPAV_UnrealizedChore@23@@Z"); SET(p__StructuredTaskCollection__RunAndWait, "?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z"); SET(p_critical_section_ctor, "??0critical_section@Concurrency@@QAA@XZ"); SET(p_critical_section_dtor, "??1critical_section@Concurrency@@QAA@XZ"); SET(p_critical_section_lock, "?lock@critical_section@Concurrency@@QAAXXZ"); SET(p_critical_section_unlock, "?unlock@critical_section@Concurrency@@QAAXXZ"); SET(p_critical_section_native_handle, "?native_handle@critical_section@Concurrency@@QAAAAV12@XZ"); SET(p_critical_section_try_lock, "?try_lock@critical_section@Concurrency@@QAA_NXZ"); SET(p_critical_section_try_lock_for, "?try_lock_for@critical_section@Concurrency@@QAA_NI@Z"); SET(p_critical_section_scoped_lock_ctor, "??0scoped_lock@critical_section@Concurrency@@QAA@AAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QAA@XZ"); SET(p__Condition_variable_ctor, "??0_Condition_variable@details@Concurrency@@QAA@XZ"); SET(p__Condition_variable_dtor, "??1_Condition_variable@details@Concurrency@@QAA@XZ"); SET(p__Condition_variable_wait, "?wait@_Condition_variable@details@Concurrency@@QAAXAAVcritical_section@3@@Z"); SET(p__Condition_variable_wait_for, "?wait_for@_Condition_variable@details@Concurrency@@QAA_NAAVcritical_section@3@I@Z"); SET(p__Condition_variable_notify_one, "?notify_one@_Condition_variable@details@Concurrency@@QAAXXZ"); SET(p__Condition_variable_notify_all, "?notify_all@_Condition_variable@details@Concurrency@@QAAXXZ"); #else SET(p__StructuredTaskCollection_ctor, "??0_StructuredTaskCollection@details@Concurrency@@QAE@PAV_CancellationTokenState@12@@Z"); SET(p__StructuredTaskCollection_dtor, "??1_StructuredTaskCollection@details@Concurrency@@QAE@XZ"); SET(p__StructuredTaskCollection__Schedule, "?_Schedule@_StructuredTaskCollection@details@Concurrency@@QAEXPAV_UnrealizedChore@23@@Z"); SET(p__StructuredTaskCollection__RunAndWait, "?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAG?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z"); SET(p_critical_section_ctor, "??0critical_section@Concurrency@@QAE@XZ"); SET(p_critical_section_dtor, "??1critical_section@Concurrency@@QAE@XZ"); SET(p_critical_section_lock, "?lock@critical_section@Concurrency@@QAEXXZ"); SET(p_critical_section_unlock, "?unlock@critical_section@Concurrency@@QAEXXZ"); SET(p_critical_section_native_handle, "?native_handle@critical_section@Concurrency@@QAEAAV12@XZ"); SET(p_critical_section_try_lock, "?try_lock@critical_section@Concurrency@@QAE_NXZ"); SET(p_critical_section_try_lock_for, "?try_lock_for@critical_section@Concurrency@@QAE_NI@Z"); SET(p_critical_section_scoped_lock_ctor, "??0scoped_lock@critical_section@Concurrency@@QAE@AAV12@@Z"); SET(p_critical_section_scoped_lock_dtor, "??1scoped_lock@critical_section@Concurrency@@QAE@XZ"); SET(p__Condition_variable_ctor, "??0_Condition_variable@details@Concurrency@@QAE@XZ"); SET(p__Condition_variable_dtor, "??1_Condition_variable@details@Concurrency@@QAE@XZ"); SET(p__Condition_variable_wait, "?wait@_Condition_variable@details@Concurrency@@QAEXAAVcritical_section@3@@Z"); SET(p__Condition_variable_wait_for, "?wait_for@_Condition_variable@details@Concurrency@@QAE_NAAVcritical_section@3@I@Z"); SET(p__Condition_variable_notify_one, "?notify_one@_Condition_variable@details@Concurrency@@QAEXXZ"); SET(p__Condition_variable_notify_all, "?notify_all@_Condition_variable@details@Concurrency@@QAEXXZ"); #endif SET(p_Context_CurrentContext, "?CurrentContext@Context@Concurrency@@SAPAV12@XZ"); } init_thiscall_thunk(); return TRUE; } static void test_lconv_helper(const char *locstr) { struct MSVCRT_lconv *lconv; char mbs[256]; size_t i; if(!p_setlocale(LC_ALL, locstr)) { win_skip("locale %s not available\n", locstr); return; } lconv = p_localeconv(); /* If multi-byte version available, asserts that wide char version also available. * If wide char version can be converted to a multi-byte string , asserts that the * conversion result is the same as the multi-byte version. */ if(strlen(lconv->decimal_point) > 0) ok(wcslen(lconv->_W_decimal_point) > 0, "%s: decimal_point\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_decimal_point, 256) == 0) ok(strcmp(mbs, lconv->decimal_point) == 0, "%s: decimal_point\n", locstr); if(strlen(lconv->thousands_sep) > 0) ok(wcslen(lconv->_W_thousands_sep) > 0, "%s: thousands_sep\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_thousands_sep, 256) == 0) ok(strcmp(mbs, lconv->thousands_sep) == 0, "%s: thousands_sep\n", locstr); if(strlen(lconv->int_curr_symbol) > 0) ok(wcslen(lconv->_W_int_curr_symbol) > 0, "%s: int_curr_symbol\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_int_curr_symbol, 256) == 0) ok(strcmp(mbs, lconv->int_curr_symbol) == 0, "%s: int_curr_symbol\n", locstr); if(strlen(lconv->currency_symbol) > 0) ok(wcslen(lconv->_W_currency_symbol) > 0, "%s: currency_symbol\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_currency_symbol, 256) == 0) ok(strcmp(mbs, lconv->currency_symbol) == 0, "%s: currency_symbol\n", locstr); if(strlen(lconv->mon_decimal_point) > 0) ok(wcslen(lconv->_W_mon_decimal_point) > 0, "%s: decimal_point\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_mon_decimal_point, 256) == 0) ok(strcmp(mbs, lconv->mon_decimal_point) == 0, "%s: decimal_point\n", locstr); if(strlen(lconv->positive_sign) > 0) ok(wcslen(lconv->_W_positive_sign) > 0, "%s: positive_sign\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_positive_sign, 256) == 0) ok(strcmp(mbs, lconv->positive_sign) == 0, "%s: positive_sign\n", locstr); if(strlen(lconv->negative_sign) > 0) ok(wcslen(lconv->_W_negative_sign) > 0, "%s: negative_sign\n", locstr); if(p_wcstombs_s(&i, mbs, 256, lconv->_W_negative_sign, 256) == 0) ok(strcmp(mbs, lconv->negative_sign) == 0, "%s: negative_sign\n", locstr); } static void test_lconv(void) { int i; const char *locstrs[] = { "American", "Belgian", "Chinese", "Dutch", "English", "French", "German", "Hungarian", "Icelandic", "Japanese", "Korean", "Spanish" }; for(i = 0; i < ARRAY_SIZE(locstrs); i ++) test_lconv_helper(locstrs[i]); } static void test__dsign(void) { int ret; ret = p__dsign(1); ok(ret == 0, "p_dsign(1) = %x\n", ret); ret = p__dsign(0); ok(ret == 0, "p_dsign(0) = %x\n", ret); ret = p__dsign(-1); ok(ret == 0x8000, "p_dsign(-1) = %x\n", ret); ret = p__fdsign(1); ok(ret == 0, "p_fdsign(1) = %x\n", ret); ret = p__fdsign(0); ok(ret == 0, "p_fdsign(0) = %x\n", ret); ret = p__fdsign(-1); ok(ret == 0x8000, "p_fdsign(-1) = %x\n", ret); } static void test__dpcomp(void) { struct { double x, y; int ret; } tests[] = { {0, 0, 2}, {1, 1, 2}, {-1, -1, 2}, {-2, -1, 1}, {-1, 1, 1}, {1, 2, 1}, {1, -1, 4}, {2, 1, 4}, {-1, -2, 4}, {NAN, NAN, 0}, {NAN, 1, 0}, {1, NAN, 0}, {INFINITY, INFINITY, 2}, {-1, INFINITY, 1}, {1, INFINITY, 1}, }; int i, ret; for(i=0; istr[0]-(char*)ret; if(sizeof(void*) == 8) ok(size==0x2c0, "structure size: %x\n", size); else ok(size==0x164, "structure size: %x\n", size); for(i=0; istr[i], str[i]), "ret->str[%d] = %s, expected %s\n", i, ret->str[i], str[i]); MultiByteToWideChar(CP_ACP, 0, str[i], strlen(str[i])+1, buf, ARRAY_SIZE(buf)); ok(!lstrcmpW(ret->wstr[i], buf), "ret->wstr[%d] = %s, expected %s\n", i, wine_dbgstr_w(ret->wstr[i]), wine_dbgstr_w(buf)); } ok(ret->str[42] + strlen(ret->str[42]) + 1 == (char*)ret->wstr[0] || ret->str[42] + strlen(ret->str[42]) + 2 == (char*)ret->wstr[0], "ret->str[42] = %p len = %Id, ret->wstr[0] = %p\n", ret->str[42], strlen(ret->str[42]), ret->wstr[0]); p_free(ret); p_setlocale(LC_ALL, "C"); } static void test__strtof(void) { const char float1[] = "12.0"; const char float2[] = "3.402823466e+38"; /* FLT_MAX */ const char float3[] = "-3.402823466e+38"; const char float4[] = "1.7976931348623158e+308"; /* DBL_MAX */ BOOL is_arabic; char *end; float f; f = p_strtof(float1, &end); ok(f == 12.0, "f = %lf\n", f); ok(end == float1+4, "incorrect end (%d)\n", (int)(end-float1)); f = p_strtof(float2, &end); ok(f == FLT_MAX, "f = %lf\n", f); ok(end == float2+15, "incorrect end (%d)\n", (int)(end-float2)); f = p_strtof(float3, &end); ok(f == -FLT_MAX, "f = %lf\n", f); ok(end == float3+16, "incorrect end (%d)\n", (int)(end-float3)); f = p_strtof(float4, &end); ok(!p__finite(f), "f = %lf\n", f); ok(end == float4+23, "incorrect end (%d)\n", (int)(end-float4)); f = p_strtof("inf", NULL); ok(f == 0, "f = %lf\n", f); f = p_strtof("INF", NULL); ok(f == 0, "f = %lf\n", f); f = p_strtof("1.#inf", NULL); ok(f == 1, "f = %lf\n", f); f = p_strtof("INFINITY", NULL); ok(f == 0, "f = %lf\n", f); f = p_strtof("0x12", NULL); ok(f == 0, "f = %lf\n", f); f = p_wcstof(L"12.0", NULL); ok(f == 12.0, "f = %lf\n", f); f = p_wcstof(L"\x0662\x0663", NULL); /* 23 in Arabic numerals */ is_arabic = (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ARABIC); todo_wine_if(is_arabic) ok(f == (is_arabic ? 23.0 : 0.0), "f = %lf\n", f); f = p_wcstof(L"\x0662\x34\x0663", NULL); /* Arabic + Roman numerals mix */ todo_wine_if(is_arabic) ok(f == (is_arabic ? 243.0 : 0.0), "f = %lf\n", f); if(!p_setlocale(LC_ALL, "Arabic")) { win_skip("Arabic locale not available\n"); return; } f = p_wcstof(L"12.0", NULL); ok(f == 12.0, "f = %lf\n", f); f = p_wcstof(L"\x0662\x0663", NULL); /* 23 in Arabic numerals */ todo_wine_if(is_arabic) ok(f == (is_arabic ? 23.0 : 0.0), "f = %lf\n", f); p_setlocale(LC_ALL, "C"); } static void test_remainder(void) { struct { double x, y, r; errno_t e; } tests[] = { { 3.0, 2.0, -1.0, -1 }, { 1.0, 1.0, 0.0, -1 }, { INFINITY, 0.0, NAN, EDOM }, { INFINITY, 42.0, NAN, EDOM }, { NAN, 0.0, NAN, EDOM }, { NAN, 42.0, NAN, EDOM }, { 0.0, INFINITY, 0.0, -1 }, { 42.0, INFINITY, 42.0, -1 }, { 0.0, NAN, NAN, EDOM }, { 42.0, NAN, NAN, EDOM }, { 1.0, 0.0, NAN, EDOM }, { INFINITY, INFINITY, NAN, EDOM }, }; errno_t e; double r; int i; if(sizeof(void*) != 8) /* errno handling slightly different on 32-bit */ return; for(i=0; ics); SetEvent(arg->thread_initialized); call_func2(p__Condition_variable_wait, arg->cv, arg->cs); call_func1(p_critical_section_unlock, arg->cs); return 0; } static void test__Condition_variable(void) { critical_section cs; _Condition_variable cv; HANDLE thread_initialized = CreateEventW(NULL, FALSE, FALSE, NULL); struct wait_thread_arg wait_thread_arg = { &cs, &cv, thread_initialized }; HANDLE threads[2]; DWORD ret; MSVCRT_bool b; ok(thread_initialized != NULL, "CreateEvent failed\n"); call_func1(p_critical_section_ctor, &cs); call_func1(p__Condition_variable_ctor, &cv); call_func1(p__Condition_variable_notify_one, &cv); call_func1(p__Condition_variable_notify_all, &cv); threads[0] = CreateThread(0, 0, condition_variable_wait_thread, &wait_thread_arg, 0, 0); ok(threads[0] != NULL, "CreateThread failed\n"); WaitForSingleObject(thread_initialized, INFINITE); call_func1(p_critical_section_lock, &cs); call_func1(p_critical_section_unlock, &cs); threads[1] = CreateThread(0, 0, condition_variable_wait_thread, &wait_thread_arg, 0, 0); ok(threads[1] != NULL, "CreateThread failed\n"); WaitForSingleObject(thread_initialized, INFINITE); call_func1(p_critical_section_lock, &cs); call_func1(p_critical_section_unlock, &cs); call_func1(p__Condition_variable_notify_one, &cv); ret = WaitForSingleObject(threads[1], 500); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret); call_func1(p__Condition_variable_notify_one, &cv); ret = WaitForSingleObject(threads[0], 500); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret); CloseHandle(threads[0]); CloseHandle(threads[1]); call_func1(p_critical_section_lock, &cs); b = call_func3(p__Condition_variable_wait_for, &cv, &cs, 1); ok(!b, "_Condition_variable_wait_for returned TRUE\n"); call_func1(p_critical_section_unlock, &cs); call_func1(p_critical_section_dtor, &cs); call_func1(p__Condition_variable_dtor, &cv); CloseHandle(thread_initialized); } static void test_wctype(void) { static const struct { const char *name; unsigned short mask; } properties[] = { { "alnum", 0x107 }, { "alpha", 0x103 }, { "cntrl", 0x020 }, { "digit", 0x004 }, { "graph", 0x117 }, { "lower", 0x002 }, { "print", 0x157 }, { "punct", 0x010 }, { "space", 0x008 }, { "upper", 0x001 }, { "xdigit", 0x080 }, { "ALNUM", 0x000 }, { "Alnum", 0x000 }, { "", 0x000 } }; int i, ret; for(i=0; iproc = proc; } struct chore { _UnrealizedChore chore; BOOL executed; HANDLE start_event; HANDLE set_event; HANDLE wait_event; DWORD main_tid; }; static void __cdecl chore_proc(_UnrealizedChore *_this) { struct chore *chore = CONTAINING_RECORD(_this, struct chore, chore); if (chore->start_event) { DWORD ret = WaitForSingleObject(chore->start_event, 5000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret); } ok(!chore->executed, "Chore was already executed\n"); if (chore->main_tid) { ok(GetCurrentThreadId() == chore->main_tid, "Main chore is not running on the main thread: 0x%lx != 0x%lx\n", GetCurrentThreadId(), chore->main_tid); } if (!chore->wait_event) chore->executed = TRUE; if (chore->set_event) { BOOL b = SetEvent(chore->set_event); ok(b, "SetEvent failed\n"); } if (chore->wait_event) { DWORD ret = WaitForSingleObject(chore->wait_event, 5000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret); chore->executed = TRUE; } } static void chore_ctor(struct chore *chore) { memset(chore, 0, sizeof(*chore)); _UnrealizedChore_ctor(&chore->chore, chore_proc); } static void test_StructuredTaskCollection(void) { HANDLE chore_start_evt, chore_evt1, chore_evt2; _StructuredTaskCollection task_coll; struct chore chore1, chore2; DWORD main_thread_id; Context *context; int status; DWORD ret; BOOL b; main_thread_id = GetCurrentThreadId(); context = p_Context_CurrentContext(); memset(&task_coll, 0x55, sizeof(task_coll)); if (!call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL)) { skip("_StructuredTaskCollection constructor not implemented\n"); return; } ok(task_coll.unk2 == 0x1fffffff, "_StructuredTaskCollection ctor set wrong unk2: 0x%x != 0x1fffffff\n", task_coll.unk2); ok(task_coll.unk3 == NULL, "_StructuredTaskCollection ctor set wrong unk3: %p != NULL\n", task_coll.unk3); ok(task_coll.context == NULL, "_StructuredTaskCollection ctor set wrong context: %p != NULL\n", task_coll.context); ok(task_coll.count == 0, "_StructuredTaskCollection ctor set wrong count: %ld != 0\n", task_coll.count); ok(task_coll.finished == LONG_MIN, "_StructuredTaskCollection ctor set wrong finished: %ld != %ld\n", task_coll.finished, LONG_MIN); ok(task_coll.unk4 == NULL, "_StructuredTaskCollection ctor set wrong unk4: %p != NULL\n", task_coll.unk4); chore_start_evt = CreateEventW(NULL, TRUE, FALSE, NULL); ok(chore_start_evt != NULL, "CreateEvent failed: 0x%lx\n", GetLastError()); chore_evt1 = CreateEventW(NULL, FALSE, FALSE, NULL); ok(chore_evt1 != NULL, "CreateEvent failed: 0x%lx\n", GetLastError()); chore_evt2 = CreateEventW(NULL, FALSE, FALSE, NULL); ok(chore_evt2 != NULL, "CreateEvent failed: 0x%lx\n", GetLastError()); /* test running chores (only main) */ chore_ctor(&chore1); chore1.main_tid = main_thread_id; status = p__StructuredTaskCollection__RunAndWait(&task_coll, &chore1.chore); ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status); ok(chore1.executed, "Scheduled chore was not executed\n"); call_func1(p__StructuredTaskCollection_dtor, &task_coll); /* test running chores (main + scheduled) */ call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL); ResetEvent(chore_start_evt); chore_ctor(&chore1); chore1.start_event = chore_start_evt; chore_ctor(&chore2); chore2.main_tid = main_thread_id; call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore); ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n", &task_coll, chore1.chore.task_collection); ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n"); ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count); ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context); b = SetEvent(chore_start_evt); ok(b, "SetEvent failed\n"); status = p__StructuredTaskCollection__RunAndWait(&task_coll, &chore2.chore); ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status); ok(chore1.executed, "Scheduled chore was not executed\n"); ok(chore2.executed, "Main chore was not executed\n"); call_func1(p__StructuredTaskCollection_dtor, &task_coll); /* test that scheduled chores may run in parallel */ call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL); ResetEvent(chore_start_evt); chore_ctor(&chore1); chore1.start_event = chore_start_evt; chore1.set_event = chore_evt2; chore1.wait_event = chore_evt1; chore_ctor(&chore2); chore2.start_event = chore_start_evt; chore2.set_event = chore_evt1; chore2.wait_event = chore_evt2; call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore); ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n", &task_coll, chore1.chore.task_collection); ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n"); ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count); ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context); call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore2.chore); ok(chore2.chore.task_collection == &task_coll, "Wrong chore #2 task_collection: expected %p, actual %p\n", &task_coll, chore2.chore.task_collection); ok(chore2.chore.proc_wrapper != NULL, "Chore #2 proc_wrapper was not set\n"); ok(task_coll.count == 2, "Wrong chore count: %ld != 2\n", task_coll.count); ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context); b = SetEvent(chore_start_evt); ok(b, "SetEvent failed\n"); status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL); ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status); ok(chore1.executed, "Chore #1 was not executed\n"); ok(chore2.executed, "Chore #2 was not executed\n"); call_func1(p__StructuredTaskCollection_dtor, &task_coll); /* test that scheduled chores are executed even if _RunAndWait is not called */ call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL); ResetEvent(chore_start_evt); chore_ctor(&chore1); chore1.start_event = chore_start_evt; chore1.set_event = chore_evt1; call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore); ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n", &task_coll, chore1.chore.task_collection); ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n"); ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count); ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context); b = SetEvent(chore_start_evt); ok(b, "SetEvent failed\n"); ret = WaitForSingleObject(chore_evt1, 5000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", ret); ok(chore1.executed, "Chore was not executed\n"); status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL); ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status); ok(chore1.chore.task_collection == NULL, "Chore's task collection was not reset after execution\n"); call_func1(p__StructuredTaskCollection_dtor, &task_coll); /* test that finished chores can be scheduled again */ call_func2(p__StructuredTaskCollection_ctor, &task_coll, NULL); ResetEvent(chore_start_evt); chore1.set_event = NULL; chore1.executed = FALSE; call_func2(p__StructuredTaskCollection__Schedule, &task_coll, &chore1.chore); ok(chore1.chore.task_collection == &task_coll, "Wrong chore #1 task_collection: expected %p, actual %p\n", &task_coll, chore1.chore.task_collection); ok(chore1.chore.proc_wrapper != NULL, "Chore #1 proc_wrapper was not set\n"); ok(task_coll.count == 1, "Wrong chore count: %ld != 1\n", task_coll.count); ok(task_coll.context == context, "Unexpected context: %p != %p\n", task_coll.context, context); b = SetEvent(chore_start_evt); ok(b, "SetEvent failed\n"); status = p__StructuredTaskCollection__RunAndWait(&task_coll, NULL); ok(status == 1, "_StructuredTaskCollection::_RunAndWait failed: %d\n", status); ok(chore1.executed, "Chore was not executed\n"); call_func1(p__StructuredTaskCollection_dtor, &task_coll); CloseHandle(chore_start_evt); CloseHandle(chore_evt1); CloseHandle(chore_evt2); } START_TEST(msvcr120) { if (!init()) return; test_lconv(); test__dsign(); test__dpcomp(); test____lc_locale_name_func(); test__GetConcurrency(); test_gettnames(p__W_Gettnames); test_gettnames(p__Gettnames); test__strtof(); test_remainder(); test_critical_section(); test_feenv(); test__wcreate_locale(); test__Condition_variable(); test_wctype(); test_vsscanf(); test__Cbuild(); test_nexttoward(); test_towctrans(); test_CurrentContext(); test_StructuredTaskCollection(); }