[PATCH v3] msvcirt: Implement most of ifstream.

Arkadiusz Hiler ahiler at codeweavers.com
Wed Sep 2 11:13:33 CDT 2020


Based on semi-stubs by Gijs Vermeulen.

Tested with Power Tab Editor and GraphCalc - the crashes are gone and loading
saved files seems to work correctly.

ifstream::setbuf() is left as a stub - it will need some changes to
filebuf::setbuf() first.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22616
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30014
Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
---

v3:
 * constructors now return NULL and print a FIXME in OOM cases
 * ifstream_open_ctor and ifstream_open now come with implicit OPENMODE_in
 * IOSTATE is now handled in open, close and attach
 * test for IOSTATE changes as well as for lack of them
 * win32: fixed compilation warnings
 * fixed psb/pfb mixup

v2:
 * use correct mangled symbols in the comment on top of setmode
 * set p_ifstream_dtor and p_ifstream_vbase_dtor in win32 path

 dlls/msvcirt/msvcirt.c       | 182 +++++++++++++++++++++++++
 dlls/msvcirt/msvcirt.spec    |  68 +++++-----
 dlls/msvcirt/tests/msvcirt.c | 249 +++++++++++++++++++++++++++++++++++
 dlls/msvcrt20/msvcrt20.spec  |  68 +++++-----
 dlls/msvcrt40/msvcrt40.spec  |  68 +++++-----
 5 files changed, 533 insertions(+), 102 deletions(-)

diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index f76eaf6d7ac..4c3bf8eb653 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -192,6 +192,8 @@ extern const vtable_ptr MSVCP_istream_vtable;
 extern const vtable_ptr MSVCP_istream_withassign_vtable;
 /* ??_7istrstream@@6B@ */
 extern const vtable_ptr MSVCP_istrstream_vtable;
+/* ??_7ifstream@@6B@ */
+extern const vtable_ptr MSVCP_ifstream_vtable;
 /* ??_7iostream@@6B@ */
 extern const vtable_ptr MSVCP_iostream_vtable;
 /* ??_7strstream@@6B@ */
@@ -262,6 +264,8 @@ __ASM_BLOCK_BEGIN(vtables)
             VTABLE_ADD_FUNC(istream_vector_dtor));
     __ASM_VTABLE(istrstream,
             VTABLE_ADD_FUNC(istream_vector_dtor));
+    __ASM_VTABLE(ifstream,
+            VTABLE_ADD_FUNC(istream_vector_dtor));
     __ASM_VTABLE(iostream,
             VTABLE_ADD_FUNC(iostream_vector_dtor));
     __ASM_VTABLE(strstream,
@@ -280,6 +284,7 @@ const int ostream_vbtable[] = {0, VBTABLE_ENTRY(ostream, FIELD_OFFSET(ostream, v
 /* ??_8istream@@7B@ */
 /* ??_8istream_withassign@@7B@ */
 /* ??_8istrstream@@7B@ */
+/* ??_8ifstream@@7B@ */
 const int istream_vbtable[] = {0, VBTABLE_ENTRY(istream, FIELD_OFFSET(istream, vbtable), ios)};
 /* ??_8iostream@@7Bistream@@@ */
 /* ??_8stdiostream@@7Bistream@@@ */
@@ -305,6 +310,8 @@ DEFINE_RTTI_DATA2(istream_withassign, sizeof(istream),
     &istream_rtti_base_descriptor, &ios_rtti_base_descriptor, ".?AVistream_withassign@@")
 DEFINE_RTTI_DATA2(istrstream, sizeof(istream),
     &istream_rtti_base_descriptor, &ios_rtti_base_descriptor, ".?AVistrstream@@")
+DEFINE_RTTI_DATA2(ifstream, sizeof(istream),
+    &istream_rtti_base_descriptor, &ios_rtti_base_descriptor, ".?AVifstream@@")
 DEFINE_RTTI_DATA4(iostream, sizeof(iostream),
     &istream_rtti_base_descriptor, &ios_rtti_base_descriptor,
     &ostream_rtti_base_descriptor, &ios_rtti_base_descriptor, ".?AViostream@@")
@@ -3113,6 +3120,8 @@ istream* __thiscall istream_copy_ctor(istream *this, const istream *copy, BOOL v
 /* ??1istream_withassign@@UEAA at XZ */
 /* ??1istrstream@@UAE at XZ */
 /* ??1istrstream@@UEAA at XZ */
+/* ??1ifstream@@UAE at XZ */
+/* ??1ifstream@@UEAA at XZ */
 DEFINE_THISCALL_WRAPPER(istream_dtor, 4)
 void __thiscall istream_dtor(ios *base)
 {
@@ -3152,6 +3161,8 @@ istream* __thiscall istream_assign_sb(istream *this, streambuf *sb)
 /* ??4istream_withassign@@QEAAAEAVistream@@AEBV1@@Z */
 /* ??4istrstream@@QAEAAV0 at ABV0@@Z */
 /* ??4istrstream@@QEAAAEAV0 at AEBV0@@Z */
+/* ??4ifstream@@QAEAAV0 at ABV0@@Z */
+/* ??4ifstream@@QEAAAEAV0 at AEBV0@@Z */
 DEFINE_THISCALL_WRAPPER(istream_assign, 8)
 istream* __thiscall istream_assign(istream *this, const istream *rhs)
 {
@@ -3164,6 +3175,8 @@ istream* __thiscall istream_assign(istream *this, const istream *rhs)
 /* ??_Distream_withassign@@QEAAXXZ */
 /* ??_Distrstream@@QAEXXZ */
 /* ??_Distrstream@@QEAAXXZ */
+/* ??_Difstream@@QAEXXZ */
+/* ??_Difstream@@QEAAXXZ */
 DEFINE_THISCALL_WRAPPER(istream_vbase_dtor, 4)
 void __thiscall istream_vbase_dtor(istream *this)
 {
@@ -3178,6 +3191,7 @@ void __thiscall istream_vbase_dtor(istream *this)
 /* ??_Eistream@@UAEPAXI at Z */
 /* ??_Eistream_withassign@@UAEPAXI at Z */
 /* ??_Eistrstream@@UAEPAXI at Z */
+/* ??_Eifstream@@UAEPAXI at Z */
 DEFINE_THISCALL_WRAPPER(istream_vector_dtor, 8)
 istream* __thiscall istream_vector_dtor(ios *base, unsigned int flags)
 {
@@ -3203,6 +3217,7 @@ istream* __thiscall istream_vector_dtor(ios *base, unsigned int flags)
 /* ??_Gistream@@UAEPAXI at Z */
 /* ??_Gistream_withassign@@UAEPAXI at Z */
 /* ??_Gistrstream@@UAEPAXI at Z */
+/* ??_Gifstream@@UAEPAXI at Z */
 DEFINE_THISCALL_WRAPPER(istream_scalar_dtor, 8)
 istream* __thiscall istream_scalar_dtor(ios *base, unsigned int flags)
 {
@@ -4089,6 +4104,172 @@ char* __thiscall istrstream_str(istream *this)
     return strstreambuf_str(istrstream_rdbuf(this));
 }
 
+/* ??0ifstream@@QAE at ABV0@@Z */
+/* ??0ifstream@@QEAA at AEBV0@@Z */
+DEFINE_THISCALL_WRAPPER(ifstream_copy_ctor, 12)
+istream* __thiscall ifstream_copy_ctor(istream *this, const istream *copy, BOOL virt_init)
+{
+    TRACE("(%p %p %d)\n", this, copy, virt_init);
+    istream_withassign_copy_ctor(this, copy, virt_init);
+    istream_get_ios(this)->vtable = &MSVCP_ifstream_vtable;
+    return this;
+}
+
+/* ??0ifstream@@QAE at HPADH@Z */
+/* ??0ifstream@@QEAA at HPEADH@Z */
+DEFINE_THISCALL_WRAPPER(ifstream_buffer_ctor, 20)
+istream* __thiscall ifstream_buffer_ctor(istream *this, filedesc fd, char *buffer, int length, BOOL virt_init)
+{
+    ios *base;
+    filebuf *fb = MSVCRT_operator_new(sizeof(filebuf));
+
+    TRACE("(%p %d %p %d %d)\n", this, fd, buffer, length, virt_init);
+
+    if (!fb)
+    {
+        FIXME("out of memory\n");
+        return NULL;
+    }
+
+    filebuf_fd_reserve_ctor(fb, fd, buffer, length);
+    istream_sb_ctor(this, &fb->base, virt_init);
+
+    base = istream_get_ios(this);
+    base->vtable = &MSVCP_ifstream_vtable;
+    base->delbuf = 1;
+
+    return this;
+}
+
+/* ??0ifstream@@QAE at H@Z */
+/* ??0ifstream@@QEAA at H@Z */
+DEFINE_THISCALL_WRAPPER(ifstream_fd_ctor, 12)
+istream* __thiscall ifstream_fd_ctor(istream *this, filedesc fd, BOOL virt_init)
+{
+    ios *base;
+    filebuf *fb = MSVCRT_operator_new(sizeof(filebuf));
+
+    TRACE("(%p %d %d)\n", this, fd, virt_init);
+
+    if (!fb)
+    {
+        FIXME("out of memory\n");
+        return NULL;
+    }
+
+    filebuf_fd_ctor(fb, fd);
+    istream_sb_ctor(this, &fb->base, virt_init);
+
+    base = istream_get_ios(this);
+    base->vtable = &MSVCP_ifstream_vtable;
+    base->delbuf = 1;
+
+    return this;
+}
+
+/* ??0ifstream@@QAE at PBDHH@Z */
+/* ??0ifstream@@QEAA at PEBDHH@Z */
+DEFINE_THISCALL_WRAPPER(ifstream_open_ctor, 20)
+istream* __thiscall ifstream_open_ctor(istream *this, const char *name, ios_open_mode mode, int protection, BOOL virt_init)
+{
+    ios *base;
+    filebuf *fb = MSVCRT_operator_new(sizeof(filebuf));
+
+    TRACE("(%p %s %d %d %d)\n", this, name, mode, protection, virt_init);
+
+    if (!fb)
+    {
+        FIXME("out of memory\n");
+        return NULL;
+    }
+
+    filebuf_ctor(fb);
+    istream_sb_ctor(this, &fb->base, virt_init);
+    filebuf_open(fb, name, mode|OPENMODE_in, protection);
+
+    base = istream_get_ios(this);
+    base->vtable = &MSVCP_ifstream_vtable;
+    base->delbuf = 1;
+
+    return this;
+}
+
+/* ??0ifstream@@QAE at XZ */
+/* ??0ifstream@@QEAA at XZ */
+DEFINE_THISCALL_WRAPPER(ifstream_ctor, 8)
+istream* __thiscall ifstream_ctor(istream *this, BOOL virt_init)
+{
+    return ifstream_fd_ctor(this, -1, virt_init);
+}
+
+/* ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ */
+/* ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ */
+DEFINE_THISCALL_WRAPPER(ifstream_rdbuf, 4)
+filebuf* __thiscall ifstream_rdbuf(const istream *this)
+{
+    TRACE("(%p)\n", this);
+    return (filebuf*) istream_get_ios(this)->sb;
+}
+
+/* ?fd at ifstream@@QBEHXZ */
+/* ?fd at ifstream@@QEBAHXZ */
+DEFINE_THISCALL_WRAPPER(ifstream_fd, 4)
+filedesc __thiscall ifstream_fd(istream *this)
+{
+    TRACE("(%p)\n", this);
+    return filebuf_fd(ifstream_rdbuf(this));
+}
+
+/* ?attach at ifstream@@QAEXH at Z */
+/* ?attach at ifstream@@QEAAXH at Z */
+DEFINE_THISCALL_WRAPPER(ifstream_attach, 8)
+void __thiscall ifstream_attach(istream *this, filedesc fd)
+{
+    TRACE("(%p %d)\n", this, fd);
+    if (filebuf_attach(ifstream_rdbuf(this), fd) == NULL)
+        ios_clear(istream_get_ios(this), IOSTATE_failbit);
+}
+
+/* ?close at ifstream@@QAEXXZ */
+/* ?close at ifstream@@QEAAXXZ */
+DEFINE_THISCALL_WRAPPER(ifstream_close, 4)
+void __thiscall ifstream_close(istream *this)
+{
+    TRACE("(%p)\n", this);
+    if (filebuf_close(ifstream_rdbuf(this)) == NULL)
+        ios_clear(istream_get_ios(this), IOSTATE_failbit);
+    else
+        ios_clear(istream_get_ios(this), IOSTATE_goodbit);
+}
+
+/* ?is_open at ifstream@@QBEHXZ */
+/* ?is_open at ifstream@@QEBAHXZ */
+DEFINE_THISCALL_WRAPPER(ifstream_is_open, 4)
+int __thiscall ifstream_is_open(const istream *this)
+{
+    TRACE("(%p)\n", this);
+    return filebuf_is_open(ifstream_rdbuf(this));
+}
+
+/* ?open at ifstream@@QAEXPBDHH at Z */
+/* ?open at ifstream@@QEAAXPEBDHH at Z */
+DEFINE_THISCALL_WRAPPER(ifstream_open, 16)
+void __thiscall ifstream_open(istream *this, const char *name, ios_open_mode mode, int protection)
+{
+    TRACE("(%p %s %d %d)\n", this, name, mode, protection);
+    if (filebuf_open(ifstream_rdbuf(this), name, mode|OPENMODE_in, protection) == NULL)
+        ios_clear(istream_get_ios(this), IOSTATE_failbit);
+}
+
+/* ?setmode at ifstream@@QAEHH at Z */
+/* ?setmode at ifstream@@QEAAHH at Z */
+DEFINE_THISCALL_WRAPPER(ifstream_setmode, 8)
+int __thiscall ifstream_setmode(istream *this, int mode)
+{
+    TRACE("(%p %d)\n", this, mode);
+    return filebuf_setmode(ifstream_rdbuf(this), mode);
+}
+
 static inline ios* iostream_to_ios(const iostream *this)
 {
     return (ios*)((char*)this + iostream_vbtable_istream[1]);
@@ -4522,6 +4703,7 @@ static void init_io(void *base)
     init_istream_rtti(base);
     init_istream_withassign_rtti(base);
     init_istrstream_rtti(base);
+    init_ifstream_rtti(base);
     init_iostream_rtti(base);
     init_strstream_rtti(base);
     init_stdiostream_rtti(base);
diff --git a/dlls/msvcirt/msvcirt.spec b/dlls/msvcirt/msvcirt.spec
index f2e875695ef..75ae312b486 100644
--- a/dlls/msvcirt/msvcirt.spec
+++ b/dlls/msvcirt/msvcirt.spec
@@ -26,16 +26,16 @@
 @ stub -arch=win64 ??0fstream@@QEAA at PEBDHH@Z
 @ stub -arch=win32 ??0fstream@@QAE at XZ  # __thiscall fstream::fstream(void)
 @ stub -arch=win64 ??0fstream@@QEAA at XZ
-@ stub -arch=win32 ??0ifstream@@QAE at ABV0@@Z  # __thiscall ifstream::ifstream(class ifstream const &)
-@ stub -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z
-@ stub -arch=win32 ??0ifstream@@QAE at H@Z  # __thiscall ifstream::ifstream(int)
-@ stub -arch=win64 ??0ifstream@@QEAA at H@Z
-@ stub -arch=win32 ??0ifstream@@QAE at HPADH@Z  # __thiscall ifstream::ifstream(int,char *,int)
-@ stub -arch=win64 ??0ifstream@@QEAA at HPEADH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at PBDHH@Z  # __thiscall ifstream::ifstream(char const *,int,int)
-@ stub -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at XZ  # __thiscall ifstream::ifstream(void)
-@ stub -arch=win64 ??0ifstream@@QEAA at XZ
+@ thiscall -arch=win32 ??0ifstream@@QAE at ABV0@@Z(ptr ptr long) ifstream_copy_ctor
+@ cdecl -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z(ptr ptr long) ifstream_copy_ctor
+@ thiscall -arch=win32 ??0ifstream@@QAE at H@Z(ptr long long) ifstream_fd_ctor
+@ cdecl -arch=win64 ??0ifstream@@QEAA at H@Z(ptr long long) ifstream_fd_ctor
+@ thiscall -arch=win32 ??0ifstream@@QAE at HPADH@Z(ptr long ptr long long) ifstream_buffer_ctor
+@ cdecl -arch=win64 ??0ifstream@@QEAA at HPEADH@Z(ptr long ptr long long) ifstream_buffer_ctor
+@ thiscall -arch=win32 ??0ifstream@@QAE at PBDHH@Z(ptr str long long long) ifstream_open_ctor
+@ cdecl -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z(ptr str long long long) ifstream_open_ctor
+@ thiscall -arch=win32 ??0ifstream@@QAE at XZ(ptr long) ifstream_ctor
+@ cdecl -arch=win64 ??0ifstream@@QEAA at XZ(ptr long) ifstream_ctor
 @ thiscall -arch=win32 ??0ios@@IAE at ABV0@@Z(ptr ptr) ios_copy_ctor
 @ cdecl -arch=win64 ??0ios@@IEAA at AEBV0@@Z(ptr ptr) ios_copy_ctor
 @ thiscall -arch=win32 ??0ios@@IAE at XZ(ptr) ios_ctor
@@ -138,8 +138,8 @@
 @ cdecl -arch=win64 ??1filebuf@@UEAA at XZ(ptr) filebuf_dtor
 @ stub -arch=win32 ??1fstream@@UAE at XZ  # virtual __thiscall fstream::~fstream(void)
 @ stub -arch=win64 ??1fstream@@UEAA at XZ
-@ stub -arch=win32 ??1ifstream@@UAE at XZ  # virtual __thiscall ifstream::~ifstream(void)
-@ stub -arch=win64 ??1ifstream@@UEAA at XZ
+@ thiscall -arch=win32 ??1ifstream@@UAE at XZ(ptr) istream_dtor
+@ cdecl -arch=win64 ??1ifstream@@UEAA at XZ(ptr) istream_dtor
 @ thiscall -arch=win32 ??1ios@@UAE at XZ(ptr) ios_dtor
 @ cdecl -arch=win64 ??1ios@@UEAA at XZ(ptr) ios_dtor
 @ thiscall -arch=win32 ??1iostream@@UAE at XZ(ptr) iostream_dtor
@@ -178,8 +178,8 @@
 @ cdecl -arch=win64 ??4filebuf@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) filebuf_assign
 @ stub -arch=win32 ??4fstream@@QAEAAV0 at AAV0@@Z  # class fstream & __thiscall fstream::operator=(class fstream &)
 @ stub -arch=win64 ??4fstream@@QEAAAEAV0 at AEAV0@@Z
-@ stub -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z  # class ifstream & __thiscall ifstream::operator=(class ifstream const &)
-@ stub -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z
+@ thiscall -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z(ptr ptr) istream_assign
+@ cdecl -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) istream_assign
 @ thiscall -arch=win32 ??4ios@@IAEAAV0 at ABV0@@Z(ptr ptr) ios_assign
 @ cdecl -arch=win64 ??4ios@@IEAAAEAV0 at AEBV0@@Z(ptr ptr) ios_assign
 @ thiscall -arch=win32 ??4iostream@@IAEAAV0 at AAV0@@Z(ptr ptr) iostream_assign
@@ -305,7 +305,7 @@
 @ extern ??_7exception@@6B@ MSVCP_exception_vtable
 @ extern ??_7filebuf@@6B@ MSVCP_filebuf_vtable
 # @ extern ??_7fstream@@6B@  # const fstream::`vftable'
-# @ extern ??_7ifstream@@6B@  # const ifstream::`vftable'
+@ extern ??_7ifstream@@6B@ MSVCP_ifstream_vtable
 @ extern ??_7ios@@6B@ MSVCP_ios_vtable
 @ extern ??_7iostream@@6B@ MSVCP_iostream_vtable
 @ extern ??_7istream@@6B@ MSVCP_istream_vtable
@@ -323,7 +323,7 @@
 @ extern ??_7strstreambuf@@6B@ MSVCP_strstreambuf_vtable
 # @ extern ??_8fstream@@7Bistream@@@  # const fstream::`vbtable'{for `istream'}
 # @ extern ??_8fstream@@7Bostream@@@  # const fstream::`vbtable'{for `ostream'}
-# @ extern ??_8ifstream@@7B@  # const ifstream::`vbtable'
+@ extern ??_8ifstream@@7B@ istream_vbtable
 @ extern ??_8iostream@@7Bistream@@@ iostream_vbtable_istream
 @ extern ??_8iostream@@7Bostream@@@ iostream_vbtable_ostream
 @ extern ??_8istream@@7B@ istream_vbtable
@@ -339,8 +339,8 @@
 @ extern ??_8strstream@@7Bostream@@@ iostream_vbtable_ostream
 @ stub -arch=win32 ??_Dfstream@@QAEXXZ  # void __thiscall fstream::`vbase destructor'(void)
 @ stub -arch=win64 ??_Dfstream@@QEAAXXZ
-@ stub -arch=win32 ??_Difstream@@QAEXXZ  # void __thiscall ifstream::`vbase destructor'(void)
-@ stub -arch=win64 ??_Difstream@@QEAAXXZ
+@ thiscall -arch=win32 ??_Difstream@@QAEXXZ(ptr) istream_vbase_dtor
+@ cdecl -arch=win64 ??_Difstream@@QEAAXXZ(ptr) istream_vbase_dtor
 @ thiscall -arch=win32 ??_Diostream@@QAEXXZ(ptr) iostream_vbase_dtor
 @ cdecl -arch=win64 ??_Diostream@@QEAAXXZ(ptr) iostream_vbase_dtor
 @ thiscall -arch=win32 ??_Distream@@QAEXXZ(ptr) istream_vbase_dtor
@@ -364,7 +364,7 @@
 @ thiscall -arch=win32 ??_Eexception@@UAEPAXI at Z(ptr long) MSVCP_exception_vector_dtor
 @ thiscall -arch=win32 ??_Efilebuf@@UAEPAXI at Z(ptr long) filebuf_vector_dtor
 @ stub -arch=win32 ??_Efstream@@UAEPAXI at Z  # virtual void * __thiscall fstream::`vector deleting destructor'(unsigned int)
-@ stub -arch=win32 ??_Eifstream@@UAEPAXI at Z  # virtual void * __thiscall ifstream::`vector deleting destructor'(unsigned int)
+@ thiscall -arch=win32 ??_Eifstream@@UAEPAXI at Z(ptr long) istream_vector_dtor
 @ thiscall -arch=win32 ??_Eios@@UAEPAXI at Z(ptr long) ios_vector_dtor
 @ thiscall -arch=win32 ??_Eiostream@@UAEPAXI at Z(ptr long) iostream_vector_dtor
 @ thiscall -arch=win32 ??_Eistream@@UAEPAXI at Z(ptr long) istream_vector_dtor
@@ -383,7 +383,7 @@
 @ thiscall -arch=win32 ??_Gexception@@UAEPAXI at Z(ptr long) MSVCP_exception_scalar_dtor
 @ thiscall -arch=win32 ??_Gfilebuf@@UAEPAXI at Z(ptr long) filebuf_scalar_dtor
 @ stub -arch=win32 ??_Gfstream@@UAEPAXI at Z  # virtual void * __thiscall fstream::`scalar deleting destructor'(unsigned int)
-@ stub -arch=win32 ??_Gifstream@@UAEPAXI at Z  # virtual void * __thiscall ifstream::`scalar deleting destructor'(unsigned int)
+@ thiscall -arch=win32 ??_Gifstream@@UAEPAXI at Z(ptr long) istream_scalar_dtor
 @ thiscall -arch=win32 ??_Gios@@UAEPAXI at Z(ptr long) ios_scalar_dtor
 @ thiscall -arch=win32 ??_Giostream@@UAEPAXI at Z(ptr long) iostream_scalar_dtor
 @ thiscall -arch=win32 ??_Gistream@@UAEPAXI at Z(ptr long) istream_scalar_dtor
@@ -406,8 +406,8 @@
 @ cdecl -arch=win64 ?attach at filebuf@@QEAAPEAV1 at H@Z(ptr long) filebuf_attach
 @ stub -arch=win32 ?attach at fstream@@QAEXH at Z  # void __thiscall fstream::attach(int)
 @ stub -arch=win64 ?attach at fstream@@QEAAXH at Z
-@ stub -arch=win32 ?attach at ifstream@@QAEXH at Z  # void __thiscall ifstream::attach(int)
-@ stub -arch=win64 ?attach at ifstream@@QEAAXH at Z
+@ thiscall -arch=win32 ?attach at ifstream@@QAEXH at Z(ptr long) ifstream_attach
+@ cdecl -arch=win64 ?attach at ifstream@@QEAAXH at Z(ptr long) ifstream_attach
 @ stub -arch=win32 ?attach at ofstream@@QAEXH at Z  # void __thiscall ofstream::attach(int)
 @ stub -arch=win64 ?attach at ofstream@@QEAAXH at Z
 @ thiscall -arch=win32 ?bad at ios@@QBEHXZ(ptr) ios_bad
@@ -428,8 +428,8 @@
 @ cdecl -arch=win64 ?close at filebuf@@QEAAPEAV1 at XZ(ptr) filebuf_close
 @ stub -arch=win32 ?close at fstream@@QAEXXZ  # void __thiscall fstream::close(void)
 @ stub -arch=win64 ?close at fstream@@QEAAXXZ
-@ stub -arch=win32 ?close at ifstream@@QAEXXZ  # void __thiscall ifstream::close(void)
-@ stub -arch=win64 ?close at ifstream@@QEAAXXZ
+@ thiscall -arch=win32 ?close at ifstream@@QAEXXZ(ptr) ifstream_close
+@ cdecl -arch=win64 ?close at ifstream@@QEAAXXZ(ptr) ifstream_close
 @ stub -arch=win32 ?close at ofstream@@QAEXXZ  # void __thiscall ofstream::close(void)
 @ stub -arch=win64 ?close at ofstream@@QEAAXXZ
 @ cdecl -arch=win32 ?clrlock at ios@@QAAXXZ(ptr) ios_clrlock
@@ -472,8 +472,8 @@
 @ cdecl -arch=win64 ?fd at filebuf@@QEBAHXZ(ptr) filebuf_fd
 @ stub -arch=win32 ?fd at fstream@@QBEHXZ  # int __thiscall fstream::fd(void)const 
 @ stub -arch=win64 ?fd at fstream@@QEBAHXZ
-@ stub -arch=win32 ?fd at ifstream@@QBEHXZ  # int __thiscall ifstream::fd(void)const 
-@ stub -arch=win64 ?fd at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?fd at ifstream@@QBEHXZ(ptr) ifstream_fd
+@ cdecl -arch=win64 ?fd at ifstream@@QEBAHXZ(ptr) ifstream_fd
 @ stub -arch=win32 ?fd at ofstream@@QBEHXZ  # int __thiscall ofstream::fd(void)const 
 @ stub -arch=win64 ?fd at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?fill at ios@@QAEDD at Z(ptr long) ios_fill_set
@@ -541,8 +541,8 @@
 @ cdecl -arch=win64 ?is_open at filebuf@@QEBAHXZ(ptr) filebuf_is_open
 @ stub -arch=win32 ?is_open at fstream@@QBEHXZ  # int __thiscall fstream::is_open(void)const 
 @ stub -arch=win64 ?is_open at fstream@@QEBAHXZ
-@ stub -arch=win32 ?is_open at ifstream@@QBEHXZ  # int __thiscall ifstream::is_open(void)const 
-@ stub -arch=win64 ?is_open at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?is_open at ifstream@@QBEHXZ(ptr) ifstream_is_open
+@ cdecl -arch=win64 ?is_open at ifstream@@QEBAHXZ(ptr) ifstream_is_open
 @ stub -arch=win32 ?is_open at ofstream@@QBEHXZ  # int __thiscall ofstream::is_open(void)const 
 @ stub -arch=win64 ?is_open at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?isfx at istream@@QAEXXZ(ptr) istream_isfx
@@ -566,8 +566,8 @@
 @ cdecl -arch=win64 ?open at filebuf@@QEAAPEAV1 at PEBDHH@Z(ptr str long long) filebuf_open
 @ stub -arch=win32 ?open at fstream@@QAEXPBDHH at Z  # void __thiscall fstream::open(char const *,int,int)
 @ stub -arch=win64 ?open at fstream@@QEAAXPEBDHH at Z
-@ stub -arch=win32 ?open at ifstream@@QAEXPBDHH at Z  # void __thiscall ifstream::open(char const *,int,int)
-@ stub -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z
+@ thiscall -arch=win32 ?open at ifstream@@QAEXPBDHH at Z(ptr str long long) ifstream_open
+@ cdecl -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z(ptr str long long) ifstream_open
 @ stub -arch=win32 ?open at ofstream@@QAEXPBDHH at Z  # void __thiscall ofstream::open(char const *,int,int)
 @ stub -arch=win64 ?open at ofstream@@QEAAXPEBDHH at Z
 @ extern ?openprot at filebuf@@2HB filebuf_openprot
@@ -615,8 +615,8 @@
 @ cdecl -arch=win64 ?pword at ios@@QEBAAEAPEAXH at Z(ptr long) ios_pword
 @ stub -arch=win32 ?rdbuf at fstream@@QBEPAVfilebuf@@XZ  # class filebuf * __thiscall fstream::rdbuf(void)const 
 @ stub -arch=win64 ?rdbuf at fstream@@QEBAPEAVfilebuf@@XZ
-@ stub -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ  # class filebuf * __thiscall ifstream::rdbuf(void)const 
-@ stub -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ
+@ thiscall -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ(ptr) ifstream_rdbuf
+@ cdecl -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ(ptr) ifstream_rdbuf
 @ thiscall -arch=win32 ?rdbuf at ios@@QBEPAVstreambuf@@XZ(ptr) ios_rdbuf
 @ cdecl -arch=win64 ?rdbuf at ios@@QEBAPEAVstreambuf@@XZ(ptr) ios_rdbuf
 @ thiscall -arch=win32 ?rdbuf at istrstream@@QBEPAVstrstreambuf@@XZ(ptr) istrstream_rdbuf
@@ -685,8 +685,8 @@
 @ cdecl -arch=win64 ?setmode at filebuf@@QEAAHH at Z(ptr long) filebuf_setmode
 @ stub -arch=win32 ?setmode at fstream@@QAEHH at Z  # int __thiscall fstream::setmode(int)
 @ stub -arch=win64 ?setmode at fstream@@QEAAHH at Z
-@ stub -arch=win32 ?setmode at ifstream@@QAEHH at Z  # int __thiscall ifstream::setmode(int)
-@ stub -arch=win64 ?setmode at ifstream@@QEAAHH at Z
+@ thiscall -arch=win32 ?setmode at ifstream@@QAEHH at Z(ptr long) ifstream_setmode
+@ cdecl -arch=win64 ?setmode at ifstream@@QEAAHH at Z(ptr long) ifstream_setmode
 @ stub -arch=win32 ?setmode at ofstream@@QAEHH at Z  # int __thiscall ofstream::setmode(int)
 @ stub -arch=win64 ?setmode at ofstream@@QEAAHH at Z
 @ thiscall -arch=win32 ?setp at streambuf@@IAEXPAD0 at Z(ptr ptr ptr) streambuf_setp
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index 6440bc0dab7..8c0eb1ba131 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <windef.h>
 #include <winbase.h>
+#include <sys/stat.h>
 #include "wine/test.h"
 
 typedef void (*vtable_ptr)(void);
@@ -403,6 +404,22 @@ static void (*__thiscall p_iostream_vbase_dtor)(iostream*);
 static iostream* (*__thiscall p_iostream_assign_sb)(iostream*, streambuf*);
 static iostream* (*__thiscall p_iostream_assign)(iostream*, const iostream*);
 
+/* ifstream */
+static istream* (*__thiscall p_ifstream_copy_ctor)(istream*, const istream*, BOOL);
+static istream* (*__thiscall p_ifstream_buffer_ctor)(istream*, filedesc, char*, int, BOOL);
+static istream* (*__thiscall p_ifstream_fd_ctor)(istream*, filedesc fd, BOOL virt_init);
+static istream* (*__thiscall p_ifstream_open_ctor)(istream*, const char *name, ios_open_mode, int, BOOL);
+static istream* (*__thiscall p_ifstream_ctor)(istream*, BOOL);
+static void (*__thiscall p_ifstream_dtor)(ios*);
+static void (*__thiscall p_ifstream_vbase_dtor)(istream*);
+static void (*__thiscall p_ifstream_attach)(istream*, filedesc);
+static void (*__thiscall p_ifstream_close)(istream*);
+static filedesc (*__thiscall p_ifstream_fd)(istream*);
+static int (*__thiscall p_ifstream_is_open)(const istream*);
+static void (*__thiscall p_ifstream_open)(istream*, const char*, ios_open_mode, int);
+static filebuf* (*__thiscall p_ifstream_rdbuf)(const istream*);
+static int (*__thiscall p_ifstream_setmode)(istream*, int);
+
 /* strstream */
 static iostream* (*__thiscall p_strstream_copy_ctor)(iostream*, const iostream*, BOOL);
 static iostream* (*__thiscall p_strstream_buffer_ctor)(iostream*, char*, int, int, BOOL);
@@ -703,6 +720,21 @@ static BOOL init(void)
         SET(p_iostream_assign_sb, "??4iostream@@IEAAAEAV0 at PEAVstreambuf@@@Z");
         SET(p_iostream_assign, "??4iostream@@IEAAAEAV0 at AEAV0@@Z");
 
+        SET(p_ifstream_copy_ctor, "??0ifstream@@QEAA at AEBV0@@Z");
+        SET(p_ifstream_buffer_ctor, "??0ifstream@@QEAA at HPEADH@Z");
+        SET(p_ifstream_fd_ctor, "??0ifstream@@QEAA at H@Z");
+        SET(p_ifstream_open_ctor, "??0ifstream@@QEAA at PEBDHH@Z");
+        SET(p_ifstream_ctor, "??0ifstream@@QEAA at XZ");
+        SET(p_ifstream_dtor, "??1ifstream@@UEAA at XZ");
+        SET(p_ifstream_vbase_dtor, "??_Difstream@@QEAAXXZ");
+        SET(p_ifstream_attach, "?attach at ifstream@@QEAAXH at Z");
+        SET(p_ifstream_close, "?close at ifstream@@QEAAXXZ");
+        SET(p_ifstream_fd, "?fd at ifstream@@QEBAHXZ");
+        SET(p_ifstream_is_open, "?is_open at ifstream@@QEBAHXZ");
+        SET(p_ifstream_open, "?open at ifstream@@QEAAXPEBDHH at Z");
+        SET(p_ifstream_rdbuf, "?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ");
+        SET(p_ifstream_setmode, "?setmode at ifstream@@QEAAHH at Z");
+
         SET(p_strstream_copy_ctor, "??0strstream@@QEAA at AEBV0@@Z");
         SET(p_strstream_buffer_ctor, "??0strstream@@QEAA at PEADHH@Z");
         SET(p_strstream_ctor, "??0strstream@@QEAA at XZ");
@@ -917,6 +949,21 @@ static BOOL init(void)
         SET(p_iostream_assign_sb, "??4iostream@@IAEAAV0 at PAVstreambuf@@@Z");
         SET(p_iostream_assign, "??4iostream@@IAEAAV0 at AAV0@@Z");
 
+        SET(p_ifstream_copy_ctor, "??0ifstream@@QAE at ABV0@@Z");
+        SET(p_ifstream_fd_ctor, "??0ifstream@@QAE at H@Z");
+        SET(p_ifstream_buffer_ctor, "??0ifstream@@QAE at HPADH@Z");
+        SET(p_ifstream_open_ctor, "??0ifstream@@QAE at PBDHH@Z");
+        SET(p_ifstream_ctor, "??0ifstream@@QAE at XZ");
+        SET(p_ifstream_dtor, "??1ifstream@@UAE at XZ");
+        SET(p_ifstream_vbase_dtor, "??_Difstream@@QAEXXZ");
+        SET(p_ifstream_attach, "?attach at ifstream@@QAEXH at Z");
+        SET(p_ifstream_close, "?close at ifstream@@QAEXXZ");
+        SET(p_ifstream_fd, "?fd at ifstream@@QBEHXZ");
+        SET(p_ifstream_is_open, "?is_open at ifstream@@QBEHXZ");
+        SET(p_ifstream_open, "?open at ifstream@@QAEXPBDHH at Z");
+        SET(p_ifstream_rdbuf, "?rdbuf at ifstream@@QBEPAVfilebuf@@XZ");
+        SET(p_ifstream_setmode, "?setmode at ifstream@@QAEHH at Z");
+
         SET(p_strstream_copy_ctor, "??0strstream@@QAE at ABV0@@Z");
         SET(p_strstream_buffer_ctor, "??0strstream@@QAE at PADHH@Z");
         SET(p_strstream_ctor, "??0strstream@@QAE at XZ");
@@ -6720,6 +6767,207 @@ static void test_iostream(void)
     ok(ios2.base_ios.do_lock == 0xcdcdcdcd, "expected %d got %d\n", 0xcdcdcdcd, ios2.base_ios.do_lock);
 }
 
+static void test_ifstream(void)
+{
+    const char *filename = "ifstream_test";
+    istream ifs, ifs_copy, *pifs;
+    filebuf *pfb;
+    char buffer[64];
+    char st[8];
+    int fd, ret, i;
+
+    memset(&ifs, 0xab, sizeof(istream));
+
+    /* constructors/destructors */
+    pifs = call_func2(p_ifstream_ctor, &ifs, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(ifs.extract_delim == 0, "expected 0 got %d\n", ifs.extract_delim);
+    ok(ifs.count == 0, "expected 0 got %d\n", ifs.count);
+    ok(ifs.base_ios.sb != NULL, "expected not %p got %p\n", NULL, ifs.base_ios.sb);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(ifs.base_ios.delbuf == 1, "expected 1 got %d\n", ifs.base_ios.delbuf);
+    ok(ifs.base_ios.tie == NULL, "expected %p got %p\n", NULL, ifs.base_ios.tie);
+    ok(ifs.base_ios.flags == FLAGS_skipws, "expected %x got %x\n", FLAGS_skipws, ifs.base_ios.flags);
+    ok(ifs.base_ios.precision == 6, "expected 6 got %d\n", ifs.base_ios.precision);
+    ok(ifs.base_ios.fill == ' ', "expected 32 got %d\n", ifs.base_ios.fill);
+    ok(ifs.base_ios.width == 0, "expected 0 got %d\n", ifs.base_ios.width);
+    ok(ifs.base_ios.do_lock == -1, "expected -1 got %d\n", ifs.base_ios.do_lock);
+    ok(pfb->fd == -1, "wrong fd, expected -1 got %d\n", pfb->fd);
+    ok(pfb->close == 0, "wrong value, expected 0 got %d\n", pfb->close);
+    ok(pfb->base.allocated == 0, "wrong allocate value, expected 0 got %d\n", pfb->base.allocated);
+    ok(pfb->base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", pfb->base.unbuffered);
+    ok(pfb->base.base == NULL, "wrong buffer, expected %p got %p\n", NULL, pfb->base.base);
+    ok(pfb->base.ebuf == NULL, "wrong ebuf, expected %p got %p\n", NULL, pfb->base.ebuf);
+    ok(pfb->fd == -1, "wrong fd, expected 0 got %d\n", pfb->fd);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+
+    pifs = call_func3(p_ifstream_fd_ctor, &ifs, 42, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(ifs.base_ios.delbuf == 1, "expected 1 got %d\n", ifs.base_ios.delbuf);
+    ok(pfb->base.allocated == 0, "wrong allocate value, expected 0 got %d\n", pfb->base.allocated);
+    ok(pfb->base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", pfb->base.unbuffered);
+    ok(pfb->base.base == NULL, "wrong buffer, expected %p got %p\n", NULL, pfb->base.base);
+    ok(pfb->base.ebuf == NULL, "wrong ebuf, expected %p got %p\n", NULL, pfb->base.ebuf);
+    ok(pfb->fd == 42, "wrong fd, expected 42 got %d\n", pfb->fd);
+    ok(pfb->close == 0, "wrong value, expected 0 got %d\n", pfb->close);
+
+    pifs = call_func3(p_ifstream_copy_ctor, &ifs_copy, &ifs, TRUE);
+    pfb = (filebuf*) ifs_copy.base_ios.sb;
+    ok(pifs == &ifs_copy, "wrong return, expected %p got %p\n", &ifs_copy, pifs);
+    ok(ifs_copy.base_ios.sb == ifs.base_ios.sb, "expected shared streambuf\n");
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(ifs_copy.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs_copy.base_ios.state);
+
+    call_func1(p_ifstream_vbase_dtor, &ifs_copy);
+    call_func1(p_ifstream_dtor, &ifs.base_ios);
+
+    pifs = call_func5(p_ifstream_buffer_ctor, &ifs, 53, buffer, ARRAY_SIZE(buffer), TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(ifs.base_ios.delbuf == 1, "expected 1 got %d\n", ifs.base_ios.delbuf);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(pfb->base.allocated == 0, "wrong allocate value, expected 0 got %d\n", pfb->base.allocated);
+    ok(pfb->base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", pfb->base.unbuffered);
+    ok(pfb->base.base == buffer, "wrong buffer, expected %p got %p\n", buffer, pfb->base.base);
+    ok(pfb->base.ebuf == buffer + ARRAY_SIZE(buffer), "wrong ebuf, expected %p got %p\n", buffer + ARRAY_SIZE(buffer), pfb->base.ebuf);
+    ok(pfb->fd == 53, "wrong fd, expected 53 got %d\n", pfb->fd);
+    ok(pfb->close == 0, "wrong value, expected 0 got %d\n", pfb->close);
+    call_func1(p_ifstream_dtor, &ifs.base_ios);
+
+    pifs = call_func5(p_ifstream_buffer_ctor, &ifs, 64, NULL, 0, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(ifs.base_ios.delbuf == 1, "expected 1 got %d\n", ifs.base_ios.delbuf);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(pfb->base.allocated == 0, "wrong allocate value, expected 0 got %d\n", pfb->base.allocated);
+    ok(pfb->base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", pfb->base.unbuffered);
+    ok(pfb->base.base == NULL, "wrong buffer, expected %p got %p\n", NULL, pfb->base.base);
+    ok(pfb->base.ebuf == NULL, "wrong ebuf, expected %p got %p\n", NULL, pfb->base.ebuf);
+    ok(pfb->fd == 64, "wrong fd, expected 64 got %d\n", pfb->fd);
+    ok(pfb->close == 0, "wrong value, expected 0 got %d\n", pfb->close);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+
+    pifs = call_func5(p_ifstream_open_ctor, &ifs, filename, OPENMODE_in, filebuf_openprot, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(ifs.base_ios.delbuf == 1, "expected 1 got %d\n", ifs.base_ios.delbuf);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(pfb->base.allocated == 1, "wrong allocate value, expected 1 got %d\n", pfb->base.allocated);
+    ok(pfb->base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", pfb->base.unbuffered);
+    ok(pfb->base.base != NULL, "wrong buffer, expected not %p got %p\n", NULL, pfb->base.base);
+    ok(pfb->base.ebuf != NULL, "wrong ebuf, expected not %p got %p\n", NULL, pfb->base.ebuf);
+    ok(pfb->fd != -1, "wrong fd, expected not -1 got %d\n", pfb->fd);
+    fd = pfb->fd;
+    ok(pfb->close == 1, "wrong value, expected 1 got %d\n", pfb->close);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+    ok(_close(fd) == -1, "expected ifstream to close opened file\n");
+
+    /* attach */
+    pifs = call_func2(p_ifstream_ctor, &ifs, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    call_func2(p_ifstream_attach, &ifs, 42);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "attaching on vanilla stream set some state bits\n");
+    fd = (int) call_func1(p_ifstream_fd, &ifs);
+    ok(fd == 42, "wrong fd, expected 42 got %d\n", fd);
+    ok(pfb->close == 0, "wrong close value, expected 0 got %d\n", pfb->close);
+    call_func2(p_ifstream_attach, &ifs, 53);
+    ok(ifs.base_ios.state == IOSTATE_failbit, "attaching on already setup stream did not set failbit\n");
+    ok(fd == 42, "wrong fd, expected 42 got %d\n", fd);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+
+    /* fd */
+    pifs = call_func2(p_ifstream_ctor, &ifs, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    fd = (int) call_func1(p_ifstream_fd, &ifs);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(fd == -1, "wrong fd, expected -1 but got %d\n", fd);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+
+    pifs = call_func5(p_ifstream_open_ctor, &ifs, filename, OPENMODE_in, filebuf_openprot, TRUE);
+    pfb = (filebuf*) ifs.base_ios.sb;
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    fd = (int) call_func1(p_ifstream_fd, &ifs);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ok(fd == pfb->fd, "wrong fd, expected %d but got %d\n", pfb->fd, fd);
+
+    /* rdbuf */
+    pfb = (filebuf*) call_func1(p_ifstream_rdbuf, &ifs);
+    ok((streambuf*) pfb == ifs.base_ios.sb, "wrong return, expected %p got %p\n", ifs.base_ios.sb, pfb);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+
+    /* setmode */
+    ret = (int) call_func2(p_ifstream_setmode, &ifs, filebuf_binary);
+    ok(ret == filebuf_text, "wrong return, expected %d got %d\n", filebuf_text, ret);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ret = (int) call_func2(p_ifstream_setmode, &ifs, filebuf_binary);
+    ok(ret == filebuf_binary, "wrong return, expected %d got %d\n", filebuf_binary, ret);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ret = (int) call_func2(p_ifstream_setmode, &ifs, filebuf_text);
+    ok(ret == filebuf_binary, "wrong return, expected %d got %d\n", filebuf_binary, ret);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+    ret = (int) call_func2(p_ifstream_setmode, &ifs, 0x9000);
+    ok(ret == -1, "wrong return, expected -1 got %d\n", ret);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, ifs.base_ios.state);
+
+    /* close && is_open */
+    ok((int) call_func1(p_ifstream_is_open, &ifs) == 1, "expected ifstream to be open\n");
+    ifs.base_ios.state = IOSTATE_failbit|IOSTATE_eofbit;
+    call_func1(p_ifstream_close, &ifs);
+    ok(ifs.base_ios.state == 0, "close did not clear state = %d\n", ifs.base_ios.state);
+    call_func1(p_ifstream_close, &ifs);
+    ok(ifs.base_ios.state == IOSTATE_failbit, "close on a closed stream did not set state to failbit\n");
+    ok((int) call_func1(p_ifstream_is_open, &ifs) == 0, "expected ifstream to not be open\n");
+    ok(_close(fd) == -1, "expected close to close the opened file\n");
+
+    /* open */
+    ifs.base_ios.state = IOSTATE_goodbit; /* open doesn't clear the state */
+    call_func4(p_ifstream_open, &ifs, filename, OPENMODE_in, filebuf_openprot);
+    fd = (int) call_func1(p_ifstream_fd, &ifs);
+    ok(fd != -1, "wrong fd, expected not -1 got %d\n", fd);
+    ok(ifs.base_ios.state == IOSTATE_goodbit, "open did not succeed\n");
+    call_func4(p_ifstream_open, &ifs, filename, OPENMODE_in, filebuf_openprot);
+    ok(ifs.base_ios.state == IOSTATE_failbit, "second open did not set state to failbit\n");
+    call_func1(p_ifstream_close, &ifs);
+
+    /* write something we can read later */
+    fd = _open(filename, _O_TRUNC|_O_CREAT|_O_RDWR, _S_IWRITE);
+    ok(fd != -1, "_open failed\n");
+    ok(_write(fd, "test 12", 7) == 7, "_write failed\n");
+    ok(_close(fd) == 0, "_close failed\n");
+
+    /* integration with parent istream - reading */
+    ifs.base_ios.state = IOSTATE_goodbit; /* open doesn't clear the state */
+    call_func4(p_ifstream_open, &ifs, filename, OPENMODE_out, filebuf_openprot); /* make sure that OPENMODE_in is implicit */
+    memset(st, 'A', sizeof(st));
+    st[7] = 0;
+    pifs = call_func2(p_istream_read_str, &ifs, st);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(!strcmp(st, "test"), "expected 'test' got '%s'\n", st);
+
+    i = 12345;
+    pifs = call_func2(p_istream_read_int, pifs, &i);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(i == 12, "expected 12 got %d\n", i);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+
+    /* make sure that OPENMODE_in is implicit with open_ctor */
+    pifs = call_func5(p_ifstream_open_ctor, &ifs, filename, OPENMODE_out, filebuf_openprot, TRUE);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    memset(st, 'A', sizeof(st));
+    st[7] = 0;
+    pifs = call_func2(p_istream_read_str, &ifs, st);
+    ok(pifs == &ifs, "wrong return, expected %p got %p\n", &ifs, pifs);
+    ok(!strcmp(st, "test"), "expected 'test' got '%s'\n", st);
+    call_func1(p_ifstream_vbase_dtor, &ifs);
+    ok(_unlink(filename) == 0, "Couldn't unlink file named '%s'\n", filename);
+}
+
 static void test_strstream(void)
 {
     iostream ios1, ios2, *pios;
@@ -7538,6 +7786,7 @@ START_TEST(msvcirt)
     test_istream_withassign();
     test_istrstream();
     test_iostream();
+    test_ifstream();
     test_strstream();
     test_stdiostream();
     test_Iostream_init();
diff --git a/dlls/msvcrt20/msvcrt20.spec b/dlls/msvcrt20/msvcrt20.spec
index f06a53cc601..96c6c681478 100644
--- a/dlls/msvcrt20/msvcrt20.spec
+++ b/dlls/msvcrt20/msvcrt20.spec
@@ -20,16 +20,16 @@
 @ stub -arch=win64 ??0fstream@@QEAA at PEBDHH@Z
 @ stub -arch=win32 ??0fstream@@QAE at XZ
 @ stub -arch=win64 ??0fstream@@QEAA at XZ
-@ stub -arch=win32 ??0ifstream@@QAE at ABV0@@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z
-@ stub -arch=win32 ??0ifstream@@QAE at H@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at H@Z
-@ stub -arch=win32 ??0ifstream@@QAE at HPADH@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at HPEADH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at PBDHH@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at XZ
-@ stub -arch=win64 ??0ifstream@@QEAA at XZ
+@ thiscall -arch=win32 ??0ifstream@@QAE at ABV0@@Z(ptr ptr long) msvcirt.??0ifstream@@QAE at ABV0@@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z(ptr ptr long) msvcirt.??0ifstream@@QEAA at AEBV0@@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at H@Z(ptr long long) msvcirt.??0ifstream@@QAE at H@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at H@Z(ptr long long) msvcirt.??0ifstream@@QEAA at H@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at HPADH@Z(ptr long ptr long long) msvcirt.??0ifstream@@QAE at HPADH@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at HPEADH@Z(ptr long ptr long long) msvcirt.??0ifstream@@QEAA at HPEADH@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at PBDHH@Z(ptr str long long long) msvcirt.??0ifstream@@QAE at PBDHH@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z(ptr str long long long) msvcirt.??0ifstream@@QEAA at PEBDHH@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at XZ(ptr long) msvcirt.??0ifstream@@QAE at XZ
+@ cdecl -arch=win64 ??0ifstream@@QEAA at XZ(ptr long) msvcirt.??0ifstream@@QEAA at XZ
 @ thiscall -arch=win32 ??0ios@@IAE at ABV0@@Z(ptr ptr) msvcirt.??0ios@@IAE at ABV0@@Z
 @ cdecl -arch=win64 ??0ios@@IEAA at AEBV0@@Z(ptr ptr) msvcirt.??0ios@@IEAA at AEBV0@@Z
 @ thiscall -arch=win32 ??0ios@@IAE at XZ(ptr) msvcirt.??0ios@@IAE at XZ
@@ -124,8 +124,8 @@
 @ cdecl -arch=win64 ??1filebuf@@UEAA at XZ(ptr) msvcirt.??1filebuf@@UEAA at XZ
 @ stub -arch=win32 ??1fstream@@UAE at XZ
 @ stub -arch=win64 ??1fstream@@UEAA at XZ
-@ stub -arch=win32 ??1ifstream@@UAE at XZ
-@ stub -arch=win64 ??1ifstream@@UEAA at XZ
+@ thiscall -arch=win32 ??1ifstream@@UAE at XZ(ptr) msvcirt.??1ifstream@@UAE at XZ
+@ cdecl -arch=win64 ??1ifstream@@UEAA at XZ(ptr) msvcirt.??1ifstream@@UEAA at XZ
 @ thiscall -arch=win32 ??1ios@@UAE at XZ(ptr) msvcirt.??1ios@@UAE at XZ
 @ cdecl -arch=win64 ??1ios@@UEAA at XZ(ptr) msvcirt.??1ios@@UEAA at XZ
 @ thiscall -arch=win32 ??1iostream@@UAE at XZ(ptr) msvcirt.??1iostream@@UAE at XZ
@@ -164,8 +164,8 @@
 @ cdecl -arch=win64 ??4filebuf@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4filebuf@@QEAAAEAV0 at AEBV0@@Z
 @ stub -arch=win32 ??4fstream@@QAEAAV0 at AAV0@@Z
 @ stub -arch=win64 ??4fstream@@QEAAAEAV0 at AEAV0@@Z
-@ stub -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z
-@ stub -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z
+@ thiscall -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z(ptr ptr) msvcirt.??4ifstream@@QAEAAV0 at ABV0@@Z
+@ cdecl -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4ifstream@@QEAAAEAV0 at AEBV0@@Z
 @ thiscall -arch=win32 ??4ios@@IAEAAV0 at ABV0@@Z(ptr ptr) msvcirt.??4ios@@IAEAAV0 at ABV0@@Z
 @ cdecl -arch=win64 ??4ios@@IEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4ios@@IEAAAEAV0 at AEBV0@@Z
 @ thiscall -arch=win32 ??4iostream@@IAEAAV0 at AAV0@@Z(ptr ptr) msvcirt.??4iostream@@IAEAAV0 at AAV0@@Z
@@ -288,7 +288,7 @@
 @ cdecl -arch=win64 ??Bios@@QEBAPEAXXZ(ptr) msvcirt.??Bios@@QEBAPEAXXZ
 @ extern ??_7filebuf@@6B@ msvcirt.??_7filebuf@@6B@
 # @ extern ??_7fstream@@6B@
-# @ extern ??_7ifstream@@6B@
+@ extern ??_7ifstream@@6B@ msvcirt.??_7ifstream@@6B@
 @ extern ??_7ios@@6B@ msvcirt.??_7ios@@6B@
 @ extern ??_7iostream@@6B@ msvcirt.??_7iostream@@6B@
 @ extern ??_7istream@@6B@ msvcirt.??_7istream@@6B@
@@ -305,7 +305,7 @@
 @ extern ??_7strstreambuf@@6B@ msvcirt.??_7strstreambuf@@6B@
 # @ extern ??_8fstream@@7Bistream@@@
 # @ extern ??_8fstream@@7Bostream@@@
-# @ extern ??_8ifstream@@7B@
+@ extern ??_8ifstream@@7B@ msvcirt.??_8ifstream@@7B@
 @ extern ??_8iostream@@7Bistream@@@ msvcirt.??_8iostream@@7Bistream@@@
 @ extern ??_8iostream@@7Bostream@@@ msvcirt.??_8iostream@@7Bostream@@@
 @ extern ??_8istream@@7B@ msvcirt.??_8istream@@7B@
@@ -321,8 +321,8 @@
 @ extern ??_8strstream@@7Bostream@@@ msvcirt.??_8strstream@@7Bostream@@@
 @ stub -arch=win32 ??_Dfstream@@QAEXXZ
 @ stub -arch=win64 ??_Dfstream@@QEAAXXZ
-@ stub -arch=win32 ??_Difstream@@QAEXXZ
-@ stub -arch=win64 ??_Difstream@@QEAAXXZ
+@ thiscall -arch=win32 ??_Difstream@@QAEXXZ(ptr) msvcirt.??_Difstream@@QAEXXZ
+@ cdecl -arch=win64 ??_Difstream@@QEAAXXZ(ptr) msvcirt.??_Difstream@@QEAAXXZ
 @ thiscall -arch=win32 ??_Diostream@@QAEXXZ(ptr) msvcirt.??_Diostream@@QAEXXZ
 @ cdecl -arch=win64 ??_Diostream@@QEAAXXZ(ptr) msvcirt.??_Diostream@@QEAAXXZ
 @ thiscall -arch=win32 ??_Distream@@QAEXXZ(ptr) msvcirt.??_Distream@@QAEXXZ
@@ -346,7 +346,7 @@
 @ stub -arch=win32 ??_EIostream_init@@QAEPAXI at Z
 @ thiscall -arch=win32 ??_Efilebuf@@UAEPAXI at Z(ptr long) msvcirt.??_Efilebuf@@UAEPAXI at Z
 @ stub -arch=win32 ??_Efstream@@UAEPAXI at Z
-@ stub -arch=win32 ??_Eifstream@@UAEPAXI at Z
+@ thiscall -arch=win32 ??_Eifstream@@UAEPAXI at Z(ptr long) msvcirt.??_Eifstream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eios@@UAEPAXI at Z(ptr long) msvcirt.??_Eios@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eiostream@@UAEPAXI at Z(ptr long) msvcirt.??_Eiostream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eistream@@UAEPAXI at Z(ptr long) msvcirt.??_Eistream@@UAEPAXI at Z
@@ -364,7 +364,7 @@
 @ stub -arch=win32 ??_GIostream_init@@QAEPAXI at Z
 @ thiscall -arch=win32 ??_Gfilebuf@@UAEPAXI at Z(ptr long) msvcirt.??_Gfilebuf@@UAEPAXI at Z
 @ stub -arch=win32 ??_Gfstream@@UAEPAXI at Z
-@ stub -arch=win32 ??_Gifstream@@UAEPAXI at Z
+@ thiscall -arch=win32 ??_Gifstream@@UAEPAXI at Z(ptr long) msvcirt.??_Gifstream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Gios@@UAEPAXI at Z(ptr long) msvcirt.??_Gios@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Giostream@@UAEPAXI at Z(ptr long) msvcirt.??_Giostream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Gistream@@UAEPAXI at Z(ptr long) msvcirt.??_Gistream@@UAEPAXI at Z
@@ -394,8 +394,8 @@
 @ cdecl -arch=win64 ?attach at filebuf@@QEAAPEAV1 at H@Z(ptr long) msvcirt.?attach at filebuf@@QEAAPEAV1 at H@Z
 @ stub -arch=win32 ?attach at fstream@@QAEXH at Z
 @ stub -arch=win64 ?attach at fstream@@QEAAXH at Z
-@ stub -arch=win32 ?attach at ifstream@@QAEXH at Z
-@ stub -arch=win64 ?attach at ifstream@@QEAAXH at Z
+@ thiscall -arch=win32 ?attach at ifstream@@QAEXH at Z(ptr long) msvcirt.?attach at ifstream@@QAEXH at Z
+@ cdecl -arch=win64 ?attach at ifstream@@QEAAXH at Z(ptr long) msvcirt.?attach at ifstream@@QEAAXH at Z
 @ stub -arch=win32 ?attach at ofstream@@QAEXH at Z
 @ stub -arch=win64 ?attach at ofstream@@QEAAXH at Z
 @ thiscall -arch=win32 ?bad at ios@@QBEHXZ(ptr) msvcirt.?bad at ios@@QBEHXZ
@@ -416,8 +416,8 @@
 @ cdecl -arch=win64 ?close at filebuf@@QEAAPEAV1 at XZ(ptr) msvcirt.?close at filebuf@@QEAAPEAV1 at XZ
 @ stub -arch=win32 ?close at fstream@@QAEXXZ
 @ stub -arch=win64 ?close at fstream@@QEAAXXZ
-@ stub -arch=win32 ?close at ifstream@@QAEXXZ
-@ stub -arch=win64 ?close at ifstream@@QEAAXXZ
+@ thiscall -arch=win32 ?close at ifstream@@QAEXXZ(ptr) msvcirt.?close at ifstream@@QAEXXZ
+@ cdecl -arch=win64 ?close at ifstream@@QEAAXXZ(ptr) msvcirt.?close at ifstream@@QEAAXXZ
 @ stub -arch=win32 ?close at ofstream@@QAEXXZ
 @ stub -arch=win64 ?close at ofstream@@QEAAXXZ
 @ cdecl -arch=win32 ?clrlock at ios@@QAAXXZ(ptr) msvcirt.?clrlock at ios@@QAAXXZ
@@ -460,8 +460,8 @@
 @ cdecl -arch=win64 ?fd at filebuf@@QEBAHXZ(ptr) msvcirt.?fd at filebuf@@QEBAHXZ
 @ stub -arch=win32 ?fd at fstream@@QBEHXZ
 @ stub -arch=win64 ?fd at fstream@@QEBAHXZ
-@ stub -arch=win32 ?fd at ifstream@@QBEHXZ
-@ stub -arch=win64 ?fd at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?fd at ifstream@@QBEHXZ(ptr) msvcirt.?fd at ifstream@@QBEHXZ
+@ cdecl -arch=win64 ?fd at ifstream@@QEBAHXZ(ptr) msvcirt.?fd at ifstream@@QEBAHXZ
 @ stub -arch=win32 ?fd at ofstream@@QBEHXZ
 @ stub -arch=win64 ?fd at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?fill at ios@@QAEDD at Z(ptr long) msvcirt.?fill at ios@@QAEDD at Z
@@ -527,8 +527,8 @@
 @ cdecl -arch=win64 ?is_open at filebuf@@QEBAHXZ(ptr) msvcirt.?is_open at filebuf@@QEBAHXZ
 @ stub -arch=win32 ?is_open at fstream@@QBEHXZ
 @ stub -arch=win64 ?is_open at fstream@@QEBAHXZ
-@ stub -arch=win32 ?is_open at ifstream@@QBEHXZ
-@ stub -arch=win64 ?is_open at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?is_open at ifstream@@QBEHXZ(ptr) msvcirt.?is_open at ifstream@@QBEHXZ
+@ cdecl -arch=win64 ?is_open at ifstream@@QEBAHXZ(ptr) msvcirt.?is_open at ifstream@@QEBAHXZ
 @ stub -arch=win32 ?is_open at ofstream@@QBEHXZ
 @ stub -arch=win64 ?is_open at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?isfx at istream@@QAEXXZ(ptr) msvcirt.?isfx at istream@@QAEXXZ
@@ -552,8 +552,8 @@
 @ cdecl -arch=win64 ?open at filebuf@@QEAAPEAV1 at PEBDHH@Z(ptr str long long) msvcirt.?open at filebuf@@QEAAPEAV1 at PEBDHH@Z
 @ stub -arch=win32 ?open at fstream@@QAEXPBDHH at Z
 @ stub -arch=win64 ?open at fstream@@QEAAXPEBDHH at Z
-@ stub -arch=win32 ?open at ifstream@@QAEXPBDHH at Z
-@ stub -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z
+@ thiscall -arch=win32 ?open at ifstream@@QAEXPBDHH at Z(ptr str long long) msvcirt.?open at ifstream@@QAEXPBDHH at Z
+@ cdecl -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z(ptr str long long) msvcirt.?open at ifstream@@QEAAXPEBDHH at Z
 @ stub -arch=win32 ?open at ofstream@@QAEXPBDHH at Z
 @ stub -arch=win64 ?open at ofstream@@QEAAXPEBDHH at Z
 @ extern ?openprot at filebuf@@2HB msvcirt.?openprot at filebuf@@2HB
@@ -601,8 +601,8 @@
 @ cdecl -arch=win64 ?pword at ios@@QEBAAEAPEAXH at Z(ptr long) msvcirt.?pword at ios@@QEBAAEAPEAXH at Z
 @ stub -arch=win32 ?rdbuf at fstream@@QBEPAVfilebuf@@XZ
 @ stub -arch=win64 ?rdbuf at fstream@@QEBAPEAVfilebuf@@XZ
-@ stub -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ
-@ stub -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ
+@ thiscall -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ(ptr) msvcirt.?rdbuf at ifstream@@QBEPAVfilebuf@@XZ
+@ cdecl -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ(ptr) msvcirt.?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ
 @ thiscall -arch=win32 ?rdbuf at ios@@QBEPAVstreambuf@@XZ(ptr) msvcirt.?rdbuf at ios@@QBEPAVstreambuf@@XZ
 @ cdecl -arch=win64 ?rdbuf at ios@@QEBAPEAVstreambuf@@XZ(ptr) msvcirt.?rdbuf at ios@@QEBAPEAVstreambuf@@XZ
 @ thiscall -arch=win32 ?rdbuf at istrstream@@QBEPAVstrstreambuf@@XZ(ptr) msvcirt.?rdbuf at istrstream@@QBEPAVstrstreambuf@@XZ
@@ -673,8 +673,8 @@
 @ cdecl -arch=win64 ?setmode at filebuf@@QEAAHH at Z(ptr long) msvcirt.?setmode at filebuf@@QEAAHH at Z
 @ stub -arch=win32 ?setmode at fstream@@QAEHH at Z
 @ stub -arch=win64 ?setmode at fstream@@QEAAHH at Z
-@ stub -arch=win32 ?setmode at ifstream@@QAEHH at Z
-@ stub -arch=win64 ?setmode at ifstream@@QEAAHH at Z
+@ thiscall -arch=win32 ?setmode at ifstream@@QAEHH at Z(ptr long) msvcirt.?setmode at ifstream@@QAEHH at Z
+@ cdecl -arch=win64 ?setmode at ifstream@@QEAAHH at Z(ptr long) msvcirt.?setmode at ifstream@@QEAAHH at Z
 @ stub -arch=win32 ?setmode at ofstream@@QAEHH at Z
 @ stub -arch=win64 ?setmode at ofstream@@QEAAHH at Z
 @ thiscall -arch=win32 ?setp at streambuf@@IAEXPAD0 at Z(ptr ptr ptr) msvcirt.?setp at streambuf@@IAEXPAD0 at Z
diff --git a/dlls/msvcrt40/msvcrt40.spec b/dlls/msvcrt40/msvcrt40.spec
index f0d966acd7c..6a2c9a7e52e 100644
--- a/dlls/msvcrt40/msvcrt40.spec
+++ b/dlls/msvcrt40/msvcrt40.spec
@@ -38,16 +38,16 @@
 @ stub -arch=win64 ??0fstream@@QEAA at PEBDHH@Z
 @ stub -arch=win32 ??0fstream@@QAE at XZ
 @ stub -arch=win64 ??0fstream@@QEAA at XZ
-@ stub -arch=win32 ??0ifstream@@QAE at ABV0@@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z
-@ stub -arch=win32 ??0ifstream@@QAE at H@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at H@Z
-@ stub -arch=win32 ??0ifstream@@QAE at HPADH@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at HPEADH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at PBDHH@Z
-@ stub -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z
-@ stub -arch=win32 ??0ifstream@@QAE at XZ
-@ stub -arch=win64 ??0ifstream@@QEAA at XZ
+@ thiscall -arch=win32 ??0ifstream@@QAE at ABV0@@Z(ptr ptr long) msvcirt.??0ifstream@@QAE at ABV0@@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at AEBV0@@Z(ptr ptr long) msvcirt.??0ifstream@@QEAA at AEBV0@@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at H@Z(ptr long long) msvcirt.??0ifstream@@QAE at H@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at H@Z(ptr long long) msvcirt.??0ifstream@@QEAA at H@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at HPADH@Z(ptr long ptr long long) msvcirt.??0ifstream@@QAE at HPADH@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at HPEADH@Z(ptr long ptr long long) msvcirt.??0ifstream@@QEAA at HPEADH@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at PBDHH@Z(ptr str long long long) msvcirt.??0ifstream@@QAE at PBDHH@Z
+@ cdecl -arch=win64 ??0ifstream@@QEAA at PEBDHH@Z(ptr str long long long) msvcirt.??0ifstream@@QEAA at PEBDHH@Z
+@ thiscall -arch=win32 ??0ifstream@@QAE at XZ(ptr long) msvcirt.??0ifstream@@QAE at XZ
+@ cdecl -arch=win64 ??0ifstream@@QEAA at XZ(ptr long) msvcirt.??0ifstream@@QEAA at XZ
 @ thiscall -arch=win32 ??0ios@@IAE at ABV0@@Z(ptr ptr) msvcirt.??0ios@@IAE at ABV0@@Z
 @ cdecl -arch=win64 ??0ios@@IEAA at AEBV0@@Z(ptr ptr) msvcirt.??0ios@@IEAA at AEBV0@@Z
 @ thiscall -arch=win32 ??0ios@@IAE at XZ(ptr) msvcirt.??0ios@@IAE at XZ
@@ -154,8 +154,8 @@
 @ cdecl -arch=win64 ??1filebuf@@UEAA at XZ(ptr) msvcirt.??1filebuf@@UEAA at XZ
 @ stub -arch=win32 ??1fstream@@UAE at XZ
 @ stub -arch=win64 ??1fstream@@UEAA at XZ
-@ stub -arch=win32 ??1ifstream@@UAE at XZ
-@ stub -arch=win64 ??1ifstream@@UEAA at XZ
+@ thiscall -arch=win32 ??1ifstream@@UAE at XZ(ptr) msvcirt.??1ifstream@@UAE at XZ
+@ cdecl -arch=win64 ??1ifstream@@UEAA at XZ(ptr) msvcirt.??1ifstream@@UEAA at XZ
 @ thiscall -arch=win32 ??1ios@@UAE at XZ(ptr) msvcirt.??1ios@@UAE at XZ
 @ cdecl -arch=win64 ??1ios@@UEAA at XZ(ptr) msvcirt.??1ios@@UEAA at XZ
 @ thiscall -arch=win32 ??1iostream@@UAE at XZ(ptr) msvcirt.??1iostream@@UAE at XZ
@@ -206,8 +206,8 @@
 @ cdecl -arch=win64 ??4filebuf@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4filebuf@@QEAAAEAV0 at AEBV0@@Z
 @ stub -arch=win32 ??4fstream@@QAEAAV0 at AAV0@@Z
 @ stub -arch=win64 ??4fstream@@QEAAAEAV0 at AEAV0@@Z
-@ stub -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z
-@ stub -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z
+@ thiscall -arch=win32 ??4ifstream@@QAEAAV0 at ABV0@@Z(ptr ptr) msvcirt.??4ifstream@@QAEAAV0 at ABV0@@Z
+@ cdecl -arch=win64 ??4ifstream@@QEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4ifstream@@QEAAAEAV0 at AEBV0@@Z
 @ thiscall -arch=win32 ??4ios@@IAEAAV0 at ABV0@@Z(ptr ptr) msvcirt.??4ios@@IAEAAV0 at ABV0@@Z
 @ cdecl -arch=win64 ??4ios@@IEAAAEAV0 at AEBV0@@Z(ptr ptr) msvcirt.??4ios@@IEAAAEAV0 at AEBV0@@Z
 @ thiscall -arch=win32 ??4iostream@@IAEAAV0 at AAV0@@Z(ptr ptr) msvcirt.??4iostream@@IAEAAV0 at AAV0@@Z
@@ -340,7 +340,7 @@
 @ extern ??_7exception@@6B@ msvcrt.??_7exception@@6B@
 @ extern ??_7filebuf@@6B@ msvcirt.??_7filebuf@@6B@
 # @ extern ??_7fstream@@6B@
-# @ extern ??_7ifstream@@6B@
+@ extern ??_7ifstream@@6B@ msvcirt.??_7ifstream@@6B@
 @ extern ??_7ios@@6B@ msvcirt.??_7ios@@6B@
 @ extern ??_7iostream@@6B@ msvcirt.??_7iostream@@6B@
 @ extern ??_7istream@@6B@ msvcirt.??_7istream@@6B@
@@ -358,7 +358,7 @@
 @ extern ??_7strstreambuf@@6B@ msvcirt.??_7strstreambuf@@6B@
 # @ extern ??_8fstream@@7Bistream@@@
 # @ extern ??_8fstream@@7Bostream@@@
-# @ extern ??_8ifstream@@7B@
+@ extern ??_8ifstream@@7B@ msvcirt.??_8ifstream@@7B@
 @ extern ??_8iostream@@7Bistream@@@ msvcirt.??_8iostream@@7Bistream@@@
 @ extern ??_8iostream@@7Bostream@@@ msvcirt.??_8iostream@@7Bostream@@@
 @ extern ??_8istream@@7B@ msvcirt.??_8istream@@7B@
@@ -374,8 +374,8 @@
 @ extern ??_8strstream@@7Bostream@@@ msvcirt.??_8strstream@@7Bostream@@@
 @ stub -arch=win32 ??_Dfstream@@QAEXXZ
 @ stub -arch=win64 ??_Dfstream@@QEAAXXZ
-@ stub -arch=win32 ??_Difstream@@QAEXXZ
-@ stub -arch=win64 ??_Difstream@@QEAAXXZ
+@ thiscall -arch=win32 ??_Difstream@@QAEXXZ(ptr) msvcirt.??_Difstream@@QAEXXZ
+@ cdecl -arch=win64 ??_Difstream@@QEAAXXZ(ptr) msvcirt.??_Difstream@@QEAAXXZ
 @ thiscall -arch=win32 ??_Diostream@@QAEXXZ(ptr) msvcirt.??_Diostream@@QAEXXZ
 @ cdecl -arch=win64 ??_Diostream@@QEAAXXZ(ptr) msvcirt.??_Diostream@@QEAAXXZ
 @ thiscall -arch=win32 ??_Distream@@QAEXXZ(ptr) msvcirt.??_Distream@@QAEXXZ
@@ -403,7 +403,7 @@
 @ thiscall -arch=win32 ??_Eexception@@UAEPAXI at Z(ptr long) msvcrt.??_Eexception@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Efilebuf@@UAEPAXI at Z(ptr long) msvcirt.??_Efilebuf@@UAEPAXI at Z
 @ stub -arch=win32 ??_Efstream@@UAEPAXI at Z
-@ stub -arch=win32 ??_Eifstream@@UAEPAXI at Z
+@ thiscall -arch=win32 ??_Eifstream@@UAEPAXI at Z(ptr long) msvcirt.??_Eifstream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eios@@UAEPAXI at Z(ptr long) msvcirt.??_Eios@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eiostream@@UAEPAXI at Z(ptr long) msvcirt.??_Eiostream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Eistream@@UAEPAXI at Z(ptr long) msvcirt.??_Eistream@@UAEPAXI at Z
@@ -426,7 +426,7 @@
 @ thiscall -arch=win32 ??_Gexception@@UAEPAXI at Z(ptr long) msvcrt.??_Gexception@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Gfilebuf@@UAEPAXI at Z(ptr long) msvcirt.??_Gfilebuf@@UAEPAXI at Z
 @ stub -arch=win32 ??_Gfstream@@UAEPAXI at Z
-@ stub -arch=win32 ??_Gifstream@@UAEPAXI at Z
+@ thiscall -arch=win32 ??_Gifstream@@UAEPAXI at Z(ptr long) msvcirt.??_Gifstream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Gios@@UAEPAXI at Z(ptr long) msvcirt.??_Gios@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Giostream@@UAEPAXI at Z(ptr long) msvcirt.??_Giostream@@UAEPAXI at Z
 @ thiscall -arch=win32 ??_Gistream@@UAEPAXI at Z(ptr long) msvcirt.??_Gistream@@UAEPAXI at Z
@@ -457,8 +457,8 @@
 @ cdecl -arch=win64 ?attach at filebuf@@QEAAPEAV1 at H@Z(ptr long) msvcirt.?attach at filebuf@@QEAAPEAV1 at H@Z
 @ stub -arch=win32 ?attach at fstream@@QAEXH at Z
 @ stub -arch=win64 ?attach at fstream@@QEAAXH at Z
-@ stub -arch=win32 ?attach at ifstream@@QAEXH at Z
-@ stub -arch=win64 ?attach at ifstream@@QEAAXH at Z
+@ thiscall -arch=win32 ?attach at ifstream@@QAEXH at Z(ptr long) msvcirt.?attach at ifstream@@QAEXH at Z
+@ cdecl -arch=win64 ?attach at ifstream@@QEAAXH at Z(ptr long) msvcirt.?attach at ifstream@@QEAAXH at Z
 @ stub -arch=win32 ?attach at ofstream@@QAEXH at Z
 @ stub -arch=win64 ?attach at ofstream@@QEAAXH at Z
 @ thiscall -arch=win32 ?bad at ios@@QBEHXZ(ptr) msvcirt.?bad at ios@@QBEHXZ
@@ -481,8 +481,8 @@
 @ cdecl -arch=win64 ?close at filebuf@@QEAAPEAV1 at XZ(ptr) msvcirt.?close at filebuf@@QEAAPEAV1 at XZ
 @ stub -arch=win32 ?close at fstream@@QAEXXZ
 @ stub -arch=win64 ?close at fstream@@QEAAXXZ
-@ stub -arch=win32 ?close at ifstream@@QAEXXZ
-@ stub -arch=win64 ?close at ifstream@@QEAAXXZ
+@ thiscall -arch=win32 ?close at ifstream@@QAEXXZ(ptr) msvcirt.?close at ifstream@@QAEXXZ
+@ cdecl -arch=win64 ?close at ifstream@@QEAAXXZ(ptr) msvcirt.?close at ifstream@@QEAAXXZ
 @ stub -arch=win32 ?close at ofstream@@QAEXXZ
 @ stub -arch=win64 ?close at ofstream@@QEAAXXZ
 @ cdecl -arch=win32 ?clrlock at ios@@QAAXXZ(ptr) msvcirt.?clrlock at ios@@QAAXXZ
@@ -525,8 +525,8 @@
 @ cdecl -arch=win64 ?fd at filebuf@@QEBAHXZ(ptr) msvcirt.?fd at filebuf@@QEBAHXZ
 @ stub -arch=win32 ?fd at fstream@@QBEHXZ
 @ stub -arch=win64 ?fd at fstream@@QEBAHXZ
-@ stub -arch=win32 ?fd at ifstream@@QBEHXZ
-@ stub -arch=win64 ?fd at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?fd at ifstream@@QBEHXZ(ptr) msvcirt.?fd at ifstream@@QBEHXZ
+@ cdecl -arch=win64 ?fd at ifstream@@QEBAHXZ(ptr) msvcirt.?fd at ifstream@@QEBAHXZ
 @ stub -arch=win32 ?fd at ofstream@@QBEHXZ
 @ stub -arch=win64 ?fd at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?fill at ios@@QAEDD at Z(ptr long) msvcirt.?fill at ios@@QAEDD at Z
@@ -594,8 +594,8 @@
 @ cdecl -arch=win64 ?is_open at filebuf@@QEBAHXZ(ptr) msvcirt.?is_open at filebuf@@QEBAHXZ
 @ stub -arch=win32 ?is_open at fstream@@QBEHXZ
 @ stub -arch=win64 ?is_open at fstream@@QEBAHXZ
-@ stub -arch=win32 ?is_open at ifstream@@QBEHXZ
-@ stub -arch=win64 ?is_open at ifstream@@QEBAHXZ
+@ thiscall -arch=win32 ?is_open at ifstream@@QBEHXZ(ptr) msvcirt.?is_open at ifstream@@QBEHXZ
+@ cdecl -arch=win64 ?is_open at ifstream@@QEBAHXZ(ptr) msvcirt.?is_open at ifstream@@QEBAHXZ
 @ stub -arch=win32 ?is_open at ofstream@@QBEHXZ
 @ stub -arch=win64 ?is_open at ofstream@@QEBAHXZ
 @ thiscall -arch=win32 ?isfx at istream@@QAEXXZ(ptr) msvcirt.?isfx at istream@@QAEXXZ
@@ -621,8 +621,8 @@
 @ cdecl -arch=win64 ?open at filebuf@@QEAAPEAV1 at PEBDHH@Z(ptr str long long) msvcirt.?open at filebuf@@QEAAPEAV1 at PEBDHH@Z
 @ stub -arch=win32 ?open at fstream@@QAEXPBDHH at Z
 @ stub -arch=win64 ?open at fstream@@QEAAXPEBDHH at Z
-@ stub -arch=win32 ?open at ifstream@@QAEXPBDHH at Z
-@ stub -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z
+@ thiscall -arch=win32 ?open at ifstream@@QAEXPBDHH at Z(ptr str long long) msvcirt.?open at ifstream@@QAEXPBDHH at Z
+@ cdecl -arch=win64 ?open at ifstream@@QEAAXPEBDHH at Z(ptr str long long) msvcirt.?open at ifstream@@QEAAXPEBDHH at Z
 @ stub -arch=win32 ?open at ofstream@@QAEXPBDHH at Z
 @ stub -arch=win64 ?open at ofstream@@QEAAXPEBDHH at Z
 @ extern ?openprot at filebuf@@2HB msvcirt.?openprot at filebuf@@2HB
@@ -672,8 +672,8 @@
 @ cdecl -arch=win64 ?raw_name at type_info@@QEBAPEBDXZ(ptr) msvcrt.?raw_name at type_info@@QEBAPEBDXZ
 @ stub -arch=win32 ?rdbuf at fstream@@QBEPAVfilebuf@@XZ
 @ stub -arch=win64 ?rdbuf at fstream@@QEBAPEAVfilebuf@@XZ
-@ stub -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ
-@ stub -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ
+@ thiscall -arch=win32 ?rdbuf at ifstream@@QBEPAVfilebuf@@XZ(ptr) msvcirt.?rdbuf at ifstream@@QBEPAVfilebuf@@XZ
+@ cdecl -arch=win64 ?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ(ptr) msvcirt.?rdbuf at ifstream@@QEBAPEAVfilebuf@@XZ
 @ thiscall -arch=win32 ?rdbuf at ios@@QBEPAVstreambuf@@XZ(ptr) msvcirt.?rdbuf at ios@@QBEPAVstreambuf@@XZ
 @ cdecl -arch=win64 ?rdbuf at ios@@QEBAPEAVstreambuf@@XZ(ptr) msvcirt.?rdbuf at ios@@QEBAPEAVstreambuf@@XZ
 @ thiscall -arch=win32 ?rdbuf at istrstream@@QBEPAVstrstreambuf@@XZ(ptr) msvcirt.?rdbuf at istrstream@@QBEPAVstrstreambuf@@XZ
@@ -745,8 +745,8 @@
 @ cdecl -arch=win64 ?setmode at filebuf@@QEAAHH at Z(ptr long) msvcirt.?setmode at filebuf@@QEAAHH at Z
 @ stub -arch=win32 ?setmode at fstream@@QAEHH at Z
 @ stub -arch=win64 ?setmode at fstream@@QEAAHH at Z
-@ stub -arch=win32 ?setmode at ifstream@@QAEHH at Z
-@ stub -arch=win64 ?setmode at ifstream@@QEAAHH at Z
+@ thiscall -arch=win32 ?setmode at ifstream@@QAEHH at Z(ptr long) msvcirt.?setmode at ifstream@@QAEHH at Z
+@ cdecl -arch=win64 ?setmode at ifstream@@QEAAHH at Z(ptr long) msvcirt.?setmode at ifstream@@QEAAHH at Z
 @ stub -arch=win32 ?setmode at ofstream@@QAEHH at Z
 @ stub -arch=win64 ?setmode at ofstream@@QEAAHH at Z
 @ thiscall -arch=win32 ?setp at streambuf@@IAEXPAD0 at Z(ptr ptr ptr) msvcirt.?setp at streambuf@@IAEXPAD0 at Z
-- 
2.28.0




More information about the wine-devel mailing list