@Armin Zingler Give the following example code a try. Of course you'll need to conform paths and so forth for your own system.
VB Child Process -
Sub Main()
For i As Integer = 1 To 10
Console.WriteLine($"Line {i}")
Console.Error.WriteLine($"Line {i}")
Next
Console.Error.WriteLine("Hit a key to exit")
Console.ReadLine()
End Sub
Parent Process -
Imports System.IO
Imports System.Runtime.InteropServices
Module Module1
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Public Structure STARTUPINFO
Public cb As Integer
Public lpReserved As String
Public lpDesktop As String
Public lpTitle As String
Public dwX As Integer
Public dwY As Integer
Public dwXSize As Integer
Public dwYSize As Integer
Public dwXCountChars As Integer
Public dwYCountChars As Integer
Public dwFillAttribute As Integer
Public dwFlags As Integer
Public wWhowWindow As Short
Public cbReserved2 As Short
Public lpReserved2 As IntPtr
Public hStdInput As IntPtr
Public hStdOutput As IntPtr
Public hStdError As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure PROCESS_INFORMATION
Public hProcess As IntPtr
Public hThread As IntPtr
Public dwProcessId As Integer
Public dwThreadId As Integer
End Structure
Public Const STARTF_USESTDHANDLES As Integer = &H100
Public Const CREATE_NEW_CONSOLE As Integer = &H10
Public Const HANDLE_FLAG_INHERIT As UInteger = &H1
Public Const INVALID_HANDLE_VALUE As Integer = -1
<DllImport("kernel32.dll", CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Unicode, SetLastError:=True)>
Function CreateProcess(lpApplicationName As String, lpCommandLine As String, lpProcessAttributes As IntPtr,
lpThreadAttributes As IntPtr, bInheritHandles As Integer, dwCreationFlags As Integer,
lpEnvironment As IntPtr, lpDirectory As IntPtr, si As STARTUPINFO, pi As PROCESS_INFORMATION) As Boolean
End Function
<DllImport("kernel32.dll", CallingConvention:=CallingConvention.StdCall, SetLastError:=True)>
Function CreatePipe(ByRef hReadPipe As SafeFileHandle, ByRef hWriteByte As SafeFileHandle, lpPipeAttributes As IntPtr, nSize As UInteger) As Boolean
End Function
<DllImport("kernel32.dll", CallingConvention:=CallingConvention.StdCall, SetLastError:=True)>
Function SetHandleInformation(hObject As SafeFileHandle, mask As UInteger, dwFlags As UInteger) As Boolean
End Function
Sub Main()
Dim SI As STARTUPINFO = Nothing
Dim PI As PROCESS_INFORMATION
Dim exePath = "C:\Users\RLWA32\source\repos\RlwA32\PipeTest\VBChildProcess\bin\Debug\VBChildProcess.exe"
Dim hRead As New SafeFileHandle(INVALID_HANDLE_VALUE, True)
Dim hWrite As New SafeFileHandle(INVALID_HANDLE_VALUE, True)
Try
If CreatePipe(hRead, hWrite, IntPtr.Zero, 0) Then
SetHandleInformation(hWrite, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
SI.cb = CUInt(Marshal.SizeOf(GetType(STARTUPINFO)))
SI.dwFlags = STARTF_USESTDHANDLES
SI.hStdOutput = hWrite.DangerousGetHandle()
Dim result As String
If CreateProcess(
exePath, String.Empty, IntPtr.Zero, IntPtr.Zero, True,
CREATE_NEW_CONSOLE, IntPtr.Zero, Nothing, SI, PI) Then
hWrite.Close()
Using reader As New StreamReader(New FileStream(hRead, FileAccess.Read))
result = reader.ReadToEnd()
Console.Write(result)
End Using
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Catch ex As Exception
Console.WriteLine($"Exception: {ex.Message}")
Finally
hRead.Dispose()
hWrite.Dispose()
End Try
End Sub
End Module
And the result -