Kaydet (Commit) 601bdc41 authored tarafından Mike Kaganski's avatar Mike Kaganski

tdf#100826: Use parent console for output if possible

This patch uses either passed standard handles, or parent console
for output of --help and --version command line switches.

Change-Id: Iabbec79d3792ae091ca06d134345c1669eb1ac13
Reviewed-on: https://gerrit.libreoffice.org/31187Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarMike Kaganski <mike.kaganski@collabora.com>
üst 46d3163f
......@@ -27,6 +27,10 @@
#include "cmdlinehelp.hxx"
#ifdef _WIN32
#if _WIN32_WINNT < 0x0501
// For AttachConsole() and MAPVK_VK_TO_VSC
#define _WIN32_WINNT 0x0501
#endif
#include "windows.h"
#include "io.h"
#include "fcntl.h"
......@@ -172,45 +176,105 @@ namespace desktop
#ifdef _WIN32
namespace{
class lcl_Console {
enum eConsoleMode { unknown, attached, allocated };
public:
explicit lcl_Console(short nBufHeight)
: mConsoleMode(unknown)
{
bFreeConsole = AllocConsole() != FALSE;
CONSOLE_SCREEN_BUFFER_INFO cinfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cinfo);
cinfo.dwSize.Y = nBufHeight;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), cinfo.dwSize);
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE),
hOut = GetStdHandle(STD_OUTPUT_HANDLE),
hErr = GetStdHandle(STD_ERROR_HANDLE);
if (hOut == NULL) // application does not have associated standard handles
{
STARTUPINFOA aStartupInfo{ sizeof(aStartupInfo) };
GetStartupInfoA(&aStartupInfo);
if ((aStartupInfo.dwFlags & STARTF_USESTDHANDLES) == STARTF_USESTDHANDLES)
{
// If standard handles had been passed to this process, use them
hIn = aStartupInfo.hStdInput;
hOut = aStartupInfo.hStdOutput;
hErr = aStartupInfo.hStdError;
}
else
{
// Try to attach parent console; on error try to create new.
// If this process already has its console, these will simply fail.
if (AttachConsole(ATTACH_PARENT_PROCESS) != FALSE)
mConsoleMode = attached;
else if (AllocConsole() != FALSE)
mConsoleMode = allocated;
hIn = GetStdHandle(STD_INPUT_HANDLE);
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
hErr = GetStdHandle(STD_ERROR_HANDLE);
// Ensure that console buffer is enough to hold required data
CONSOLE_SCREEN_BUFFER_INFO cinfo;
GetConsoleScreenBufferInfo(hOut, &cinfo);
if (cinfo.dwSize.Y < nBufHeight)
{
cinfo.dwSize.Y = nBufHeight;
SetConsoleScreenBufferSize(hOut, cinfo.dwSize);
}
}
}
// stdin
intptr_t stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE));
int fileHandle = _open_osfhandle(stdHandle, _O_TEXT);
int fileHandle = _open_osfhandle(reinterpret_cast<intptr_t>(hIn), _O_TEXT);
FILE *fp = _fdopen(fileHandle, "r");
*stdin = *fp;
setvbuf(stdin, nullptr, _IONBF, 0);
// stdout
stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE));
fileHandle = _open_osfhandle(stdHandle, _O_TEXT);
fileHandle = _open_osfhandle(reinterpret_cast<intptr_t>(hOut), _O_TEXT);
fp = _fdopen(fileHandle, "w");
*stdout = *fp;
setvbuf(stdout, nullptr, _IONBF, 0);
// stderr
stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE));
fileHandle = _open_osfhandle(stdHandle, _O_TEXT);
fileHandle = _open_osfhandle(reinterpret_cast<intptr_t>(hErr), _O_TEXT);
fp = _fdopen(fileHandle, "w");
*stderr = *fp;
setvbuf(stderr, nullptr, _IONBF, 0);
std::ios::sync_with_stdio(true);
// In case we use parent's console, emit an empty string
// to avoid output on a line with command prompt
if (mConsoleMode == attached)
fprintf(stdout, "\n");
}
~lcl_Console()
{
if (bFreeConsole)
switch (mConsoleMode) {
case unknown:
// Don't free the console
return;
case attached:
{
fprintf(stdout, "Press Enter to close this console...");
// Put Enter keypress to console input buffer to emit next command prompt after the command
INPUT_RECORD ir;
ir.EventType = KEY_EVENT;
KEY_EVENT_RECORD& ke = ir.Event.KeyEvent;
ke.bKeyDown = TRUE;
ke.wRepeatCount = 1;
ke.wVirtualKeyCode = VK_RETURN;
ke.wVirtualScanCode = MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC);
ke.uChar.AsciiChar = '\r';
ke.dwControlKeyState = 0;
DWORD nEvents;
WriteConsoleInputA(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &nEvents);
break;
}
case allocated:
fprintf(stdout, "Press Enter to continue...");
fgetc(stdin);
FreeConsole();
break;
}
FreeConsole();
}
private:
bool bFreeConsole;
eConsoleMode mConsoleMode;
};
}
#endif
......
......@@ -23,6 +23,9 @@
#include <cstddef>
#include <cwchar>
#if _WIN32_WINNT < 0x0501
#define _WIN32_WINNT 0x0501
#endif
#define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
......@@ -71,10 +74,16 @@ int WINAPI _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int )
ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
aStartupInfo.cb = sizeof(aStartupInfo);
GetStartupInfo( &aStartupInfo );
// Create process with same command line, environment and stdio handles which
// are directed to the created pipes
GetStartupInfo(&aStartupInfo);
// If this process hasn't its stdio handles set, then check if its parent
// has a console (i.e. this process is launched from command line), and if so,
// attach to it. It will enable child process to retrieve this console if it needs
// to output to console
if ((aStartupInfo.dwFlags & STARTF_USESTDHANDLES) == 0)
AttachConsole(ATTACH_PARENT_PROCESS);
DWORD dwExitCode = (DWORD)-1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment