C# - Redirect child process input to read what win service parent process writes

0

I'm reading a lot about the topic but I am not able to get it. I have an SSCCE with a service who create a child process with CreateProcessAsUser. This child process is only intended to read from its stdin; what parent process writes, but I don't get anything from parent.

Parent service code:

    public static unsafe int WriteToHandle(byte[] buffer, int index, int count, IntPtr hStdOut)
    {
        int n = 0;
        bool cont = true;

            fixed (byte* p = buffer)
            {
               cont = WriteFile(hStdOut, p + index, count, &n, 0);

            }
        return n;
    }

    public static bool StartProcessAsCurrentUser()
    {
        var hUserToken = IntPtr.Zero;
        var sInfo = new STARTUPINFO();
        var procInfo = new PROCESS_INFORMATION();
        var pEnv = IntPtr.Zero;
        int iResultOfCreateProcessAsUser;
        string cmdLine = "ClientFormApp.exe";

        sInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
        byte[] buffer = new byte[BUFSIZE];

        bool result = false;

        const int STARTF_USESTDHANDLES = 0x00000100;
        const int STARTF_USESHOWWINDOW = 0x00000001;
        const int WAIT_TIMEOUT = 0x102;
        const int ERROR_SUCCESS = 0x0;
        const int HANDLE_FLAG_INHERIT = 1;

        try
        {
            var tSecurity = new SECURITY_ATTRIBUTES();
            tSecurity.nLength = Marshal.SizeOf(tSecurity);
            var pSecurity = new SECURITY_ATTRIBUTES();
            pSecurity.nLength = Marshal.SizeOf(pSecurity);
            pSecurity.bInheritHandle = true; 

            IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(pSecurity));
            Marshal.StructureToPtr(pSecurity, pointer, true);

            if (!CreatePipe(out hReadOut, out hWriteOut, pointer, 0)) // hReadOut -> read data from output | hWriteOut -> send data to output
                return result = false;
            if (!CreatePipe(out hReadIn, out hWriteIn, pointer, 0)) // hReadOut -> read data from output | hWriteOut -> send data to output
                return result = false;

            if (!SetHandleInformation(hWriteOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
                return result = false;
            if (!SetHandleInformation(hReadOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
                return result = false;

            if (!SetHandleInformation(hWriteIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
                return result = false;
            if (!SetHandleInformation(hReadIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
                return result = false;

            sInfo.hStdOutput = hWriteOut; 
            sInfo.hStdInput = hReadIn; 
            sInfo.hStdError = hWriteOut; 

            if (!GetSessionUserToken(ref hUserToken))
            {
                throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
            }

            uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)CREATE_NEW_CONSOLE;
            sInfo.wShowWindow = (short)SW.SW_SHOW;
            sInfo.lpDesktop = "winsta0\\default";

            if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
            {
                throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
            }

            if (!CreateProcessAsUser(hUserToken,
                null, // Application Name
                cmdLine, // Command Line
                IntPtr.Zero,
                IntPtr.Zero,
                true,
                dwCreationFlags,
                pEnv,
                null, // Working directory
                ref sInfo,
                out procInfo))
            {
                throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n");
            }

            iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
            string message = "Message";
            byte[] messageByte = System.Text.Encoding.Unicode.GetBytes(message);
            int bytesWrited = WriteToHandle(messageByte, 0, messageByte.Length, hWriteIn);
        }
        finally
        {
            //Clossing handles
        }

        return true;
    }
}

I have verified that bytesWrited is not 0.

Following this example, this is my child process:

    public static unsafe int ReadFromHandle(byte[] buffer, int index, int count, IntPtr hStdOut)
    {
        int n = 0;

        try
        {
            fixed (byte* p = buffer)
            {
                if (!ReadFile(hStdOut, p + index, count, &n, 0)) //Nothing to read from handle
                    return 0;
            }
            return n;
        }
        catch (Exception e)
        {
            return 0;
        }
    }

    private void OnNewStep()
    {
        byte[] buffer = new byte[BUFSIZE];
        const int STD_OUTPUT_HANDLE = -11;
        const int STD_INPUT_HANDLE = -10;
        const int STD_ERROR_HANDLE = -12;
        string content = "";

        hStdin = GetStdHandle(STD_INPUT_HANDLE);

        do
        {
            bytesReadOutput = ReadFromHandle(buffer, 0, buffer.Length, hStdin);
            content = content + System.Text.Encoding.Unicode.GetString(buffer, 0, bytesReadOutput);
        }
    }

But bytesReadOutput is always 0. I don't really understand the purpose of the line hStdin = GetStdHandle(STD_INPUT_HANDLE). If I'm not wrong, when I create the child process in service process, I'm setting redirected standard input here sInfo.hStdInput = hReadIn; and hStdin = GetStdHandle(STD_INPUT_HANDLE) in child process will get that hReadIn service handle. But I have checked it and hStdin is always 0.

What I'm doing wrong? Thanks in advance.

c#
.net
asked on Stack Overflow Jun 9, 2016 by AdSsa • edited Jun 9, 2016 by Irshu

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0