- 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.
This commit is contained in:
Christoph Oelckers 2019-02-14 22:22:15 +01:00
parent 8efc3188b9
commit 868ac5adf8
30 changed files with 325 additions and 228 deletions

View file

@ -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} )

View file

@ -1569,13 +1569,14 @@ void FExecList::AddPullins(TArray<FString> &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
{

View file

@ -2679,7 +2679,7 @@ void D_DoomMain (void)
if (StoredWarp.IsNotEmpty())
{
AddCommandString(StoredWarp);
StoredWarp = NULL;
StoredWarp = "";
}
}
else

View file

@ -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()))

View file

@ -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)
{
}

View file

@ -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)
{

View file

@ -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)

View file

@ -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;
}

View file

@ -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()

View file

@ -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)
{

View file

@ -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, "<Driver not installed>");
text = "<Driver not installed>";
else if (res == MMSYSERR_NOMEM)
strcpy (caps.szPname, "<No memory for description>");
else if (res != MMSYSERR_NOERROR)
text = "<No memory for description>";
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);
}
}
}

View file

@ -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<bool(TArray<uint8_t>&)> getter)
bool FileWriter::OpenDirect(const char *filename)
{
File = fopen(filename, "wb");
File = myfopen(filename, "wb");
return (File != NULL);
}

View file

@ -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;
}

View file

@ -38,6 +38,7 @@
#include <new> // for bad_alloc
#include "zstring.h"
#include "v_text.h"
FNullStringData FString::NullString =
{
@ -1231,6 +1232,51 @@ void FString::Split(TArray<FString>& tokens, const char *delimiter, EmptyTokenTy
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// 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<wchar_t> 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

View file

@ -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);

View file

@ -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)

View file

@ -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"

View file

@ -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;

View file

@ -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:

View file

@ -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");

View file

@ -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)
{

View file

@ -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)&paraformat);
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());
}

View file

@ -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

View file

@ -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<wchar_t> 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<FString> I_GetGogPaths()
{
TArray<FString> 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<FString> 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<FString> 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<WCHAR> 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;
}

View file

@ -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

View file

@ -9,15 +9,10 @@
#include "i_module.h"
extern FModule Kernel32Module;
extern FModule Shell32Module;
extern FModule User32Module;
namespace OptWin32 {
extern TOptProc<Shell32Module, HRESULT(WINAPI*)(HWND, int, HANDLE, DWORD, LPTSTR)> SHGetFolderPathA;
extern TOptProc<Shell32Module, HRESULT(WINAPI*)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *)> SHGetKnownFolderPath;
extern TOptProc<Kernel32Module, DWORD (WINAPI*)(LPCTSTR, LPTSTR, DWORD)> GetLongPathNameA;
extern TOptProc<User32Module, BOOL(WINAPI*)(HMONITOR, LPMONITORINFO)> GetMonitorInfoA;
} // namespace OptWin32

View file

@ -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)

View file

@ -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<DumpAdaptersState *>(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);

View file

@ -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));
}

View file

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