- moved all exception handling out of the backends
The main catch is now in D_DoomMain, only calling platform specific functions to handle the output for the error. As a nice side effect, -norun can now be done without an exception, just by exiting D_DoomMain with a special exit code.
This commit is contained in:
parent
b5fa08bf15
commit
96006eb94f
11 changed files with 251 additions and 289 deletions
|
|
@ -145,15 +145,6 @@ static HMODULE hwtsapi32; // handle to wtsapi32.dll
|
|||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static int NewFailure (size_t size)
|
||||
{
|
||||
I_FatalError ("Failed to allocate %d bytes from process heap", size);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// UnCOM
|
||||
|
|
@ -765,214 +756,213 @@ void DoMain (HINSTANCE hInstance)
|
|||
RECT cRect;
|
||||
TIMECAPS tc;
|
||||
DEVMODE displaysettings;
|
||||
|
||||
try
|
||||
|
||||
// Do not use the multibyte __argv here because we want UTF-8 arguments
|
||||
// and those can only be done by converting the Unicode variants.
|
||||
Args = new FArgs();
|
||||
auto argc = __argc;
|
||||
auto wargv = __wargv;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_set_new_handler (NewFailure);
|
||||
#endif
|
||||
|
||||
// Do not use the multibyte __argv here because we want UTF-8 arguments
|
||||
// and those can only be done by converting the Unicode variants.
|
||||
Args = new FArgs();
|
||||
auto argc = __argc;
|
||||
auto wargv = __wargv;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
Args->AppendArg(FString(wargv[i]));
|
||||
}
|
||||
|
||||
// Load Win32 modules
|
||||
Kernel32Module.Load({"kernel32.dll"});
|
||||
Shell32Module.Load({"shell32.dll"});
|
||||
User32Module.Load({"user32.dll"});
|
||||
|
||||
// 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 = GetModuleHandleA ("kernel32.dll");
|
||||
|
||||
if (Args->CheckParm("-stdout"))
|
||||
{
|
||||
// As a GUI application, we don't normally get a console when we start.
|
||||
// If we were run from the shell and are on XP+, we can attach to its
|
||||
// console. Otherwise, we can create a new one. If we already have a
|
||||
// stdout handle, then we have been redirected and should just use that
|
||||
// handle instead of creating a console window.
|
||||
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (StdOut != NULL)
|
||||
{
|
||||
// It seems that running from a shell always creates a std output
|
||||
// for us, even if it doesn't go anywhere. (Running from Explorer
|
||||
// does not.) If we can get file information for this handle, it's
|
||||
// a file or pipe, so use it. Otherwise, pretend it wasn't there
|
||||
// and find a console to use instead.
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!GetFileInformationByHandle(StdOut, &info))
|
||||
{
|
||||
StdOut = NULL;
|
||||
}
|
||||
}
|
||||
if (StdOut == NULL)
|
||||
{
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
{
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD foo; WriteFile(StdOut, "\n", 1, &foo, NULL);
|
||||
AttachedStdOut = true;
|
||||
}
|
||||
if (StdOut == NULL && AllocConsole())
|
||||
{
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
// These two functions do not exist in Windows XP.
|
||||
BOOL (WINAPI* p_GetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
|
||||
BOOL (WINAPI* p_SetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
|
||||
|
||||
p_SetCurrentConsoleFontEx = (decltype(p_SetCurrentConsoleFontEx))GetProcAddress(kernel, "SetCurrentConsoleFontEx");
|
||||
p_GetCurrentConsoleFontEx = (decltype(p_GetCurrentConsoleFontEx))GetProcAddress(kernel, "GetCurrentConsoleFontEx");
|
||||
if (p_SetCurrentConsoleFontEx && p_GetCurrentConsoleFontEx)
|
||||
{
|
||||
CONSOLE_FONT_INFOEX cfi;
|
||||
cfi.cbSize = sizeof(cfi);
|
||||
|
||||
if (p_GetCurrentConsoleFontEx(StdOut, false, &cfi))
|
||||
{
|
||||
if (*cfi.FaceName == 0) // If the face name is empty, the default (useless) raster font is actoive.
|
||||
{
|
||||
//cfi.dwFontSize = { 8, 14 };
|
||||
wcscpy(cfi.FaceName, L"Lucida Console");
|
||||
cfi.FontFamily = FF_DONTCARE;
|
||||
p_SetCurrentConsoleFontEx(StdOut, false, &cfi);
|
||||
}
|
||||
}
|
||||
}
|
||||
FancyStdOut = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the timer to be as accurate as possible
|
||||
if (timeGetDevCaps (&tc, sizeof(tc)) != TIMERR_NOERROR)
|
||||
TimerPeriod = 1; // Assume minimum resolution of 1 ms
|
||||
else
|
||||
TimerPeriod = tc.wPeriodMin;
|
||||
|
||||
timeBeginPeriod (TimerPeriod);
|
||||
atexit(UnTbp);
|
||||
|
||||
atexit (call_terms);
|
||||
|
||||
// Figure out what directory the program resides in.
|
||||
WCHAR progbuff[1024];
|
||||
if (GetModuleFileNameW(nullptr, progbuff, sizeof progbuff) == 0)
|
||||
{
|
||||
I_FatalError("Could not determine program location.");
|
||||
}
|
||||
progbuff[1023] = '\0';
|
||||
if (auto lastsep = wcsrchr(progbuff, '\\'))
|
||||
{
|
||||
lastsep[1] = '\0';
|
||||
}
|
||||
|
||||
progdir = progbuff;
|
||||
FixPathSeperator(progdir);
|
||||
|
||||
HDC screenDC = GetDC(0);
|
||||
int dpi = GetDeviceCaps(screenDC, LOGPIXELSX);
|
||||
ReleaseDC(0, screenDC);
|
||||
width = (512 * dpi + 96 / 2) / 96;
|
||||
height = (384 * dpi + 96 / 2) / 96;
|
||||
|
||||
// Many Windows structures that specify their size do so with the first
|
||||
// element. DEVMODE is not one of those structures.
|
||||
memset (&displaysettings, 0, sizeof(displaysettings));
|
||||
displaysettings.dmSize = sizeof(displaysettings);
|
||||
EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
|
||||
x = (displaysettings.dmPelsWidth - width) / 2;
|
||||
y = (displaysettings.dmPelsHeight - height) / 2;
|
||||
|
||||
if (Args->CheckParm ("-0"))
|
||||
{
|
||||
x = y = 0;
|
||||
}
|
||||
|
||||
WNDCLASS WndClass;
|
||||
WndClass.style = 0;
|
||||
WndClass.lpfnWndProc = LConProc;
|
||||
WndClass.cbClsExtra = 0;
|
||||
WndClass.cbWndExtra = 0;
|
||||
WndClass.hInstance = hInstance;
|
||||
WndClass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1));
|
||||
WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
WndClass.hbrBackground = NULL;
|
||||
WndClass.lpszMenuName = NULL;
|
||||
WndClass.lpszClassName = WinClassName;
|
||||
|
||||
/* register this new class with Windows */
|
||||
if (!RegisterClass((LPWNDCLASS)&WndClass))
|
||||
I_FatalError ("Could not register window class");
|
||||
|
||||
/* create window */
|
||||
FStringf caption("" GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime());
|
||||
std::wstring wcaption = caption.WideString();
|
||||
Window = CreateWindowExW(
|
||||
WS_EX_APPWINDOW,
|
||||
WinClassName,
|
||||
wcaption.c_str(),
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
|
||||
x, y, width, height,
|
||||
(HWND) NULL,
|
||||
(HMENU) NULL,
|
||||
hInstance,
|
||||
NULL);
|
||||
|
||||
if (!Window)
|
||||
{
|
||||
MessageBoxA(nullptr, "Unable to create main window", "Fatal", MB_ICONEXCLAMATION|MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (kernel != NULL)
|
||||
{
|
||||
typedef BOOL (WINAPI *pts)(DWORD, DWORD *);
|
||||
pts pidsid = (pts)GetProcAddress (kernel, "ProcessIdToSessionId");
|
||||
if (pidsid != 0)
|
||||
{
|
||||
if (!pidsid (GetCurrentProcessId(), &SessionID))
|
||||
{
|
||||
SessionID = 0;
|
||||
}
|
||||
hwtsapi32 = LoadLibraryA ("wtsapi32.dll");
|
||||
if (hwtsapi32 != 0)
|
||||
{
|
||||
FARPROC reg = GetProcAddress (hwtsapi32, "WTSRegisterSessionNotification");
|
||||
if (reg == 0 || !((BOOL(WINAPI *)(HWND, DWORD))reg) (Window, NOTIFY_FOR_THIS_SESSION))
|
||||
{
|
||||
FreeLibrary (hwtsapi32);
|
||||
hwtsapi32 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
atexit (UnWTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetClientRect (Window, &cRect);
|
||||
|
||||
WinWidth = cRect.right;
|
||||
WinHeight = cRect.bottom;
|
||||
|
||||
CoInitialize (NULL);
|
||||
atexit (UnCOM);
|
||||
|
||||
D_DoomMain ();
|
||||
Args->AppendArg(FString(wargv[i]));
|
||||
}
|
||||
catch (class CNoRunExit &)
|
||||
|
||||
// Load Win32 modules
|
||||
Kernel32Module.Load({"kernel32.dll"});
|
||||
Shell32Module.Load({"shell32.dll"});
|
||||
User32Module.Load({"user32.dll"});
|
||||
|
||||
// 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 = GetModuleHandleA ("kernel32.dll");
|
||||
|
||||
if (Args->CheckParm("-stdout"))
|
||||
{
|
||||
// As a GUI application, we don't normally get a console when we start.
|
||||
// If we were run from the shell and are on XP+, we can attach to its
|
||||
// console. Otherwise, we can create a new one. If we already have a
|
||||
// stdout handle, then we have been redirected and should just use that
|
||||
// handle instead of creating a console window.
|
||||
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (StdOut != NULL)
|
||||
{
|
||||
// It seems that running from a shell always creates a std output
|
||||
// for us, even if it doesn't go anywhere. (Running from Explorer
|
||||
// does not.) If we can get file information for this handle, it's
|
||||
// a file or pipe, so use it. Otherwise, pretend it wasn't there
|
||||
// and find a console to use instead.
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!GetFileInformationByHandle(StdOut, &info))
|
||||
{
|
||||
StdOut = NULL;
|
||||
}
|
||||
}
|
||||
if (StdOut == NULL)
|
||||
{
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
{
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD foo; WriteFile(StdOut, "\n", 1, &foo, NULL);
|
||||
AttachedStdOut = true;
|
||||
}
|
||||
if (StdOut == NULL && AllocConsole())
|
||||
{
|
||||
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
// These two functions do not exist in Windows XP.
|
||||
BOOL (WINAPI* p_GetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
|
||||
BOOL (WINAPI* p_SetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
|
||||
|
||||
p_SetCurrentConsoleFontEx = (decltype(p_SetCurrentConsoleFontEx))GetProcAddress(kernel, "SetCurrentConsoleFontEx");
|
||||
p_GetCurrentConsoleFontEx = (decltype(p_GetCurrentConsoleFontEx))GetProcAddress(kernel, "GetCurrentConsoleFontEx");
|
||||
if (p_SetCurrentConsoleFontEx && p_GetCurrentConsoleFontEx)
|
||||
{
|
||||
CONSOLE_FONT_INFOEX cfi;
|
||||
cfi.cbSize = sizeof(cfi);
|
||||
|
||||
if (p_GetCurrentConsoleFontEx(StdOut, false, &cfi))
|
||||
{
|
||||
if (*cfi.FaceName == 0) // If the face name is empty, the default (useless) raster font is actoive.
|
||||
{
|
||||
//cfi.dwFontSize = { 8, 14 };
|
||||
wcscpy(cfi.FaceName, L"Lucida Console");
|
||||
cfi.FontFamily = FF_DONTCARE;
|
||||
p_SetCurrentConsoleFontEx(StdOut, false, &cfi);
|
||||
}
|
||||
}
|
||||
}
|
||||
FancyStdOut = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the timer to be as accurate as possible
|
||||
if (timeGetDevCaps (&tc, sizeof(tc)) != TIMERR_NOERROR)
|
||||
TimerPeriod = 1; // Assume minimum resolution of 1 ms
|
||||
else
|
||||
TimerPeriod = tc.wPeriodMin;
|
||||
|
||||
timeBeginPeriod (TimerPeriod);
|
||||
atexit(UnTbp);
|
||||
|
||||
atexit (call_terms);
|
||||
|
||||
// Figure out what directory the program resides in.
|
||||
WCHAR progbuff[1024];
|
||||
if (GetModuleFileNameW(nullptr, progbuff, sizeof progbuff) == 0)
|
||||
{
|
||||
MessageBoc(nullptr, "Fatal", "Could not determine program location.", MB_ICONEXCLAMATION|MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
progbuff[1023] = '\0';
|
||||
if (auto lastsep = wcsrchr(progbuff, '\\'))
|
||||
{
|
||||
lastsep[1] = '\0';
|
||||
}
|
||||
|
||||
progdir = progbuff;
|
||||
FixPathSeperator(progdir);
|
||||
|
||||
HDC screenDC = GetDC(0);
|
||||
int dpi = GetDeviceCaps(screenDC, LOGPIXELSX);
|
||||
ReleaseDC(0, screenDC);
|
||||
width = (512 * dpi + 96 / 2) / 96;
|
||||
height = (384 * dpi + 96 / 2) / 96;
|
||||
|
||||
// Many Windows structures that specify their size do so with the first
|
||||
// element. DEVMODE is not one of those structures.
|
||||
memset (&displaysettings, 0, sizeof(displaysettings));
|
||||
displaysettings.dmSize = sizeof(displaysettings);
|
||||
EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
|
||||
x = (displaysettings.dmPelsWidth - width) / 2;
|
||||
y = (displaysettings.dmPelsHeight - height) / 2;
|
||||
|
||||
if (Args->CheckParm ("-0"))
|
||||
{
|
||||
x = y = 0;
|
||||
}
|
||||
|
||||
WNDCLASS WndClass;
|
||||
WndClass.style = 0;
|
||||
WndClass.lpfnWndProc = LConProc;
|
||||
WndClass.cbClsExtra = 0;
|
||||
WndClass.cbWndExtra = 0;
|
||||
WndClass.hInstance = hInstance;
|
||||
WndClass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1));
|
||||
WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
WndClass.hbrBackground = NULL;
|
||||
WndClass.lpszMenuName = NULL;
|
||||
WndClass.lpszClassName = WinClassName;
|
||||
|
||||
/* register this new class with Windows */
|
||||
if (!RegisterClass((LPWNDCLASS)&WndClass))
|
||||
{
|
||||
MessageBoxA(nullptr, "Could not register window class", "Fatal", MB_ICONEXCLAMATION|MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* create window */
|
||||
FStringf caption("" GAMESIG " %s " X64 " (%s)", GetVersionString(), GetGitTime());
|
||||
std::wstring wcaption = caption.WideString();
|
||||
Window = CreateWindowExW(
|
||||
WS_EX_APPWINDOW,
|
||||
WinClassName,
|
||||
wcaption.c_str(),
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
|
||||
x, y, width, height,
|
||||
(HWND) NULL,
|
||||
(HMENU) NULL,
|
||||
hInstance,
|
||||
NULL);
|
||||
|
||||
if (!Window)
|
||||
{
|
||||
MessageBoxA(nullptr, "Unable to create main window", "Fatal", MB_ICONEXCLAMATION|MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (kernel != NULL)
|
||||
{
|
||||
typedef BOOL (WINAPI *pts)(DWORD, DWORD *);
|
||||
pts pidsid = (pts)GetProcAddress (kernel, "ProcessIdToSessionId");
|
||||
if (pidsid != 0)
|
||||
{
|
||||
if (!pidsid (GetCurrentProcessId(), &SessionID))
|
||||
{
|
||||
SessionID = 0;
|
||||
}
|
||||
hwtsapi32 = LoadLibraryA ("wtsapi32.dll");
|
||||
if (hwtsapi32 != 0)
|
||||
{
|
||||
FARPROC reg = GetProcAddress (hwtsapi32, "WTSRegisterSessionNotification");
|
||||
if (reg == 0 || !((BOOL(WINAPI *)(HWND, DWORD))reg) (Window, NOTIFY_FOR_THIS_SESSION))
|
||||
{
|
||||
FreeLibrary (hwtsapi32);
|
||||
hwtsapi32 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
atexit (UnWTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetClientRect (Window, &cRect);
|
||||
|
||||
WinWidth = cRect.right;
|
||||
WinHeight = cRect.bottom;
|
||||
|
||||
CoInitialize (NULL);
|
||||
atexit (UnCOM);
|
||||
|
||||
int ret = D_DoomMain ();
|
||||
if (ret == 1337) // special exit code for 'norun'.
|
||||
{
|
||||
// The only way D_DoomMain can exit regularly is by executing a -norun startup, which was previously handled via exception.
|
||||
I_ShutdownGraphics();
|
||||
if (!batchrun)
|
||||
{
|
||||
|
|
@ -980,7 +970,7 @@ void DoMain (HINSTANCE hInstance)
|
|||
{ // Outputting to a new console window: Wait for a keypress before quitting.
|
||||
DWORD bytes;
|
||||
HANDLE stdinput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
|
||||
ShowWindow(Window, SW_HIDE);
|
||||
WriteFile(StdOut, "Press any key to exit...", 24, &bytes, NULL);
|
||||
FlushConsoleInputBuffer(stdinput);
|
||||
|
|
@ -992,32 +982,30 @@ void DoMain (HINSTANCE hInstance)
|
|||
ShowErrorPane(NULL);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
catch (std::exception &error)
|
||||
{
|
||||
I_ShutdownGraphics ();
|
||||
RestoreConView ();
|
||||
S_StopMusic(true);
|
||||
I_FlushBufferedConsoleStuff();
|
||||
auto msg = error.what();
|
||||
if (strcmp(msg, "NoRunExit"))
|
||||
{
|
||||
if (CVMAbortException::stacktrace.IsNotEmpty())
|
||||
{
|
||||
Printf("%s", CVMAbortException::stacktrace.GetChars());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!batchrun)
|
||||
{
|
||||
ShowErrorPane(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%s\n", msg);
|
||||
}
|
||||
}
|
||||
exit(-1);
|
||||
void I_ShowFatalError(const char *msg)
|
||||
{
|
||||
I_ShutdownGraphics ();
|
||||
RestoreConView ();
|
||||
S_StopMusic(true);
|
||||
I_FlushBufferedConsoleStuff();
|
||||
auto msg = error.what();
|
||||
|
||||
if (CVMAbortException::stacktrace.IsNotEmpty())
|
||||
{
|
||||
Printf("%s", CVMAbortException::stacktrace.GetChars());
|
||||
}
|
||||
|
||||
if (!batchrun)
|
||||
{
|
||||
ShowErrorPane(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%s\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue