Merge branch 'windows-console' into 'dev'

Implement a debug console for Windows

See merge request mkxp-z/mkxp-z!31
This commit is contained in:
Struma 2021-03-16 02:50:10 +00:00 committed by Roza
commit 524dff4346
3 changed files with 99 additions and 0 deletions

View file

@ -47,6 +47,10 @@ extern "C" {
#endif
}
#ifdef __WINDOWS__
#include <fcntl.h>
#endif
#include <assert.h>
#include <string>
#include <zlib.h>
@ -70,6 +74,7 @@ extern const char module_rpg3[];
static void mriBindingExecute();
static void mriBindingTerminate();
static void mriBindingReset();
static void configureWindowsStreams();
ScriptBinding scriptBindingImpl = {mriBindingExecute, mriBindingTerminate,
mriBindingReset};
@ -219,6 +224,10 @@ static void mriBindingInit() {
rb_gv_set("TEST", debug);
rb_gv_set("BTEST", rb_bool_new(shState->config().editor.battleTest));
// Set $stdout and its ilk accordingly on Windows
if (shState->config().editor.debug)
configureWindowsStreams();
// Load zlib, if it's present. Requires --with-static-linked-ext or zlib.so.
// It's okay if it fails, normally it wouldn't be defined anyway.
@ -746,6 +755,41 @@ static void runRMXPScripts(BacktraceData &btData) {
}
#endif
// Attempts to set $stdout and $stdin accordingly on Windows. Only
// called when debug mode is on, since that's when the console
// should be active.
static void configureWindowsStreams() {
#ifdef __WINDOWS__
#define HANDLE_VALID(handle) handle && handle != INVALID_HANDLE_VALUE
const HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
// Configure $stdout
if (HANDLE_VALID(outputHandle)) {
const int stdoutFD = _open_osfhandle((intptr_t)outputHandle, _O_TEXT);
VALUE winStdout = rb_funcall(rb_cIO, rb_intern("new"), 2,
INT2NUM(stdoutFD), rb_str_new_cstr("w"));
rb_gv_set("stdout", winStdout);
}
const HANDLE inputHandle = GetStdHandle(STD_INPUT_HANDLE);
// Configure $stdin
if (HANDLE_VALID(inputHandle)) {
const int stdinFD = _open_osfhandle((intptr_t)inputHandle, _O_TEXT);
VALUE winStdin = rb_funcall(rb_cIO, rb_intern("new"), 2,
INT2NUM(stdinFD), rb_str_new_cstr("r"));
rb_gv_set("stdin", winStdin);
}
#undef HANDLE_VALID
#endif // #ifdef __WINDOWS__
}
static void showExc(VALUE exc, const BacktraceData &btData) {
VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL);
VALUE msg = rb_funcall2(exc, rb_intern("message"), 0, NULL);
@ -821,9 +865,15 @@ static void mriBindingExecute() {
/* Normally only a ruby executable would do a sysinit,
* but not doing it will lead to crashes due to closed
* stdio streams on some platforms (eg. Windows) */
#ifdef __WINDOWS__
if (!conf.editor.debug) {
#endif
int argc = 0;
char **argv = 0;
ruby_sysinit(&argc, &argv);
#ifdef __WINDOWS__
}
#endif
RUBY_INIT_STACK;
ruby_init();

View file

@ -48,6 +48,7 @@
#if defined(__WINDOWS__)
#include "resource.h"
#include <Winsock2.h>
#include "util/win-consoleutils.h"
#endif
#ifdef MKXPZ_STEAM
@ -282,6 +283,20 @@ int main(int argc, char *argv[]) {
showInitError(
std::string(buf)); // Not an error worth ending the program over
}
// Create a debug console in debug mode
if (conf.editor.debug) {
HANDLE winConsoleHandle;
if (setupWindowsConsole(winConsoleHandle)) {
reopenWindowsStreams();
} else {
char buf[200];
snprintf(buf, sizeof(buf), "Error allocating console: %lu",
GetLastError());
showInitError(std::string(buf));
}
}
#endif
SDL_Window *win;

View file

@ -0,0 +1,34 @@
#ifndef WIN_CONSOLEUTIL_H
#define WIN_CONSOLEUTIL_H
#include <iostream>
#include "windows.h"
// Attempts to allocate a console and fetch the output handle.
// Returns whether the operation was successful.
// Extended error information can be received via GetLastError().
bool setupWindowsConsole(HANDLE &handle)
{
if (!AllocConsole())
return false;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
return (handle != NULL && handle != INVALID_HANDLE_VALUE);
}
// Reopens the file streams. This should be done after successfully
// setting up the console.
void reopenWindowsStreams()
{
FILE* fDummy;
freopen_s(&fDummy, "CONOUT$", "w", stdout);
freopen_s(&fDummy, "CONOUT$", "w", stderr);
freopen_s(&fDummy, "CONIN$", "r", stdin);
std::cout.clear();
std::clog.clear();
std::cerr.clear();
std::cin.clear();
}
#endif