Created
April 21, 2019 15:02
-
-
Save seikichi/84988f038633581dd4a0b7c6b3feb82b to your computer and use it in GitHub Desktop.
ConPTY scratch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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