diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 1b7588c4a90..13f4d19c1d6 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -260,8 +260,8 @@ @ cdecl -arch=win64 ?_invalid_parameter@@YAXPEBG00I_K@Z(wstr wstr wstr long long) msvcrt._invalid_parameter @ stub -arch=win32 ?_is_exception_typeof@@YAHABVtype_info@@PAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const &,struct _EXCEPTION_POINTERS *) @ stub -arch=win64 ?_is_exception_typeof@@YAHAEBVtype_info@@PEAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const & __ptr64,struct _EXCEPTION_POINTERS * __ptr64) -@ stub -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z # public: char const * __thiscall type_info::_name_internal_method(struct __type_info_node *)const -@ stub -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z # public: char const * __ptr64 __cdecl type_info::_name_internal_method(struct __type_info_node * __ptr64)const __ptr64 +@ thiscall -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z(ptr ptr) msvcr90.?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z +@ cdecl -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z(ptr ptr) msvcr90.?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z @ varargs -arch=win32 ?_open@@YAHPBDHH@Z(str long) msvcrt._open @ varargs -arch=win64 ?_open@@YAHPEBDHH@Z(str long) msvcrt._open @ cdecl -arch=win32 ?_query_new_handler@@YAP6AHI@ZXZ() msvcrt.?_query_new_handler@@YAP6AHI@ZXZ diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 90ec5200153..aca11e7e195 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -83,8 +83,8 @@ @ cdecl -arch=win64 ?_invalid_parameter@@YAXPEBG00I_K@Z(wstr wstr wstr long long) msvcrt._invalid_parameter @ stub -arch=win32 ?_is_exception_typeof@@YAHABVtype_info@@PAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const &,struct _EXCEPTION_POINTERS *) @ stub -arch=win64 ?_is_exception_typeof@@YAHAEBVtype_info@@PEAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const & __ptr64,struct _EXCEPTION_POINTERS * __ptr64) -@ stub -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z # public: char const * __thiscall type_info::_name_internal_method(struct __type_info_node *)const -@ stub -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z # public: char const * __ptr64 __cdecl type_info::_name_internal_method(struct __type_info_node * __ptr64)const __ptr64 +@ thiscall -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z(ptr ptr) msvcr90.?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z +@ cdecl -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z(ptr ptr) msvcr90.?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z @ varargs -arch=win32 ?_open@@YAHPBDHH@Z(str long) msvcrt._open @ varargs -arch=win64 ?_open@@YAHPEBDHH@Z(str long) msvcrt._open @ cdecl -arch=win32 ?_query_new_handler@@YAP6AHI@ZXZ() msvcrt.?_query_new_handler@@YAP6AHI@ZXZ diff --git a/dlls/msvcr90/msvcr90.c b/dlls/msvcr90/msvcr90.c index 34ee20ffb91..2c811cb3381 100644 --- a/dlls/msvcr90/msvcr90.c +++ b/dlls/msvcr90/msvcr90.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" #include #include "stdlib.h" @@ -30,6 +31,46 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcr90); +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define THISCALL(func) __thiscall_ ## func +#define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) +#define __thiscall __stdcall +#define DEFINE_THISCALL_WRAPPER(func,args) \ + extern void THISCALL(func)(void); \ + __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ + "popl %eax\n\t" \ + "pushl %ecx\n\t" \ + "pushl %eax\n\t" \ + "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) ) + +#else /* __i386__ */ + +#define THISCALL(func) func +#define THISCALL_NAME(func) __ASM_NAME(#func) +#define __thiscall __cdecl +#define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */ + +#endif /* __i386__ */ + +struct __type_info_node +{ + void *memPtr; + struct __type_info_node* next; +}; + +typedef struct __type_info +{ + const void *vtable; + char *name; /* Unmangled name, allocated lazily */ + char mangled[32]; /* Variable length, but we declare it large enough for static RTTI */ +} type_info; + +typedef void* (*__cdecl malloc_func_t)(size_t); +typedef void (*__cdecl free_func_t)(void*); + +extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t,unsigned short int); + /********************************************************************* * msvcr90_stat64_to_stat32 [internal] */ @@ -260,3 +301,40 @@ int CDECL _atoflt( _CRT_FLOAT *value, char *str ) { return _atoflt_l( value, str, NULL ); } + +/********************************************************************* + * ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z (MSVCR90.@) + */ +DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_name_internal_method,8) +const char * __thiscall MSVCRT_type_info_name_internal_method(type_info * _this, struct __type_info_node *node) +{ + static int once; + + if (node && !once++) FIXME("type_info_node parameter ignored\n"); + + if (!_this->name) + { + /* Create and set the demangled name */ + /* Nota: mangled name in type_info struct always start with a '.', while + * it isn't valid for mangled name. + * Is this '.' really part of the mangled name, or has it some other meaning ? + */ + char* name = __unDName(0, _this->mangled + 1, 0, malloc, free, 0x2800); + if (name) + { + unsigned int len = strlen(name); + + /* It seems _unDName may leave blanks at the end of the demangled name */ + while (len && name[--len] == ' ') + name[len] = '\0'; + + if (InterlockedCompareExchangePointer((void**)&_this->name, name, NULL)) + { + /* Another thread set this member since we checked above - use it */ + free(name); + } + } + } + TRACE("(%p) returning %s\n", _this, _this->name); + return _this->name; +} diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index c89bfda0faa..b269b87e2bd 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -83,8 +83,8 @@ @ cdecl -arch=win64 ?_invalid_parameter@@YAXPEBG00I_K@Z(wstr wstr wstr long long) msvcrt._invalid_parameter @ stub -arch=win32 ?_is_exception_typeof@@YAHABVtype_info@@PAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const &,struct _EXCEPTION_POINTERS *) @ stub -arch=win64 ?_is_exception_typeof@@YAHAEBVtype_info@@PEAU_EXCEPTION_POINTERS@@@Z # int __cdecl _is_exception_typeof(class type_info const & __ptr64,struct _EXCEPTION_POINTERS * __ptr64) -@ stub -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z # public: char const * __thiscall type_info::_name_internal_method(struct __type_info_node *)const -@ stub -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z # public: char const * __ptr64 __cdecl type_info::_name_internal_method(struct __type_info_node * __ptr64)const __ptr64 +@ thiscall -arch=win32 ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z(ptr ptr) MSVCRT_type_info_name_internal_method +@ cdecl -arch=win64 ?_name_internal_method@type_info@@QEBAPEBDPEAU__type_info_node@@@Z(ptr ptr) MSVCRT_type_info_name_internal_method @ varargs -arch=win32 ?_open@@YAHPBDHH@Z(str long) msvcrt._open @ varargs -arch=win64 ?_open@@YAHPEBDHH@Z(str long) msvcrt._open @ cdecl -arch=win32 ?_query_new_handler@@YAP6AHI@ZXZ() msvcrt.?_query_new_handler@@YAP6AHI@ZXZ diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c index 67b00fcc1af..dc90103797c 100644 --- a/dlls/msvcr90/tests/msvcr90.c +++ b/dlls/msvcr90/tests/msvcr90.c @@ -79,6 +79,17 @@ static void* (__cdecl *p_realloc_crt)(void*, size_t); static void* (__cdecl *p_malloc)(size_t); static void (__cdecl *p_free)(void*); +/* type info */ +typedef struct __type_info +{ + void *vtable; + char *name; + char mangled[16]; +} type_info; + +static char* (WINAPI *p_type_info_name_internal_method)(type_info*); +static void (WINAPI *ptype_info_dtor)(type_info*); + static void* (WINAPI *pEncodePointer)(void *); static int cb_called[4]; @@ -91,6 +102,62 @@ static inline int almost_equal_f(float f1, float f2) /* ########## */ +/* thiscall emulation */ +/* Emulate a __thiscall */ +#ifdef _MSC_VER +static inline void* do_call_func1(void *func, void *_this) +{ + volatile void* retval = 0; + __asm + { + push ecx + mov ecx, _this + call func + mov retval, eax + pop ecx + } + return (void*)retval; +} + +static inline void* do_call_func2(void *func, void *_this, const void* arg) +{ + volatile void* retval = 0; + __asm + { + push ecx + push arg + mov ecx, _this + call func + mov retval, eax + pop ecx + } + return (void*)retval; +} +#else +static void* do_call_func1(void *func, void *_this) +{ + void *ret, *dummy; + __asm__ __volatile__ ("call *%2" + : "=a" (ret), "=c" (dummy) + : "g" (func), "1" (_this) + : "edx", "memory" ); + return ret; +} + +static void* do_call_func2(void *func, void *_this, const void* arg) +{ + void *ret, *dummy; + __asm__ __volatile__ ("pushl %3\n\tcall *%2" + : "=a" (ret), "=c" (dummy) + : "r" (func), "r" (arg), "1" (_this) + : "edx", "memory" ); + return ret; +} +#endif + +#define call_func1(x,y) do_call_func1((void*)x,(void*)y) +#define call_func2(x,y,z) do_call_func2((void*)x,(void*)y,(void*)z) + static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned line, uintptr_t arg) @@ -796,6 +863,43 @@ if (0) p_free(mem); } +#ifdef __i386__ + +struct __type_info_node { + void *memPtr; + struct __type_info_node* next; +}; + +static void test_typeinfo(void) +{ + static type_info t1 = { NULL, NULL,{'.','?','A','V','t','e','s','t','1','@','@',0,0,0,0,0 } }; + struct __type_info_node node; + char *name; + + if (!p_type_info_name_internal_method) + { + win_skip("public: char const * __thiscall type_info::_name_internal_method(struct \ + __type_info_node *)const not supported\n"); + return; + } + + /* name */ + t1.name = NULL; + node.memPtr = NULL; + node.next = NULL; + name = call_func2(p_type_info_name_internal_method, &t1, &node); + ok(name != NULL, "got %p\n", name); + ok(name && t1.name && !strcmp(name, t1.name), "bad name '%s' for t1\n", name); + + ok(t1.name && !strcmp(t1.name, "class test1"), "demangled to '%s' for t1\n", t1.name); + call_func1(ptype_info_dtor, &t1); +} +#else +static void test_typeinfo(void) +{ +} +#endif + START_TEST(msvcr90) { HMODULE hcrt; @@ -834,6 +938,9 @@ START_TEST(msvcr90) p_realloc_crt = (void*) GetProcAddress(hcrt, "_realloc_crt"); p_malloc = (void*) GetProcAddress(hcrt, "malloc"); p_free = (void*)GetProcAddress(hcrt, "free"); + p_type_info_name_internal_method = (void*)GetProcAddress(hcrt, + "?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z"); + ptype_info_dtor = (void*)GetProcAddress(hcrt, "??1type_info@@UAE@XZ"); hkernel32 = GetModuleHandleA("kernel32.dll"); pEncodePointer = (void *) GetProcAddress(hkernel32, "EncodePointer"); @@ -851,4 +958,5 @@ START_TEST(msvcr90) test__sopen_s(); test__wsopen_s(); test__realloc_crt(); + test_typeinfo(); }