I’m making a program in C++ that makes use of a pseudo-terminal using ConPTY.exe to create interactive terminal sessions. My write method to the pty is not working, please suggest some solutions.
I tried googling a lot of stuff but i could get no result which could solve my problem. Even my code has no error which makes me confused.
My code:
pty.h:
#ifndef PTY_H
#define PTY_H
#include <windows.h>
#include <string>
#include <functional>
#include <thread>
class Pty {
public:
Pty(COORD size);
~Pty();
bool spawn(const std::wstring& command, const std::wstring& cmdline);
//std::string read();
void onData(const std::function<void(const std::string&)>& callback);
void write(const std::string& data);
void resize(COORD size);
void close();
private:
HANDLE hInputRead = NULL;
HANDLE hInputWrite = NULL;
HANDLE hOutputRead = NULL;
HANDLE hOutputWrite = NULL;
HPCON hPC = NULL;
std::function<void(const std::string&)> dataCallback;
std::thread readThread;
void readLoop();
};
#endif // !PTY_H
pty.cpp:
#include "pty.h"
#include <iostream>
Pty::Pty(COORD size) {
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
if (!CreatePipe(&hOutputRead, &hOutputWrite, &sa, 0) ||
!CreatePipe(&hInputRead, &hInputWrite, &sa, 0)) {
std::cerr << "Failed to create pipes" << std::endl;
return;
}
std::cout << "Pipes created. " << hInputRead << " && - && " << hInputWrite << std::endl;
if (CreatePseudoConsole(size, hInputRead, hOutputWrite, 0, &hPC) != S_OK) {
std::cerr << "Failed to create pseudo console" << std::endl;
return;
}
}
Pty::~Pty() {
close();
}
bool Pty::spawn(const std::wstring& command, const std::wstring& cmdline)
{
STARTUPINFOEX siEx;
PROCESS_INFORMATION pi;
ZeroMemory(&siEx, sizeof(siEx));
siEx.StartupInfo.cb = sizeof(siEx);
siEx.StartupInfo.hStdInput = hInputRead;
siEx.StartupInfo.hStdOutput = hOutputWrite;
siEx.StartupInfo.hStdError = hOutputWrite; ZeroMemory(&pi, sizeof(pi));
siEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
// extra env setup
WCHAR env[] = L"TERM=xterm-256color";
LPWCH lpEnvironment = (LPWCH)malloc(sizeof(env));
memcpy(lpEnvironment, env, sizeof(env));
SIZE_T attrSize = 0;
InitializeProcThreadAttributeList(NULL, 1, 0, &attrSize);
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)malloc(attrSize);
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &attrSize);
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, hPC, sizeof(hPC), NULL, NULL);
BOOL success = CreateProcessW(NULL, const_cast<LPWSTR>(cmdline.c_str()), NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &siEx.StartupInfo, &pi);
if (!success) {
std::cerr << "Failed to spawn process" << std::endl;
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
free(lpEnvironment);
return true;
}
void Pty::onData(const std::function<void(const std::string&)>& callback)
{
dataCallback = callback;
//readThread = std::thread(&Pty::readLoop, this);
if (!readThread.joinable()) {
readThread = std::thread(&Pty::readLoop, this);
}
}
void Pty::readLoop()
{
char buffer[256];
DWORD read;
/*while (ReadFile(hOutputRead, buffer, sizeof(buffer), &read, NULL) && read > 0) {
buffer[read] = '';
std::string data(buffer);
if (dataCallback) {
dataCallback(data);
}
}*/
while (true) {
BOOL result = ReadFile(hOutputRead, buffer, sizeof(buffer) - 1, &read, NULL);
if (!result || read == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
std::cerr << "Read failed: Pipe was closed" << std::endl;
}
else {
std::cerr << "Read failed: " << GetLastError() << std::endl;
}
break;
}
buffer[read] = '';
std::string data(buffer, read);
std::cout << "test - pty data: " << data << std::endl;
if (dataCallback) {
dataCallback(data);
}
}
}
void Pty::write(const std::string& data) {
if (hInputWrite == NULL) {
std::cerr << "Write Failed: Input handle is NULL" << std::endl;
return;
}
DWORD written = 0;
BOOL success = WriteFile(hInputWrite, data.c_str(), data.size(), &written, NULL);
if (success) {
FlushFileBuffers(hInputWrite);
}
if (!success || written != data.size()) {
std::cerr << "Write failed: " << GetLastError() << std::endl;
}
else {
std::cout << "Successfully wrote to PTY: " << data << std::endl;
}
}
void Pty::resize(COORD size) {
if (hPC) {
ResizePseudoConsole(hPC, size);
}
}
void Pty::close() {
if (readThread.joinable()) {
readThread.join();
}
if (hPC) ClosePseudoConsole(hPC);
CloseHandle(hOutputRead);
CloseHandle(hOutputWrite);
CloseHandle(hInputRead);
CloseHandle(hInputWrite);
hPC = NULL;
}
whenever i call the write method, it always prints out a successful message, but it takes no effect.
Any help is appreciated.