/* * Copyright (C) 2007 Alexandre Julliard * Copyright (C) 2015 Iván Matellanes * * 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 "config.h" #include #include #include "msvcirt.h" #include "windef.h" #include "winbase.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msvcirt); #define RESERVE_SIZE 512 /* class streambuf */ typedef struct { const vtable_ptr *vtable; int allocated; int unbuffered; int stored_char; char *base; char *ebuf; char *pbase; char *pptr; char *epptr; char *eback; char *gptr; char *egptr; int do_lock; CRITICAL_SECTION lock; } streambuf; void __thiscall streambuf_setb(streambuf*, char*, char*, int); streambuf* __thiscall streambuf_setbuf(streambuf*, char*, int); void __thiscall streambuf_setg(streambuf*, char*, char*, char*); void __thiscall streambuf_setp(streambuf*, char*, char*); typedef struct { LPVOID VTable; } class_ios; typedef struct { LPVOID VTable; } class_ostream; typedef struct { LPVOID VTable; } class_strstreambuf; /* ??_7streambuf@@6B@ */ extern const vtable_ptr MSVCP_streambuf_vtable; #ifndef __GNUC__ void __asm_dummy_vtables(void) { #endif __ASM_VTABLE(streambuf, VTABLE_ADD_FUNC(streambuf_vector_dtor) VTABLE_ADD_FUNC(streambuf_sync) VTABLE_ADD_FUNC(streambuf_setbuf) VTABLE_ADD_FUNC(streambuf_seekoff) VTABLE_ADD_FUNC(streambuf_seekpos) VTABLE_ADD_FUNC(streambuf_xsputn) VTABLE_ADD_FUNC(streambuf_xsgetn) VTABLE_ADD_FUNC(streambuf_overflow) VTABLE_ADD_FUNC(streambuf_underflow) VTABLE_ADD_FUNC(streambuf_pbackfail) VTABLE_ADD_FUNC(streambuf_doallocate)); #ifndef __GNUC__ } #endif DEFINE_RTTI_DATA0(streambuf, 0, ".?AVstreambuf@@") /* ??0streambuf@@IAE@PADH@Z */ /* ??0streambuf@@IEAA@PEADH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_reserve_ctor, 12) streambuf* __thiscall streambuf_reserve_ctor(streambuf *this, char *buffer, int length) { TRACE("(%p %p %d)\n", this, buffer, length); this->vtable = &MSVCP_streambuf_vtable; this->allocated = 0; this->stored_char = EOF; this->do_lock = -1; this->base = NULL; streambuf_setbuf(this, buffer, length); streambuf_setg(this, NULL, NULL, NULL); streambuf_setp(this, NULL, NULL); InitializeCriticalSection(&this->lock); return this; } /* ??0streambuf@@IAE@XZ */ /* ??0streambuf@@IEAA@XZ */ DEFINE_THISCALL_WRAPPER(streambuf_ctor, 4) streambuf* __thiscall streambuf_ctor(streambuf *this) { streambuf_reserve_ctor(this, NULL, 0); this->unbuffered = 0; return this; } /* ??0streambuf@@QAE@ABV0@@Z */ /* ??0streambuf@@QEAA@AEBV0@@Z */ DEFINE_THISCALL_WRAPPER(streambuf_copy_ctor, 8) streambuf* __thiscall streambuf_copy_ctor(streambuf *this, const streambuf *copy) { TRACE("(%p %p)\n", this, copy); *this = *copy; this->vtable = &MSVCP_streambuf_vtable; return this; } /* ??1streambuf@@UAE@XZ */ /* ??1streambuf@@UEAA@XZ */ DEFINE_THISCALL_WRAPPER(streambuf_dtor, 4) void __thiscall streambuf_dtor(streambuf *this) { TRACE("(%p)\n", this); if (this->allocated) MSVCRT_operator_delete(this->base); DeleteCriticalSection(&this->lock); } /* ??4streambuf@@QAEAAV0@ABV0@@Z */ /* ??4streambuf@@QEAAAEAV0@AEBV0@@Z */ DEFINE_THISCALL_WRAPPER(streambuf_assign, 8) streambuf* __thiscall streambuf_assign(streambuf *this, const streambuf *rhs) { streambuf_dtor(this); return streambuf_copy_ctor(this, rhs); } /* ??_Estreambuf@@UAEPAXI@Z */ DEFINE_THISCALL_WRAPPER(streambuf_vector_dtor, 8) streambuf* __thiscall streambuf_vector_dtor(streambuf *this, unsigned int flags) { TRACE("(%p %x)\n", this, flags); if (flags & 2) { /* we have an array, with the number of elements stored before the first object */ INT_PTR i, *ptr = (INT_PTR *)this-1; for (i = *ptr-1; i >= 0; i--) streambuf_dtor(this+i); MSVCRT_operator_delete(ptr); } else { streambuf_dtor(this); if (flags & 1) MSVCRT_operator_delete(this); } return this; } /* ??_Gstreambuf@@UAEPAXI@Z */ DEFINE_THISCALL_WRAPPER(streambuf_scalar_dtor, 8) streambuf* __thiscall streambuf_scalar_dtor(streambuf *this, unsigned int flags) { TRACE("(%p %x)\n", this, flags); streambuf_dtor(this); if (flags & 1) MSVCRT_operator_delete(this); return this; } /* ?doallocate@streambuf@@MAEHXZ */ /* ?doallocate@streambuf@@MEAAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_doallocate, 4) #define call_streambuf_doallocate(this) CALL_VTBL_FUNC(this, 40, int, (streambuf*), (this)) int __thiscall streambuf_doallocate(streambuf *this) { char *reserve; TRACE("(%p)\n", this); reserve = MSVCRT_operator_new(RESERVE_SIZE); if (!reserve) return EOF; streambuf_setb(this, reserve, reserve + RESERVE_SIZE, 1); return 1; } /* ?allocate@streambuf@@IAEHXZ */ /* ?allocate@streambuf@@IEAAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_allocate, 4) int __thiscall streambuf_allocate(streambuf *this) { TRACE("(%p)\n", this); if (this->base != NULL || this->unbuffered) return 0; return call_streambuf_doallocate(this); } /* ?base@streambuf@@IBEPADXZ */ /* ?base@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_base, 4) char* __thiscall streambuf_base(const streambuf *this) { TRACE("(%p)\n", this); return this->base; } /* ?blen@streambuf@@IBEHXZ */ /* ?blen@streambuf@@IEBAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_blen, 4) int __thiscall streambuf_blen(const streambuf *this) { TRACE("(%p)\n", this); return this->ebuf - this->base; } /* ?eback@streambuf@@IBEPADXZ */ /* ?eback@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_eback, 4) char* __thiscall streambuf_eback(const streambuf *this) { TRACE("(%p)\n", this); return this->eback; } /* ?ebuf@streambuf@@IBEPADXZ */ /* ?ebuf@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_ebuf, 4) char* __thiscall streambuf_ebuf(const streambuf *this) { TRACE("(%p)\n", this); return this->ebuf; } /* ?egptr@streambuf@@IBEPADXZ */ /* ?egptr@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_egptr, 4) char* __thiscall streambuf_egptr(const streambuf *this) { TRACE("(%p)\n", this); return this->egptr; } /* ?epptr@streambuf@@IBEPADXZ */ /* ?epptr@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_epptr, 4) char* __thiscall streambuf_epptr(const streambuf *this) { TRACE("(%p)\n", this); return this->epptr; } /* ?gptr@streambuf@@IBEPADXZ */ /* ?gptr@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_gptr, 4) char* __thiscall streambuf_gptr(const streambuf *this) { TRACE("(%p)\n", this); return this->gptr; } /* ?pbase@streambuf@@IBEPADXZ */ /* ?pbase@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_pbase, 4) char* __thiscall streambuf_pbase(const streambuf *this) { TRACE("(%p)\n", this); return this->pbase; } /* ?pptr@streambuf@@IBEPADXZ */ /* ?pptr@streambuf@@IEBAPEADXZ */ DEFINE_THISCALL_WRAPPER(streambuf_pptr, 4) char* __thiscall streambuf_pptr(const streambuf *this) { TRACE("(%p)\n", this); return this->pptr; } /* ?clrlock@streambuf@@QAEXXZ */ /* ?clrlock@streambuf@@QEAAXXZ */ DEFINE_THISCALL_WRAPPER(streambuf_clrlock, 4) void __thiscall streambuf_clrlock(streambuf *this) { TRACE("(%p)\n", this); if (this->do_lock <= 0) this->do_lock++; } /* ?lock@streambuf@@QAEXXZ */ /* ?lock@streambuf@@QEAAXXZ */ DEFINE_THISCALL_WRAPPER(streambuf_lock, 4) void __thiscall streambuf_lock(streambuf *this) { TRACE("(%p)\n", this); if (this->do_lock < 0) EnterCriticalSection(&this->lock); } /* ?lockptr@streambuf@@IAEPAU_CRT_CRITICAL_SECTION@@XZ */ /* ?lockptr@streambuf@@IEAAPEAU_CRT_CRITICAL_SECTION@@XZ */ DEFINE_THISCALL_WRAPPER(streambuf_lockptr, 4) CRITICAL_SECTION* __thiscall streambuf_lockptr(streambuf *this) { TRACE("(%p)\n", this); return &this->lock; } /* ?gbump@streambuf@@IAEXH@Z */ /* ?gbump@streambuf@@IEAAXH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_gbump, 8) void __thiscall streambuf_gbump(streambuf *this, int count) { TRACE("(%p %d)\n", this, count); this->gptr += count; } /* ?pbump@streambuf@@IAEXH@Z */ /* ?pbump@streambuf@@IEAAXH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_pbump, 8) void __thiscall streambuf_pbump(streambuf *this, int count) { TRACE("(%p %d)\n", this, count); this->pptr += count; } /* ?in_avail@streambuf@@QBEHXZ */ /* ?in_avail@streambuf@@QEBAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_in_avail, 4) int __thiscall streambuf_in_avail(const streambuf *this) { TRACE("(%p)\n", this); return this->egptr - this->gptr; } /* ?out_waiting@streambuf@@QBEHXZ */ /* ?out_waiting@streambuf@@QEBAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_out_waiting, 4) int __thiscall streambuf_out_waiting(const streambuf *this) { TRACE("(%p)\n", this); return this->pptr - this->pbase; } /* Unexported */ DEFINE_THISCALL_WRAPPER(streambuf_overflow, 8) #define call_streambuf_overflow(this, c) CALL_VTBL_FUNC(this, 28, int, (streambuf*, int), (this, c)) int __thiscall streambuf_overflow(streambuf *this, int c) { ERR("overflow is not implemented in streambuf\n"); return EOF; } /* ?pbackfail@streambuf@@UAEHH@Z */ /* ?pbackfail@streambuf@@UEAAHH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_pbackfail, 8) int __thiscall streambuf_pbackfail(streambuf *this, int c) { FIXME("(%p %d): stub\n", this, c); return 0; } /* ?seekoff@streambuf@@UAEJJW4seek_dir@ios@@H@Z */ /* ?seekoff@streambuf@@UEAAJJW4seek_dir@ios@@H@Z */ DEFINE_THISCALL_WRAPPER(streambuf_seekoff, 16) #define call_streambuf_seekoff(this, off, dir, mode) CALL_VTBL_FUNC(this, 12, streampos, (streambuf*, streamoff, ios_seek_dir, int), (this, off, dir, mode)) streampos __thiscall streambuf_seekoff(streambuf *this, streamoff offset, ios_seek_dir dir, int mode) { TRACE("(%p %d %d %d)\n", this, offset, dir, mode); return EOF; } /* ?seekpos@streambuf@@UAEJJH@Z */ /* ?seekpos@streambuf@@UEAAJJH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_seekpos, 12) streampos __thiscall streambuf_seekpos(streambuf *this, streampos pos, int mode) { TRACE("(%p %d %d)\n", this, pos, mode); return call_streambuf_seekoff(this, pos, SEEKDIR_beg, mode); } /* ?setb@streambuf@@IAEXPAD0H@Z */ /* ?setb@streambuf@@IEAAXPEAD0H@Z */ DEFINE_THISCALL_WRAPPER(streambuf_setb, 16) void __thiscall streambuf_setb(streambuf *this, char *ba, char *eb, int delete) { TRACE("(%p %p %p %d)\n", this, ba, eb, delete); if (this->allocated) MSVCRT_operator_delete(this->base); this->allocated = delete; this->base = ba; this->ebuf = eb; } /* ?setbuf@streambuf@@UAEPAV1@PADH@Z */ /* ?setbuf@streambuf@@UEAAPEAV1@PEADH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_setbuf, 12) streambuf* __thiscall streambuf_setbuf(streambuf *this, char *buffer, int length) { TRACE("(%p %p %d)\n", this, buffer, length); if (this->base != NULL) return NULL; if (buffer == NULL || !length) { this->unbuffered = 1; this->base = this->ebuf = NULL; } else { this->unbuffered = 0; this->base = buffer; this->ebuf = buffer + length; } return this; } /* ?setg@streambuf@@IAEXPAD00@Z */ /* ?setg@streambuf@@IEAAXPEAD00@Z */ DEFINE_THISCALL_WRAPPER(streambuf_setg, 16) void __thiscall streambuf_setg(streambuf *this, char *ek, char *gp, char *eg) { TRACE("(%p %p %p %p)\n", this, ek, gp, eg); this->eback = ek; this->gptr = gp; this->egptr = eg; } /* ?setlock@streambuf@@QAEXXZ */ /* ?setlock@streambuf@@QEAAXXZ */ DEFINE_THISCALL_WRAPPER(streambuf_setlock, 4) void __thiscall streambuf_setlock(streambuf *this) { TRACE("(%p)\n", this); this->do_lock--; } /* ?setp@streambuf@@IAEXPAD0@Z */ /* ?setp@streambuf@@IEAAXPEAD0@Z */ DEFINE_THISCALL_WRAPPER(streambuf_setp, 12) void __thiscall streambuf_setp(streambuf *this, char *pb, char *ep) { TRACE("(%p %p %p)\n", this, pb, ep); this->pbase = this->pptr = pb; this->epptr = ep; } /* ?sync@streambuf@@UAEHXZ */ /* ?sync@streambuf@@UEAAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_sync, 4) int __thiscall streambuf_sync(streambuf *this) { TRACE("(%p)\n", this); return (this->gptr >= this->egptr && this->pbase >= this->pptr) ? 0 : EOF; } /* ?unbuffered@streambuf@@IAEXH@Z */ /* ?unbuffered@streambuf@@IEAAXH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_unbuffered_set, 8) void __thiscall streambuf_unbuffered_set(streambuf *this, int buf) { TRACE("(%p %d)\n", this, buf); this->unbuffered = buf; } /* ?unbuffered@streambuf@@IBEHXZ */ /* ?unbuffered@streambuf@@IEBAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_unbuffered_get, 4) int __thiscall streambuf_unbuffered_get(const streambuf *this) { TRACE("(%p)\n", this); return this->unbuffered; } /* Unexported */ DEFINE_THISCALL_WRAPPER(streambuf_underflow, 4) #define call_streambuf_underflow(this) CALL_VTBL_FUNC(this, 32, int, (streambuf*), (this)) int __thiscall streambuf_underflow(streambuf *this) { ERR("underflow is not implemented in streambuf\n"); return EOF; } /* ?unlock@streambuf@@QAEXXZ */ /* ?unlock@streambuf@@QEAAXXZ */ DEFINE_THISCALL_WRAPPER(streambuf_unlock, 4) void __thiscall streambuf_unlock(streambuf *this) { TRACE("(%p)\n", this); if (this->do_lock < 0) LeaveCriticalSection(&this->lock); } /* ?xsgetn@streambuf@@UAEHPADH@Z */ /* ?xsgetn@streambuf@@UEAAHPEADH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_xsgetn, 12) #define call_streambuf_xsgetn(this, buffer, count) CALL_VTBL_FUNC(this, 24, int, (streambuf*, char*, int), (this, buffer, count)) int __thiscall streambuf_xsgetn(streambuf *this, char *buffer, int count) { int copied = 0, chunk; TRACE("(%p %p %d)\n", this, buffer, count); if (this->unbuffered) { if (this->stored_char == EOF) this->stored_char = call_streambuf_underflow(this); while (copied < count && this->stored_char != EOF) { buffer[copied++] = this->stored_char; this->stored_char = call_streambuf_underflow(this); } } else { while (copied < count) { if (call_streambuf_underflow(this) == EOF) break; chunk = this->egptr - this->gptr; if (chunk > count - copied) chunk = count - copied; memcpy(buffer+copied, this->gptr, chunk); this->gptr += chunk; copied += chunk; } } return copied; } /* ?xsputn@streambuf@@UAEHPBDH@Z */ /* ?xsputn@streambuf@@UEAAHPEBDH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_xsputn, 12) #define call_streambuf_xsputn(this, data, length) CALL_VTBL_FUNC(this, 20, int, (streambuf*, const char*, int), (this, data, length)) int __thiscall streambuf_xsputn(streambuf *this, const char *data, int length) { int copied = 0, chunk; TRACE("(%p %p %d)\n", this, data, length); while (copied < length) { if (this->unbuffered || this->pptr == this->epptr) { if (call_streambuf_overflow(this, data[copied]) == EOF) break; copied++; } else { chunk = this->epptr - this->pptr; if (chunk > length - copied) chunk = length - copied; memcpy(this->pptr, data+copied, chunk); this->pptr += chunk; copied += chunk; } } return copied; } /* ?sgetc@streambuf@@QAEHXZ */ /* ?sgetc@streambuf@@QEAAHXZ */ DEFINE_THISCALL_WRAPPER(streambuf_sgetc, 4) int __thiscall streambuf_sgetc(streambuf *this) { TRACE("(%p)\n", this); if (this->unbuffered) { if (this->stored_char == EOF) this->stored_char = call_streambuf_underflow(this); return this->stored_char; } else return call_streambuf_underflow(this); } /* ?sputc@streambuf@@QAEHH@Z */ /* ?sputc@streambuf@@QEAAHH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_sputc, 8) int __thiscall streambuf_sputc(streambuf *this, int ch) { TRACE("(%p %d)\n", this, ch); return (this->pptr < this->epptr) ? *this->pptr++ = ch : call_streambuf_overflow(this, ch); } /* ?sgetn@streambuf@@QAEHPADH@Z */ /* ?sgetn@streambuf@@QEAAHPEADH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_sgetn, 12) int __thiscall streambuf_sgetn(streambuf *this, char *buffer, int count) { return call_streambuf_xsgetn(this, buffer, count); } /* ?sputn@streambuf@@QAEHPBDH@Z */ /* ?sputn@streambuf@@QEAAHPEBDH@Z */ DEFINE_THISCALL_WRAPPER(streambuf_sputn, 12) int __thiscall streambuf_sputn(streambuf *this, const char *data, int length) { return call_streambuf_xsputn(this, data, length); } /****************************************************************** * ??1ios@@UAE@XZ (MSVCRTI.@) * class ios & __thiscall ios::-ios<<(void) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_ios_sl_void,4) void * __thiscall MSVCIRT_ios_sl_void(class_ios * _this) { FIXME("(%p) stub\n", _this); return _this; } /****************************************************************** * ??0ostrstream@@QAE@XZ (MSVCRTI.@) * class ostream & __thiscall ostrstream::ostrstream<<(void) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_ostrstream_sl_void,4) void * __thiscall MSVCIRT_ostrstream_sl_void(class_ostream * _this) { FIXME("(%p) stub\n", _this); return _this; } /****************************************************************** * ??6ostream@@QAEAAV0@E@Z (MSVCRTI.@) * class ostream & __thiscall ostream::operator<<(unsigned char) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_uchar,8) void * __thiscall MSVCIRT_operator_sl_uchar(class_ostream * _this, unsigned char ch) { FIXME("(%p)->(%c) stub\n", _this, ch); return _this; } /****************************************************************** * ??6ostream@@QAEAAV0@H@Z (MSVCRTI.@) * class ostream & __thiscall ostream::operator<<(int) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_int,8) void * __thiscall MSVCIRT_operator_sl_int(class_ostream * _this, int integer) { FIXME("(%p)->(%d) stub\n", _this, integer); return _this; } /****************************************************************** * ??6ostream@@QAEAAV0@PBD@Z (MSVCRTI.@) * class ostream & __thiscall ostream::operator<<(char const *) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_pchar,8) void * __thiscall MSVCIRT_operator_sl_pchar(class_ostream * _this, const char * string) { FIXME("(%p)->(%s) stub\n", _this, debugstr_a(string)); return _this; } /****************************************************************** * ??6ostream@@QAEAAV0@P6AAAV0@AAV0@@Z@Z (MSVCRTI.@) * class ostream & __thiscall ostream::operator<<(class ostream & (__cdecl*)(class ostream &)) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_callback,8) void * __thiscall MSVCIRT_operator_sl_callback(class_ostream * _this, class_ostream * (__cdecl*func)(class_ostream*)) { TRACE("%p, %p\n", _this, func); return func(_this); } /****************************************************************** * ?endl@@YAAAVostream@@AAV1@@Z (MSVCRTI.@) * class ostream & __cdecl endl(class ostream &) */ void * CDECL MSVCIRT_endl(class_ostream * _this) { FIXME("(%p)->() stub\n", _this); return _this; } /****************************************************************** * ?ends@@YAAAVostream@@AAV1@@Z (MSVCRTI.@) * class ostream & __cdecl ends(class ostream &) */ void * CDECL MSVCIRT_ends(class_ostream * _this) { FIXME("(%p)->() stub\n", _this); return _this; } /****************************************************************** * ?str@strstreambuf@@QAEPADXZ (MSVCRTI.@) * class strstreambuf & __thiscall strstreambuf::str(class strstreambuf &) */ DEFINE_THISCALL_WRAPPER(MSVCIRT_str_sl_void,4) char * __thiscall MSVCIRT_str_sl_void(class_strstreambuf * _this) { FIXME("(%p)->() stub\n", _this); return 0; } #ifdef __i386__ #define DEFINE_VTBL_WRAPPER(off) \ __ASM_GLOBAL_FUNC(vtbl_wrapper_ ## off, \ "popl %eax\n\t" \ "popl %ecx\n\t" \ "pushl %eax\n\t" \ "movl 0(%ecx), %eax\n\t" \ "jmp *" #off "(%eax)\n\t") DEFINE_VTBL_WRAPPER(0); DEFINE_VTBL_WRAPPER(4); DEFINE_VTBL_WRAPPER(8); DEFINE_VTBL_WRAPPER(12); DEFINE_VTBL_WRAPPER(16); DEFINE_VTBL_WRAPPER(20); DEFINE_VTBL_WRAPPER(24); DEFINE_VTBL_WRAPPER(28); DEFINE_VTBL_WRAPPER(32); DEFINE_VTBL_WRAPPER(36); DEFINE_VTBL_WRAPPER(40); DEFINE_VTBL_WRAPPER(44); DEFINE_VTBL_WRAPPER(48); DEFINE_VTBL_WRAPPER(52); DEFINE_VTBL_WRAPPER(56); #endif void* (__cdecl *MSVCRT_operator_new)(SIZE_T); void (__cdecl *MSVCRT_operator_delete)(void*); static void init_cxx_funcs(void) { HMODULE hmod = GetModuleHandleA("msvcrt.dll"); if (sizeof(void *) > sizeof(int)) /* 64-bit has different names */ { MSVCRT_operator_new = (void*)GetProcAddress(hmod, "??2@YAPEAX_K@Z"); MSVCRT_operator_delete = (void*)GetProcAddress(hmod, "??3@YAXPEAX@Z"); } else { MSVCRT_operator_new = (void*)GetProcAddress(hmod, "??2@YAPAXI@Z"); MSVCRT_operator_delete = (void*)GetProcAddress(hmod, "??3@YAXPAX@Z"); } } static void init_io(void *base) { #ifdef __x86_64__ init_streambuf_rtti(base); #endif } BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { switch (reason) { case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: init_cxx_funcs(); init_exception(inst); init_io(inst); DisableThreadLibraryCalls( inst ); break; } return TRUE; }