Skip to content

Instantly share code, notes, and snippets.

@seikichi
Created April 21, 2019 15:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seikichi/84988f038633581dd4a0b7c6b3feb82b to your computer and use it in GitHub Desktop.
Save seikichi/84988f038633581dd4a0b7c6b3feb82b to your computer and use it in GitHub Desktop.
ConPTY scratch
// ConPTY 手習い (with winapi-rs, vte)
//
// https://github.com/jwilm/alacritty/blob/master/src/tty/windows/conpty.rs
// https://github.com/chyyran/conmux/blob/master/src/conpty.rs
// https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/
use std::fs::File;
use std::io::prelude::*;
use std::io::Write;
use std::mem;
use std::os::windows::io::{FromRawHandle, RawHandle};
use std::ptr::{null, null_mut};
use vte::{Parser, Perform};
use widestring::U16CString;
use winapi::shared::basetsd::{PSIZE_T, SIZE_T};
use winapi::shared::minwindef::BYTE;
use winapi::shared::ntdef::LPWSTR;
use winapi::um::consoleapi::{ClosePseudoConsole, CreatePseudoConsole};
use winapi::um::namedpipeapi::CreatePipe;
use winapi::um::processthreadsapi::{
CreateProcessW, InitializeProcThreadAttributeList, UpdateProcThreadAttribute,
PROCESS_INFORMATION, STARTUPINFOW,
};
use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTUPINFOEXW};
use winapi::um::wincontypes::{COORD, HPCON};
use winapi::um::winnt::HANDLE;
struct Handler {}
impl Perform for Handler {
fn print(&mut self, c: char) {
println!("print: {}", c);
}
fn execute(&mut self, _byte: u8) {}
fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {}
fn put(&mut self, _byte: u8) {}
fn unhook(&mut self) {}
fn osc_dispatch(&mut self, _params: &[&[u8]]) {}
fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {}
fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {}
}
fn main() {
let cwd = "C:\\";
let cmdline = "cmd";
let commands = vec!["echo HELLO\r\n", "dir\r\n"];
let mut pipe_in: HANDLE = null_mut();
let mut pipe_out: HANDLE = null_mut();
let mut pipe_pty_in: HANDLE = null_mut();
let mut pipe_pty_out: HANDLE = null_mut();
let mut hpc = null_mut();
unsafe {
CreatePipe(&mut pipe_pty_in, &mut pipe_in, null_mut(), 0);
CreatePipe(&mut pipe_out, &mut pipe_pty_out, null_mut(), 0);
CreatePseudoConsole(
COORD { X: 80, Y: 32 },
pipe_pty_in,
pipe_pty_out,
0,
&mut hpc,
);
let mut si_ex: STARTUPINFOEXW = { mem::zeroed() };
si_ex.StartupInfo.cb = mem::size_of::<STARTUPINFOEXW>() as u32;
let mut size: SIZE_T = 0;
InitializeProcThreadAttributeList(null_mut(), 1, 0, &mut size as PSIZE_T);
let mut attr_list: Box<[BYTE]> = vec![0; size].into_boxed_slice();
si_ex.lpAttributeList = attr_list.as_mut_ptr() as _;
InitializeProcThreadAttributeList(si_ex.lpAttributeList, 1, 0, &mut size as PSIZE_T);
UpdateProcThreadAttribute(
si_ex.lpAttributeList,
0,
22 | 0x0002_0000, // PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
hpc,
mem::size_of::<HPCON>(),
null_mut(),
null_mut(),
);
let mut proc_info: PROCESS_INFORMATION = { mem::zeroed() };
let result = CreateProcessW(
null(),
U16CString::from_str(cmdline).unwrap().as_ptr() as LPWSTR,
null_mut(),
null_mut(),
false as i32,
EXTENDED_STARTUPINFO_PRESENT,
null_mut(),
U16CString::from_str(cwd).unwrap().as_ptr(),
&mut si_ex.StartupInfo as *mut STARTUPINFOW,
&mut proc_info as *mut PROCESS_INFORMATION,
);
println!("create process result: {}", result);
let mut fin = File::from_raw_handle(pipe_in as RawHandle);
for command in &commands {
write!(fin, "{}", command).unwrap();
}
fin.flush().unwrap();
let mut parser = Parser::new();
let mut handler = Handler {};
let mut fout = File::from_raw_handle(pipe_out as RawHandle);
// 適当...
for _ in 0..50 {
let mut buffer = [0; 32];
let n = fout.read(&mut buffer).unwrap();
for b in &buffer[..n] {
parser.advance(&mut handler, *b);
}
}
ClosePseudoConsole(hpc);
}
println!("Done!");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment