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.";