From bab514cbd46f1d96d4c7ebad6f5bc3872b940aa3 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Mon, 7 Nov 2016 13:44:25 +0100 Subject: [PATCH] WideCharToMultiByte() and MultiByteToWideChar() template fixed to char/wchar_t and additional variants supporting std::basic_string<> added --- include/WinStd/Win.h | 77 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/include/WinStd/Win.h b/include/WinStd/Win.h index 503c8359..f2de60d8 100644 --- a/include/WinStd/Win.h +++ b/include/WinStd/Win.h @@ -195,14 +195,28 @@ template inline LSTATUS RegLoadMUIStringW /// /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// -template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); +template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); + +/// +/// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. +/// +/// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) +/// +template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); /// /// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. /// /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// -template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sWideCharStr); +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr); + +/// +/// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. +/// +/// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) +/// +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr); /// @copydoc LoadStringW template inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer); @@ -1193,10 +1207,10 @@ inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out #endif -template -inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) +template +inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) { - _Elem szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; // Try to convert to stack buffer first. int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); @@ -1206,7 +1220,7 @@ inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_cou } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Query the required output size. Allocate buffer. Then convert again. cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); - std::unique_ptr<_Elem[]> szBuffer(new _Elem[cch]); + std::unique_ptr szBuffer(new CHAR[cch]); cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : cch - 1); } @@ -1215,10 +1229,32 @@ inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_cou } -template -inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sWideCharStr) +template +inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) { - _Elem szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. + sMultiByteStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar); + std::unique_ptr szBuffer(new CHAR[cch]); + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.assign(szBuffer.get(), cch); + } + + return cch; +} + + +template +inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; // Try to convert to stack buffer first. int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); @@ -1228,7 +1264,7 @@ inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_cou } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Query the required output size. Allocate buffer. Then convert again. cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); - std::unique_ptr<_Elem[]> szBuffer(new _Elem[cch]); + std::unique_ptr szBuffer(new WCHAR[cch]); cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch); sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : cch - 1); } @@ -1237,6 +1273,27 @@ inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_cou } +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr) +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0); + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch); + sWideCharStr.assign(szBuffer.get(), cch); + } + + return cch; +} + + template inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) {