diff --git a/include/share/compat.h b/include/share/compat.h
index 3ae9d8d..db5f7ca 100644
--- a/include/share/compat.h
+++ b/include/share/compat.h
@@ -188,10 +188,12 @@
  *
  * This function wraps the MS version to behave more like the the ISO version.
  */
+#include <stdarg.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
 int flac_snprintf(char *str, size_t size, const char *fmt, ...);
+int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
 #ifdef __cplusplus
 };
 #endif
diff --git a/src/flac/utils.c b/src/flac/utils.c
index d0102b4..59dd845 100644
--- a/src/flac/utils.c
+++ b/src/flac/utils.c
@@ -247,12 +247,8 @@ void stats_print_info(int level, const char *format, ...)
 	if (flac__utils_verbosity_ >= level) {
 		va_list args;
 		va_start(args, format);
-		len = vsnprintf(tmp, sizeof(tmp), format, args);
+		len = flac_vsnprintf(tmp, sizeof(tmp), format, args);
 		va_end(args);
-		if (len < 0 || len == sizeof(tmp)) {
-			tmp[sizeof(tmp)-1] = '\0';
-			len = sizeof(tmp)-1;
-		}
 		stats_clear();
 		if (len >= console_chars_left) {
 			clear_len = console_chars_left;
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
index 778bb8c..d50df39 100644
--- a/src/libFLAC/metadata_iterators.c
+++ b/src/libFLAC/metadata_iterators.c
@@ -3201,13 +3201,18 @@ static int
 local_snprintf(char *str, size_t size, const char *fmt, ...)
 {
 	va_list va;
-	int rc ;
+	int rc;
 
 	va_start (va, fmt);
 
-#ifdef _MSC_VER
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
 	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
-	rc = (rc > 0) ? rc : (size == 0 ? 1024 : size * 2);
+	if (rc < 0)
+		rc = size - 1;
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
 #else
 	rc = vsnprintf (str, size, fmt, va);
 #endif
diff --git a/src/share/grabbag/snprintf.c b/src/share/grabbag/snprintf.c
index 3a0661f..d19e42c 100644
--- a/src/share/grabbag/snprintf.c
+++ b/src/share/grabbag/snprintf.c
@@ -49,7 +49,7 @@
  * does not over-write the end of the buffer. MS's snprintf_s in this case
  * returns -1.
  *
- * The _MSC_VER code below attempts to modify the return code for snprintf_s
+ * The _MSC_VER code below attempts to modify the return code for vsnprintf_s
  * to something that is more compatible with the behaviour of the ISO C version.
  */
 
@@ -57,13 +57,18 @@ int
 flac_snprintf(char *str, size_t size, const char *fmt, ...)
 {
 	va_list va;
-	int rc ;
+	int rc;
 
 	va_start (va, fmt);
 
-#ifdef _MSC_VER
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
 	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
-	rc = (rc > 0) ? rc : (size == 0 ? 1024 : size * 2);
+	if (rc < 0)
+		rc = size - 1;
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
 #else
 	rc = vsnprintf (str, size, fmt, va);
 #endif
@@ -71,3 +76,23 @@ flac_snprintf(char *str, size_t size, const char *fmt, ...)
 
 	return rc;
 }
+
+int
+flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+	int rc;
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+	if (rc < 0)
+		rc = size - 1;
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+	rc = vsnprintf (str, size, fmt, va);
+#endif
+
+	return rc;
+}
diff --git a/src/share/win_utf8_io/win_utf8_io.c b/src/share/win_utf8_io/win_utf8_io.c
index 31b4443..d7a2d09 100644
--- a/src/share/win_utf8_io/win_utf8_io.c
+++ b/src/share/win_utf8_io/win_utf8_io.c
@@ -45,6 +45,28 @@
 
 #include "share/win_utf8_io.h"
 
+#define UTF8_BUFFER_SIZE 32768
+
+static
+int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+	int rc;
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+	if (rc < 0)
+		rc = size - 1;
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+	rc = vsnprintf (str, size, fmt, va);
+#endif
+
+	return rc;
+}
+
 static UINT win_utf8_io_codepage = CP_ACP;
 
 /* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */
@@ -177,9 +199,9 @@ int printf_utf8(const char *format, ...)
 
 	while (1) {
 		va_list argptr;
-		if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
+		if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
 		va_start(argptr, format);
-		ret = vsnprintf_s(utmp, 32768, _TRUNCATE, format, argptr);
+		ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr);
 		va_end(argptr);
 		if (ret < 0) break;
 		if (!(wout = wchar_from_utf8(utmp))) {
@@ -203,9 +225,9 @@ int fprintf_utf8(FILE *stream, const char *format, ...)
 
 	while (1) {
 		va_list argptr;
-		if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
+		if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
 		va_start(argptr, format);
-		ret = vsnprintf_s(utmp, 32768, _TRUNCATE, format, argptr);
+		ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr);
 		va_end(argptr);
 		if (ret < 0) break;
 		if (!(wout = wchar_from_utf8(utmp))) {
@@ -228,8 +250,8 @@ int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
 	int ret = -1;
 
 	while (1) {
-		if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
-		if ((ret = vsnprintf_s(utmp, 32768, _TRUNCATE, format, argptr)) < 0) break;
+		if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
+		if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr)) < 0) break;
 		if (!(wout = wchar_from_utf8(utmp))) {
 			ret = -1;
 			break;
