2929#include <strsafe.h>
3030#include <Psapi.h>
3131
32+ #ifndef EXTENDED_STARTUPINFO_PRESENT
33+ #define EXTENDED_STARTUPINFO_PRESENT 0x00080000
34+ #endif
35+
36+ #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
37+ #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
38+ #endif
39+
40+ typedef VOID * HPCON ;
41+ typedef HRESULT (WINAPI * PFN_CREATE_PSEUDO_CONSOLE )(COORD , HANDLE , HANDLE , DWORD , HPCON * );
42+ typedef VOID (WINAPI * PFN_CLOSE_PSEUDO_CONSOLE )(HPCON );
43+ typedef BOOL (WINAPI * PFN_INITIALIZE_PROC_THREAD_ATTRIBUTE_LIST )(LPPROC_THREAD_ATTRIBUTE_LIST , DWORD , DWORD , PSIZE_T );
44+ typedef BOOL (WINAPI * PFN_UPDATE_PROC_THREAD_ATTRIBUTE )(LPPROC_THREAD_ATTRIBUTE_LIST , DWORD , DWORD_PTR , PVOID , SIZE_T , PVOID , PSIZE_T );
45+ typedef VOID (WINAPI * PFN_DELETE_PROC_THREAD_ATTRIBUTE_LIST )(LPPROC_THREAD_ATTRIBUTE_LIST );
46+
3247void
3348lws_spawn_timeout (struct lws_sorted_usec_list * sul )
3449{
@@ -123,6 +138,17 @@ lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp)
123138 lsp -> hJob = NULL ;
124139 }
125140
141+ if (lsp -> hPC ) {
142+ HMODULE hKernel32 = GetModuleHandleW (L"kernel32.dll" );
143+ PFN_CLOSE_PSEUDO_CONSOLE pClosePseudoConsole = NULL ;
144+ if (hKernel32 ) {
145+ pClosePseudoConsole = (PFN_CLOSE_PSEUDO_CONSOLE )GetProcAddress (hKernel32 , "ClosePseudoConsole" );
146+ if (pClosePseudoConsole )
147+ pClosePseudoConsole (lsp -> hPC );
148+ }
149+ lsp -> hPC = NULL ;
150+ }
151+
126152 for (n = 0 ; n < 3 ; n ++ ) {
127153 if (lsp -> pipe_fds [n ][!!(n == 0 )]) {
128154 CloseHandle (lsp -> pipe_fds [n ][n == 0 ]);
@@ -421,23 +447,28 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i)
421447 sa .lpSecurityDescriptor = NULL ;
422448
423449 for (n = 0 ; n < 3 ; n ++ ) {
424- DWORD waitmode = PIPE_NOWAIT ;
450+ if (i -> pty_mode && n == LWS_STDERR ) {
451+ /* fuse stderr to stdout for pty */
452+ lsp -> pipe_fds [n ][0 ] = NULL ;
453+ lsp -> pipe_fds [n ][1 ] = lsp -> pipe_fds [LWS_STDOUT ][1 ];
454+ } else {
455+ DWORD waitmode = PIPE_NOWAIT ;
425456
426- if (!CreatePipe (& lsp -> pipe_fds [n ][0 ], & lsp -> pipe_fds [n ][1 ],
427- & sa , 0 )) {
428- lwsl_err ("%s: CreatePipe() failed\n" , __func__ );
429- goto bail1 ;
430- }
457+ if (!CreatePipe (& lsp -> pipe_fds [n ][0 ], & lsp -> pipe_fds [n ][1 ],
458+ & sa , 0 )) {
459+ lwsl_err ("%s: CreatePipe() failed\n" , __func__ );
460+ goto bail1 ;
461+ }
431462
432- SetNamedPipeHandleState ( lsp -> pipe_fds [ 1 ][ 0 ], & waitmode , NULL , NULL );
433- SetNamedPipeHandleState (lsp -> pipe_fds [2 ][0 ], & waitmode , NULL , NULL );
463+ if ( n != LWS_STDIN )
464+ SetNamedPipeHandleState (lsp -> pipe_fds [n ][0 ], & waitmode , NULL , NULL );
434465
435- /* don't inherit the pipe side that belongs to the parent */
466+ /* don't inherit the pipe side that belongs to the parent */
436467
437- if (!SetHandleInformation (& lsp -> pipe_fds [n ][!n ],
438- HANDLE_FLAG_INHERIT , 0 )) {
439- lwsl_info ("%s: SetHandleInformation() failed\n" , __func__ );
440- //goto bail1;
468+ if (!SetHandleInformation (& lsp -> pipe_fds [n ][!n ],
469+ HANDLE_FLAG_INHERIT , 0 )) {
470+ // lwsl_info("%s: SetHandleInformation() failed\n", __func__);
471+ }
441472 }
442473 }
443474
@@ -459,12 +490,15 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i)
459490 lsp -> stdwsi [n ]-> a .protocol = pcol ;
460491 lsp -> stdwsi [n ]-> a .opaque_user_data = i -> opaque ;
461492
493+ if (!lsp -> pipe_fds [n ][!n ])
494+ continue ;
495+
462496 lsp -> stdwsi [n ]-> desc .filefd = lsp -> pipe_fds [n ][!n ];
463497 lsp -> stdwsi [n ]-> file_desc = 1 ;
464498
465499 lws_dll2_remove (& lsp -> stdwsi [n ]-> pre_natal );
466500
467- lwsl_debug ("%s: lsp stdwsi %p: pipe idx %d -> fd %d / %d \n" ,
501+ lwsl_debug ("%s: lsp stdwsi %p: pipe idx %d -> fd %p / %p \n" ,
468502 __func__ , lsp -> stdwsi [n ], n ,
469503 lsp -> pipe_fds [n ][!!(n == 0 )],
470504 lsp -> pipe_fds [n ][!(n == 0 )]);
@@ -524,22 +558,75 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i)
524558 * (-- p ) = '\0' ;
525559 // puts(cli);
526560
561+ STARTUPINFOEXA siex ;
562+ STARTUPINFOA * psi ;
563+ HMODULE hKernel32 ;
564+ PFN_CREATE_PSEUDO_CONSOLE pCreatePseudoConsole = NULL ;
565+ PFN_INITIALIZE_PROC_THREAD_ATTRIBUTE_LIST pInitializeProcThreadAttributeList = NULL ;
566+ PFN_UPDATE_PROC_THREAD_ATTRIBUTE pUpdateProcThreadAttribute = NULL ;
567+ PFN_DELETE_PROC_THREAD_ATTRIBUTE_LIST pDeleteProcThreadAttributeList = NULL ;
568+ SIZE_T attr_list_size = 0 ;
569+ DWORD creation_flags = CREATE_SUSPENDED ;
570+ int pty_active = 0 ;
571+
527572 memset (& pi , 0 , sizeof (pi ));
528573 memset (& si , 0 , sizeof (si ));
574+ memset (& siex , 0 , sizeof (siex ));
575+
576+ if (i -> pty_mode ) {
577+ hKernel32 = GetModuleHandleW (L"kernel32.dll" );
578+ if (hKernel32 ) {
579+ pCreatePseudoConsole = (PFN_CREATE_PSEUDO_CONSOLE )GetProcAddress (hKernel32 , "CreatePseudoConsole" );
580+ pInitializeProcThreadAttributeList = (PFN_INITIALIZE_PROC_THREAD_ATTRIBUTE_LIST )GetProcAddress (hKernel32 , "InitializeProcThreadAttributeList" );
581+ pUpdateProcThreadAttribute = (PFN_UPDATE_PROC_THREAD_ATTRIBUTE )GetProcAddress (hKernel32 , "UpdateProcThreadAttribute" );
582+ pDeleteProcThreadAttributeList = (PFN_DELETE_PROC_THREAD_ATTRIBUTE_LIST )GetProcAddress (hKernel32 , "DeleteProcThreadAttributeList" );
583+ }
584+
585+ if (pCreatePseudoConsole && pInitializeProcThreadAttributeList && pUpdateProcThreadAttribute && pDeleteProcThreadAttributeList ) {
586+ COORD size ;
587+ size .X = 80 ;
588+ size .Y = 24 ;
589+
590+ if (pCreatePseudoConsole (size , lsp -> pipe_fds [LWS_STDIN ][0 ], lsp -> pipe_fds [LWS_STDOUT ][1 ], 0 , & lsp -> hPC ) == S_OK ) {
591+ pty_active = 1 ;
592+ siex .StartupInfo .cb = sizeof (STARTUPINFOEXA );
593+ pInitializeProcThreadAttributeList (NULL , 1 , 0 , & attr_list_size );
594+ siex .lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST )lws_malloc (attr_list_size , "ptyattr" );
595+ pInitializeProcThreadAttributeList (siex .lpAttributeList , 1 , 0 , & attr_list_size );
596+ pUpdateProcThreadAttribute (siex .lpAttributeList , 0 , PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE , lsp -> hPC , sizeof (HPCON ), NULL , NULL );
597+ }
598+ }
599+ }
600+
601+ if (pty_active ) {
602+ psi = (STARTUPINFOA * )& siex ;
603+ creation_flags |= EXTENDED_STARTUPINFO_PRESENT ;
604+ } else {
605+ si .cb = sizeof (STARTUPINFOA );
606+ psi = (STARTUPINFOA * )& si ;
607+ }
529608
530- si .cb = sizeof (STARTUPINFO );
531- si .hStdInput = lsp -> pipe_fds [LWS_STDIN ][0 ];
532- si .hStdOutput = lsp -> pipe_fds [LWS_STDOUT ][1 ];
533- si .hStdError = lsp -> pipe_fds [LWS_STDERR ][1 ];
534- si .dwFlags = STARTF_USESTDHANDLES | CREATE_NO_WINDOW ;
535- si .wShowWindow = TRUE;
609+ psi -> hStdInput = lsp -> pipe_fds [LWS_STDIN ][0 ];
610+ psi -> hStdOutput = lsp -> pipe_fds [LWS_STDOUT ][1 ];
611+ psi -> hStdError = lsp -> pipe_fds [LWS_STDERR ][1 ];
612+ psi -> dwFlags = STARTF_USESTDHANDLES | CREATE_NO_WINDOW ;
613+ psi -> wShowWindow = TRUE;
536614
537- if (!CreateProcess (NULL , cli , NULL , NULL , TRUE, CREATE_SUSPENDED , NULL , NULL , & si , & pi )) {
538- lwsl_err ("%s: CreateProcess failed 0x%x \n" , __func__ ,
615+ if (!CreateProcessA (NULL , cli , NULL , NULL , TRUE, creation_flags , NULL , NULL , psi , & pi )) {
616+ lwsl_err ("%s: CreateProcess failed 0x%lx \n" , __func__ ,
539617 (unsigned long )GetLastError ());
618+ if (pty_active && siex .lpAttributeList ) {
619+ pDeleteProcThreadAttributeList (siex .lpAttributeList );
620+ lws_free (siex .lpAttributeList );
621+ }
540622 goto bail3 ;
541623 }
542624
625+ if (pty_active && siex .lpAttributeList ) {
626+ pDeleteProcThreadAttributeList (siex .lpAttributeList );
627+ lws_free (siex .lpAttributeList );
628+ }
629+
543630 lsp -> child_pid = pi .hProcess ;
544631 lsp -> hJob = CreateJobObjectW (NULL , NULL );
545632 if (lsp -> hJob ) {
@@ -563,10 +650,12 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i)
563650 /*
564651 * close: stdin:r, stdout:w, stderr:w
565652 */
566- for (n = 0 ; n < 3 ; n ++ )
567- CloseHandle (lsp -> pipe_fds [n ][n != 0 ]);
653+ for (n = 0 ; n < 3 ; n ++ ) {
654+ if (lsp -> pipe_fds [n ][n != 0 ] && (!i -> pty_mode || n != LWS_STDERR ))
655+ CloseHandle (lsp -> pipe_fds [n ][n != 0 ]);
656+ }
568657
569- lsp -> pipes_alive = 3 ;
658+ lsp -> pipes_alive = i -> pty_mode ? 2 : 3 ;
570659 lsp -> created = lws_now_usecs ();
571660
572661 if (i -> owner )
0 commit comments