From 868ac5adf89f4aa2bb63679644424c6846c87bf2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 14 Feb 2019 22:22:15 +0100 Subject: [PATCH] - switched the Windows backend to use the Windows Unicode API. With localization for non-Latin languages on the support list the multibyte API doesn't cut it anymore. It neither can handle system text output outside the local code page nor can an ANSI window receive text input outside its own code page. Similar problems exist for file names. With the multibyte API it is impossible to handle any file containing characters outside the active local code page. So as of now, everything that may pass along some Unicode text will use the Unicode API with some text conversion functions. The only places where calls to the multibyte API were left are those where known string literals are passed or where the information is not used for anything but comparing it to other return values from the same API. --- CMakeLists.txt | 4 +- src/c_dispatch.cpp | 12 +- src/d_main.cpp | 2 +- src/d_netinfo.cpp | 2 +- src/g_statusbar/sbarinfo_commands.cpp | 2 +- src/gamedata/resourcefiles/file_lump.cpp | 2 +- src/gamedata/resourcefiles/file_wad.cpp | 2 +- src/gamedata/resourcefiles/resourcefile.cpp | 4 +- .../postprocessing/hw_postprocess.h | 8 +- .../mididevices/music_win_mididevice.cpp | 4 +- src/sound/music_midi_base.cpp | 11 +- src/utility/files.cpp | 15 ++- src/utility/i_module.cpp | 6 +- src/utility/zstring.cpp | 46 +++++++ src/utility/zstring.h | 9 ++ src/v_text.cpp | 41 ++++++ src/version.h | 1 + src/win32/base_sysfb.cpp | 4 +- src/win32/i_cd.cpp | 12 +- src/win32/i_crash.cpp | 58 ++++----- src/win32/i_input.cpp | 10 +- src/win32/i_main.cpp | 86 ++++++------- src/win32/i_specialpaths.cpp | 31 ++--- src/win32/i_system.cpp | 117 ++++++++++-------- src/win32/i_system.h | 26 ++-- src/win32/optwin32.h | 5 - src/win32/st_start.cpp | 11 +- src/win32/win32basevideo.cpp | 8 +- src/win32/win32glvideo.cpp | 12 +- wadsrc/static/language.enu | 2 + 30 files changed, 325 insertions(+), 228 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc858f3f1..94c79b109 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,9 +229,7 @@ if( MSVC ) set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" ) # Disable warnings for unsecure CRT functions from VC8+ - if( MSVC_VERSION GREATER 1399 ) - set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996" ) - endif() + set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996 /DUNICODE /D_UNICODE" ) # The CMake configurations set /GR and /MD by default, which conflict with our settings. string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} ) diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 127f5f2f6..a826216fc 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -1569,13 +1569,14 @@ void FExecList::AddPullins(TArray &wads) const FExecList *C_ParseExecFile(const char *file, FExecList *exec) { - FILE *f; char cmd[4096]; int retval = 0; - if ( (f = fopen (file, "r")) ) + FileReader fr; + + if ( (fr.OpenFile(file)) ) { - while (fgets(cmd, countof(cmd)-1, f)) + while (fr.Gets(cmd, countof(cmd)-1)) { // Comments begin with // char *stop = cmd + strlen(cmd) - 1; @@ -1611,11 +1612,6 @@ FExecList *C_ParseExecFile(const char *file, FExecList *exec) } exec->AddCommand(cmd, file); } - if (!feof(f)) - { - Printf("Error parsing \"%s\"\n", file); - } - fclose(f); } else { diff --git a/src/d_main.cpp b/src/d_main.cpp index cc684976d..31e241418 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2679,7 +2679,7 @@ void D_DoomMain (void) if (StoredWarp.IsNotEmpty()) { AddCommandString(StoredWarp); - StoredWarp = NULL; + StoredWarp = ""; } } else diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6452c1f29..9c938f43b 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -933,7 +933,7 @@ void ReadUserInfo(FSerializer &arc, userinfo_t &info, FString &skin) const char *str; info.Reset(); - skin = NULL; + skin = ""; if (arc.BeginObject("userinfo")) { while ((key = arc.GetKey())) diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index bd565cbc7..b5a265c65 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -1025,7 +1025,7 @@ class CommandDrawNumber : public CommandDrawString usePrefix(false), interpolationSpeed(0), drawValue(0), length(3), lowValue(-1), lowTranslation(CR_UNTRANSLATED), highValue(-1), highTranslation(CR_UNTRANSLATED), value(CONSTANT), - inventoryItem(NULL), cvarName(nullptr) + inventoryItem(NULL) { } diff --git a/src/gamedata/resourcefiles/file_lump.cpp b/src/gamedata/resourcefiles/file_lump.cpp index da458303a..5e47183ea 100644 --- a/src/gamedata/resourcefiles/file_lump.cpp +++ b/src/gamedata/resourcefiles/file_lump.cpp @@ -79,7 +79,7 @@ bool FLumpFile::Open(bool quiet) Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].Namespace = ns_global; Lumps[0].Flags = 0; - Lumps[0].FullName = NULL; + Lumps[0].FullName = ""; NumLumps = 1; if (!quiet) { diff --git a/src/gamedata/resourcefiles/file_wad.cpp b/src/gamedata/resourcefiles/file_wad.cpp index 7b8e81bf9..f34138e62 100644 --- a/src/gamedata/resourcefiles/file_wad.cpp +++ b/src/gamedata/resourcefiles/file_wad.cpp @@ -187,7 +187,7 @@ bool FWadFile::Open(bool quiet) Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); Lumps[i].Namespace = ns_global; Lumps[i].Flags = Lumps[i].Compressed? LUMPF_COMPRESSED : 0; - Lumps[i].FullName = NULL; + Lumps[i].FullName = ""; // Check if the lump is within the WAD file and print a warning if not. if (Lumps[i].Position + Lumps[i].LumpSize > wadSize || Lumps[i].Position < 0 || Lumps[i].LumpSize < 0) diff --git a/src/gamedata/resourcefiles/resourcefile.cpp b/src/gamedata/resourcefiles/resourcefile.cpp index 1cb1f4e9f..20fb57ad3 100644 --- a/src/gamedata/resourcefiles/resourcefile.cpp +++ b/src/gamedata/resourcefiles/resourcefile.cpp @@ -490,7 +490,7 @@ void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t m for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize) { FResourceLump *lump = (FResourceLump *)p; - lump->FullName = 0; + lump->FullName = ""; lump->Name[0] = '\0'; lump->Namespace = ns_hidden; } @@ -720,7 +720,7 @@ bool FMemoryFile::Open(bool quiet) Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].Namespace = ns_global; Lumps[0].Flags = 0; - Lumps[0].FullName = nullptr; + Lumps[0].FullName = ""; NumLumps = 1; return true; } diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h b/src/rendering/hwrenderer/postprocessing/hw_postprocess.h index 0b11ec124..67b95b56c 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h +++ b/src/rendering/hwrenderer/postprocessing/hw_postprocess.h @@ -117,7 +117,7 @@ public: tex.Filter = filter; tex.Wrap = wrap; tex.Type = type; - tex.Texture = {}; + tex.Texture = ""; } void SetOutputTexture(PPTextureName texture) @@ -129,19 +129,19 @@ public: void SetOutputCurrent() { Output.Type = PPTextureType::CurrentPipelineTexture; - Output.Texture = {}; + Output.Texture = ""; } void SetOutputNext() { Output.Type = PPTextureType::NextPipelineTexture; - Output.Texture = {}; + Output.Texture = ""; } void SetOutputSceneColor() { Output.Type = PPTextureType::SceneColor; - Output.Texture = {}; + Output.Texture = ""; } void SetNoBlend() diff --git a/src/sound/mididevices/music_win_mididevice.cpp b/src/sound/mididevices/music_win_mididevice.cpp index e2605297d..71ddb4efc 100644 --- a/src/sound/mididevices/music_win_mididevice.cpp +++ b/src/sound/mididevices/music_win_mididevice.cpp @@ -664,9 +664,9 @@ void CALLBACK WinMIDIDevice::CallbackFunc(HMIDIOUT hOut, UINT uMsg, DWORD_PTR dw static bool IgnoreMIDIVolume(UINT id) { - MIDIOUTCAPS caps; + MIDIOUTCAPSA caps; - if (MMSYSERR_NOERROR == midiOutGetDevCaps(id, &caps, sizeof(caps))) + if (MMSYSERR_NOERROR == midiOutGetDevCapsA(id, &caps, sizeof(caps))) { if (caps.wTechnology == MIDIDEV_MAPPER) { diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index ac34d1cf5..bd7fa1c02 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -207,15 +207,18 @@ CCMD (snd_listmididevices) { for (id = 0; id < nummididevices; ++id) { + FString text; res = midiOutGetDevCaps (id, &caps, sizeof(caps)); if (res == MMSYSERR_NODRIVER) - strcpy (caps.szPname, ""); + text = ""; else if (res == MMSYSERR_NOMEM) - strcpy (caps.szPname, ""); - else if (res != MMSYSERR_NOERROR) + text = ""; + else if (res == MMSYSERR_NOERROR) + text = caps.szPname; + else continue; - PrintMidiDevice (id, caps.szPname, caps.wTechnology, caps.dwSupport); + PrintMidiDevice (id, text, caps.wTechnology, caps.dwSupport); } } } diff --git a/src/utility/files.cpp b/src/utility/files.cpp index 3e288a0fd..e5a17dd4f 100644 --- a/src/utility/files.cpp +++ b/src/utility/files.cpp @@ -37,6 +37,17 @@ #include "templates.h" +FILE *myfopen(const char *filename, const char *flags) +{ +#ifndef _WIN32 + return fopen(filename, flags); +#else + auto widename = WideString(filename); + auto wideflags = WideString(flags); + return _wfopen(widename.c_str(), wideflags.c_str()); +#endif +} + //========================================================================== // @@ -67,7 +78,7 @@ public: bool Open(const char *filename, long startpos = 0, long len = -1) { - File = fopen(filename, "rb"); + File = myfopen(filename, "rb"); if (File == nullptr) return false; FilePos = startpos; StartPos = startpos; @@ -407,7 +418,7 @@ bool FileReader::OpenMemoryArray(std::function&)> getter) bool FileWriter::OpenDirect(const char *filename) { - File = fopen(filename, "wb"); + File = myfopen(filename, "wb"); return (File != NULL); } diff --git a/src/utility/i_module.cpp b/src/utility/i_module.cpp index f28942109..f22a55791 100644 --- a/src/utility/i_module.cpp +++ b/src/utility/i_module.cpp @@ -41,7 +41,7 @@ #endif #ifndef _WIN32 -#define LoadLibrary(x) dlopen((x), RTLD_LAZY) +#define LoadLibraryA(x) dlopen((x), RTLD_LAZY) #define GetProcAddress(a,b) dlsym((a),(b)) #define FreeLibrary(x) dlclose((x)) using HMODULE = void*; @@ -83,14 +83,14 @@ void FModule::Unload() bool FModule::Open(const char* lib) { #ifdef _WIN32 - if((handle = GetModuleHandle(lib)) != nullptr) + if((handle = GetModuleHandleA(lib)) != nullptr) return true; #else // Loading an empty string in Linux doesn't do what we expect it to. if(*lib == '\0') return false; #endif - handle = LoadLibrary(lib); + handle = LoadLibraryA(lib); return handle != nullptr; } diff --git a/src/utility/zstring.cpp b/src/utility/zstring.cpp index 0eb8fe67d..0cffb38a2 100644 --- a/src/utility/zstring.cpp +++ b/src/utility/zstring.cpp @@ -38,6 +38,7 @@ #include // for bad_alloc #include "zstring.h" +#include "v_text.h" FNullStringData FString::NullString = { @@ -1231,6 +1232,51 @@ void FString::Split(TArray& tokens, const char *delimiter, EmptyTokenTy #define WIN32_LEAN_AND_MEAN #include +// Convert from and to Windows wide strings so that we can interface with the Unicode version of the Windows API. +FString::FString(const wchar_t *copyStr) +{ + if (copyStr == NULL || *copyStr == '\0') + { + ResetToNull(); + } + else + { + auto len = wcslen(copyStr); + int size_needed = WideCharToMultiByte(CP_UTF8, 0, copyStr, (int)len, nullptr, 0, nullptr, nullptr); + AllocBuffer(size_needed); + WideCharToMultiByte(CP_UTF8, 0, copyStr, (int)len, Chars, size_needed, nullptr, nullptr); + } +} + +FString &FString::operator=(const wchar_t *copyStr) +{ + if (copyStr == NULL || *copyStr == '\0') + { + Data()->Release(); + ResetToNull(); + } + else + { + auto len = wcslen(copyStr); + int size_needed = WideCharToMultiByte(CP_UTF8, 0, copyStr, (int)len, nullptr, 0, nullptr, nullptr); + ReallocBuffer(size_needed); + WideCharToMultiByte(CP_UTF8, 0, copyStr, (int)len, Chars, size_needed, nullptr, nullptr); + } + return *this; +} + +std::wstring WideString(const char *cin) +{ + const uint8_t *in = (const uint8_t*)cin; + // This is a bit tricky because we need to support both UTF-8 and legacy content in ISO-8859-1 + // and thanks to user-side string manipulation it can be that a text mixes both. + // To convert the string this uses the same function as all text printing in the engine. + TArray buildbuffer; + while (*in) buildbuffer.Push((wchar_t)GetCharFromString(in)); + buildbuffer.Push(0); + return std::wstring(buildbuffer.Data()); +} + static HANDLE StringHeap; const SIZE_T STRING_HEAP_SIZE = 64*1024; #endif diff --git a/src/utility/zstring.h b/src/utility/zstring.h index 2924de96d..f2130ab84 100644 --- a/src/utility/zstring.h +++ b/src/utility/zstring.h @@ -57,6 +57,9 @@ #define IGNORE_FORMAT_POST #endif +#ifdef _WIN32 +std::wstring WideString(const char *); +#endif struct FStringData { @@ -128,6 +131,12 @@ public: FString (const char *copyStr); FString (const char *copyStr, size_t copyLen); FString (char oneChar); + // This is intentionally #ifdef'd. The only code which needs this is parts of the Windows backend that receive Unicode text from the system. +#ifdef _WIN32 + explicit FString(const wchar_t *copyStr); + FString &operator = (const wchar_t *copyStr); + std::wstring WideString() const { return ::WideString(Chars); } +#endif // Concatenation constructors FString (const FString &head, const FString &tail); diff --git a/src/v_text.cpp b/src/v_text.cpp index 345f4b731..313abb275 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -55,6 +55,8 @@ int ListGetInt(VMVa_List &tags); // This can handle both ISO 8859-1 and UTF-8, as well as mixed strings // between both encodings, which may happen if inconsistent encoding is // used between different files in a mod. +// The long term goal should be to convert all text to UTF-8 on loading and +// make this require pure UTF-8 input. // //========================================================================== @@ -66,6 +68,45 @@ int GetCharFromString(const uint8_t *&string) if (z < 192) { + // Handle Windows 1252 characters + if (z >= 128 && z < 160) + { + static const uint16_t map0x80_0x9f[] = { + 0x20AC, + 0x81 , + 0x201A, + 0x0192, + 0x201E, + 0x2026, + 0x2020, + 0x2021, + 0x02C6, + 0x2030, + 0x0160, + 0x2039, + 0x0152, + 0x8d , + 0x017D, + 0x8f , + 0x90 , + 0x2018, + 0x2019, + 0x201C, + 0x201D, + 0x2022, + 0x2013, + 0x2014, + 0x02DC, + 0x2122, + 0x0161, + 0x203A, + 0x0153, + 0x9d , + 0x017E, + 0x0178, + }; + return map0x80_0x9f[z - 128]; + } return z; } else if (z <= 223) diff --git a/src/version.h b/src/version.h index 1336b47c6..2dec05a54 100644 --- a/src/version.h +++ b/src/version.h @@ -100,6 +100,7 @@ const char *GetVersionString(); // More stuff that needs to be different for derivatives. #define GAMENAME "GZDoom" +#define WGAMENAME L"GZDoom" #define GAMENAMELOWERCASE "gzdoom" #define FORUM_URL "http://forum.zdoom.org/" #define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=2" diff --git a/src/win32/base_sysfb.cpp b/src/win32/base_sysfb.cpp index c5f14404b..53384cf2b 100644 --- a/src/win32/base_sysfb.cpp +++ b/src/win32/base_sysfb.cpp @@ -287,10 +287,10 @@ void SystemBaseFrameBuffer::PositionWindow(bool fullscreen, bool initialcall) if (!m_Fullscreen && fullscreen && !initialcall) SaveWindowedPos(); if (m_Monitor) { - MONITORINFOEX mi; + MONITORINFOEXA mi; mi.cbSize = sizeof mi; - if (GetMonitorInfo(HMONITOR(m_Monitor), &mi)) + if (GetMonitorInfoA(HMONITOR(m_Monitor), &mi)) { strcpy(m_displayDeviceNameBuffer, mi.szDevice); m_displayDeviceName = m_displayDeviceNameBuffer; diff --git a/src/win32/i_cd.cpp b/src/win32/i_cd.cpp index c8dcc3d62..a127a1378 100644 --- a/src/win32/i_cd.cpp +++ b/src/win32/i_cd.cpp @@ -173,7 +173,7 @@ bool FCDThread::Init () CD_WindowClass.style = CS_NOCLOSE; CD_WindowClass.lpfnWndProc = CD_WndProc; CD_WindowClass.hInstance = g_hInst; - CD_WindowClass.lpszClassName = GAMENAME " CD Player"; + CD_WindowClass.lpszClassName = WGAMENAME " CD Player"; CD_WindowAtom = RegisterClass (&CD_WindowClass); if (CD_WindowAtom == 0) @@ -181,7 +181,7 @@ bool FCDThread::Init () CD_Window = CreateWindow ( (LPCTSTR)(INT_PTR)(int)CD_WindowAtom, - GAMENAME " CD Player", + WGAMENAME " CD Player", 0, 0, 0, 10, 10, NULL, @@ -263,12 +263,12 @@ DWORD FCDThread::Dispatch (DWORD method, DWORD parm1, DWORD parm2, DWORD parm3) DWORD firstTrack, lastTrack, numTracks; DWORD length; DWORD openFlags; - char ident[32]; + wchar_t ident[32]; switch (method) { case CDM_Init: - mciOpen.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO; + mciOpen.lpstrDeviceType = (LPCWSTR)MCI_DEVTYPE_CD_AUDIO; openFlags = MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT; if ((signed)parm1 >= 0) { @@ -411,7 +411,7 @@ DWORD FCDThread::Dispatch (DWORD method, DWORD parm1, DWORD parm2, DWORD parm3) case CDM_GetMediaIdentity: case CDM_GetMediaUPC: - char ident[32]; + wchar_t ident[32]; infoParms.lpstrReturn = ident; infoParms.dwRetSize = sizeof(ident); @@ -423,7 +423,7 @@ DWORD FCDThread::Dispatch (DWORD method, DWORD parm1, DWORD parm2, DWORD parm3) } else { - return strtoul (ident, NULL, 0); + return wcstoul (ident, NULL, 0); } default: diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index 64ffc32bd..f74fc8264 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -397,7 +397,7 @@ DWORD *GetTopOfStack (void *top) static HANDLE WriteMyMiniDump (void) { MINIDUMP_EXCEPTION_INFORMATION exceptor = { DbgThreadID, &CrashPointers, FALSE }; - char dbghelpPath[MAX_PATH+12], *bs; + WCHAR dbghelpPath[MAX_PATH+12], *bs; WRITEDUMP pMiniDumpWriteDump; HANDLE file; BOOL good = FALSE; @@ -405,17 +405,17 @@ static HANDLE WriteMyMiniDump (void) // Make sure dbghelp.dll and MiniDumpWriteDump are available // Try loading from the application directory first, then from the search path. - GetModuleFileName (NULL, dbghelpPath, MAX_PATH); + GetModuleFileNameW (NULL, dbghelpPath, MAX_PATH); dbghelpPath[MAX_PATH] = 0; - bs = strrchr (dbghelpPath, '\\'); + bs = wcsrchr (dbghelpPath, '\\'); if (bs != NULL) { - strcpy (bs + 1, "dbghelp.dll"); - dbghelp = LoadLibrary (dbghelpPath); + wcscpy (bs + 1, L"dbghelp.dll"); + dbghelp = LoadLibraryW (dbghelpPath); } if (dbghelp == NULL) { - dbghelp = LoadLibrary ("dbghelp.dll"); + dbghelp = LoadLibraryA ("dbghelp.dll"); if (dbghelp == NULL) { NeedDbgHelp = true; @@ -852,7 +852,7 @@ HANDLE WriteTextReport () static void AddToolHelp (HANDLE file) { - HMODULE kernel = GetModuleHandle ("kernel32.dll"); + HMODULE kernel = GetModuleHandleA ("kernel32.dll"); if (kernel == NULL) return; @@ -1251,7 +1251,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD Writef (file, "\r\nCall trace:\r\n rip=%p <- Here it dies.\r\n", CrashAddress); - kernel = GetModuleHandle("kernel32.dll"); + kernel = GetModuleHandleA("kernel32.dll"); if (kernel == NULL || NULL == (RtlLookupFunctionEntry = (RTLLOOKUPFUNCTIONENTRY)GetProcAddress(kernel, "RtlLookupFunctionEntry"))) { @@ -1391,18 +1391,18 @@ static void DumpBytes (HANDLE file, uint8_t *address) static HANDLE CreateTempFile () { - char temppath[MAX_PATH-13]; - char tempname[MAX_PATH]; - if (!GetTempPath (sizeof(temppath), temppath)) + WCHAR temppath[MAX_PATH-13]; + WCHAR tempname[MAX_PATH]; + if (!GetTempPathW (countof(temppath), temppath)) { temppath[0] = '.'; temppath[1] = '\0'; } - if (!GetTempFileName (temppath, "zdo", 0, tempname)) + if (!GetTempFileNameW (temppath, L"zdo", 0, tempname)) { return INVALID_HANDLE_VALUE; } - return CreateFile (tempname, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS, + return CreateFileW (tempname, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE|FILE_FLAG_SEQUENTIAL_SCAN, NULL); } @@ -1939,7 +1939,7 @@ static INT_PTR CALLBACK OverviewDlgProc (HWND hDlg, UINT message, WPARAM wParam, { if (link->msg == WM_LBUTTONDOWN) { - ShellExecute (NULL, "open", BUGS_FORUM_URL, NULL, NULL, 0); + ShellExecuteA (NULL, "open", BUGS_FORUM_URL, NULL, NULL, 0); SetWindowLongPtr (hDlg, DWLP_MSGRESULT, 1); return TRUE; } @@ -1965,8 +1965,8 @@ static INT_PTR CALLBACK OverviewDlgProc (HWND hDlg, UINT message, WPARAM wParam, static INT_PTR CALLBACK CrashDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - static CHAR overview[] = "Overview"; - static CHAR details[] = "Details"; + static WCHAR overview[] = L"Overview"; + static WCHAR details[] = L"Details"; HWND edit; TCITEM tcitem; RECT tabrect, tcrect; @@ -1987,14 +1987,14 @@ static INT_PTR CALLBACK CrashDlgProc (HWND hDlg, UINT message, WPARAM wParam, LP // dialog template, and the resultant window is stored as the lParam for // the corresponding tab. tcitem.pszText = overview; - tcitem.lParam = (LPARAM)CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_CRASHOVERVIEW), hDlg, OverviewDlgProc, (LPARAM)edit); + tcitem.lParam = (LPARAM)CreateDialogParamW (g_hInst, MAKEINTRESOURCE(IDD_CRASHOVERVIEW), hDlg, OverviewDlgProc, (LPARAM)edit); TabCtrl_InsertItem (edit, 0, &tcitem); TabCtrl_GetItemRect (edit, 0, &tabrect); SetWindowPos ((HWND)tcitem.lParam, HWND_TOP, tcrect.left + 3, tcrect.top + tabrect.bottom + 3, tcrect.right - tcrect.left - 8, tcrect.bottom - tcrect.top - tabrect.bottom - 8, 0); tcitem.pszText = details; - tcitem.lParam = (LPARAM)CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_CRASHDETAILS), hDlg, DetailsDlgProc, (LPARAM)edit); + tcitem.lParam = (LPARAM)CreateDialogParamW (g_hInst, MAKEINTRESOURCE(IDD_CRASHDETAILS), hDlg, DetailsDlgProc, (LPARAM)edit); TabCtrl_InsertItem (edit, 1, &tcitem); SetWindowPos ((HWND)tcitem.lParam, HWND_TOP, tcrect.left + 3, tcrect.top + tabrect.bottom + 3, tcrect.right - tcrect.left - 8, tcrect.bottom - tcrect.top - tabrect.bottom - 8, 0); @@ -2083,7 +2083,7 @@ static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, SendMessage (ctrl, LB_RESETCONTENT, 0, 0); for (i = 0; i < NumFiles; ++i) { - SendMessage (ctrl, LB_ADDSTRING, 0, (LPARAM)TarFiles[i].Filename); + SendMessageA (ctrl, LB_ADDSTRING, 0, (LPARAM)TarFiles[i].Filename); } if (j == LB_ERR || j >= i) j = 0; SendMessage (ctrl, LB_SETCURSEL, j, 0); @@ -2258,7 +2258,7 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum) { mysnprintf (sizebuf, countof(sizebuf), "(%lu KB)", size/1024); } - SetWindowText (sizedisplay, sizebuf); + SetWindowTextA (sizedisplay, sizebuf); SetWindowLongPtr (edit, GWLP_USERDATA, filenum); @@ -3243,21 +3243,21 @@ static void SaveReport (HANDLE file) sizeof(ofn) #endif , }; - char filename[256]; + WCHAR filename[256]; - ofn.lpstrFilter = "Zip file (*.zip)\0*.zip\0"; - strcpy (filename, "CrashReport.zip"); + ofn.lpstrFilter = L"Zip file (*.zip)\0*.zip\0"; + wcscpy (filename, L"CrashReport.zip"); ofn.lpstrFile = filename; - ofn.nMaxFile = sizeof(filename); + ofn.nMaxFile = countof(filename); - while (GetSaveFileName (&ofn)) + while (GetSaveFileNameW (&ofn)) { - HANDLE ofile = CreateFile (ofn.lpstrFile, GENERIC_WRITE, 0, NULL, + HANDLE ofile = CreateFileW (ofn.lpstrFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (ofile == INVALID_HANDLE_VALUE) { - if (MessageBox (NULL, "Could not open the crash report file", + if (MessageBoxA (NULL, "Could not open the crash report file", "Save As failed", MB_RETRYCANCEL) == IDRETRY) { continue; @@ -3306,7 +3306,7 @@ void DisplayCrashLog () "detailed information about the crash.\n" "\nThis is all that is available:\n\nCode=XXXXXXXX\nAddr=XXXXXXXX"; mysnprintf (ohPoo + countof(ohPoo) - 23, 23, "%08lX\nAddr=%p", CrashCode, CrashAddress); - MessageBox (NULL, ohPoo, GAMENAME" Very Fatal Error", MB_OK|MB_ICONSTOP); + MessageBoxA (NULL, ohPoo, GAMENAME" Very Fatal Error", MB_OK|MB_ICONSTOP); if (WinHlp32 != NULL) { FreeLibrary (WinHlp32); @@ -3314,7 +3314,7 @@ void DisplayCrashLog () } else { - HMODULE uxtheme = LoadLibrary ("uxtheme.dll"); + HMODULE uxtheme = LoadLibraryA ("uxtheme.dll"); if (uxtheme != NULL) { pEnableThemeDialogTexture = (HRESULT (__stdcall *)(HWND,DWORD))GetProcAddress (uxtheme, "EnableThemeDialogTexture"); diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 990ab416e..2854290c6 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -553,7 +553,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (message == WM_WTSSESSION_CHANGE && lParam == (LPARAM)SessionID) { #ifdef _DEBUG - OutputDebugString ("SessionID matched\n"); + OutputDebugStringA ("SessionID matched\n"); #endif // When using fast user switching, XP will lock a session before // disconnecting it, and the session will be unlocked before reconnecting it. @@ -601,7 +601,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) #ifdef _DEBUG char foo[256]; mysnprintf (foo, countof(foo), "Session Change: %ld %d\n", lParam, wParam); - OutputDebugString (foo); + OutputDebugStringA (foo); #endif } break; @@ -640,7 +640,7 @@ bool I_InitInput (void *hwnd) FindRawInputFunctions(); // Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit. - DInputDLL = LoadLibrary("dinput8.dll"); + DInputDLL = LoadLibraryA("dinput8.dll"); if (DInputDLL != NULL) { typedef HRESULT (WINAPI *blah)(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN); @@ -666,7 +666,7 @@ bool I_InitInput (void *hwnd) { FreeLibrary(DInputDLL); } - DInputDLL = LoadLibrary ("dinput.dll"); + DInputDLL = LoadLibraryA ("dinput.dll"); if (DInputDLL == NULL) { I_FatalError ("Could not load dinput.dll: %08lx", GetLastError()); @@ -967,7 +967,7 @@ static void FindRawInputFunctions() { if (!norawinput) { - HMODULE user32 = GetModuleHandle("user32.dll"); + HMODULE user32 = GetModuleHandleA("user32.dll"); if (user32 == NULL) { diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 4ca5bdce4..f3ab51d73 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -73,6 +73,7 @@ #include "s_sound.h" #include "vm.h" #include "i_system.h" +#include "gstrings.h" #include "stats.h" #include "st_start.h" @@ -143,10 +144,7 @@ FModule User32Module{"User32"}; namespace OptWin32 { #define DYN_WIN32_SYM(x) decltype(x) x{#x} -DYN_WIN32_SYM(SHGetFolderPathA); DYN_WIN32_SYM(SHGetKnownFolderPath); -DYN_WIN32_SYM(GetLongPathNameA); -DYN_WIN32_SYM(GetMonitorInfoA); #undef DYN_WIN32_SYM } // namespace OptWin32 @@ -422,7 +420,6 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) HBRUSH hbr; HGDIOBJ oldfont; RECT rect; - int titlelen; SIZE size; LOGFONT lf; TEXTMETRIC tm; @@ -440,7 +437,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) lf.lfCharSet = ANSI_CHARSET; lf.lfWeight = FW_BOLD; lf.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; - strcpy (lf.lfFaceName, "Trebuchet MS"); + wcscpy (lf.lfFaceName, L"Trebuchet MS"); GameTitleFont = CreateFontIndirect (&lf); oldfont = SelectObject (hdc, GetStockObject (DEFAULT_GUI_FONT)); @@ -459,7 +456,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) SelectObject (hdc, oldfont); // Create log read-only edit control - view = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "RichEdit20W", NULL, + view = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"RichEdit20W", nullptr, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_CLIPSIBLINGS, 0, 0, 0, 0, @@ -489,8 +486,8 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) ConWindow = view; ReleaseDC (hWnd, hdc); - view = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, hWnd, NULL, inst, NULL); - if (view == NULL) + view = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, hWnd, nullptr, inst, nullptr); + if (view == nullptr) { return -1; } @@ -526,14 +523,14 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) // Calculate width of the title string. SetTextAlign (drawitem->hDC, TA_TOP); oldfont = SelectObject (drawitem->hDC, GameTitleFont != NULL ? GameTitleFont : (HFONT)GetStockObject (DEFAULT_GUI_FONT)); - titlelen = (int)DoomStartupInfo.Name.Len(); - GetTextExtentPoint32 (drawitem->hDC, DoomStartupInfo.Name, titlelen, &size); + auto widename = DoomStartupInfo.Name.WideString(); + GetTextExtentPoint32W (drawitem->hDC, widename.c_str(), (int)widename.length(), &size); // Draw the title. c = (const PalEntry *)&DoomStartupInfo.FgColor; SetTextColor (drawitem->hDC, RGB(c->r,c->g,c->b)); SetBkMode (drawitem->hDC, TRANSPARENT); - TextOut (drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, DoomStartupInfo.Name, titlelen); + TextOutW (drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, widename.c_str(), (int)widename.length()); SelectObject (drawitem->hDC, oldfont); return TRUE; } @@ -555,12 +552,12 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) // where the command prompt would have been in DOS. if (GameTitleWindow == NULL) { - static const char QuitText[] = "Press any key or click anywhere in the window to quit."; + auto quitmsg = WideString(GStrings("TXT_QUITENDOOM")); SetTextColor (drawitem->hDC, RGB(240,240,240)); SetBkMode (drawitem->hDC, TRANSPARENT); oldfont = SelectObject (drawitem->hDC, (HFONT)GetStockObject (DEFAULT_GUI_FONT)); - TextOut (drawitem->hDC, 3, drawitem->rcItem.bottom - DefaultGUIFontHeight - 3, QuitText, countof(QuitText)-1); + TextOutW (drawitem->hDC, 3, drawitem->rcItem.bottom - DefaultGUIFontHeight - 3, quitmsg.c_str(), (int)quitmsg.length()); SelectObject (drawitem->hDC, oldfont); } return TRUE; @@ -714,12 +711,13 @@ void RestoreConView() void ShowErrorPane(const char *text) { - if (Window == NULL || ConWindow == NULL) + auto widetext = WideString(text); + if (Window == nullptr || ConWindow == nullptr) { if (text != NULL) { - MessageBox (Window, text, - GAMESIG " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); + MessageBoxW (Window, widetext.c_str(), + WGAMENAME " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); } return; } @@ -730,10 +728,10 @@ void ShowErrorPane(const char *text) } if (text != NULL) { - char caption[100]; - mysnprintf(caption, countof(caption), "Fatal Error - " GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - SetWindowText (Window, caption); - ErrorIcon = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, g_hInst, NULL); + FStringf caption("Fatal Error - " GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + auto wcaption = caption.WideString(); + SetWindowTextW (Window, wcaption.c_str()); + ErrorIcon = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, g_hInst, NULL); if (ErrorIcon != NULL) { SetWindowLong (ErrorIcon, GWL_ID, IDC_ICONPIC); @@ -768,21 +766,21 @@ void ShowErrorPane(const char *text) paraformat.dwMask = PFM_STARTINDENT | PFM_OFFSETINDENT | PFM_RIGHTINDENT; paraformat.dxStartIndent = paraformat.dxOffset = paraformat.dxRightIndent = 120; SendMessage (ConWindow, EM_SETPARAFORMAT, 0, (LPARAM)¶format); - SendMessage (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)"\n"); + SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)"\n"); // Find out where the error lines start for the error icon display control. SendMessage (ConWindow, EM_EXGETSEL, 0, (LPARAM)&end); ErrorIconChar = end.cpMax; // Now start adding the actual error message. - SendMessage (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)"Execution could not continue.\n\n"); + SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)L"Execution could not continue.\n\n"); // Restore old charformat but with light yellow text. oldformat.crTextColor = RGB(255,255,170); SendMessage (ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&oldformat); // Add the error text. - SendMessage (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)text); + SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)widetext.c_str()); // Make sure the error text is not scrolled below the window. SendMessage (ConWindow, EM_LINESCROLL, 0, SendMessage (ConWindow, EM_GETLINECOUNT, 0, 0)); @@ -798,8 +796,7 @@ void ShowErrorPane(const char *text) { if (bRet == -1) { - MessageBox (Window, text, - GAMESIG " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); + MessageBoxW (Window, widetext.c_str(), WGAMENAME " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); return; } else if (!IsDialogMessage (ErrorPane, &msg)) @@ -847,7 +844,7 @@ void DoMain (HINSTANCE hInstance) // Under XP, get our session ID so we can know when the user changes/locks sessions. // Since we need to remain binary compatible with older versions of Windows, we // need to extract the ProcessIdToSessionId function from kernel32.dll manually. - HMODULE kernel = GetModuleHandle ("kernel32.dll"); + HMODULE kernel = GetModuleHandleA ("kernel32.dll"); if (Args->CheckParm("-stdout")) { @@ -917,23 +914,19 @@ void DoMain (HINSTANCE hInstance) atterm (I_Quit); // Figure out what directory the program resides in. - char progbuff[1024]; - if (GetModuleFileName(nullptr, progbuff, sizeof progbuff) == 0) + WCHAR progbuff[1024]; + if (GetModuleFileNameW(nullptr, progbuff, sizeof progbuff) == 0) { I_FatalError("Could not determine program location."); } progbuff[1023] = '\0'; - - char *program = progbuff; - progdir = program; - program = progdir.LockBuffer(); - if (char *lastsep = strrchr(program, '\\')) + if (auto lastsep = wcsrchr(progbuff, '\\')) { lastsep[1] = '\0'; } - FixPathSeperator(program); - progdir.Truncate((long)strlen(program)); - progdir.UnlockBuffer(); + + progdir = progbuff; + FixPathSeperator(progdir); HDC screenDC = GetDC(0); int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); @@ -971,12 +964,12 @@ void DoMain (HINSTANCE hInstance) I_FatalError ("Could not register window class"); /* create window */ - char caption[100]; - mysnprintf(caption, countof(caption), "" GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + FStringf caption("" GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + std::wstring wcaption = caption.WideString(); Window = CreateWindowEx( WS_EX_APPWINDOW, (LPCTSTR)WinClassName, - (LPCTSTR)caption, + wcaption.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, x, y, width, height, (HWND) NULL, @@ -1273,7 +1266,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n InitCommonControls (); // Load some needed controls and be pretty under XP // We need to load riched20.dll so that we can create the control. - if (NULL == LoadLibrary ("riched20.dll")) + if (NULL == LoadLibraryA ("riched20.dll")) { // This should only happen on basic Windows 95 installations, but since we // don't support Windows 95, we have no obligation to provide assistance in @@ -1357,12 +1350,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n // each platform has its own specific version of this function. void I_SetWindowTitle(const char* caption) { - if (caption) - SetWindowText(Window, (LPCTSTR)caption); + std::wstring widecaption; + if (!caption) + { + FStringf default_caption("" GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + widecaption = default_caption.WideString(); + } else { - char default_caption[100]; - mysnprintf(default_caption, countof(default_caption), "" GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - SetWindowText(Window, default_caption); + widecaption = WideString(caption); } + SetWindowText(Window, widecaption.c_str()); } diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index ecd24efb1..d7a9e7c2e 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -68,15 +68,14 @@ bool UseKnownFolders() // of the program. (e.g. Somebody could add write access while the // program is running.) static INTBOOL iswritable = -1; - FString testpath; HANDLE file; if (iswritable >= 0) { return !iswritable; } - testpath << progdir << "writest"; - file = CreateFile(testpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, + std::wstring testpath = progdir.WideString() + L"writest"; + file = CreateFile(testpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); if (file != INVALID_HANDLE_VALUE) @@ -102,19 +101,14 @@ bool UseKnownFolders() bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) { - using OptWin32::SHGetFolderPathA; using OptWin32::SHGetKnownFolderPath; - char pathstr[MAX_PATH]; + WCHAR pathstr[MAX_PATH]; // SHGetKnownFolderPath knows about more folders than SHGetFolderPath, but is // new to Vista, hence the reason we support both. if (!SHGetKnownFolderPath) { - // NT4 doesn't even have this function. - if (!SHGetFolderPathA) - return false; - if (shell_folder < 0) { // Not supported by SHGetFolderPath return false; @@ -123,7 +117,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create { shell_folder |= CSIDL_FLAG_CREATE; } - if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr))) + if (FAILED(SHGetFolderPathW(NULL, shell_folder, NULL, 0, pathstr))) { return false; } @@ -137,18 +131,9 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create { return false; } - // FIXME: Support Unicode, at least for filenames. This function - // has no MBCS equivalent, so we have to convert it since we don't - // support Unicode. :( - bool converted = false; - if (WideCharToMultiByte(GetACP(), WC_NO_BEST_FIT_CHARS, wpath, -1, - pathstr, countof(pathstr), NULL, NULL) > 0) - { - path = pathstr; - converted = true; - } + path = wpath; CoTaskMemFree(wpath); - return converted; + return true; } } @@ -279,14 +264,14 @@ FString M_GetConfigPath(bool for_reading) { // Is it valid for a user name to have slashes? // Check for them and substitute just in case. - char *probe = uname; + auto probe = uname; while (*probe != 0) { if (*probe == '\\' || *probe == '/') *probe = '_'; ++probe; } - path << GAMENAMELOWERCASE "-" << uname << ".ini"; + path << GAMENAMELOWERCASE "-" << FString(uname) << ".ini"; } else { // Couldn't get user name, so just use zdoom.ini diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index bc0fb865b..5431f8b5b 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -285,10 +285,10 @@ static void SubsetLanguageIDs(LCID id, LCTYPE type, int idx) LCID langid; char *idp; - if (!GetLocaleInfo(id, type, buf, 8)) + if (!GetLocaleInfoA(id, type, buf, 8)) return; langid = MAKELCID(strtoul(buf, NULL, 16), SORT_DEFAULT); - if (!GetLocaleInfo(langid, LOCALE_SABBREVLANGNAME, buf, 8)) + if (!GetLocaleInfoA(langid, LOCALE_SABBREVLANGNAME, buf, 8)) return; idp = (char *)(&LanguageIDs[idx]); memset (idp, 0, 4); @@ -444,7 +444,7 @@ void I_FatalError(const char *error, ...) va_start(argptr, error); myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr); va_end(argptr); - OutputDebugString(errortext); + OutputDebugStringA(errortext); // Record error to log (if logging) if (Logfile) @@ -480,7 +480,7 @@ void I_Error(const char *error, ...) va_start(argptr, error); myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr); va_end(argptr); - OutputDebugString(errortext); + OutputDebugStringA(errortext); throw CRecoverableError(errortext); } @@ -768,7 +768,7 @@ static void SetQueryIWad(HWND dialog) if (!query && queryiwad) { - MessageBox(dialog, + MessageBoxA(dialog, "You have chosen not to show this dialog box in the future.\n" "If you wish to see it again, hold down SHIFT while starting " GAMENAME ".", "Don't ask me this again", @@ -796,12 +796,14 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa case WM_INITDIALOG: // Add our program name to the window title { - TCHAR label[256]; + WCHAR label[256]; FString newlabel; - GetWindowText(hDlg, label, countof(label)); - newlabel.Format(GAMESIG " %s: %s", GetVersionString(), label); - SetWindowText(hDlg, newlabel.GetChars()); + GetWindowTextW(hDlg, label, countof(label)); + FString alabel(label); + newlabel.Format(GAMESIG " %s: %s", GetVersionString(), alabel.GetChars()); + auto wlabel = newlabel.WideString(); + SetWindowTextW(hDlg, wlabel.c_str()); } // [SP] Upstreamed from Zandronum @@ -818,20 +820,20 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa // Set up our version string. sprintf(szString, "Version %s.", GetVersionString()); - SetDlgItemText (hDlg, IDC_WELCOME_VERSION, szString); + SetDlgItemTextA (hDlg, IDC_WELCOME_VERSION, szString); // Populate the list with all the IWADs found ctrl = GetDlgItem(hDlg, IDC_IWADLIST); for (i = 0; i < NumWads; i++) { - FString work; const char *filepart = strrchr(WadList[i].Path, '/'); if (filepart == NULL) filepart = WadList[i].Path; else filepart++; - work.Format("%s (%s)", WadList[i].Name.GetChars(), filepart); - SendMessage(ctrl, LB_ADDSTRING, 0, (LPARAM)work.GetChars()); + FStringf work("%s (%s)", WadList[i].Name.GetChars(), filepart); + std::wstring wide = work.WideString(); + SendMessage(ctrl, LB_ADDSTRING, 0, (LPARAM)wide.c_str()); SendMessage(ctrl, LB_SETITEMDATA, i, (LPARAM)i); } SendMessage(ctrl, LB_SETCURSEL, DefaultWad, 0); @@ -1177,7 +1179,7 @@ bool I_WriteIniFailed() ); errortext.Format ("The config file %s could not be written:\n%s", GameConfig->GetPathName(), lpMsgBuf); LocalFree (lpMsgBuf); - return MessageBox(Window, errortext.GetChars(), GAMENAME " configuration not saved", MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDRETRY; + return MessageBoxA(Window, errortext.GetChars(), GAMENAME " configuration not saved", MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDRETRY; } //========================================================================== @@ -1188,9 +1190,13 @@ bool I_WriteIniFailed() // //========================================================================== + void *I_FindFirst(const char *filespec, findstate_t *fileinfo) { - return FindFirstFileA(filespec, (LPWIN32_FIND_DATAA)fileinfo); + static_assert(sizeof(WIN32_FIND_DATAW) == sizeof(fileinfo->FindData), "Findata size mismatch"); + auto widespec = WideString(filespec); + fileinfo->UTF8Name = ""; + return FindFirstFileW(widespec.c_str(), (LPWIN32_FIND_DATAW)&fileinfo->FindData); } //========================================================================== @@ -1203,7 +1209,8 @@ void *I_FindFirst(const char *filespec, findstate_t *fileinfo) int I_FindNext(void *handle, findstate_t *fileinfo) { - return !FindNextFileA((HANDLE)handle, (LPWIN32_FIND_DATAA)fileinfo); + fileinfo->UTF8Name = ""; + return !FindNextFileW((HANDLE)handle, (LPWIN32_FIND_DATAW)&fileinfo->FindData); } //========================================================================== @@ -1219,6 +1226,20 @@ int I_FindClose(void *handle) return FindClose((HANDLE)handle); } +//========================================================================== +// +// I_FindName +// +// Returns the name for an entry +// +//========================================================================== + +const char *I_FindName(findstate_t *fileinfo) +{ + if (fileinfo->UTF8Name.IsEmpty()) fileinfo->UTF8Name = fileinfo->FindData.Name; + return fileinfo->UTF8Name.GetChars(); +} + //========================================================================== // // QueryPathKey @@ -1227,26 +1248,23 @@ int I_FindClose(void *handle) // //========================================================================== -static bool QueryPathKey(HKEY key, const char *keypath, const char *valname, FString &value) +static bool QueryPathKey(HKEY key, const wchar_t *keypath, const wchar_t *valname, FString &value) { HKEY pathkey; DWORD pathtype; DWORD pathlen; LONG res; + value = ""; if(ERROR_SUCCESS == RegOpenKeyEx(key, keypath, 0, KEY_QUERY_VALUE, &pathkey)) { if (ERROR_SUCCESS == RegQueryValueEx(pathkey, valname, 0, &pathtype, NULL, &pathlen) && pathtype == REG_SZ && pathlen != 0) { // Don't include terminating null in count - char *chars = value.LockNewBuffer(pathlen - 1); - res = RegQueryValueEx(pathkey, valname, 0, NULL, (LPBYTE)chars, &pathlen); - value.UnlockBuffer(); - if (res != ERROR_SUCCESS) - { - value = ""; - } + TArray chars(pathlen + 1, true); + res = RegQueryValueEx(pathkey, valname, 0, NULL, (LPBYTE)chars.Data(), &pathlen); + if (res == ERROR_SUCCESS) value = FString(chars.Data()); } RegCloseKey(pathkey); } @@ -1268,35 +1286,35 @@ TArray I_GetGogPaths() { TArray result; FString path; - FString gamepath; + std::wstring gamepath; #ifdef _WIN64 - FString gogregistrypath = "Software\\Wow6432Node\\GOG.com\\Games"; + std::wstring gogregistrypath = L"Software\\Wow6432Node\\GOG.com\\Games"; #else // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and // automatically redirected to the Wow6432Node address instead, so this address // should be safe to use in all cases. - FString gogregistrypath = "Software\\GOG.com\\Games"; + std::wstring gogregistrypath = "Software\\GOG.com\\Games"; #endif // Look for Ultimate Doom - gamepath = gogregistrypath + "\\1435827232"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + gamepath = gogregistrypath + L"\\1435827232"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) { result.Push(path); // directly in install folder } // Look for Doom II - gamepath = gogregistrypath + "\\1435848814"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + gamepath = gogregistrypath + L"\\1435848814"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) { result.Push(path + "/doom2"); // in a subdirectory // If direct support for the Master Levels is ever added, they are in path + /master/wads } // Look for Final Doom - gamepath = gogregistrypath + "\\1435848742"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + gamepath = gogregistrypath + L"\\1435848742"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) { // in subdirectories result.Push(path + "/TNT"); @@ -1304,15 +1322,15 @@ TArray I_GetGogPaths() } // Look for Doom 3: BFG Edition - gamepath = gogregistrypath + "\\1135892318"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + gamepath = gogregistrypath + L"\\1135892318"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) { result.Push(path + "/base/wads"); // in a subdirectory } // Look for Strife: Veteran Edition - gamepath = gogregistrypath + "\\1432899949"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + gamepath = gogregistrypath + L"\\1432899949"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) { result.Push(path); // directly in install folder } @@ -1346,9 +1364,9 @@ TArray I_GetSteamPath() FString path; - if (!QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path)) + if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", path)) { - if (!QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path)) + if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", path)) return result; } path += "/SteamApps/common/"; @@ -1375,7 +1393,7 @@ unsigned int I_MakeRNGSeed() // If RtlGenRandom is available, use that to avoid increasing the // working set by pulling in all of the crytographic API. - HMODULE advapi = GetModuleHandle("advapi32.dll"); + HMODULE advapi = GetModuleHandleA("advapi32.dll"); if (advapi != NULL) { BOOLEAN (APIENTRY *RtlGenRandom)(void *, ULONG) = @@ -1414,28 +1432,21 @@ unsigned int I_MakeRNGSeed() // //========================================================================== -FString I_GetLongPathName(FString shortpath) +FString I_GetLongPathName(const FString &shortpath) { - using OptWin32::GetLongPathNameA; - - // Doesn't exist on NT4 - if (!GetLongPathNameA) - return shortpath; - - DWORD buffsize = GetLongPathNameA(shortpath.GetChars(), NULL, 0); + std::wstring wshortpath = shortpath.WideString(); + DWORD buffsize = GetLongPathNameW(wshortpath.c_str(), nullptr, 0); if (buffsize == 0) { // nothing to change (it doesn't exist, maybe?) return shortpath; } - TCHAR *buff = new TCHAR[buffsize]; - DWORD buffsize2 = GetLongPathNameA(shortpath.GetChars(), buff, buffsize); + TArray buff(buffsize, true); + DWORD buffsize2 = GetLongPathNameW(wshortpath.c_str(), buff.Data(), buffsize); if (buffsize2 >= buffsize) { // Failure! Just return the short path - delete[] buff; return shortpath; } - FString longpath(buff, buffsize2); - delete[] buff; + FString longpath(buff.Data()); return longpath; } diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 59551a865..d03f21044 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -137,7 +137,7 @@ typedef long WLONG_PTR; #endif // Wrapper for GetLongPathName -FString I_GetLongPathName(FString shortpath); +FString I_GetLongPathName(const FString &shortpath); // Directory searching routines @@ -152,12 +152,17 @@ FString I_GetLongPathName(FString shortpath); struct findstate_t { private: - uint32_t Attribs; - uint32_t Times[3*2]; - uint32_t Size[2]; - uint32_t Reserved[2]; - char Name[MAX_PATH]; - char AltName[14]; + struct WinData + { + uint32_t Attribs; + uint32_t Times[3 * 2]; + uint32_t Size[2]; + uint32_t Reserved[2]; + wchar_t Name[MAX_PATH]; + wchar_t AltName[14]; + }; + WinData FindData; + FString UTF8Name; friend void *I_FindFirst(const char *filespec, findstate_t *fileinfo); friend int I_FindNext(void *handle, findstate_t *fileinfo); @@ -169,13 +174,10 @@ void *I_FindFirst (const char *filespec, findstate_t *fileinfo); int I_FindNext (void *handle, findstate_t *fileinfo); int I_FindClose (void *handle); -inline const char *I_FindName(findstate_t *fileinfo) -{ - return fileinfo->Name; -} +const char *I_FindName(findstate_t *fileinfo); inline int I_FindAttr(findstate_t *fileinfo) { - return fileinfo->Attribs; + return fileinfo->FindData.Attribs; } #define FA_RDONLY 0x00000001 diff --git a/src/win32/optwin32.h b/src/win32/optwin32.h index c6cced98b..2a54e8e5d 100644 --- a/src/win32/optwin32.h +++ b/src/win32/optwin32.h @@ -9,15 +9,10 @@ #include "i_module.h" -extern FModule Kernel32Module; extern FModule Shell32Module; -extern FModule User32Module; namespace OptWin32 { -extern TOptProc SHGetFolderPathA; extern TOptProc SHGetKnownFolderPath; -extern TOptProc GetLongPathNameA; -extern TOptProc GetMonitorInfoA; } // namespace OptWin32 diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index c2a0d5941..dc6b0694d 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -400,7 +400,8 @@ void FBasicStartupScreen::NetInit(const char *message, int numplayers) { HWND ctl; - SetDlgItemText (NetStartPane, IDC_NETSTARTMESSAGE, message); + std::wstring wmessage = WideString(message); + SetDlgItemTextW (NetStartPane, IDC_NETSTARTMESSAGE, wmessage.c_str()); ctl = GetDlgItem (NetStartPane, IDC_NETSTARTPROGRESS); if (numplayers == 0) @@ -416,7 +417,7 @@ void FBasicStartupScreen::NetInit(const char *message, int numplayers) // If we don't set the PBS_MARQUEE style, then the marquee will never show up. SetWindowLong (ctl, GWL_STYLE, GetWindowLong (ctl, GWL_STYLE) | PBS_MARQUEE); } - SetDlgItemText (NetStartPane, IDC_NETSTARTCOUNT, ""); + SetDlgItemTextW (NetStartPane, IDC_NETSTARTCOUNT, L""); } else { @@ -429,7 +430,7 @@ void FBasicStartupScreen::NetInit(const char *message, int numplayers) if (numplayers == 1) { SendMessage (ctl, PBM_SETPOS, 1, 0); - SetDlgItemText (NetStartPane, IDC_NETSTARTCOUNT, ""); + SetDlgItemTextW (NetStartPane, IDC_NETSTARTCOUNT, L""); } } } @@ -510,7 +511,7 @@ void FBasicStartupScreen :: NetProgress(int count) char buf[16]; mysnprintf (buf, countof(buf), "%d/%d", NetCurPos, NetMaxPos); - SetDlgItemText (NetStartPane, IDC_NETSTARTCOUNT, buf); + SetDlgItemTextA (NetStartPane, IDC_NETSTARTCOUNT, buf); SendDlgItemMessage (NetStartPane, IDC_NETSTARTPROGRESS, PBM_SETPOS, MIN(NetCurPos, NetMaxPos), 0); } } @@ -1194,7 +1195,7 @@ void ST_Endoom() bool ST_Util_CreateStartupWindow () { - StartupScreen = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "STATIC", NULL, + StartupScreen = CreateWindowEx (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, g_hInst, NULL); if (StartupScreen == NULL) diff --git a/src/win32/win32basevideo.cpp b/src/win32/win32basevideo.cpp index 300905b09..090b0bb1d 100644 --- a/src/win32/win32basevideo.cpp +++ b/src/win32/win32basevideo.cpp @@ -128,11 +128,11 @@ void Win32BaseVideo::GetDisplayDeviceName() { if (mes.hFoundMonitor) { - MONITORINFOEX mi; + MONITORINFOEXA mi; mi.cbSize = sizeof mi; - if (GetMonitorInfo(mes.hFoundMonitor, &mi)) + if (GetMonitorInfoA(mes.hFoundMonitor, &mi)) { strcpy(m_DisplayDeviceBuffer, mi.szDevice); m_DisplayDeviceName = m_DisplayDeviceBuffer; @@ -159,14 +159,14 @@ static BOOL CALLBACK DumpAdaptersMonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, { DumpAdaptersState *state = reinterpret_cast(dwData); - MONITORINFOEX mi; + MONITORINFOEXA mi; mi.cbSize = sizeof mi; char moreinfo[64] = ""; bool active = true; - if (GetMonitorInfo(hMonitor, &mi)) + if (GetMonitorInfoA(hMonitor, &mi)) { bool primary = !!(mi.dwFlags & MONITORINFOF_PRIMARY); diff --git a/src/win32/win32glvideo.cpp b/src/win32/win32glvideo.cpp index 2fb24b464..9104e546b 100644 --- a/src/win32/win32glvideo.cpp +++ b/src/win32/win32glvideo.cpp @@ -124,7 +124,7 @@ HWND Win32GLVideo::InitDummy() wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; - wc.lpszClassName = "GZDoomOpenGLDummyWindow"; + wc.lpszClassName = L"GZDoomOpenGLDummyWindow"; //Register window class if (!RegisterClass(&wc)) @@ -141,9 +141,9 @@ HWND Win32GLVideo::InitDummy() AdjustWindowRectEx(&windowRect, style, false, exStyle); //Create Window - if (!(dummy = CreateWindowEx(exStyle, - "GZDoomOpenGLDummyWindow", - "GZDOOM", + if (!(dummy = CreateWindowExW(exStyle, + L"GZDoomOpenGLDummyWindow", + WGAMENAME, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style, 0, 0, windowRect.right - windowRect.left, @@ -152,7 +152,7 @@ HWND Win32GLVideo::InitDummy() g_hInst, NULL))) { - UnregisterClass("GZDoomOpenGLDummyWindow", g_hInst); + UnregisterClassW(L"GZDoomOpenGLDummyWindow", g_hInst); return 0; } ShowWindow(dummy, SW_HIDE); @@ -169,7 +169,7 @@ HWND Win32GLVideo::InitDummy() void Win32GLVideo::ShutdownDummy(HWND dummy) { DestroyWindow(dummy); - UnregisterClass("GZDoomOpenGLDummyWindow", GetModuleHandle(NULL)); + UnregisterClassW(L"GZDoomOpenGLDummyWindow", GetModuleHandle(NULL)); } diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 6e8635a15..d23bfa65b 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2990,3 +2990,5 @@ TXT_NEED_OPASS = "You need the Oracle Pass!"; TXT_FREED_PRISONERS = "You've freed the prisoners!"; TXT_DESTROYED_CONVERTER = "You've destroyed the Converter!"; TXT_COMPLETED_TRAINING = "Congratulations! You have completed the training area"; + +TXT_QUITENDOOM = "Press any key or click anywhere in the window to quit.";