Skip to content

Instantly share code, notes, and snippets.

@tkojitu
Last active November 15, 2021 04:50
Show Gist options
  • Save tkojitu/0fdae83d9c74a9c11ca6454f0a337714 to your computer and use it in GitHub Desktop.
Save tkojitu/0fdae83d9c74a9c11ca6454f0a337714 to your computer and use it in GitHub Desktop.
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
if (hstdout == INVALID_HANDLE_VALUE || hstdin == INVALID_HANDLE_VALUE)
ExitProcess(1);
for (;;) {
CHAR buf[4096];
DWORD nread = 0;
BOOL ret = ReadFile(hstdin, buf, sizeof(buf), &nread, NULL);
if (!ret || nread == 0)
break;
DWORD nwrite = 0;
if (!WriteFile(hstdout, buf, nread, &nwrite, NULL))
break;
}
return 0;
}
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
class App {
public:
App() {
InitSecAttr();
}
virtual ~App() {}
virtual void Demo(const wchar_t* argv) {
if (!argv)
ErrorExit(L"Please specify an input file.\n");
CreatePipeForChildStdout();
CreatePipeForChildStdin();
CreateChildProcess();
GetHandleInputFileForParent(argv);
WriteToPipe();
ReadFromPipe();
}
virtual void InitSecAttr() {
m_sec_attr.nLength = sizeof(m_sec_attr);
m_sec_attr.bInheritHandle = TRUE;
m_sec_attr.lpSecurityDescriptor = NULL;
}
virtual void CreatePipeForChildStdout() {
if (!CreatePipe(&m_child_stdout_rd, &m_child_stdout_wr, &m_sec_attr, 0))
ErrorExit(L"StdoutRd CreatePipe");
if (!SetHandleInformation(m_child_stdout_rd, HANDLE_FLAG_INHERIT, 0))
ErrorExit(L"Stdout SetHandleInformation");
}
virtual void CreatePipeForChildStdin() {
if (!CreatePipe(&m_child_stdin_rd, &m_child_stdin_wr, &m_sec_attr, 0))
ErrorExit(L"Stdin CreatePipe");
if (!SetHandleInformation(m_child_stdin_wr, HANDLE_FLAG_INHERIT, 0))
ErrorExit(L"Stdin SetHandleInformation");
}
virtual void CreateChildProcess() {
TCHAR cmdline[] = L"child";
PROCESS_INFORMATION pinfo;
ZeroMemory(&pinfo, sizeof(pinfo));
STARTUPINFO sinfo;
ZeroMemory(&sinfo, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.hStdError = m_child_stdout_wr;
sinfo.hStdOutput = m_child_stdout_wr;
sinfo.hStdInput = m_child_stdin_rd;
sinfo.dwFlags |= STARTF_USESTDHANDLES;
BOOL ret = CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo);
if (!ret)
ErrorExit(L"CreateProcess");
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
CloseHandle(m_child_stdout_wr);
CloseHandle(m_child_stdin_rd);
}
virtual void GetHandleInputFileForParent(const wchar_t* filepath) {
m_input_file = CreateFile(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (m_input_file == INVALID_HANDLE_VALUE)
ErrorExit(L"CreateFile");
}
virtual void WriteToPipe() {
for (;;) {
CHAR buf[BUFSIZE] = { 0 };
DWORD nread = 0;
BOOL ret = ReadFile(m_input_file, buf, BUFSIZE, &nread, NULL);
if (!ret || nread == 0)
break;
DWORD nwrite = 0;
if (!WriteFile(m_child_stdin_wr, buf, nread, &nwrite, NULL))
break;
}
if (!CloseHandle(m_child_stdin_wr))
ErrorExit(L"StdInWr CloseHandle");
}
virtual void ReadFromPipe() {
HANDLE parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;) {
CHAR buf[BUFSIZE] = { 0 };
DWORD nread = 0;
BOOL ret = ReadFile(m_child_stdout_rd, buf, BUFSIZE, &nread, NULL);
if (!ret || nread == 0)
break;
DWORD nwrite = 0;
if (!WriteFile(parent_stdout, buf, nread, &nwrite, NULL))
break;
}
}
virtual void ErrorExit(const wchar_t* lpszFunction) {
LPVOID msg = nullptr;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&msg,
0, NULL);
LPVOID disp = LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)msg) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)disp, LocalSize(disp) / sizeof(TCHAR), L"%s failed with error %d: %s", lpszFunction, dw, msg);
MessageBox(NULL, (LPCTSTR)disp, L"Error", MB_OK);
LocalFree(msg);
LocalFree(disp);
ExitProcess(1);
}
private:
enum {
BUFSIZE = 4096
};
SECURITY_ATTRIBUTES m_sec_attr;
HANDLE m_child_stdin_rd = NULL;
HANDLE m_child_stdin_wr = NULL;
HANDLE m_child_stdout_rd = NULL;
HANDLE m_child_stdout_wr = NULL;
HANDLE m_input_file = NULL;
};
int _tmain(int argc, TCHAR* argv[])
{
App app;
app.Demo(argv[1]);
return 0;
}
#include "pch.h"
#include "StringPipe.h"
#define ERR_EXIT(msg) do { \
OutputDebugStringA(msg); \
exit(1); \
} while (0);
CStringPipe::CStringPipe() {
InitSecAttr();
}
CStringPipe::~CStringPipe() {}
void CStringPipe::Doit(CString cmdline, CStringA& input, CStringA& output) {
CreatePipeForChildStdout();
CreatePipeForChildStdin();
CreateChildProcess(cmdline);
WriteToPipe(input);
ReadFromPipe(output);
}
void CStringPipe::InitSecAttr() {
m_sec_attr.nLength = sizeof(m_sec_attr);
m_sec_attr.bInheritHandle = TRUE;
m_sec_attr.lpSecurityDescriptor = NULL;
}
void CStringPipe::CreatePipeForChildStdout() {
if (!CreatePipe(&m_child_stdout_rd, &m_child_stdout_wr, &m_sec_attr, 0))
ERR_EXIT("StdoutRd CreatePipe");
if (!SetHandleInformation(m_child_stdout_rd, HANDLE_FLAG_INHERIT, 0))
ERR_EXIT("Stdout SetHandleInformation");
}
void CStringPipe::CreatePipeForChildStdin() {
if (!CreatePipe(&m_child_stdin_rd, &m_child_stdin_wr, &m_sec_attr, 0))
ERR_EXIT("Stdin CreatePipe");
if (!SetHandleInformation(m_child_stdin_wr, HANDLE_FLAG_INHERIT, 0))
ERR_EXIT("Stdin SetHandleInformation");
}
void CStringPipe::CreateChildProcess(CString cmdline) {
PROCESS_INFORMATION pinfo;
ZeroMemory(&pinfo, sizeof(pinfo));
STARTUPINFO sinfo;
ZeroMemory(&sinfo, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.hStdError = m_child_stdout_wr;
sinfo.hStdOutput = m_child_stdout_wr;
sinfo.hStdInput = m_child_stdin_rd;
sinfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, _bstr_t(cmdline), NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo))
ERR_EXIT("CreateProcess");
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
CloseHandle(m_child_stdout_wr);
CloseHandle(m_child_stdin_rd);
}
void CStringPipe::WriteToPipe(CStringA& input) {
for (int i = 0; i < input.GetLength(); ++i) {
char ch = input.GetAt(i);
DWORD nwritten = 0;
BOOL ret = WriteFile(m_child_stdin_wr, &ch, 1, &nwritten, NULL);
if (!ret || nwritten != 1)
ERR_EXIT("WriteFile");
}
if (!CloseHandle(m_child_stdin_wr))
ERR_EXIT("StdInWr CloseHandle");
}
void CStringPipe::ReadFromPipe(CStringA& output) {
for (;;) {
CHAR ch = 0;
DWORD nread = 0;
if (!ReadFile(m_child_stdout_rd, &ch, 1, &nread, NULL)) {
DWORD err = GetLastError();
if (err == ERROR_SUCCESS || err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF)
break;
ERR_EXIT("ReadFile");
}
if (nread == 0)
break;
output.AppendChar(ch);
}
}
#pragma once
class CStringPipe {
public:
CStringPipe();
virtual ~CStringPipe();
virtual void Doit(CString cmdline, CStringA& input, CStringA& output);
virtual void InitSecAttr();
virtual void CreatePipeForChildStdout();
virtual void CreatePipeForChildStdin();
virtual void CreateChildProcess(CString cmdline);
virtual void WriteToPipe(CStringA& input);
virtual void ReadFromPipe(CStringA& output);
private:
enum {
BUFSIZE = 4096
};
SECURITY_ATTRIBUTES m_sec_attr;
HANDLE m_child_stdin_rd = NULL;
HANDLE m_child_stdin_wr = NULL;
HANDLE m_child_stdout_rd = NULL;
HANDLE m_child_stdout_wr = NULL;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment