winpty/misc/buffer-tests/harness/TestCommon.h
2015-10-21 19:56:12 -05:00

149 lines
5.0 KiB
C++

#pragma once
#include <windows.h>
#include <cstdint>
#include <string>
#include <vector>
#include "Event.h"
#include "ShmemParcel.h"
#include "Spawn.h"
#include "WorkerApi.h"
#include <DebugClient.h>
#include <UnicodeConversions.h>
class Worker;
class Handle {
friend class Worker;
private:
Handle(HANDLE value, Worker &worker) : m_value(value), m_worker(&worker) {}
public:
static Handle invent(HANDLE h, Worker &worker) { return Handle(h, worker); }
static Handle invent(uint64_t h, Worker &worker) { return Handle(reinterpret_cast<HANDLE>(h), worker); }
Handle &activate();
void write(const std::string &msg);
void close();
Handle &setStdin();
Handle &setStdout();
Handle &setStderr();
Handle dup(Worker &target, BOOL bInheritHandle=FALSE);
Handle dup(BOOL bInheritHandle=FALSE) { return dup(worker(), bInheritHandle); }
static Handle dup(HANDLE h, Worker &target, BOOL bInheritHandle=FALSE);
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo();
bool tryScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO *info=nullptr);
DWORD flags();
bool tryFlags(DWORD *flags=nullptr);
void setFlags(DWORD mask, DWORD flags);
bool trySetFlags(DWORD mask, DWORD flags);
wchar_t firstChar();
Handle &setFirstChar(wchar_t ch);
bool tryNumberOfConsoleInputEvents(DWORD *ret=nullptr);
HANDLE value() const { return m_value; }
uint64_t uvalue() const { return reinterpret_cast<uint64_t>(m_value); }
Worker &worker() const { return *m_worker; }
private:
HANDLE m_value;
Worker *m_worker;
};
class Worker {
friend class Handle;
private:
Worker(const std::string &name);
public:
Worker() : Worker(SpawnParams {}) {}
Worker(SpawnParams params);
Worker child() { return child(SpawnParams {}); }
Worker child(const SpawnParams &params);
~Worker();
private:
void cleanup();
public:
// basic worker info
HANDLE processHandle() { return m_process; }
DWORD pid() { return GetProcessId(m_process); }
// allow moving
Worker(Worker &&other) :
m_name(std::move(other.m_name)),
m_parcel(std::move(other.m_parcel)),
m_startEvent(std::move(other.m_startEvent)),
m_finishEvent(std::move(other.m_finishEvent)),
m_process(std::move(other.m_process))
{
other.m_valid = false;
}
Worker &operator=(Worker &&other) {
cleanup();
m_name = std::move(other.m_name);
m_parcel = std::move(other.m_parcel);
m_startEvent = std::move(other.m_startEvent);
m_finishEvent = std::move(other.m_finishEvent);
m_process = std::move(other.m_process);
other.m_valid = false;
m_valid = true;
return *this;
}
// Commands
Handle getStdin() { rpc(Command::GetStdin); return Handle(cmd().handle, *this); }
Handle getStdout() { rpc(Command::GetStdout); return Handle(cmd().handle, *this); }
Handle getStderr() { rpc(Command::GetStderr); return Handle(cmd().handle, *this); }
bool detach() { rpc(Command::FreeConsole); return cmd().success; }
bool attach(Worker &worker) { cmd().dword = GetProcessId(worker.m_process); rpc(Command::AttachConsole); return cmd().success; }
bool alloc() { rpc(Command::AllocConsole); return cmd().success; }
void dumpStandardHandles() { rpc(Command::DumpStandardHandles); }
int system(const std::string &arg) { cmd().u.systemText = arg; rpc(Command::System); return cmd().dword; }
HWND consoleWindow() { rpc(Command::GetConsoleWindow); return cmd().hwnd; }
CONSOLE_SELECTION_INFO selectionInfo();
void dumpConsoleHandles(BOOL writeToEach=FALSE);
std::vector<Handle> scanForConsoleHandles();
void setTitle(const std::string &str) { auto b = setTitleInternal(widenString(str)); ASSERT(b && "setTitle failed"); }
bool setTitleInternal(const std::wstring &str);
DWORD getTitleInternal(std::array<wchar_t, 1024> &buf, DWORD bufSize);
Handle openConin(BOOL bInheritHandle=FALSE) {
cmd().bInheritHandle = bInheritHandle;
rpc(Command::OpenConin);
return Handle(cmd().handle, *this);
}
Handle openConout(BOOL bInheritHandle=FALSE) {
cmd().bInheritHandle = bInheritHandle;
rpc(Command::OpenConout);
return Handle(cmd().handle, *this);
}
Handle newBuffer(BOOL bInheritHandle=FALSE, wchar_t firstChar=L'\0') {
cmd().bInheritHandle = bInheritHandle;
rpc(Command::NewBuffer);
auto h = Handle(cmd().handle, *this);
if (firstChar != L'\0') {
h.setFirstChar(firstChar);
}
return h;
}
private:
Command &cmd() { return m_parcel.value(); }
void rpc(Command::Kind kind);
void rpcAsync(Command::Kind kind);
void rpcImpl(Command::Kind kind);
private:
bool m_valid = true;
std::string m_name;
ShmemParcelTyped<Command> m_parcel;
Event m_startEvent;
Event m_finishEvent;
HANDLE m_process = NULL;
};