diff --git a/MSVC/config.h b/MSVC/config.h
index 9fbc913d3e994cc1e28b176bcf705664bb77f4a1..b901b64900de3f93e8fcd5cf1032fd8863d0cc55 100644
--- a/MSVC/config.h
+++ b/MSVC/config.h
@@ -191,7 +191,8 @@ STACK_DIRECTION = 0 => direction of growth unknown */
 #define TIME_WITH_SYS_TIME 1
 
 /* Define to 1 for Unicode (Wide Chars) APIs. */
-/* #undef UNICODE */
+#define UNICODE 1
+#undef _MBCS
 
 /* Version number of package */
 #define VERSION "2.3.0"
diff --git a/MSVC/ring-daemon.vcxproj b/MSVC/ring-daemon.vcxproj
index 1f777b471a91858dc8e69007a7348c0092198ab6..487b41eb40ff84205d6ea0fabb9b0f06e87ec794 100644
--- a/MSVC/ring-daemon.vcxproj
+++ b/MSVC/ring-daemon.vcxproj
@@ -118,7 +118,7 @@
     <UseDebugLibraries>false</UseDebugLibraries>
     <PlatformToolset>v141</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
-    <CharacterSet>MultiByte</CharacterSet>
+    <CharacterSet>Unicode</CharacterSet>
     <WindowsAppContainer>false</WindowsAppContainer>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLib|x64'" Label="Configuration">
@@ -579,7 +579,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>false</SDLCheck>
       <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\src;$(ProjectDir)..\src\client;$(ProjectDir)..\src\config;$(ProjectDir)..\src\dring;$(ProjectDir)..\src\hooks;$(ProjectDir)..\src\im;$(ProjectDir)..\src\media;$(ProjectDir)..\src\jamidht;$(ProjectDir)..\src\security;$(ProjectDir)..\src\sip;$(ProjectDir)..\src\upnp;$(ProjectDir)..\src\upnp\igd;$(ProjectDir)..\src\upnp\protocol;$(ProjectDir)..\src\upnp\mapping;$(ProjectDir)..\src\jamidht\eth;$(ProjectDir)..\contrib\msvc;$(ProjectDir)..\contrib\msvc\include;$(ProjectDir)..\contrib\build\pupnp\upnp\inc;$(ProjectDir)..\contrib\build\msgpack-c\include;$(ProjectDir)..\contrib\build\jsoncpp\include;$(ProjectDir)..\contrib\build\yaml-cpp\include;$(ProjectDir)..\contrib\build\pjproject\pjlib\include;$(ProjectDir)..\contrib\build\pjproject\pjnath\include;$(ProjectDir)..\contrib\build\pjproject\pjlib-util\include;$(ProjectDir)..\contrib\build\pjproject\pjsip\include;$(ProjectDir)..\contrib\build\pjproject\third_party;$(ProjectDir)..\contrib\build\pjproject\pjmedia\include;$(ProjectDir)..\contrib\build\restbed\source;$(ProjectDir)..\contrib\build\ffmpeg\Build\Windows10\x64\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>RING_UWP;STATICLIB;_USE_MATH_DEFINES;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;HAVE_CONFIG_H;WIN32_LEAN_AND_MEAN;WIN32_NATIVE;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>STATICLIB;_USE_MATH_DEFINES;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;HAVE_CONFIG_H;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <DisableSpecificWarnings>4996;4503;4180;4244;4267;</DisableSpecificWarnings>
       <SuppressStartupBanner>true</SuppressStartupBanner>
       <BasicRuntimeChecks>
@@ -587,6 +587,7 @@
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
diff --git a/src/archiver.cpp b/src/archiver.cpp
index 7a68157aa26cce13c13cff789bf949cc0dc5204f..b62fc24d5689d7b8e978747a7bb010cd7cb1b739 100644
--- a/src/archiver.cpp
+++ b/src/archiver.cpp
@@ -75,7 +75,7 @@ accountToJsonValue(const std::map<std::string, std::string>& details) {
                    i.first == DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE ||
                    i.first == DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE) {
             // replace paths by the files content
-            std::ifstream ifs(i.second);
+            std::ifstream ifs = fileutils::ifstream(i.second);
             std::string fileContent((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
             root[i.first] = fileContent;
         } else
diff --git a/src/data_transfer.cpp b/src/data_transfer.cpp
index 05e638b32f6c3bc6b01cc53fb8283e5ad378a71f..5b8a46e56f960d15a0aa1e2240d364743a58af87 100644
--- a/src/data_transfer.cpp
+++ b/src/data_transfer.cpp
@@ -276,7 +276,7 @@ SubOutgoingFileTransfer::SubOutgoingFileTransfer(DRing::DataTransferId tid,
 {
 
     info_ = metaInfo_->info();
-    input_.open(info_.path, std::ios::binary);
+    fileutils::openStream(input_, info_.path, std::ios::binary);
     if (!input_)
         throw std::runtime_error("input file open failed");
     metaInfo_->addLinkedTransfer(this);
@@ -438,7 +438,7 @@ private:
 OutgoingFileTransfer::OutgoingFileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info)
 : DataTransfer(tid)
 {
-    input_.open(info.path, std::ios::binary);
+    fileutils::openStream(input_, info.path, std::ios::binary);
     if (!input_)
         throw std::runtime_error("input file open failed");
 
@@ -518,7 +518,7 @@ IncomingFileTransfer::start()
     if (!DataTransfer::start())
         return false;
 
-    fout_.open(&info_.path[0], std::ios::binary);
+    fileutils::openStream(fout_, &info_.path[0], std::ios::binary);
     if (!fout_) {
         JAMI_ERR() << "[FTP] Can't open file " << info_.path;
         return false;
@@ -725,7 +725,7 @@ DataTransferFacade::acceptAsFile(const DRing::DataTransferId& id,
 #ifndef _WIN32
     iter->second->accept(file_path, offset);
 #else
-    iter->second->accept(decodeMultibyteString(file_path), offset);
+    iter->second->accept(file_path, offset);
 #endif
     return DRing::DataTransferError::success;
 }
diff --git a/src/fileutils.cpp b/src/fileutils.cpp
index 6e433073efa1788365d8de5ac9b6312ffb3e7a83..cdea17da706326a563ac90bb6e66492211806079 100644
--- a/src/fileutils.cpp
+++ b/src/fileutils.cpp
@@ -231,23 +231,29 @@ getFileLock(const std::string& path)
 
 bool isFile(const std::string& path, bool resolveSymlink)
 {
+#ifdef _WIN32
     if (resolveSymlink) {
-        struct stat s;
-        if (stat(path.c_str(), &s) == 0)
+        struct _stat64i32 s;
+        if (_wstat(jami::to_wstring(path).c_str(), &s) == 0)
             return S_ISREG(s.st_mode);
     } else {
-#ifdef _WIN32
-        DWORD attr = GetFileAttributesA(path.c_str());
+        DWORD attr = GetFileAttributes(jami::to_wstring(path).c_str());
         if ((attr != INVALID_FILE_ATTRIBUTES) &&
             !(attr & FILE_ATTRIBUTE_DIRECTORY) &&
             !(attr & FILE_ATTRIBUTE_REPARSE_POINT))
             return true;
+    }
 #else
+    if (resolveSymlink) {
+        struct stat s;
+        if (stat(path.c_str(), &s) == 0)
+            return S_ISREG(s.st_mode);
+    } else {
         struct stat s;
         if (lstat(path.c_str(), &s) == 0)
             return S_ISREG(s.st_mode);
-#endif
     }
+#endif
 
     return false;
 }
@@ -262,10 +268,7 @@ bool isDirectory(const std::string& path)
 
 bool isDirectoryWritable(const std::string &directory)
 {
-#ifdef _WIN32
-    return access(decodeMultibyteString(directory).c_str(), W_OK) == 0;
-#endif
-    return access(directory.c_str(), W_OK) == 0;
+    return accessFile(directory, W_OK) == 0;
 }
 
 bool isSymLink(const std::string& path)
@@ -301,10 +304,8 @@ writeTime(const std::string& path)
     ext_params.lpSecurityAttributes = nullptr;
     ext_params.hTemplateFile = nullptr;
     HANDLE h = CreateFile2(jami::to_wstring(path).c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &ext_params);
-#elif _MSC_VER
-    HANDLE h = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
-#else
-    HANDLE h = CreateFile(jami::to_wstring(path).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+#elif _WIN32
+    HANDLE h = CreateFileW(jami::to_wstring(path).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
 #endif
     if (h == INVALID_HANDLE_VALUE)
         throw std::runtime_error("Can't open: " + path);
@@ -359,7 +360,7 @@ std::vector<uint8_t>
 loadFile(const std::string& path, const std::string& default_dir)
 {
     std::vector<uint8_t> buffer;
-    std::ifstream file(getFullPath(default_dir, path), std::ios::binary);
+    std::ifstream file = ifstream(getFullPath(default_dir, path), std::ios::binary);
     if (!file)
         throw std::runtime_error("Can't read file: "+path);
     file.seekg(0, std::ios::end);
@@ -378,7 +379,7 @@ saveFile(const std::string& path,
         const std::vector<uint8_t>& data,
         mode_t UNUSED mode)
 {
-    std::ofstream file(path, std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(path, std::ios::trunc | std::ios::binary);
     if (!file.is_open()) {
         JAMI_ERR("Could not write data to %s", path.c_str());
         return;
@@ -581,12 +582,9 @@ get_home_dir()
         files_path = paths[0];
     return files_path;
 #elif defined _WIN32
-    WCHAR path[MAX_PATH];
-    if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, 0, path))) {
-        char tmp[MAX_PATH];
-        char DefChar = ' ';
-        WideCharToMultiByte(CP_ACP, 0, path, -1, tmp, MAX_PATH, &DefChar, nullptr);
-        return std::string(tmp);
+    TCHAR path[MAX_PATH];
+    if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PROFILE, nullptr, 0, path))) {
+        return jami::to_string(path);
     }
     return program_dir;
 #else
@@ -727,14 +725,14 @@ recursive_mkdir(const std::string& path, mode_t mode)
 #ifndef _WIN32
     if (mkdir(path.data(), mode) != 0) {
 #else
-    if (mkdir(path.data()) != 0) {
+    if (_wmkdir(jami::to_wstring(path.data()).c_str()) != 0) {
 #endif
         if (errno == ENOENT) {
             recursive_mkdir(path.substr(0, path.find_last_of(DIR_SEPARATOR_CH)), mode);
 #ifndef _WIN32
             if (mkdir(path.data(), mode) != 0) {
 #else
-            if (mkdir(path.data()) != 0) {
+            if (_wmkdir(jami::to_wstring(path.data()).c_str()) != 0) {
 #endif
                 JAMI_ERR("Could not create directory.");
                 return false;
@@ -891,4 +889,54 @@ removeAll(const std::string& path, bool erase)
     return remove(path, erase);
 }
 
+void
+openStream(std::ifstream& file, const std::string& path, std::ios_base::openmode mode)
+{
+#ifdef _WIN32
+    file.open(jami::to_wstring(path), mode);
+#else
+    file.open(path, mode);
+#endif
+}
+
+void
+openStream(std::ofstream& file, const std::string& path, std::ios_base::openmode mode)
+{
+#ifdef _WIN32
+    file.open(jami::to_wstring(path), mode);
+#else
+    file.open(path, mode);
+#endif
+}
+
+std::ifstream
+ifstream(const std::string& path, std::ios_base::openmode mode)
+{
+#ifdef _WIN32
+    return std::ifstream(jami::to_wstring(path), mode);
+#else
+    return std::ifstream(path, mode);
+#endif
+}
+
+std::ofstream
+ofstream(const std::string& path, std::ios_base::openmode mode)
+{
+#ifdef _WIN32
+    return std::ofstream(jami::to_wstring(path), mode);
+#else
+    return std::ofstream(path, mode);
+#endif
+}
+
+int
+accessFile(const std::string& file, int mode)
+{
+#ifdef _WIN32
+    return _waccess(jami::to_wstring(file).c_str(), mode);
+#else
+    return access(file.c_str(), mode);
+#endif
+}
+
 }} // namespace jami::fileutils
diff --git a/src/fileutils.h b/src/fileutils.h
index 06a561f0b16e817ec0cf99ce8c883239965d0ca5..05ceabd6c1de03cc90c190af896a6be46ccdef53 100644
--- a/src/fileutils.h
+++ b/src/fileutils.h
@@ -26,6 +26,7 @@
 #include <chrono>
 #include <mutex>
 #include <cstdio>
+#include <ios>
 
 #include "dring/def.h"
 
@@ -134,6 +135,20 @@ namespace jami { namespace fileutils {
      */
     int removeAll(const std::string& path, bool erase = false);
 
+    /**
+     * Wrappers for fstream opening that will convert paths to wstring
+     * on windows
+     */
+    void openStream(std::ifstream& file, const std::string& path, std::ios_base::openmode mode = std::ios_base::in);
+    void openStream(std::ofstream& file, const std::string& path, std::ios_base::openmode mode = std::ios_base::out);
+    std::ifstream ifstream(const std::string& path, std::ios_base::openmode mode = std::ios_base::in);
+    std::ofstream ofstream(const std::string& path, std::ios_base::openmode mode = std::ios_base::out);
+
+    /**
+     * Windows compatibility wrapper for checking read-only attribute
+     */
+    int accessFile(const std::string& file, int mode);
+
 }} // namespace jami::fileutils
 
 #endif // FILEUTILS_H_
diff --git a/src/im/message_engine.cpp b/src/im/message_engine.cpp
index c13ac59602074d9f5aed69394a8ef3ecd99759d6..033fdec71cee957bf5c4f93bc30556164be26e41 100644
--- a/src/im/message_engine.cpp
+++ b/src/im/message_engine.cpp
@@ -182,7 +182,7 @@ MessageEngine::load()
             std::lock_guard<std::mutex> lock(fileutils::getFileLock(savePath_));
             std::ifstream file;
             file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
-            file.open(savePath_);
+            fileutils::openStream(file, savePath_);
             file >> root;
         }
         std::lock_guard<std::mutex> lock(messagesMutex_);
@@ -262,7 +262,7 @@ MessageEngine::save_() const
                 const std::unique_ptr<Json::StreamWriter> writer(wbuilder.newStreamWriter());
                 std::ofstream file;
                 file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
-                file.open(path, std::ios::trunc);
+                fileutils::openStream(file, path, std::ios::trunc);
                 writer->write(root, &file);
             } catch (const std::exception& e) {
                 JAMI_ERR("[Account %s] Couldn't save messages to %s: %s", accountID.c_str(), path.c_str(), e.what());
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 72c2f509d6316270cda364884c417238300226a6..4b69a43d31b999740955c6ac3ce32bad5895f4ea 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -233,7 +233,6 @@ static const auto PROXY_REGEX = std::regex("(https?://)?([\\w\\.]+)(:(\\d+)|:\\[
 static const std::string PEER_DISCOVERY_JAMI_SERVICE = "jami";
 const constexpr auto PEER_DISCOVERY_EXPIRATION = std::chrono::minutes(1);
 
-
 constexpr const char* const JamiAccount::ACCOUNT_TYPE;
 /* constexpr */ const std::pair<uint16_t, uint16_t> JamiAccount::DHT_PORT_RANGE {4000, 8888};
 
@@ -310,9 +309,9 @@ JamiAccount::JamiAccount(const std::string& accountID, bool /* presenceEnabled *
     turnServerRealm_ = DEFAULT_TURN_REALM;
     turnEnabled_ = true;
 
-    std::ifstream proxyCache(cachePath_ + DIR_SEPARATOR_STR "dhtproxy");
+    std::ifstream proxyCache = fileutils::ifstream(cachePath_ + DIR_SEPARATOR_STR "dhtproxy");
     if (proxyCache)
-      std::getline(proxyCache, proxyServerCached_);
+        std::getline(proxyCache, proxyServerCached_);
 
     setActiveCodecs({});
 }
@@ -662,7 +661,6 @@ JamiAccount::SIPStartCall(SIPCall& call, IpAddr target)
              (int)pjContact.slen, pjContact.ptr, from.c_str(), toUri.c_str(),
              (int)pjTarget.slen, pjTarget.ptr);
 
-
     auto local_sdp = call.getSDP().getLocalSdpSession();
     pjsip_dialog* dialog {nullptr};
     pjsip_inv_session* inv {nullptr};
@@ -712,7 +710,7 @@ void JamiAccount::saveConfig() const
         auto accountConfig = getPath() + DIR_SEPARATOR_STR + "config.yml";
 
         std::lock_guard<std::mutex> lock(fileutils::getFileLock(accountConfig));
-        std::ofstream fout(accountConfig);
+        std::ofstream fout = fileutils::ofstream(accountConfig);
         fout << accountOut.c_str();
         JAMI_DBG("Exported account to %s", accountConfig.c_str());
     } catch (const std::exception& e) {
@@ -1022,7 +1020,6 @@ JamiAccount::readArchive(const std::string& pwd) const
     return AccountArchive(fileutils::getFullPath(idPath_, archivePath_), pwd);
 }
 
-
 void
 JamiAccount::updateArchive(AccountArchive& archive) const
 {
@@ -1190,9 +1187,9 @@ JamiAccount::exportArchive(const std::string& destinationPath, const std::string
         }
         // Export the file
         auto sourcePath = fileutils::getFullPath(idPath_, archivePath_);
-        std::ifstream src(sourcePath, std::ios::in | std::ios::binary);
+        std::ifstream src = fileutils::ifstream(sourcePath, std::ios::in | std::ios::binary);
         if (!src) return false;
-        std::ofstream dst(destinationPath, std::ios::out | std::ios::binary);
+        std::ofstream dst = fileutils::ofstream(destinationPath, std::ios::out | std::ios::binary);
         dst << src.rdbuf();
     } catch (const std::runtime_error& ex) {
         JAMI_ERR("[Account %s] Can't export archive: %s", getAccountID().c_str(), ex.what());
@@ -2083,7 +2080,6 @@ JamiAccount::doRegister()
     }
 }
 
-
 std::vector<std::string>
 JamiAccount::loadBootstrap() const
 {
@@ -2809,7 +2805,7 @@ std::set<ID>
 loadIdList(const std::string& path)
 {
     std::set<ID> ids;
-    std::ifstream file(path);
+    std::ifstream file = fileutils::ifstream(path);
     if (!file.is_open()) {
         JAMI_DBG("Could not load %s", path.c_str());
         return ids;
@@ -2828,7 +2824,7 @@ template<typename ID=dht::Value::Id>
 void
 saveIdList(const std::string& path, const std::set<ID>& ids)
 {
-    std::ofstream file(path, std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(path, std::ios::trunc | std::ios::binary);
     if (!file.is_open()) {
         JAMI_ERR("Could not save to %s", path.c_str());
         return;
@@ -2915,7 +2911,7 @@ JamiAccount::loadKnownDevices()
 void
 JamiAccount::saveKnownDevices() const
 {
-    std::ofstream file(idPath_+DIR_SEPARATOR_STR "knownDevicesNames", std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(idPath_+DIR_SEPARATOR_STR "knownDevicesNames", std::ios::trunc | std::ios::binary);
 
     std::map<dht::InfoHash, std::pair<std::string, uint64_t>> devices;
     for (const auto& id : knownDevices_)
@@ -2996,7 +2992,7 @@ JamiAccount::getDhtProxyServer()
         // Cache it!
         fileutils::check_dir(cachePath_.c_str(), 0700);
         std::string proxyCachePath = cachePath_ + DIR_SEPARATOR_STR "dhtproxy";
-        std::ofstream file(proxyCachePath);
+        std::ofstream file = fileutils::ofstream(proxyCachePath);
         JAMI_DBG("Cache DHT proxy server: %s", proxyServerCached_.c_str());
         if (file.is_open())
             file << proxyServerCached_;
@@ -3202,7 +3198,7 @@ JamiAccount::loadContacts()
 void
 JamiAccount::saveContacts() const
 {
-    std::ofstream file(idPath_+DIR_SEPARATOR_STR "contacts", std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(idPath_+DIR_SEPARATOR_STR "contacts", std::ios::trunc | std::ios::binary);
     msgpack::pack(file, contacts_);
 }
 
@@ -3292,7 +3288,7 @@ JamiAccount::sendTrustRequestConfirm(const dht::InfoHash& to)
 void
 JamiAccount::saveTrustRequests() const
 {
-    std::ofstream file(idPath_+DIR_SEPARATOR_STR "incomingTrustRequests", std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(idPath_+DIR_SEPARATOR_STR "incomingTrustRequests", std::ios::trunc | std::ios::binary);
     msgpack::pack(file, trustRequests_);
 }
 
@@ -3661,7 +3657,6 @@ void JamiAccount::pushNotificationReceived(const std::string& from, const std::m
     dht_.pushNotificationReceived(data);
 }
 
-
 std::string
 JamiAccount::getUserUri() const
 {
@@ -3672,7 +3667,6 @@ JamiAccount::getUserUri() const
     return username_;
 }
 
-
 std::vector<DRing::Message>
 JamiAccount::getLastMessages(const uint64_t& base_timestamp)
 {
@@ -3746,7 +3740,6 @@ JamiAccount::getNearbyPeers() const
     return discoveredPeerMap_;
 }
 
-
 void
 JamiAccount::setActiveCodecs(const std::vector<unsigned>& list)
 {
diff --git a/src/jamidht/namedirectory.cpp b/src/jamidht/namedirectory.cpp
index 37f4dbb3b8872a918c3c9276602cf1a1711f9f5c..04e54076ee270b32a5813491a42a94a0d1de44a8 100644
--- a/src/jamidht/namedirectory.cpp
+++ b/src/jamidht/namedirectory.cpp
@@ -399,7 +399,7 @@ NameDirectory::saveCache()
 {
     fileutils::recursive_mkdir(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+CACHE_DIRECTORY);
     std::lock_guard<std::mutex> lock(fileutils::getFileLock(cachePath_));
-    std::ofstream file(cachePath_, std::ios::trunc | std::ios::binary);
+    std::ofstream file = fileutils::ofstream(cachePath_, std::ios::trunc | std::ios::binary);
     {
         std::lock_guard<std::mutex> l(lock_);
         msgpack::pack(file, nameCache_);
@@ -415,7 +415,7 @@ NameDirectory::loadCache()
     // read file
     {
         std::lock_guard<std::mutex> lock(fileutils::getFileLock(cachePath_));
-        std::ifstream file(cachePath_);
+        std::ifstream file = fileutils::ifstream(cachePath_);
         if (!file.is_open()) {
             JAMI_DBG("Could not load %s", cachePath_.c_str());
             return;
diff --git a/src/manager.cpp b/src/manager.cpp
index 8d0c00fa62a053bc805eb45869784ff1eef6dfe8..644108eec5bb1256006132493931a685f1e15053 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -120,8 +120,8 @@ std::atomic_bool Manager::initialized = {false};
 static void
 copy_over(const std::string &srcPath, const std::string &destPath)
 {
-    std::ifstream src(srcPath.c_str());
-    std::ofstream dest(destPath.c_str());
+    std::ifstream src = fileutils::ifstream(srcPath.c_str());
+    std::ofstream dest = fileutils::ofstream(destPath.c_str());
     dest << src.rdbuf();
     src.close();
     dest.close();
@@ -439,7 +439,8 @@ Manager::ManagerPimpl::parseConfiguration()
     bool result = true;
 
     try {
-        YAML::Node parsedFile = YAML::LoadFile(path_);
+        std::ifstream file = fileutils::ifstream(path_);
+        YAML::Node parsedFile = YAML::Load(file);
         const int error_count = base_.loadAccountMap(parsedFile);
 
         if (error_count > 0) {
@@ -1772,7 +1773,7 @@ Manager::saveConfig()
         shortcutPreferences.serialize(out);
 
         std::lock_guard<std::mutex> lock(fileutils::getFileLock(pimpl_->path_));
-        std::ofstream fout(pimpl_->path_);
+        std::ofstream fout = fileutils::ofstream(pimpl_->path_);
         fout << out.c_str();
     } catch (const YAML::Exception &e) {
         JAMI_ERR("%s", e.what());
@@ -2158,9 +2159,7 @@ Manager::playRingtone(const std::string& accountID)
     CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
     const char *buindlePath = CFStringGetCStringPtr(stringPath, encodingMethod);
     ringchoice = std::string(buindlePath) + DIR_SEPARATOR_STR + ringchoice;
-#elif _WIN32
-    ringchoice = decodeMultibyteString(ringchoice);
-#else
+#elif !defined(_WIN32)
     if (ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos) {
         // check inside global share directory
         static const char * const RINGDIR = "ringtones";
@@ -2858,7 +2857,8 @@ Manager::loadAccountMap(const YAML::Node& node)
             if (fileutils::isFile(configFile)) {
                 try {
                     if (auto a = accountFactory.createAccount(JamiAccount::ACCOUNT_TYPE, dir)) {
-                        YAML::Node parsedConfig = YAML::LoadFile(configFile);
+                        std::ifstream file = fileutils::ifstream(configFile);
+                        YAML::Node parsedConfig = YAML::Load(file);
                         a->unserialize(parsedConfig);
                     }
                 } catch (const std::exception& e) {
diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index 1203670210ac2fa9749b5ee827a563c783ea790c..8287162bdcb5e2e7194bfcd54ef10d4df886bf94 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -832,7 +832,6 @@ MediaEncoder::getCurrentVideoAVCtx()
     return nullptr;
 }
 
-
 void
 MediaEncoder::stopEncoder()
 {
@@ -858,7 +857,7 @@ MediaEncoder::readConfig(AVCodecContext* encoderCtx)
     if (fileutils::isFile(path)) {
         try {
             Json::Value root;
-            std::ifstream file(path);
+            std::ifstream file = fileutils::ifstream(path);
             file >> root;
             if (!root.isObject()) {
                 JAMI_ERR() << "Invalid encoder configuration: root is not an object";
diff --git a/src/media/recordable.cpp b/src/media/recordable.cpp
index 669615205344d74b122bd99f164a54d5f3de74db..ed8b578d628efaa4c7604527b5116d6209c72890 100644
--- a/src/media/recordable.cpp
+++ b/src/media/recordable.cpp
@@ -60,9 +60,6 @@ Recordable::toggleRecording()
         auto startTime = *std::localtime(&t);
         std::stringstream ss;
         auto dir = Manager::instance().audioPreference.getRecordPath();
-#ifdef _WIN32
-        dir = decodeMultibyteString(dir);
-#endif
         if (dir.empty())
             dir = fileutils::get_home_dir();
         ss << dir;
diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp
index 597753b863b12f8ccfd36bab70b1325c62fa00e0..88f1bd40b199d9e9e140b23239ce0b9b982a87ce 100644
--- a/src/sip/sipaccount.cpp
+++ b/src/sip/sipaccount.cpp
@@ -1308,18 +1308,11 @@ std::string SIPAccount::getLoginName()
 #elif defined (RING_UWP)
     return "Unknown";
 #else
-    TCHAR username[UNLEN + 1];
     DWORD size = UNLEN + 1;
+    TCHAR username[UNLEN + 1];
     std::string uname;
     if (GetUserName((TCHAR*)username, &size)) {
-#ifdef _MSC_VER
-        wchar_t* tmpstr = new wchar_t[UNLEN + 1];
-        mbstowcs(tmpstr, username, UNLEN + 1);
-        std::wstring wStr = tmpstr;
-#else
-        std::wstring wStr = username;
-#endif
-        uname = std::string(wStr.begin(), wStr.end());
+        uname = jami::to_string(username);
     }
     return uname;
 #endif
diff --git a/src/string_utils.cpp b/src/string_utils.cpp
index 2f432214d8f5f16a15416ace89ab1af528a9202a..3e9cbe07051d9b9af2945a7b61713206cfd581cc 100644
--- a/src/string_utils.cpp
+++ b/src/string_utils.cpp
@@ -37,25 +37,33 @@ namespace jami {
 #ifdef _WIN32
 
 std::wstring
-to_wstring(const std::string& s)
+to_wstring(const std::string& str, int codePage)
 {
-    int slength = (int)s.length();
-    int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), slength, nullptr, 0);
-    if (not len)
-        throw std::runtime_error("Can't convert string to wchar");
-    std::wstring r((size_t)len, 0);
-    if (!MultiByteToWideChar(CP_UTF8, 0, s.c_str(), slength, &(*r.begin()), len))
-        throw std::runtime_error("Can't convert string to wchar");
-    return r;
+    int srcLength = (int)str.length();
+    int requiredSize = MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, nullptr, 0);
+    if (!requiredSize) {
+        throw std::runtime_error("Can't convert string to wstring");
+    }
+    std::wstring result((size_t)requiredSize, 0);
+    if (!MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, &(*result.begin()), requiredSize)) {
+        throw std::runtime_error("Can't convert string to wstring");
+    }
+    return result;
 }
 
 std::string
-decodeMultibyteString(const std::string& s)
+to_string(const std::wstring& wstr, int codePage)
 {
-    if (not s.length())
-        return {};
-    auto wstr = to_wstring(s);
-    return std::string(wstr.begin(), wstr.end());
+    int srcLength = (int)wstr.length();
+    int requiredSize = WideCharToMultiByte(codePage, 0, wstr.c_str(), srcLength, nullptr, 0, 0, 0);
+    if (!requiredSize) {
+        throw std::runtime_error("Can't convert wstring to string");
+    }
+    std::string result((size_t)requiredSize, 0);
+    if (!WideCharToMultiByte(codePage, 0, wstr.c_str(), srcLength, &(*result.begin()), requiredSize, 0, 0)) {
+        throw std::runtime_error("Can't convert wstring to string");
+    }
+    return result;
 }
 
 std::string
diff --git a/src/string_utils.h b/src/string_utils.h
index 8f27e78690b7cb490a838dc36a6d38aa5f8d476b..f5c69cc5a76c5d2cb4335677a7c092249db36e45 100644
--- a/src/string_utils.h
+++ b/src/string_utils.h
@@ -42,8 +42,8 @@ bool_to_str(bool b) noexcept
 std::string to_string(double value);
 
 #ifdef _WIN32
-std::wstring to_wstring(const std::string& s);
-std::string decodeMultibyteString(const std::string& s);
+std::wstring to_wstring(const std::string& str, int codePage = CP_UTF8);
+std::string to_string(const std::wstring& wstr, int codePage = CP_ACP);
 std::string bstrToStdString(BSTR bstr);
 #endif