パイプリダイレクト

id:Ozyさんに触発されてちょっと実験してみた。

CreatePipe,DuplicateHandle,CreateProcessをP/Invokeで呼び出して
StreamReaderでStdOutputを読み出すというもの。

以下ソースコード

    const int STARTF_USESHOWWINDOW       = 0x00000001;
    const int STARTF_USESIZE             = 0x00000002;
    const int STARTF_USEPOSITION         = 0x00000004;
    const int STARTF_USECOUNTCHARS       = 0x00000008;
    const int STARTF_USEFILLATTRIBUTE    = 0x00000010;
    const int STARTF_RUNFULLSCREEN       = 0x00000020;
    const int STARTF_FORCEONFEEDBACK     = 0x00000040;
    const int STARTF_FORCEOFFFEEDBACK    = 0x00000080;
    const int STARTF_USESTDHANDLES       = 0x00000100;

    [StructLayout(LayoutKind.Sequential)]
    internal struct PROCESS_INFORMATION {
        public IntPtr   hProcess;
        public IntPtr   hThread;
        public UInt32   dwProcessId;
        public UInt32   dwThreadId;
    }

    const UInt32 INFINITE = 0xFFFFFFFF;

    [StructLayout(LayoutKind.Sequential)]
    internal struct PPROCESS_MEMORY_COUNTERS {
        public Int32 cb;
        public UInt32 PageFaultCount;
        public int PeakWorkingSetSize;
        public int WorkingSetSize;
        public int QuotaPeakPagedPoolUsage;
        public int QuotaPagedPoolUsage;
        public int QuotaPeakNonPagedPoolUsage;
        public int QuotaNonPagedPoolUsage;
        public int PagefileUsage;
        public int PeakPagefileUsage;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct STARTUPINFO
    {
        public int cb;
        public IntPtr lpReserved;
        public IntPtr lpDesktop;
        public IntPtr lpTitle;
        public int dwX;
        public int dwY;
        public int dwXSize;
        public int dwYSize;
        public int dwXCountChars;
        public int dwYCountChars;
        public int dwFillAttribute;
        public int dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    const int DUPLICATE_CLOSE_SOURCE = 0x00000001;
    const int DUPLICATE_SAME_ACCESS  = 0x00000002;

    const int CREATE_NO_WINDOW   = 0x08000000;
    const int CREATE_NEW_CONSOLE = 0x00000010;

    const short SW_HIDE = 0;

    [DllImport("kernel32.dll", EntryPoint="CreateProcess", CallingConvention=CallingConvention.Winapi, CharSet=CharSet.Auto, SetLastError=true)]
    static extern bool CreateProcess(string appName, StringBuilder cmdLine, ref SECURITY_ATTRIBUTES processAttr, ref SECURITY_ATTRIBUTES threadAttr, bool inheritHandles, int creationFlag, IntPtr environment, string curDir, ref STARTUPINFO startupInfo, ref PROCESS_INFORMATION processInfo);

    [DllImport("kernel32.dll", EntryPoint = "WaitForSingleObject", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 timeOut);

    [DllImport("kernel32.dll", EntryPoint = "CloseHandle", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    static extern bool CloseHandle(IntPtr hHandle);

    [DllImport("kernel32.dll", EntryPoint = "CreatePipe", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES secAttr, int nSize);

    [DllImport("kernel32.dll", EntryPoint = "DuplicateHandle", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    static extern bool DuplicateHandle(IntPtr hSrcProcess, IntPtr hSrcHandle, IntPtr hDstProcess, out IntPtr hDstHandle, UInt32 desiredAccess, bool inheritHandle, UInt32 options);

    [DllImport("kernel32.dll", EntryPoint = "GetCurrentProcess", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    static extern IntPtr GetCurrentProcess();

    [DllImport("psapi.dll", EntryPoint="GetProcessMemoryInfo", CallingConvention=CallingConvention.Winapi, SetLastError=true)]
    static extern bool GetProcessMemoryInfo( IntPtr hProcess, ref PPROCESS_MEMORY_COUNTERS processMemoryCounters, Int32 memInfoSize);

    private void CreatePipeWithSecurityAttributes(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES pipeAttributes, int nSize)
    {
        if (!CreatePipe(out hReadPipe, out hWritePipe, ref pipeAttributes, nSize))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    private void CreatePipe(out IntPtr parentHandle, out IntPtr childHandle, bool parentInputs)
    {
        SECURITY_ATTRIBUTES security_attributes1 = new SECURITY_ATTRIBUTES();
        security_attributes1.nLength = 12;
        security_attributes1.bInheritHandle = true;
        IntPtr handle1 = IntPtr.Zero;
        try
        {
            if (parentInputs)
            {
                CreatePipeWithSecurityAttributes(out childHandle, out handle1, ref security_attributes1, 0);
            }
            else
            {
                CreatePipeWithSecurityAttributes(out handle1, out childHandle, ref security_attributes1, 0);
            }
            if (!DuplicateHandle(GetCurrentProcess(), handle1, GetCurrentProcess(), out parentHandle, 0, false, DUPLICATE_SAME_ACCESS))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        finally
        {
            if (handle1 != IntPtr.Zero)
            {
                CloseHandle(handle1);
            }
        }
    }

    private void CreateProcess(string fileName)
    {
        SECURITY_ATTRIBUTES processAttr = new SECURITY_ATTRIBUTES();
        SECURITY_ATTRIBUTES threadAttr = new SECURITY_ATTRIBUTES();

        processAttr.nLength = Marshal.SizeOf(processAttr);
        threadAttr.nLength = Marshal.SizeOf(threadAttr);
        processAttr.bInheritHandle = true;
        threadAttr.bInheritHandle = true;

        STARTUPINFO si = new STARTUPINFO();

        si.cb = Marshal.SizeOf(si);

        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

        PPROCESS_MEMORY_COUNTERS pmc = new PPROCESS_MEMORY_COUNTERS();

        pmc.cb = Marshal.SizeOf(pmc);

        IntPtr hStdOutReadPipe;
        IntPtr hStdOutWritePipe;
        IntPtr hStdInReadPipe;
        IntPtr hStdInWritePipe;
        IntPtr hStdErrReadPipe;
        IntPtr hStdErrWritePipe;

        SECURITY_ATTRIBUTES pipeAttr = new SECURITY_ATTRIBUTES();

        pipeAttr.nLength = Marshal.SizeOf(pipeAttr);
        pipeAttr.bInheritHandle = true;

        CreatePipe(out hStdInWritePipe, out hStdInReadPipe, true);
        CreatePipe(out hStdOutReadPipe, out hStdOutWritePipe, false);
        CreatePipe(out hStdErrReadPipe, out hStdErrWritePipe, false);

        si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;
        si.hStdInput = hStdInReadPipe;
        si.hStdOutput = hStdOutWritePipe;
        si.hStdError = hStdErrWritePipe;

        string outStr = "";

        if (!CreateProcess(null, new StringBuilder(fileName), ref processAttr, ref threadAttr, true, CREATE_NO_WINDOW, IntPtr.Zero, null, ref si, ref pi))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        if (CloseHandle(hStdInReadPipe))
        {
            hStdInReadPipe = IntPtr.Zero;
        }
        if (CloseHandle(hStdOutWritePipe))
        {
            hStdOutWritePipe = IntPtr.Zero;
        }
        if (CloseHandle(hStdErrWritePipe))
        {
            hStdErrWritePipe = IntPtr.Zero;
        }

        using (StreamReader sr = new StreamReader(new FileStream(hStdOutReadPipe, FileAccess.Read, false, 0x1000), Encoding.ASCII, true, 0x1000))
        {
            outStr = sr.ReadToEnd();
        }

        WaitForSingleObject(pi.hProcess, INFINITE);

        if (CloseHandle(pi.hThread))
        {
            pi.hThread = IntPtr.Zero;
        }

        if (!GetProcessMemoryInfo(pi.hProcess, ref pmc, Marshal.SizeOf(pmc)))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        outStr += string.Format("\r\n\r\nWorkingSetSize = {0}(byte)\r\n", pmc.WorkingSetSize);

        if (CloseHandle(hStdInWritePipe))
        {
            hStdInWritePipe = IntPtr.Zero;
        }
        if (CloseHandle(hStdOutReadPipe))
        {
            hStdOutReadPipe = IntPtr.Zero;
        }
        if (CloseHandle(hStdErrReadPipe))
        {
            hStdErrReadPipe = IntPtr.Zero;
        }

        if (CloseHandle(pi.hProcess))
        {
            pi.hProcess = IntPtr.Zero;
        }
    }