diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 0a4fa936bf25c7eea1ace23c0cd0876a9186a696..4a724bc70b1212d58c586556817730e0ddcb8433 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -1647,8 +1647,8 @@
 @ cdecl wcsnlen(wstr long) msvcrt.wcsnlen
 @ cdecl wcspbrk(wstr wstr) msvcrt.wcspbrk
 @ cdecl wcsrchr(wstr long) msvcrt.wcsrchr
-@ stub wcsrtombs
-@ stub wcsrtombs_s
+@ cdecl wcsrtombs(ptr ptr long ptr) msvcrt.wcsrtombs
+@ cdecl wcsrtombs_s(ptr ptr long ptr long ptr) msvcrt.wcsrtombs_s
 @ cdecl wcsspn(wstr wstr) msvcrt.wcsspn
 @ cdecl wcsstr(wstr wstr) msvcrt.wcsstr
 @ cdecl wcstod(wstr ptr) msvcrt.wcstod
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index d8a5ca366840cbbf3c00159c990ae89319fd056c..3f5bd041a93b00ced06a742e2546d6fae2d37e58 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -1501,8 +1501,8 @@
 @ cdecl wcsnlen(wstr long) msvcrt.wcsnlen
 @ cdecl wcspbrk(wstr wstr) msvcrt.wcspbrk
 @ cdecl wcsrchr(wstr long) msvcrt.wcsrchr
-@ stub wcsrtombs
-@ stub wcsrtombs_s
+@ cdecl wcsrtombs(ptr ptr long ptr) msvcrt.wcsrtombs
+@ cdecl wcsrtombs_s(ptr ptr long ptr long ptr) msvcrt.wcsrtombs_s
 @ cdecl wcsspn(wstr wstr) msvcrt.wcsspn
 @ cdecl wcsstr(wstr wstr) msvcrt.wcsstr
 @ cdecl wcstod(wstr ptr) msvcrt.wcstod
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index 56d8c2dd8b56d2438952d79bd25ec1bcc037eccb..c7efd3a6f097a2a2f4167819945a9a1d5018be99 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -1485,8 +1485,8 @@
 @ cdecl wcsnlen(wstr long) msvcrt.wcsnlen
 @ cdecl wcspbrk(wstr wstr) msvcrt.wcspbrk
 @ cdecl wcsrchr(wstr long) msvcrt.wcsrchr
-@ stub wcsrtombs
-@ stub wcsrtombs_s
+@ cdecl wcsrtombs(ptr ptr long ptr) msvcrt.wcsrtombs
+@ cdecl wcsrtombs_s(ptr ptr long ptr long ptr) msvcrt.wcsrtombs_s
 @ cdecl wcsspn(wstr wstr) msvcrt.wcsspn
 @ cdecl wcsstr(wstr wstr) msvcrt.wcsstr
 @ cdecl wcstod(wstr ptr) msvcrt.wcstod
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 852fe9279ad13fe13c4e39db6746cc6d5f59e86f..40d72616c9a18ca305cd7c6cdcd7e3b89f9be1ea 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -74,6 +74,7 @@ typedef int MSVCRT_clock_t;
 typedef int MSVCRT___time32_t;
 typedef __int64 DECLSPEC_ALIGN(8) MSVCRT___time64_t;
 typedef __int64 DECLSPEC_ALIGN(8) MSVCRT_fpos_t;
+typedef int MSVCRT_mbstate_t;
 
 typedef void (*__cdecl MSVCRT_terminate_handler)(void);
 typedef void (*__cdecl MSVCRT_terminate_function)(void);
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index c1e7b75e5567ac5e5f2401b0ac0b21b5e79d332e..94064fe0d276cef69a96b5b971db710b64d4f890 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -1456,8 +1456,8 @@
 @ cdecl wcsnlen(wstr long) MSVCRT_wcsnlen
 @ cdecl wcspbrk(wstr wstr) MSVCRT_wcspbrk
 @ cdecl wcsrchr(wstr long) ntdll.wcsrchr
-# stub wcsrtombs
-# stub wcsrtombs_s
+@ cdecl wcsrtombs(ptr ptr long ptr) MSVCRT_wcsrtombs
+@ cdecl wcsrtombs_s(ptr ptr long ptr long ptr) MSVCRT_wcsrtombs_s
 @ cdecl wcsspn(wstr wstr) ntdll.wcsspn
 @ cdecl wcsstr(wstr wstr) ntdll.wcsstr
 @ cdecl wcstod(wstr ptr) MSVCRT_wcstod
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index 8b0494b11dc7967aad6c3fd18956158c849e0522..b72e001c38c4a805088faeb700f56dbaaf7361ae 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -68,6 +68,7 @@ static __int64 (__cdecl *p_strtoi64)(const char *, char **, int);
 static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int);
 static int (__cdecl *pwcstombs_s)(size_t*,char*,size_t,const wchar_t*,size_t);
 static int (__cdecl *pmbstowcs_s)(size_t*,wchar_t*,size_t,const char*,size_t);
+static size_t (__cdecl *pwcsrtombs)(char*, const wchar_t**, size_t, int*);
 static errno_t (__cdecl *p_gcvt_s)(char*,size_t,double,int);
 static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int);
 static errno_t (__cdecl *p_strlwr_s)(char*,size_t);
@@ -1283,6 +1284,7 @@ static void test_mbstowcs(void)
     static const char mSimple[] = "text";
     static const char mHiragana[] = { 0x82,0xa0,0x82,0xa1,0 };
 
+    const wchar_t *pwstr;
     wchar_t wOut[6];
     char mOut[6];
     size_t ret;
@@ -1355,6 +1357,25 @@ static void test_mbstowcs(void)
     err = pwcstombs_s(&ret, NULL, 0, wHiragana, 1);
     ok(err == 0, "err = %d\n", err);
     ok(ret == 5, "ret = %d\n", (int)ret);
+
+    if(!pwcsrtombs) {
+        win_skip("wcsrtombs not available\n");
+        return;
+    }
+
+    pwstr = wSimple;
+    err = -3;
+    ret = pwcsrtombs(mOut, &pwstr, 4, &err);
+    ok(ret == 4, "ret = %d\n", ret);
+    ok(err == 0, "err = %d\n", err);
+    ok(pwstr == wSimple+4, "pwstr = %p (wszSimple = %p)\n", pwstr, wSimple);
+    ok(!memcmp(mOut, mSimple, ret), "mOut = %s\n", mOut);
+
+    pwstr = wSimple;
+    ret = pwcsrtombs(mOut, &pwstr, 5, NULL);
+    ok(ret == 4, "ret = %d\n", ret);
+    ok(pwstr == NULL, "pwstr != NULL\n");
+    ok(!memcmp(mOut, mSimple, sizeof(mSimple)), "mOut = %s\n", mOut);
 }
 
 static void test_gcvt(void)
@@ -1974,6 +1995,7 @@ START_TEST(string)
     p_strtoui64 = (void *)GetProcAddress(hMsvcrt, "_strtoui64");
     pmbstowcs_s = (void *)GetProcAddress(hMsvcrt, "mbstowcs_s");
     pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s");
+    pwcsrtombs = (void *)GetProcAddress(hMsvcrt, "wcsrtombs");
     p_gcvt_s = (void *)GetProcAddress(hMsvcrt, "_gcvt_s");
     p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s");
     p_strlwr_s = (void *)GetProcAddress(hMsvcrt, "_strlwr_s");
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index c0cdde16a356ae8970ee6f56341b870ecc5884e8..5a7a43cfb93b613634c3d41b725b9b48c48ee4b6 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -288,9 +288,9 @@ double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
 }
 
 /*********************************************************************
- *		_wcstombs_l (MSVCRT.@)
+ * wcsrtombs_l (INTERNAL)
  */
-MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
+static MSVCRT_size_t CDECL MSVCRT_wcsrtombs_l(char *mbstr, const MSVCRT_wchar_t **wcstr,
         MSVCRT_size_t count, MSVCRT__locale_t locale)
 {
     char default_char = '\0';
@@ -302,14 +302,14 @@ MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
 
     if(!mbstr)
         return WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
-                wcstr, -1, NULL, 0, &default_char, &used_default)-1;
+                *wcstr, -1, NULL, 0, &default_char, &used_default)-1;
 
-    while(*wcstr) {
+    while(**wcstr) {
         char buf[3];
         MSVCRT_size_t i, size;
 
         size = WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
-                wcstr, 1, buf, 3, &default_char, &used_default);
+                *wcstr, 1, buf, 3, &default_char, &used_default);
         if(used_default)
             return -1;
         if(tmp+size > count)
@@ -317,40 +317,64 @@ MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
 
         for(i=0; i<size; i++)
             mbstr[tmp++] = buf[i];
-        wcstr++;
+        (*wcstr)++;
     }
 
-    if(tmp < count)
+    if(tmp < count) {
         mbstr[tmp] = '\0';
+        *wcstr = NULL;
+    }
     return tmp;
 }
 
+/*********************************************************************
+ *		_wcstombs_l (MSVCRT.@)
+ */
+MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
+        MSVCRT_size_t count, MSVCRT__locale_t locale)
+{
+    return MSVCRT_wcsrtombs_l(mbstr, &wcstr, count, locale);
+}
+
 /*********************************************************************
  *		wcstombs (MSVCRT.@)
  */
 MSVCRT_size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr,
         MSVCRT_size_t count)
 {
-    return MSVCRT__wcstombs_l(mbstr, wcstr, count, NULL);
+    return MSVCRT_wcsrtombs_l(mbstr, &wcstr, count, NULL);
 }
 
 /*********************************************************************
- *		_wcstombs_s_l (MSVCRT.@)
+ *		wcsrtombs (MSVCRT.@)
  */
-MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
-        MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
+MSVCRT_size_t CDECL MSVCRT_wcsrtombs(char *mbstr, const MSVCRT_wchar_t **wcstr,
+        MSVCRT_size_t count, MSVCRT_mbstate_t *mbstate)
+{
+    if(mbstate)
+        *mbstate = 0;
+
+    return MSVCRT_wcsrtombs_l(mbstr, wcstr, count, NULL);
+}
+
+/*********************************************************************
+ * MSVCRT_wcsrtombs_s_l (INTERNAL)
+ */
+MSVCRT_size_t CDECL MSVCRT_wcsrtombs_s_l(MSVCRT_size_t *ret, char *mbstr,
+        MSVCRT_size_t size, const MSVCRT_wchar_t **wcstr,
         MSVCRT_size_t count, MSVCRT__locale_t locale)
 {
     MSVCRT_size_t conv;
 
-    if(!mbstr && !size) {
-        conv = MSVCRT__wcstombs_l(NULL, wcstr, 0, locale);
+    if(!mbstr && !size && wcstr) {
+        conv = MSVCRT_wcsrtombs_l(NULL, wcstr, 0, locale);
         if(ret)
             *ret = conv+1;
         return 0;
     }
 
-    if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(mbstr != NULL)) {
+    if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(*wcstr != NULL)
+            || !MSVCRT_CHECK_PMT(mbstr != NULL)) {
         if(mbstr && size)
             mbstr[0] = '\0';
         *MSVCRT__errno() = MSVCRT_EINVAL;
@@ -362,7 +386,7 @@ MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
     else
         conv = count;
 
-    conv = MSVCRT__wcstombs_l(mbstr, wcstr, conv, locale);
+    conv = MSVCRT_wcsrtombs_l(mbstr, wcstr, conv, locale);
     if(conv<size)
         mbstr[conv++] = '\0';
     else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0'))
@@ -380,13 +404,35 @@ MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
     return 0;
 }
 
+/*********************************************************************
+ *		_wcstombs_s_l (MSVCRT.@)
+ */
+MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
+        MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
+        MSVCRT_size_t count, MSVCRT__locale_t locale)
+{
+    return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, &wcstr,count, locale);
+}
+
 /*********************************************************************
  *		wcstombs_s (MSVCRT.@)
  */
 MSVCRT_size_t CDECL MSVCRT_wcstombs_s(MSVCRT_size_t *ret, char *mbstr,
         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr, MSVCRT_size_t count)
 {
-    return MSVCRT__wcstombs_s_l(ret, mbstr, size, wcstr, count, NULL);
+    return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, &wcstr, count, NULL);
+}
+
+/*********************************************************************
+ *		wcsrtombs_s (MSVCRT.@)
+ */
+MSVCRT_size_t CDECL MSVCRT_wcsrtombs_s(MSVCRT_size_t *ret, char *mbstr, MSVCRT_size_t size,
+        const MSVCRT_wchar_t **wcstr, MSVCRT_size_t count, MSVCRT_mbstate_t *mbstate)
+{
+    if(mbstate)
+        *mbstate = 0;
+
+    return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, wcstr, count, NULL);
 }
 
 /*********************************************************************