I have dug up an old patch by Jon Griffiths. I updated it, cleaned it up and integrated it with current the MSVCRT code. So here it is (it should make it to CVS this time :-). Changelog: Jon Griffiths <jon_p_griffiths@yahoo.com> François Gouget <fgouget@codeweavers.com> * dlls/msvcrt/cpp.c, dlls/msvcrt/except.c, dlls/msvcrt/heap.c, dlls/msvcrt/main.c, dlls/msvcrt/msvcrt.spec Add RTTI support Fix what_exception prototype Fix new_handler_func prototype Add set_new_handler, _callnewh, _heapadd Add stubs for __unDName and __unDNameEx Added a semi-stub for __CxxFrameHandler -- François Gouget fgouget@codeweavers.com
Index: dlls/msvcrt/cpp.c =================================================================== RCS file: /home/wine/wine/dlls/msvcrt/cpp.c,v retrieving revision 1.8 diff -u -r1.8 cpp.c --- dlls/msvcrt/cpp.c 2001/07/23 23:50:18 1.8 +++ dlls/msvcrt/cpp.c 2001/12/20 05:48:23 @@ -48,6 +48,36 @@ char name[1]; } type_info; +typedef struct _rtti_base_descriptor +{ + type_info *type_descriptor; + int num_base_classes; + int base_class_offset; + unsigned int flags; +} rtti_base_descriptor; + +typedef struct _rtti_base_array +{ + rtti_base_descriptor *bases[1]; /* First element is the class itself */ +} rtti_base_array; + +typedef struct _rtti_object_hierachy +{ + int unknown1; + int unknown2; + int array_len; /* Size of the array pointed to by 'base_classes' */ + rtti_base_array *base_classes; +} rtti_object_hierachy; + +typedef struct _rtti_object_locator +{ + int unknown1; + int base_class_offset; + unsigned int flags; + type_info *type_descriptor; + rtti_object_hierachy *type_hierachy; +} rtti_object_locator; + /****************************************************************** * ??0exception@@QAE@ABQBD@Z (MSVCRT.@) */ @@ -124,7 +154,7 @@ /****************************************************************** * ?what@exception@@UBEPBDXZ (MSVCRT.@) */ -const char * __stdcall MSVCRT_exception_what(exception * _this) +const char * MSVCRT_what_exception(exception * _this) { TRACE("(%p) returning %s\n",_this,_this->name); return _this->name; @@ -358,13 +388,109 @@ } +/****************************************************************** + * __RTtypeid (MSVCRT.@) + */ +type_info* MSVCRT___RTtypeid(type_info *cppobj) +{ + /* Note: cppobj _isn't_ a type_info, we use that struct for its vtable ptr */ + TRACE("(%p)\n",cppobj); + + if (!IsBadReadPtr(cppobj, sizeof(void *)) && + !IsBadReadPtr(cppobj->vtable - 1,sizeof(void *)) && + !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator))) + { + rtti_object_locator *obj_locator = (rtti_object_locator *)cppobj->vtable[-1]; + return obj_locator->type_descriptor; + } + /* FIXME: throw a C++ exception */ + FIXME("Should throw(bad_typeid). Creating NULL reference, expect crash!\n"); + return NULL; +} + +/****************************************************************** + * __RTDynamicCast (MSVCRT.@) + */ +void* MSVCRT___RTDynamicCast(type_info *cppobj, int unknown, + type_info *src, type_info *dst, + int do_throw) +{ + /* Note: cppobj _isn't_ a type_info, we use that struct for its vtable ptr */ + TRACE("(%p,%d,%p,%p,%d)\n",cppobj, unknown, src, dst, do_throw); + + if (unknown) + FIXME("Unknown prameter is non-zero: please report\n"); + + /* To cast an object at runtime: + * 1.Find out the true type of the object from the typeinfo at vtable[-1] + * 2.Search for the destination type in the class heirachy + * 3.If destination type is found, return base object address + dest offset + * Otherwise, fail the cast + */ + if (!IsBadReadPtr(cppobj, sizeof(void *)) && + !IsBadReadPtr(cppobj->vtable - 1,sizeof(void *)) && + !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator))) + { + int count = 0; + rtti_object_locator *obj_locator = (rtti_object_locator *)cppobj->vtable[-1]; + rtti_object_hierachy *obj_bases = obj_locator->type_hierachy; + rtti_base_descriptor **base_desc = obj_bases->base_classes->bases; + int src_offset = obj_locator->base_class_offset, dst_offset = -1; + + while (count < obj_bases->array_len) + { + type_info *typ = (*base_desc)->type_descriptor; + + if (!strcmp(typ->name, dst->name)) + { + dst_offset = (*base_desc)->base_class_offset; + break; + } + base_desc++; + count++; + } + if (dst_offset >= 0) + return (void*)((unsigned long)cppobj - src_offset + dst_offset); + } + + /* VC++ sets do_throw to 1 when the result of a dynamic_cast is assigned + * to a reference, since references cannot be NULL. + */ + if (do_throw) + FIXME("Should throw(bad_cast). Creating NULL reference, expect crash!\n"); + return NULL; +} + + +/****************************************************************** + * __RTCastToVoid (MSVCRT.@) + */ +void* MSVCRT___RTCastToVoid(type_info *cppobj) +{ + /* Note: cppobj _isn't_ a type_info, we use that struct for its vtable ptr */ + TRACE("(%p)\n",cppobj); + + /* Casts to void* simply cast to the base object */ + if (!IsBadReadPtr(cppobj, sizeof(void *)) && + !IsBadReadPtr(cppobj->vtable - 1,sizeof(void *)) && + !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator))) + { + rtti_object_locator *obj_locator = (rtti_object_locator *)cppobj->vtable[-1]; + int src_offset = obj_locator->base_class_offset; + + return (void*)((unsigned long)cppobj - src_offset); + } + return NULL; +} + + /* INTERNAL: Set up vtables * FIXME:should be static, cope with versions? */ void msvcrt_init_vtables(void) { exception_vtable[0] = MSVCRT_exception_dtor; - exception_vtable[1] = (void*)MSVCRT_exception_what; + exception_vtable[1] = (void*)MSVCRT_what_exception; bad_typeid_vtable[0] = MSVCRT_bad_typeid_dtor; bad_typeid_vtable[1] = exception_vtable[1]; Index: dlls/msvcrt/except.c =================================================================== RCS file: /home/wine/wine/dlls/msvcrt/except.c,v retrieving revision 1.7 diff -u -r1.7 except.c --- dlls/msvcrt/except.c 2001/09/20 19:33:37 1.7 +++ dlls/msvcrt/except.c 2001/12/20 05:48:23 @@ -261,4 +352,21 @@ { FIXME("(%d %p):stub\n", sig, func); return (void*)-1; +} + +/********************************************************************* + * __CxxFrameHandler (MSVCRT.@) + */ +DWORD __CxxFrameHandler(PEXCEPTION_RECORD rec, struct __EXCEPTION_FRAME* frame, + PCONTEXT context, struct __EXCEPTION_FRAME** dispatch) +{ + FIXME("(%p,%p,%p,%p):stub?\n",rec,frame,context,dispatch); + + /* Copied from MSVCRT_nested_handler, I hope this is more + * or less the right thing to do + */ + if (rec->ExceptionFlags & 0x6) + return ExceptionContinueSearch; + *dispatch = frame; + return ExceptionCollidedUnwind; } Index: dlls/msvcrt/heap.c =================================================================== RCS file: /home/wine/wine/dlls/msvcrt/heap.c,v retrieving revision 1.6 diff -u -r1.6 heap.c --- dlls/msvcrt/heap.c 2001/07/02 19:59:41 1.6 +++ dlls/msvcrt/heap.c 2001/12/20 05:48:23 @@ -8,6 +8,7 @@ */ #include "msvcrt.h" +#include "ms_errno.h" #include "msvcrt/malloc.h" @@ -19,7 +20,7 @@ #define LOCK_HEAP EnterCriticalSection(&MSVCRT_heap_cs) #define UNLOCK_HEAP LeaveCriticalSection(&MSVCRT_heap_cs) -typedef void (*MSVCRT_new_handler_func)(void); +typedef void (*MSVCRT_new_handler_func)(unsigned long size); static MSVCRT_new_handler_func MSVCRT_new_handler; static int MSVCRT_new_mode; @@ -34,7 +35,7 @@ TRACE("(%ld) returning %p\n", size, retval); LOCK_HEAP; if(retval && MSVCRT_new_handler) - (*MSVCRT_new_handler)(); + (*MSVCRT_new_handler)(size); UNLOCK_HEAP; return retval; } @@ -80,6 +81,16 @@ } /********************************************************************* + * ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) + */ +MSVCRT_new_handler_func MSVCRT_set_new_handler(void *func) +{ + TRACE("(%p)\n",func); + MSVCRT__set_new_handler(NULL); + return NULL; +} + +/********************************************************************* * ?_set_new_mode@@YAHH@Z (MSVCRT.@) */ int MSVCRT__set_new_mode(int mode) @@ -93,6 +104,16 @@ } /********************************************************************* + * _callnewh (MSVCRT.@) + */ +int _callnewh(unsigned long size) +{ + if(MSVCRT_new_handler) + (*MSVCRT_new_handler)(size); + return 0; +} + +/********************************************************************* * _expand (MSVCRT.@) */ void* _expand(void* mem, MSVCRT_size_t size) @@ -185,6 +206,16 @@ } UNLOCK_HEAP; return retval == _HEAPEND? _HEAPOK : retval; +} + +/********************************************************************* + * _heapadd (MSVCRT.@) + */ +int _heapadd(void* mem, MSVCRT_size_t size) +{ + TRACE("(%p,%d) unsupported in Win32\n", mem,size); + SET_THREAD_VAR(errno,MSVCRT_ENOSYS); + return -1; } /********************************************************************* Index: dlls/msvcrt/main.c =================================================================== RCS file: /home/wine/wine/dlls/msvcrt/main.c,v retrieving revision 1.5 diff -u -r1.5 main.c --- dlls/msvcrt/main.c 2001/09/19 20:29:33 1.5 +++ dlls/msvcrt/main.c 2001/12/20 05:48:24 @@ -34,6 +34,8 @@ void msvcrt_free_args(void); void msvcrt_init_vtables(void); +typedef void* (*MSVCRT_malloc_func)(unsigned int); +typedef void (*MSVCRT_free_func)(void*); /********************************************************************* * Init @@ -159,21 +161,41 @@ /* FIXME: This is probably data, not a function */ } + /********************************************************************* * __unDName (MSVCRT.@) * Function not really understood but needed to make the DLL work */ -void MSVCRT___unDName(void) -{ - /* Called by all VC compiled progs on startup. No idea what it does */ +char* MSVCRT___unDName(int unknown, const char* mangled, + MSVCRT_malloc_func memget, + MSVCRT_free_func memfree, + unsigned int flags) +{ + char* ret; + + FIXME("(%d,%s,%p,%p,%x) stub!\n", unknown, mangled, memget, memfree, flags); + + /* Experimentation reveals the following flag meanings when set: + * 0x0001 - Dont show __ in calling convention + * 0x0002 - Dont show calling convention at all + * 0x0004 - Dont show function/method return value + * 0x0010 - Same as 0x1 + * 0x0080 - Dont show access specifier (public/protected/private) + * 0x0200 - Dont show static specifier + * 0x1000 - Only report the variable/class name + */ + /* Duplicate the mangled name; for comparisons it doesn't matter anyway */ + ret = memget(strlen(mangled) + 1); + strcpy(ret, mangled); + return ret; } + /********************************************************************* * __unDNameEx (MSVCRT.@) * Function not really understood but needed to make the DLL work */ -void MSVCRT___unDNameEx(void) +char* MSVCRT___unDNameEx(void) { - /* As above */ + return NULL; } - Index: dlls/msvcrt/msvcrt.spec =================================================================== RCS file: /home/wine/wine/dlls/msvcrt/msvcrt.spec,v retrieving revision 1.26 diff -u -r1.26 msvcrt.spec --- dlls/msvcrt/msvcrt.spec 2001/12/05 22:11:35 1.26 +++ dlls/msvcrt/msvcrt.spec 2001/12/20 05:48:24 @@ -51,12 +51,12 @@ @ stub ?before@type_info@@QBEHABV1@@Z #(ptr ptr) stdcall @ stdcall ?name@type_info@@QBEPBDXZ(ptr) MSVCRT_type_info_name @ stdcall ?raw_name@type_info@@QBEPBDXZ(ptr) MSVCRT_type_info_raw_name -@ stub ?set_new_handler@@YAP6AXXZP6AXXZ@Z +@ cdecl ?set_new_handler@@YAP6AXXZP6AXXZ@Z(ptr) MSVCRT__set_new_handler @ cdecl ?set_terminate@@YAP6AXXZP6AXXZ@Z(ptr) MSVCRT_set_terminate @ cdecl ?set_unexpected@@YAP6AXXZP6AXXZ@Z(ptr) MSVCRT_set_unexpected @ cdecl ?terminate@@YAXXZ() MSVCRT_terminate @ cdecl ?unexpected@@YAXXZ() MSVCRT_unexpected -@ stdcall ?what@exception@@UBEPBDXZ(ptr) MSVCRT_exception_what +@ cdecl ?what@exception@@UBEPBDXZ(ptr) MSVCRT_what_exception @ cdecl -noimport _CIacos() _CIacos @ cdecl -noimport _CIasin() _CIasin @ cdecl -noimport _CIatan() _CIatan @@ -81,11 +81,11 @@ @ extern _HUGE MSVCRT__HUGE @ cdecl _Strftime(str long str ptr ptr) _Strftime @ cdecl _XcptFilter(long ptr) _XcptFilter -@ stub __CxxFrameHandler +@ cdecl __CxxFrameHandler(ptr ptr ptr ptr) __CxxFrameHandler @ stub __CxxLongjmpUnwind -@ stub __RTCastToVoid -@ stub __RTDynamicCast -@ stub __RTtypeid +@ cdecl -noimport __RTCastToVoid(ptr) MSVCRT___RTCastToVoid +@ cdecl -noimport __RTDynamicCast(ptr long ptr ptr long) MSVCRT___RTDynamicCast +@ cdecl -noimport __RTtypeid(ptr) MSVCRT___RTtypeid @ stub __STRINGTOLD @ extern __argc MSVCRT___argc @ extern __argv MSVCRT___argv @@ -143,7 +143,7 @@ @ forward __threadhandle kernel32.GetCurrentThread @ forward __threadid kernel32.GetCurrentThreadId @ cdecl __toascii(long) MSVCRT___toascii -@ cdecl __unDName() MSVCRT___unDName #FIXME +@ cdecl __unDName(long str ptr ptr long) MSVCRT___unDName @ cdecl __unDNameEx() MSVCRT___unDNameEx #FIXME @ extern __unguarded_readlc_active MSVCRT___unguarded_readlc_active @ extern __wargv MSVCRT___wargv @@ -177,7 +177,7 @@ @ cdecl _beginthreadex (ptr long ptr ptr long ptr) _beginthreadex @ cdecl _c_exit() MSVCRT__c_exit @ cdecl _cabs(long) _cabs -@ stub _callnewh +@ cdecl _callnewh(long) _callnewh @ cdecl _cexit() MSVCRT__cexit @ cdecl _cgets(str) _cgets @ cdecl _chdir(str) _chdir