Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencpp.c
Go to the documentation of this file.
00001 /* 00002 * msvcrt.dll C++ objects 00003 * 00004 * Copyright 2000 Jon Griffiths 00005 * Copyright 2003, 2004 Alexandre Julliard 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <precomp.h> 00023 00024 #include <wine/exception.h> 00025 #include <internal/wine/msvcrt.h> 00026 #include <internal/wine/cppexcept.h> 00027 00028 typedef exception bad_cast; 00029 typedef exception bad_typeid; 00030 typedef exception __non_rtti_object; 00031 00032 typedef struct _rtti_base_descriptor 00033 { 00034 const type_info *type_descriptor; 00035 int num_base_classes; 00036 this_ptr_offsets offsets; /* offsets for computing the this pointer */ 00037 unsigned int attributes; 00038 } rtti_base_descriptor; 00039 00040 typedef struct _rtti_base_array 00041 { 00042 const rtti_base_descriptor *bases[3]; /* First element is the class itself */ 00043 } rtti_base_array; 00044 00045 typedef struct _rtti_object_hierarchy 00046 { 00047 unsigned int signature; 00048 unsigned int attributes; 00049 int array_len; /* Size of the array pointed to by 'base_classes' */ 00050 const rtti_base_array *base_classes; 00051 } rtti_object_hierarchy; 00052 00053 typedef struct _rtti_object_locator 00054 { 00055 unsigned int signature; 00056 int base_class_offset; 00057 unsigned int flags; 00058 const type_info *type_descriptor; 00059 const rtti_object_hierarchy *type_hierarchy; 00060 } rtti_object_locator; 00061 00062 #ifdef __i386__ /* thiscall functions are i386-specific */ 00063 00064 #define THISCALL(func) __thiscall_ ## func 00065 #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) 00066 00067 #ifdef _MSC_VER 00068 #include <internal/wine_msc.h> 00069 #else 00070 #define DEFINE_THISCALL_WRAPPER(func,args) \ 00071 extern void THISCALL(func)(void); \ 00072 __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ 00073 "popl %eax\n\t" \ 00074 "pushl %ecx\n\t" \ 00075 "pushl %eax\n\t" \ 00076 "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) ) 00077 #endif /* _MSC_VER */ 00078 00079 #else /* __i386__ */ 00080 00081 #define THISCALL(func) func 00082 #define THISCALL_NAME(func) __ASM_NAME(#func) 00083 #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */ 00084 00085 #endif /* __i386__ */ 00086 00087 extern const vtable_ptr MSVCRT_exception_vtable; 00088 extern const vtable_ptr MSVCRT_bad_typeid_vtable; 00089 extern const vtable_ptr MSVCRT_bad_cast_vtable; 00090 extern const vtable_ptr MSVCRT___non_rtti_object_vtable; 00091 extern const vtable_ptr MSVCRT_type_info_vtable; 00092 00093 /* get the vtable pointer for a C++ object */ 00094 static inline const vtable_ptr *get_vtable( void *obj ) 00095 { 00096 return *(const vtable_ptr **)obj; 00097 } 00098 00099 static inline const rtti_object_locator *get_obj_locator( void *cppobj ) 00100 { 00101 const vtable_ptr *vtable = get_vtable( cppobj ); 00102 return (const rtti_object_locator *)vtable[-1]; 00103 } 00104 00105 static void dump_obj_locator( const rtti_object_locator *ptr ) 00106 { 00107 int i; 00108 const rtti_object_hierarchy *h = ptr->type_hierarchy; 00109 00110 TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n", 00111 ptr, ptr->signature, ptr->base_class_offset, ptr->flags, 00112 ptr->type_descriptor, dbgstr_type_info(ptr->type_descriptor), ptr->type_hierarchy ); 00113 TRACE( " hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n", 00114 h->signature, h->attributes, h->array_len, h->base_classes ); 00115 for (i = 0; i < h->array_len; i++) 00116 { 00117 TRACE( " base class %p: num %d off %d,%d,%d attr %08x type %p %s\n", 00118 h->base_classes->bases[i], 00119 h->base_classes->bases[i]->num_base_classes, 00120 h->base_classes->bases[i]->offsets.this_offset, 00121 h->base_classes->bases[i]->offsets.vbase_descr, 00122 h->base_classes->bases[i]->offsets.vbase_offset, 00123 h->base_classes->bases[i]->attributes, 00124 h->base_classes->bases[i]->type_descriptor, 00125 dbgstr_type_info(h->base_classes->bases[i]->type_descriptor) ); 00126 } 00127 } 00128 00129 /* Internal common ctor for exception */ 00130 static void EXCEPTION_ctor(exception *_this, const char** name) 00131 { 00132 _this->vtable = &MSVCRT_exception_vtable; 00133 if (*name) 00134 { 00135 size_t name_len = strlen(*name) + 1; 00136 _this->name = MSVCRT_malloc(name_len); 00137 memcpy(_this->name, *name, name_len); 00138 _this->do_free = TRUE; 00139 } 00140 else 00141 { 00142 _this->name = NULL; 00143 _this->do_free = FALSE; 00144 } 00145 } 00146 00147 /****************************************************************** 00148 * ??0exception@@QAE@ABQBD@Z (MSVCRT.@) 00149 */ 00150 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor,8) 00151 exception * __stdcall MSVCRT_exception_ctor(exception * _this, const char ** name) 00152 { 00153 TRACE("(%p,%s)\n", _this, *name); 00154 EXCEPTION_ctor(_this, name); 00155 return _this; 00156 } 00157 00158 /****************************************************************** 00159 * ??0exception@@QAE@ABQBDH@Z (MSVCRT.@) 00160 */ 00161 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor_noalloc,12) 00162 exception * __stdcall MSVCRT_exception_ctor_noalloc(exception * _this, char ** name, int noalloc) 00163 { 00164 TRACE("(%p,%s)\n", _this, *name); 00165 _this->vtable = &MSVCRT_exception_vtable; 00166 _this->name = *name; 00167 _this->do_free = FALSE; 00168 return _this; 00169 } 00170 00171 /****************************************************************** 00172 * ??0exception@@QAE@ABV0@@Z (MSVCRT.@) 00173 */ 00174 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_copy_ctor,8) 00175 exception * __stdcall MSVCRT_exception_copy_ctor(exception * _this, const exception * rhs) 00176 { 00177 TRACE("(%p,%p)\n", _this, rhs); 00178 00179 if (!rhs->do_free) 00180 { 00181 _this->vtable = &MSVCRT_exception_vtable; 00182 _this->name = rhs->name; 00183 _this->do_free = FALSE; 00184 } 00185 else 00186 EXCEPTION_ctor(_this, (const char**)&rhs->name); 00187 TRACE("name = %s\n", _this->name); 00188 return _this; 00189 } 00190 00191 /****************************************************************** 00192 * ??0exception@@QAE@XZ (MSVCRT.@) 00193 */ 00194 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_default_ctor,4) 00195 exception * __stdcall MSVCRT_exception_default_ctor(exception * _this) 00196 { 00197 static const char* empty = NULL; 00198 00199 TRACE("(%p)\n", _this); 00200 EXCEPTION_ctor(_this, &empty); 00201 return _this; 00202 } 00203 00204 /****************************************************************** 00205 * ??1exception@@UAE@XZ (MSVCRT.@) 00206 */ 00207 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_dtor,4) 00208 void __stdcall MSVCRT_exception_dtor(exception * _this) 00209 { 00210 TRACE("(%p)\n", _this); 00211 _this->vtable = &MSVCRT_exception_vtable; 00212 if (_this->do_free) MSVCRT_free(_this->name); 00213 } 00214 00215 /****************************************************************** 00216 * ??4exception@@QAEAAV0@ABV0@@Z (MSVCRT.@) 00217 */ 00218 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_opequals,8) 00219 exception * __stdcall MSVCRT_exception_opequals(exception * _this, const exception * rhs) 00220 { 00221 TRACE("(%p %p)\n", _this, rhs); 00222 if (_this != rhs) 00223 { 00224 MSVCRT_exception_dtor(_this); 00225 MSVCRT_exception_copy_ctor(_this, rhs); 00226 } 00227 TRACE("name = %s\n", _this->name); 00228 return _this; 00229 } 00230 00231 /****************************************************************** 00232 * ??_Eexception@@UAEPAXI@Z (MSVCRT.@) 00233 */ 00234 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_vector_dtor,8) 00235 void * __stdcall MSVCRT_exception_vector_dtor(exception * _this, unsigned int flags) 00236 { 00237 TRACE("(%p %x)\n", _this, flags); 00238 if (flags & 2) 00239 { 00240 /* we have an array, with the number of elements stored before the first object */ 00241 int i, *ptr = (int *)_this - 1; 00242 00243 for (i = *ptr - 1; i >= 0; i--) MSVCRT_exception_dtor(_this + i); 00244 MSVCRT_operator_delete(ptr); 00245 } 00246 else 00247 { 00248 MSVCRT_exception_dtor(_this); 00249 if (flags & 1) MSVCRT_operator_delete(_this); 00250 } 00251 return _this; 00252 } 00253 00254 /****************************************************************** 00255 * ??_Gexception@@UAEPAXI@Z (MSVCRT.@) 00256 */ 00257 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_scalar_dtor,8) 00258 void * __stdcall MSVCRT_exception_scalar_dtor(exception * _this, unsigned int flags) 00259 { 00260 TRACE("(%p %x)\n", _this, flags); 00261 MSVCRT_exception_dtor(_this); 00262 if (flags & 1) MSVCRT_operator_delete(_this); 00263 return _this; 00264 } 00265 00266 /****************************************************************** 00267 * ?what@exception@@UBEPBDXZ (MSVCRT.@) 00268 */ 00269 DEFINE_THISCALL_WRAPPER(MSVCRT_what_exception,4) 00270 const char * __stdcall MSVCRT_what_exception(exception * _this) 00271 { 00272 TRACE("(%p) returning %s\n", _this, _this->name); 00273 return _this->name ? _this->name : "Unknown exception"; 00274 } 00275 00276 /****************************************************************** 00277 * ??0bad_typeid@@QAE@ABV0@@Z (MSVCRT.@) 00278 */ 00279 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_copy_ctor,8) 00280 bad_typeid * __stdcall MSVCRT_bad_typeid_copy_ctor(bad_typeid * _this, const bad_typeid * rhs) 00281 { 00282 TRACE("(%p %p)\n", _this, rhs); 00283 MSVCRT_exception_copy_ctor(_this, rhs); 00284 _this->vtable = &MSVCRT_bad_typeid_vtable; 00285 return _this; 00286 } 00287 00288 /****************************************************************** 00289 * ??0bad_typeid@@QAE@PBD@Z (MSVCRT.@) 00290 */ 00291 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_ctor,8) 00292 bad_typeid * __stdcall MSVCRT_bad_typeid_ctor(bad_typeid * _this, const char * name) 00293 { 00294 TRACE("(%p %s)\n", _this, name); 00295 EXCEPTION_ctor(_this, &name); 00296 _this->vtable = &MSVCRT_bad_typeid_vtable; 00297 return _this; 00298 } 00299 00300 /****************************************************************** 00301 * ??_Fbad_typeid@@QAEXXZ (MSVCRT.@) 00302 */ 00303 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_default_ctor,4) 00304 bad_typeid * __stdcall MSVCRT_bad_typeid_default_ctor(bad_typeid * _this) 00305 { 00306 return MSVCRT_bad_typeid_ctor( _this, "bad typeid" ); 00307 } 00308 00309 /****************************************************************** 00310 * ??1bad_typeid@@UAE@XZ (MSVCRT.@) 00311 */ 00312 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_dtor,4) 00313 void __stdcall MSVCRT_bad_typeid_dtor(bad_typeid * _this) 00314 { 00315 TRACE("(%p)\n", _this); 00316 MSVCRT_exception_dtor(_this); 00317 } 00318 00319 /****************************************************************** 00320 * ??4bad_typeid@@QAEAAV0@ABV0@@Z (MSVCRT.@) 00321 */ 00322 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_opequals,8) 00323 bad_typeid * __stdcall MSVCRT_bad_typeid_opequals(bad_typeid * _this, const bad_typeid * rhs) 00324 { 00325 TRACE("(%p %p)\n", _this, rhs); 00326 MSVCRT_exception_opequals(_this, rhs); 00327 return _this; 00328 } 00329 00330 /****************************************************************** 00331 * ??_Ebad_typeid@@UAEPAXI@Z (MSVCRT.@) 00332 */ 00333 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_vector_dtor,8) 00334 void * __stdcall MSVCRT_bad_typeid_vector_dtor(bad_typeid * _this, unsigned int flags) 00335 { 00336 TRACE("(%p %x)\n", _this, flags); 00337 if (flags & 2) 00338 { 00339 /* we have an array, with the number of elements stored before the first object */ 00340 int i, *ptr = (int *)_this - 1; 00341 00342 for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_typeid_dtor(_this + i); 00343 MSVCRT_operator_delete(ptr); 00344 } 00345 else 00346 { 00347 MSVCRT_bad_typeid_dtor(_this); 00348 if (flags & 1) MSVCRT_operator_delete(_this); 00349 } 00350 return _this; 00351 } 00352 00353 /****************************************************************** 00354 * ??_Gbad_typeid@@UAEPAXI@Z (MSVCRT.@) 00355 */ 00356 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_scalar_dtor,8) 00357 void * __stdcall MSVCRT_bad_typeid_scalar_dtor(bad_typeid * _this, unsigned int flags) 00358 { 00359 TRACE("(%p %x)\n", _this, flags); 00360 MSVCRT_bad_typeid_dtor(_this); 00361 if (flags & 1) MSVCRT_operator_delete(_this); 00362 return _this; 00363 } 00364 00365 /****************************************************************** 00366 * ??0__non_rtti_object@@QAE@ABV0@@Z (MSVCRT.@) 00367 */ 00368 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_copy_ctor,8) 00369 __non_rtti_object * __stdcall MSVCRT___non_rtti_object_copy_ctor(__non_rtti_object * _this, 00370 const __non_rtti_object * rhs) 00371 { 00372 TRACE("(%p %p)\n", _this, rhs); 00373 MSVCRT_bad_typeid_copy_ctor(_this, rhs); 00374 _this->vtable = &MSVCRT___non_rtti_object_vtable; 00375 return _this; 00376 } 00377 00378 /****************************************************************** 00379 * ??0__non_rtti_object@@QAE@PBD@Z (MSVCRT.@) 00380 */ 00381 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_ctor,8) 00382 __non_rtti_object * __stdcall MSVCRT___non_rtti_object_ctor(__non_rtti_object * _this, 00383 const char * name) 00384 { 00385 TRACE("(%p %s)\n", _this, name); 00386 EXCEPTION_ctor(_this, &name); 00387 _this->vtable = &MSVCRT___non_rtti_object_vtable; 00388 return _this; 00389 } 00390 00391 /****************************************************************** 00392 * ??1__non_rtti_object@@UAE@XZ (MSVCRT.@) 00393 */ 00394 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_dtor,4) 00395 void __stdcall MSVCRT___non_rtti_object_dtor(__non_rtti_object * _this) 00396 { 00397 TRACE("(%p)\n", _this); 00398 MSVCRT_bad_typeid_dtor(_this); 00399 } 00400 00401 /****************************************************************** 00402 * ??4__non_rtti_object@@QAEAAV0@ABV0@@Z (MSVCRT.@) 00403 */ 00404 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_opequals,8) 00405 __non_rtti_object * __stdcall MSVCRT___non_rtti_object_opequals(__non_rtti_object * _this, 00406 const __non_rtti_object *rhs) 00407 { 00408 TRACE("(%p %p)\n", _this, rhs); 00409 MSVCRT_bad_typeid_opequals(_this, rhs); 00410 return _this; 00411 } 00412 00413 /****************************************************************** 00414 * ??_E__non_rtti_object@@UAEPAXI@Z (MSVCRT.@) 00415 */ 00416 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_vector_dtor,8) 00417 void * __stdcall MSVCRT___non_rtti_object_vector_dtor(__non_rtti_object * _this, unsigned int flags) 00418 { 00419 TRACE("(%p %x)\n", _this, flags); 00420 if (flags & 2) 00421 { 00422 /* we have an array, with the number of elements stored before the first object */ 00423 int i, *ptr = (int *)_this - 1; 00424 00425 for (i = *ptr - 1; i >= 0; i--) MSVCRT___non_rtti_object_dtor(_this + i); 00426 MSVCRT_operator_delete(ptr); 00427 } 00428 else 00429 { 00430 MSVCRT___non_rtti_object_dtor(_this); 00431 if (flags & 1) MSVCRT_operator_delete(_this); 00432 } 00433 return _this; 00434 } 00435 00436 /****************************************************************** 00437 * ??_G__non_rtti_object@@UAEPAXI@Z (MSVCRT.@) 00438 */ 00439 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_scalar_dtor,8) 00440 void * __stdcall MSVCRT___non_rtti_object_scalar_dtor(__non_rtti_object * _this, unsigned int flags) 00441 { 00442 TRACE("(%p %x)\n", _this, flags); 00443 MSVCRT___non_rtti_object_dtor(_this); 00444 if (flags & 1) MSVCRT_operator_delete(_this); 00445 return _this; 00446 } 00447 00448 /****************************************************************** 00449 * ??0bad_cast@@AAE@PBQBD@Z (MSVCRT.@) 00450 * ??0bad_cast@@QAE@ABQBD@Z (MSVCRT.@) 00451 */ 00452 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor,8) 00453 bad_cast * __stdcall MSVCRT_bad_cast_ctor(bad_cast * _this, const char ** name) 00454 { 00455 TRACE("(%p %s)\n", _this, *name); 00456 EXCEPTION_ctor(_this, name); 00457 _this->vtable = &MSVCRT_bad_cast_vtable; 00458 return _this; 00459 } 00460 00461 /****************************************************************** 00462 * ??0bad_cast@@QAE@ABV0@@Z (MSVCRT.@) 00463 */ 00464 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_copy_ctor,8) 00465 bad_cast * __stdcall MSVCRT_bad_cast_copy_ctor(bad_cast * _this, const bad_cast * rhs) 00466 { 00467 TRACE("(%p %p)\n", _this, rhs); 00468 MSVCRT_exception_copy_ctor(_this, rhs); 00469 _this->vtable = &MSVCRT_bad_cast_vtable; 00470 return _this; 00471 } 00472 00473 /****************************************************************** 00474 * ??0bad_cast@@QAE@PBD@Z (MSVCRT.@) 00475 */ 00476 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor_charptr,8) 00477 bad_cast * __stdcall MSVCRT_bad_cast_ctor_charptr(bad_cast * _this, const char * name) 00478 { 00479 TRACE("(%p %s)\n", _this, name); 00480 EXCEPTION_ctor(_this, &name); 00481 _this->vtable = &MSVCRT_bad_cast_vtable; 00482 return _this; 00483 } 00484 00485 /****************************************************************** 00486 * ??_Fbad_cast@@QAEXXZ (MSVCRT.@) 00487 */ 00488 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_default_ctor,4) 00489 bad_cast * __stdcall MSVCRT_bad_cast_default_ctor(bad_cast * _this) 00490 { 00491 return MSVCRT_bad_cast_ctor_charptr( _this, "bad cast" ); 00492 } 00493 00494 /****************************************************************** 00495 * ??1bad_cast@@UAE@XZ (MSVCRT.@) 00496 */ 00497 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_dtor,4) 00498 void __stdcall MSVCRT_bad_cast_dtor(bad_cast * _this) 00499 { 00500 TRACE("(%p)\n", _this); 00501 MSVCRT_exception_dtor(_this); 00502 } 00503 00504 /****************************************************************** 00505 * ??4bad_cast@@QAEAAV0@ABV0@@Z (MSVCRT.@) 00506 */ 00507 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_opequals,8) 00508 bad_cast * __stdcall MSVCRT_bad_cast_opequals(bad_cast * _this, const bad_cast * rhs) 00509 { 00510 TRACE("(%p %p)\n", _this, rhs); 00511 MSVCRT_exception_opequals(_this, rhs); 00512 return _this; 00513 } 00514 00515 /****************************************************************** 00516 * ??_Ebad_cast@@UAEPAXI@Z (MSVCRT.@) 00517 */ 00518 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_vector_dtor,8) 00519 void * __stdcall MSVCRT_bad_cast_vector_dtor(bad_cast * _this, unsigned int flags) 00520 { 00521 TRACE("(%p %x)\n", _this, flags); 00522 if (flags & 2) 00523 { 00524 /* we have an array, with the number of elements stored before the first object */ 00525 int i, *ptr = (int *)_this - 1; 00526 00527 for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_cast_dtor(_this + i); 00528 MSVCRT_operator_delete(ptr); 00529 } 00530 else 00531 { 00532 MSVCRT_bad_cast_dtor(_this); 00533 if (flags & 1) MSVCRT_operator_delete(_this); 00534 } 00535 return _this; 00536 } 00537 00538 /****************************************************************** 00539 * ??_Gbad_cast@@UAEPAXI@Z (MSVCRT.@) 00540 */ 00541 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_scalar_dtor,8) 00542 void * __stdcall MSVCRT_bad_cast_scalar_dtor(bad_cast * _this, unsigned int flags) 00543 { 00544 TRACE("(%p %x)\n", _this, flags); 00545 MSVCRT_bad_cast_dtor(_this); 00546 if (flags & 1) MSVCRT_operator_delete(_this); 00547 return _this; 00548 } 00549 00550 /****************************************************************** 00551 * ??8type_info@@QBEHABV0@@Z (MSVCRT.@) 00552 */ 00553 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opequals_equals,8) 00554 int __stdcall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs) 00555 { 00556 int ret = !strcmp(_this->mangled + 1, rhs->mangled + 1); 00557 TRACE("(%p %p) returning %d\n", _this, rhs, ret); 00558 return ret; 00559 } 00560 00561 /****************************************************************** 00562 * ??9type_info@@QBEHABV0@@Z (MSVCRT.@) 00563 */ 00564 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opnot_equals,8) 00565 int __stdcall MSVCRT_type_info_opnot_equals(type_info * _this, const type_info * rhs) 00566 { 00567 int ret = !!strcmp(_this->mangled + 1, rhs->mangled + 1); 00568 TRACE("(%p %p) returning %d\n", _this, rhs, ret); 00569 return ret; 00570 } 00571 00572 /****************************************************************** 00573 * ?before@type_info@@QBEHABV1@@Z (MSVCRT.@) 00574 */ 00575 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_before,8) 00576 int __stdcall MSVCRT_type_info_before(type_info * _this, const type_info * rhs) 00577 { 00578 int ret = strcmp(_this->mangled + 1, rhs->mangled + 1) < 0; 00579 TRACE("(%p %p) returning %d\n", _this, rhs, ret); 00580 return ret; 00581 } 00582 00583 /****************************************************************** 00584 * ??1type_info@@UAE@XZ (MSVCRT.@) 00585 */ 00586 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_dtor,4) 00587 void __stdcall MSVCRT_type_info_dtor(type_info * _this) 00588 { 00589 TRACE("(%p)\n", _this); 00590 MSVCRT_free(_this->name); 00591 } 00592 00593 /****************************************************************** 00594 * ?name@type_info@@QBEPBDXZ (MSVCRT.@) 00595 */ 00596 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_name,4) 00597 const char * __stdcall MSVCRT_type_info_name(type_info * _this) 00598 { 00599 if (!_this->name) 00600 { 00601 /* Create and set the demangled name */ 00602 /* Note: mangled name in type_info struct always starts with a '.', while 00603 * it isn't valid for mangled name. 00604 * Is this '.' really part of the mangled name, or has it some other meaning ? 00605 */ 00606 char* name = __unDName(0, _this->mangled + 1, 0, 00607 MSVCRT_malloc, MSVCRT_free, 0x2800); 00608 if (name) 00609 { 00610 size_t len = strlen(name); 00611 00612 /* It seems _unDName may leave blanks at the end of the demangled name */ 00613 while (len && name[--len] == ' ') 00614 name[len] = '\0'; 00615 00616 if (InterlockedCompareExchangePointer((void**)&_this->name, name, NULL)) 00617 { 00618 /* Another thread set this member since we checked above - use it */ 00619 MSVCRT_free(name); 00620 } 00621 } 00622 } 00623 TRACE("(%p) returning %s\n", _this, _this->name); 00624 return _this->name; 00625 } 00626 00627 /****************************************************************** 00628 * ?raw_name@type_info@@QBEPBDXZ (MSVCRT.@) 00629 */ 00630 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_raw_name,4) 00631 const char * __stdcall MSVCRT_type_info_raw_name(type_info * _this) 00632 { 00633 TRACE("(%p) returning %s\n", _this, _this->mangled); 00634 return _this->mangled; 00635 } 00636 00637 /* Unexported */ 00638 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_vector_dtor,8) 00639 void * __stdcall MSVCRT_type_info_vector_dtor(type_info * _this, unsigned int flags) 00640 { 00641 TRACE("(%p %x)\n", _this, flags); 00642 if (flags & 2) 00643 { 00644 /* we have an array, with the number of elements stored before the first object */ 00645 int i, *ptr = (int *)_this - 1; 00646 00647 for (i = *ptr - 1; i >= 0; i--) MSVCRT_type_info_dtor(_this + i); 00648 MSVCRT_operator_delete(ptr); 00649 } 00650 else 00651 { 00652 MSVCRT_type_info_dtor(_this); 00653 if (flags & 1) MSVCRT_operator_delete(_this); 00654 } 00655 return _this; 00656 } 00657 00658 /* vtables */ 00659 00660 #ifdef __GNUC__ 00661 #ifdef _WIN64 00662 00663 #define __ASM_VTABLE(name,funcs) \ 00664 __asm__(".data\n" \ 00665 "\t.align 8\n" \ 00666 "\t.quad " __ASM_NAME(#name "_rtti") "\n" \ 00667 "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \ 00668 __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \ 00669 "\t.quad " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \ 00670 funcs "\n\t.text"); 00671 00672 #define __ASM_EXCEPTION_VTABLE(name) \ 00673 __ASM_VTABLE(name, "\t.quad " THISCALL_NAME(MSVCRT_what_exception) ) 00674 00675 #else 00676 00677 #define __ASM_VTABLE(name,funcs) \ 00678 __asm__(".data\n" \ 00679 "\t.align 4\n" \ 00680 "\t.long " __ASM_NAME(#name "_rtti") "\n" \ 00681 "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \ 00682 __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \ 00683 "\t.long " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \ 00684 funcs "\n\t.text"); 00685 00686 #define __ASM_EXCEPTION_VTABLE(name) \ 00687 __ASM_VTABLE(name, "\t.long " THISCALL_NAME(MSVCRT_what_exception) ) 00688 00689 #endif /* _WIN64 */ 00690 00691 #ifndef __GNUC__ 00692 void __asm_dummy_vtables(void) { 00693 #endif 00694 00695 __ASM_VTABLE(type_info,"") 00696 __ASM_EXCEPTION_VTABLE(exception) 00697 __ASM_EXCEPTION_VTABLE(bad_typeid) 00698 __ASM_EXCEPTION_VTABLE(bad_cast) 00699 __ASM_EXCEPTION_VTABLE(__non_rtti_object) 00700 00701 #ifndef __GNUC__ 00702 } 00703 #endif 00704 #endif 00705 00706 /* Static RTTI for exported objects */ 00707 00708 static const type_info exception_type_info = 00709 { 00710 &MSVCRT_type_info_vtable, 00711 NULL, 00712 ".?AVexception@@" 00713 }; 00714 00715 static const rtti_base_descriptor exception_rtti_base_descriptor = 00716 { 00717 &exception_type_info, 00718 0, 00719 { 0, -1, 0 }, 00720 0 00721 }; 00722 00723 static const rtti_base_array exception_rtti_base_array = 00724 { 00725 { 00726 &exception_rtti_base_descriptor, 00727 NULL, 00728 NULL 00729 } 00730 }; 00731 00732 static const rtti_object_hierarchy exception_type_hierarchy = 00733 { 00734 0, 00735 0, 00736 1, 00737 &exception_rtti_base_array 00738 }; 00739 00740 const rtti_object_locator exception_rtti = 00741 { 00742 0, 00743 0, 00744 0, 00745 &exception_type_info, 00746 &exception_type_hierarchy 00747 }; 00748 00749 static const cxx_type_info exception_cxx_type_info = 00750 { 00751 0, 00752 &exception_type_info, 00753 { 0, -1, 0 }, 00754 sizeof(exception), 00755 (cxx_copy_ctor)THISCALL(MSVCRT_exception_copy_ctor) 00756 }; 00757 00758 static const type_info bad_typeid_type_info = 00759 { 00760 &MSVCRT_type_info_vtable, 00761 NULL, 00762 ".?AVbad_typeid@@" 00763 }; 00764 00765 static const rtti_base_descriptor bad_typeid_rtti_base_descriptor = 00766 { 00767 &bad_typeid_type_info, 00768 1, 00769 { 0, -1, 0 }, 00770 0 00771 }; 00772 00773 static const rtti_base_array bad_typeid_rtti_base_array = 00774 { 00775 { 00776 &bad_typeid_rtti_base_descriptor, 00777 &exception_rtti_base_descriptor, 00778 NULL 00779 } 00780 }; 00781 00782 static const rtti_object_hierarchy bad_typeid_type_hierarchy = 00783 { 00784 0, 00785 0, 00786 2, 00787 &bad_typeid_rtti_base_array 00788 }; 00789 00790 const rtti_object_locator bad_typeid_rtti = 00791 { 00792 0, 00793 0, 00794 0, 00795 &bad_typeid_type_info, 00796 &bad_typeid_type_hierarchy 00797 }; 00798 00799 static const cxx_type_info bad_typeid_cxx_type_info = 00800 { 00801 0, 00802 &bad_typeid_type_info, 00803 { 0, -1, 0 }, 00804 sizeof(exception), 00805 (cxx_copy_ctor)THISCALL(MSVCRT_bad_typeid_copy_ctor) 00806 }; 00807 00808 static const type_info bad_cast_type_info = 00809 { 00810 &MSVCRT_type_info_vtable, 00811 NULL, 00812 ".?AVbad_cast@@" 00813 }; 00814 00815 static const rtti_base_descriptor bad_cast_rtti_base_descriptor = 00816 { 00817 &bad_cast_type_info, 00818 1, 00819 { 0, -1, 0 }, 00820 0 00821 }; 00822 00823 static const rtti_base_array bad_cast_rtti_base_array = 00824 { 00825 { 00826 &bad_cast_rtti_base_descriptor, 00827 &exception_rtti_base_descriptor, 00828 NULL 00829 } 00830 }; 00831 00832 static const rtti_object_hierarchy bad_cast_type_hierarchy = 00833 { 00834 0, 00835 0, 00836 2, 00837 &bad_cast_rtti_base_array 00838 }; 00839 00840 const rtti_object_locator bad_cast_rtti = 00841 { 00842 0, 00843 0, 00844 0, 00845 &bad_cast_type_info, 00846 &bad_cast_type_hierarchy 00847 }; 00848 00849 static const cxx_type_info bad_cast_cxx_type_info = 00850 { 00851 0, 00852 &bad_cast_type_info, 00853 { 0, -1, 0 }, 00854 sizeof(exception), 00855 (cxx_copy_ctor)THISCALL(MSVCRT_bad_cast_copy_ctor) 00856 }; 00857 00858 static const type_info __non_rtti_object_type_info = 00859 { 00860 &MSVCRT_type_info_vtable, 00861 NULL, 00862 ".?AV__non_rtti_object@@" 00863 }; 00864 00865 static const rtti_base_descriptor __non_rtti_object_rtti_base_descriptor = 00866 { 00867 &__non_rtti_object_type_info, 00868 2, 00869 { 0, -1, 0 }, 00870 0 00871 }; 00872 00873 static const rtti_base_array __non_rtti_object_rtti_base_array = 00874 { 00875 { 00876 &__non_rtti_object_rtti_base_descriptor, 00877 &bad_typeid_rtti_base_descriptor, 00878 &exception_rtti_base_descriptor 00879 } 00880 }; 00881 00882 static const rtti_object_hierarchy __non_rtti_object_type_hierarchy = 00883 { 00884 0, 00885 0, 00886 3, 00887 &__non_rtti_object_rtti_base_array 00888 }; 00889 00890 const rtti_object_locator __non_rtti_object_rtti = 00891 { 00892 0, 00893 0, 00894 0, 00895 &__non_rtti_object_type_info, 00896 &__non_rtti_object_type_hierarchy 00897 }; 00898 00899 static const cxx_type_info __non_rtti_object_cxx_type_info = 00900 { 00901 0, 00902 &__non_rtti_object_type_info, 00903 { 0, -1, 0 }, 00904 sizeof(exception), 00905 (cxx_copy_ctor)THISCALL(MSVCRT___non_rtti_object_copy_ctor) 00906 }; 00907 00908 static const type_info type_info_type_info = 00909 { 00910 &MSVCRT_type_info_vtable, 00911 NULL, 00912 ".?AVtype_info@@" 00913 }; 00914 00915 static const rtti_base_descriptor type_info_rtti_base_descriptor = 00916 { 00917 &type_info_type_info, 00918 0, 00919 { 0, -1, 0 }, 00920 0 00921 }; 00922 00923 static const rtti_base_array type_info_rtti_base_array = 00924 { 00925 { 00926 &type_info_rtti_base_descriptor, 00927 NULL, 00928 NULL 00929 } 00930 }; 00931 00932 static const rtti_object_hierarchy type_info_type_hierarchy = 00933 { 00934 0, 00935 0, 00936 1, 00937 &type_info_rtti_base_array 00938 }; 00939 00940 const rtti_object_locator type_info_rtti = 00941 { 00942 0, 00943 0, 00944 0, 00945 &type_info_type_info, 00946 &type_info_type_hierarchy 00947 }; 00948 00949 /* 00950 * Exception RTTI for cpp objects 00951 */ 00952 static const cxx_type_info_table bad_cast_type_info_table = 00953 { 00954 3, 00955 { 00956 &__non_rtti_object_cxx_type_info, 00957 &bad_typeid_cxx_type_info, 00958 &exception_cxx_type_info 00959 } 00960 }; 00961 00962 static const cxx_exception_type bad_cast_exception_type = 00963 { 00964 0, 00965 (void*)THISCALL(MSVCRT_bad_cast_dtor), 00966 NULL, 00967 &bad_cast_type_info_table 00968 }; 00969 00970 static const cxx_type_info_table bad_typeid_type_info_table = 00971 { 00972 2, 00973 { 00974 &bad_cast_cxx_type_info, 00975 &exception_cxx_type_info, 00976 NULL 00977 } 00978 }; 00979 00980 static const cxx_exception_type bad_typeid_exception_type = 00981 { 00982 0, 00983 (void*)THISCALL(MSVCRT_bad_typeid_dtor), 00984 NULL, 00985 &bad_cast_type_info_table 00986 }; 00987 00988 static const cxx_exception_type __non_rtti_object_exception_type = 00989 { 00990 0, 00991 (void*)THISCALL(MSVCRT___non_rtti_object_dtor), 00992 NULL, 00993 &bad_typeid_type_info_table 00994 }; 00995 00996 00997 /****************************************************************** 00998 * ?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) 00999 * 01000 * Install a handler to be called when terminate() is called. 01001 * 01002 * PARAMS 01003 * func [I] Handler function to install 01004 * 01005 * RETURNS 01006 * The previously installed handler function, if any. 01007 */ 01008 terminate_function CDECL MSVCRT_set_terminate(terminate_function func) 01009 { 01010 thread_data_t *data = msvcrt_get_thread_data(); 01011 terminate_function previous = data->terminate_handler; 01012 TRACE("(%p) returning %p\n",func,previous); 01013 data->terminate_handler = func; 01014 return previous; 01015 } 01016 01017 /****************************************************************** 01018 * _get_terminate (MSVCRT.@) 01019 */ 01020 terminate_function CDECL _get_terminate(void) 01021 { 01022 thread_data_t *data = msvcrt_get_thread_data(); 01023 return data->terminate_handler; 01024 } 01025 01026 /****************************************************************** 01027 * ?set_unexpected@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) 01028 * 01029 * Install a handler to be called when unexpected() is called. 01030 * 01031 * PARAMS 01032 * func [I] Handler function to install 01033 * 01034 * RETURNS 01035 * The previously installed handler function, if any. 01036 */ 01037 unexpected_function CDECL MSVCRT_set_unexpected(unexpected_function func) 01038 { 01039 thread_data_t *data = msvcrt_get_thread_data(); 01040 unexpected_function previous = data->unexpected_handler; 01041 TRACE("(%p) returning %p\n",func,previous); 01042 data->unexpected_handler = func; 01043 return previous; 01044 } 01045 01046 /****************************************************************** 01047 * _get_unexpected (MSVCRT.@) 01048 */ 01049 unexpected_function CDECL _get_unexpected(void) 01050 { 01051 thread_data_t *data = msvcrt_get_thread_data(); 01052 return data->unexpected_handler; 01053 } 01054 01055 /****************************************************************** 01056 * ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z (MSVCRT.@) 01057 */ 01058 _se_translator_function CDECL MSVCRT__set_se_translator(_se_translator_function func) 01059 { 01060 thread_data_t *data = msvcrt_get_thread_data(); 01061 _se_translator_function previous = data->se_translator; 01062 TRACE("(%p) returning %p\n",func,previous); 01063 data->se_translator = func; 01064 return previous; 01065 } 01066 01067 /****************************************************************** 01068 * ?terminate@@YAXXZ (MSVCRT.@) 01069 * 01070 * Default handler for an unhandled exception. 01071 * 01072 * PARAMS 01073 * None. 01074 * 01075 * RETURNS 01076 * This function does not return. Either control resumes from any 01077 * handler installed by calling set_terminate(), or (by default) abort() 01078 * is called. 01079 */ 01080 void CDECL MSVCRT_terminate(void) 01081 { 01082 thread_data_t *data = msvcrt_get_thread_data(); 01083 if (data->terminate_handler) data->terminate_handler(); 01084 abort(); 01085 } 01086 01087 /****************************************************************** 01088 * ?unexpected@@YAXXZ (MSVCRT.@) 01089 */ 01090 void CDECL MSVCRT_unexpected(void) 01091 { 01092 thread_data_t *data = msvcrt_get_thread_data(); 01093 if (data->unexpected_handler) data->unexpected_handler(); 01094 MSVCRT_terminate(); 01095 } 01096 01097 01098 /****************************************************************** 01099 * __RTtypeid (MSVCRT.@) 01100 * 01101 * Retrieve the Run Time Type Information (RTTI) for a C++ object. 01102 * 01103 * PARAMS 01104 * cppobj [I] C++ object to get type information for. 01105 * 01106 * RETURNS 01107 * Success: A type_info object describing cppobj. 01108 * Failure: If the object to be cast has no RTTI, a __non_rtti_object 01109 * exception is thrown. If cppobj is NULL, a bad_typeid exception 01110 * is thrown. In either case, this function does not return. 01111 * 01112 * NOTES 01113 * This function is usually called by compiler generated code as a result 01114 * of using one of the C++ dynamic cast statements. 01115 */ 01116 const type_info* CDECL MSVCRT___RTtypeid(void *cppobj) 01117 { 01118 const type_info *ret; 01119 01120 if (!cppobj) 01121 { 01122 bad_typeid e; 01123 MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" ); 01124 _CxxThrowException( &e, &bad_typeid_exception_type ); 01125 return NULL; 01126 } 01127 01128 __TRY 01129 { 01130 const rtti_object_locator *obj_locator = get_obj_locator( cppobj ); 01131 ret = obj_locator->type_descriptor; 01132 } 01133 __EXCEPT_PAGE_FAULT 01134 { 01135 __non_rtti_object e; 01136 MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" ); 01137 _CxxThrowException( &e, &bad_typeid_exception_type ); 01138 return NULL; 01139 } 01140 __ENDTRY 01141 return ret; 01142 } 01143 01144 /****************************************************************** 01145 * __RTDynamicCast (MSVCRT.@) 01146 * 01147 * Dynamically cast a C++ object to one of its base classes. 01148 * 01149 * PARAMS 01150 * cppobj [I] Any C++ object to cast 01151 * unknown [I] Reserved, set to 0 01152 * src [I] type_info object describing cppobj 01153 * dst [I] type_info object describing the base class to cast to 01154 * do_throw [I] TRUE = throw an exception if the cast fails, FALSE = don't 01155 * 01156 * RETURNS 01157 * Success: The address of cppobj, cast to the object described by dst. 01158 * Failure: NULL, If the object to be cast has no RTTI, or dst is not a 01159 * valid cast for cppobj. If do_throw is TRUE, a bad_cast exception 01160 * is thrown and this function does not return. 01161 * 01162 * NOTES 01163 * This function is usually called by compiler generated code as a result 01164 * of using one of the C++ dynamic cast statements. 01165 */ 01166 void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown, 01167 type_info *src, type_info *dst, 01168 int do_throw) 01169 { 01170 void *ret; 01171 01172 if (!cppobj) return NULL; 01173 01174 TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n", 01175 cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw); 01176 01177 /* To cast an object at runtime: 01178 * 1.Find out the true type of the object from the typeinfo at vtable[-1] 01179 * 2.Search for the destination type in the class hierarchy 01180 * 3.If destination type is found, return base object address + dest offset 01181 * Otherwise, fail the cast 01182 * 01183 * FIXME: the unknown parameter doesn't seem to be used for anything 01184 */ 01185 __TRY 01186 { 01187 int i; 01188 const rtti_object_locator *obj_locator = get_obj_locator( cppobj ); 01189 const rtti_object_hierarchy *obj_bases = obj_locator->type_hierarchy; 01190 const rtti_base_descriptor * const* base_desc = obj_bases->base_classes->bases; 01191 01192 if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator); 01193 01194 ret = NULL; 01195 for (i = 0; i < obj_bases->array_len; i++) 01196 { 01197 const type_info *typ = base_desc[i]->type_descriptor; 01198 01199 if (!strcmp(typ->mangled, dst->mangled)) 01200 { 01201 /* compute the correct this pointer for that base class */ 01202 void *this_ptr = (char *)cppobj - obj_locator->base_class_offset; 01203 ret = get_this_pointer( &base_desc[i]->offsets, this_ptr ); 01204 break; 01205 } 01206 } 01207 /* VC++ sets do_throw to 1 when the result of a dynamic_cast is assigned 01208 * to a reference, since references cannot be NULL. 01209 */ 01210 if (!ret && do_throw) 01211 { 01212 const char *msg = "Bad dynamic_cast!"; 01213 bad_cast e; 01214 MSVCRT_bad_cast_ctor( &e, &msg ); 01215 _CxxThrowException( &e, &bad_cast_exception_type ); 01216 } 01217 } 01218 __EXCEPT_PAGE_FAULT 01219 { 01220 __non_rtti_object e; 01221 MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" ); 01222 _CxxThrowException( &e, &bad_typeid_exception_type ); 01223 return NULL; 01224 } 01225 __ENDTRY 01226 return ret; 01227 } 01228 01229 01230 /****************************************************************** 01231 * __RTCastToVoid (MSVCRT.@) 01232 * 01233 * Dynamically cast a C++ object to a void*. 01234 * 01235 * PARAMS 01236 * cppobj [I] The C++ object to cast 01237 * 01238 * RETURNS 01239 * Success: The base address of the object as a void*. 01240 * Failure: NULL, if cppobj is NULL or has no RTTI. 01241 * 01242 * NOTES 01243 * This function is usually called by compiler generated code as a result 01244 * of using one of the C++ dynamic cast statements. 01245 */ 01246 void* CDECL MSVCRT___RTCastToVoid(void *cppobj) 01247 { 01248 void *ret; 01249 01250 if (!cppobj) return NULL; 01251 01252 __TRY 01253 { 01254 const rtti_object_locator *obj_locator = get_obj_locator( cppobj ); 01255 ret = (char *)cppobj - obj_locator->base_class_offset; 01256 } 01257 __EXCEPT_PAGE_FAULT 01258 { 01259 __non_rtti_object e; 01260 MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" ); 01261 _CxxThrowException( &e, &bad_typeid_exception_type ); 01262 return NULL; 01263 } 01264 __ENDTRY 01265 return ret; 01266 } Generated on Sun May 27 2012 04:36:27 for ReactOS by
1.7.6.1
|