diff --git a/src/basicio.cpp b/src/basicio.cpp
index 3971cb50c..b76f86e61 100644
--- a/src/basicio.cpp
+++ b/src/basicio.cpp
@@ -51,6 +51,64 @@ namespace fs = std::experimental::filesystem;
 #endif
 
 namespace Exiv2 {
+#if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN__))
+    /// Remove unsuportted options flags
+    unsigned long getMultiByteToWideCharOptions(const unsigned long ori_options, unsigned int cp) {
+        if (cp == CP_ACP) cp = GetACP();
+        if (cp == CP_OEMCP) cp = GetOEMCP();
+        switch (cp)
+        {
+        case 50220:
+        case 50221:
+        case 50222:
+        case 50225:
+        case 50227:
+        case 50229:
+        case CP_UTF7:
+        case 42:
+            return 0;
+        default:
+            break;
+        }
+        if (cp >= 57002 && cp <= 57011) return 0;
+        if (cp == CP_UTF8 || cp == 54936) {
+            return MB_ERR_INVALID_CHARS & ori_options;
+        }
+        return ori_options;
+    }
+    bool str_to_wstr(std::wstring& out, std::string inp, unsigned int cp) {
+        DWORD opt = getMultiByteToWideCharOptions(MB_ERR_INVALID_CHARS, cp);
+        int wlen = MultiByteToWideChar(cp, opt, inp.c_str(), inp.length(), nullptr, 0);
+        if (!wlen) {
+            return false;
+        }
+        wchar_t* wstr = (wchar_t*)malloc(wlen * sizeof(wchar_t));
+        if (wstr == nullptr) {
+            return false;
+        }
+        if (!MultiByteToWideChar(cp, opt, inp.c_str(), inp.length(), wstr, wlen)) {
+            free(wstr);
+            return false;
+        }
+        out = std::wstring(wstr, wlen);
+        free(wstr);
+        return true;
+    }
+    FILE* win32_fopen(const char* path, const char* mode) {
+        std::string p(path), m(mode);
+        FILE* f = nullptr;
+        unsigned long cps[] = { CP_UTF8, CP_ACP, CP_OEMCP };
+        for (int i = 0; i < 3; i++) {
+            std::wstring wp, wm;
+            if (str_to_wstr(wp, p, cps[i]) && str_to_wstr(wm, m, cps[i])) {
+                if ((f = _wfopen(wp.c_str(), wm.c_str()))) {
+                    return f;
+                }
+            }
+        }
+        return std::fopen(path, mode);
+    }
+#endif
 void BasicIo::readOrThrow(byte* buf, size_t rcount, ErrorCode err) {
   const size_t nread = read(buf, rcount);
   Internal::enforce(nread == rcount, err);
@@ -158,7 +216,11 @@ int FileIo::Impl::switchMode(OpMode opMode) {
   std::fclose(fp_);
   openMode_ = "r+b";
   opMode_ = opSeek;
+#if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN__))
+  fp_ = win32_fopen(path_.c_str(), openMode_.c_str());
+#else
   fp_ = std::fopen(path_.c_str(), openMode_.c_str());
+#endif
   if (!fp_)
     return 1;
 #ifdef _WIN32
@@ -479,7 +541,11 @@ int FileIo::open(const std::string& mode) {
   close();
   p_->openMode_ = mode;
   p_->opMode_ = Impl::opSeek;
+#if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN__))
+  p_->fp_ = win32_fopen(path().c_str(), mode.c_str());
+#else
   p_->fp_ = ::fopen(path().c_str(), mode.c_str());
+#endif
   if (!p_->fp_)
     return 1;
   return 0;
