【问题标题】:How to get standard output from CreateProcessWithLogonW?如何从 CreateProcessWithLogonW 获取标准输出?
【发布时间】:2009-12-29 07:27:21
【问题描述】:

我正在使用来自http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw 的代码。如何从标准输出中获取输出作为字符串?就像您在命令窗口中以交互方式运行它时显示的内容一样?

【问题讨论】:

    标签: c# winapi


    【解决方案1】:

    使用重定向的 std input\output\error 线程调用 CreateProcessWithLogonW 与使用指定了 user\domain\password 字段的 System.Diagnostics.Process 类执行下面的代码相同,并且重定向* 字段设置为 true。事实上,通过使用反射器查看 Process 类的 StartWithCreateProcess 私有方法,您会发现如果应用了上述条件,则会在那里执行 NativeMethods.CreateProcessWithLogonW 过程。

    Process process1 = new Process();
    process1.StartInfo.FileName = @"c:\windows\system32\ping.exe";
    process1.StartInfo.Arguments = "127.0.0.1";
    // all 3 redirect* fields have to be set
    process1.StartInfo.RedirectStandardOutput = true;
    process1.StartInfo.RedirectStandardInput = true;
    process1.StartInfo.RedirectStandardError = true;
    process1.StartInfo.UseShellExecute = false;
    process1.StartInfo.UserName = "admin";
    process1.StartInfo.Domain = System.Environment.MachineName;
    SecureString password = new SecureString();
    foreach (char a in "password".ToCharArray())
        password.AppendChar(a);
    process1.StartInfo.Password = password;
    process1.Start();
    string output = process1.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process1.WaitForExit();
    

    至于原问题:

    您需要为 StartupInfo 的 stdOutput、stdError、stdInput 字段设置管道句柄。像这样的:

    StartupInfo startupInfo = new StartupInfo();
    startupInfo.reserved = null;
    startupInfo.flags = STARTF_USESTDHANDLES;
    startupInfo.showWindow = SW_SHOW;
    ...
    SafeFileHandle inputHandle = null;
    SafeFileHandle outputHandle = null;
    SafeFileHandle errorHandle = null;
    
    CreatePipe(out inputHandle, out startupInfo.stdInput, true);
    CreatePipe(out outputHandle, out startupInfo.stdOutput, false);
    CreatePipe(out errorHandle, out startupInfo.stdError, false);
    

    下面是 CreatePipe 的实现:

    public static void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
    {
        SECURITY_ATTRIBUTES lpPipeAttributes = new SECURITY_ATTRIBUTES();
        lpPipeAttributes.bInheritHandle = true;
        SafeFileHandle hWritePipe = null;
        try
        {
            if (parentInputs)
                CreatePipeWithSecurityAttributes(out childHandle, out hWritePipe, lpPipeAttributes, 0);
            else
                CreatePipeWithSecurityAttributes(out hWritePipe, out childHandle, lpPipeAttributes, 0);
            if (!DuplicateHandle(GetCurrentProcess(), hWritePipe, GetCurrentProcess(), out parentHandle, 0, false, 2))
                throw new Exception();
        }
        finally
        {
            if ((hWritePipe != null) && !hWritePipe.IsInvalid)
            {
                hWritePipe.Close();
            }
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
        public SECURITY_ATTRIBUTES()
        {
            nLength = 12;
            lpSecurityDescriptor = IntPtr.Zero;
        }
    }
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
        SECURITY_ATTRIBUTES lpPipeAttributes, int nSize);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeHandle hSourceHandle,
        IntPtr hTargetProcess, out SafeFileHandle targetHandle, int dwDesiredAccess,
        bool bInheritHandle, int dwOptions);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr GetCurrentProcess();
    
    public static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
        SECURITY_ATTRIBUTES lpPipeAttributes, int nSize)
    {
        hReadPipe = null;
        if ((!CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize) || hReadPipe.IsInvalid) || hWritePipe.IsInvalid)
            throw new Exception();
    }
    

    在您完成创建管道并执行 CreateProcessWithLogonW 后,您可以从管道读取标准输出:

    StreamWriter standardInput = new StreamWriter(new FileStream(inputHandle, FileAccess.Write, 0x1000, false), Console.InputEncoding, 0x1000);
    standardInput.AutoFlush = true;
    StreamReader reader = new StreamReader(new FileStream(outputHandle, FileAccess.Read, 0x1000, false), Console.OutputEncoding, true, 0x1000);
    StreamReader error = new StreamReader(new FileStream(errorHandle, FileAccess.Read, 0x1000, false), Console.OutputEncoding, true, 0x1000);
    
    while (!reader.EndOfStream)
    {
       string line = reader.ReadLine();
       if (line.Length>0) Console.WriteLine(line);
    }
    

    上面的代码基本上是在Process类的StartWithCreateProcess方法中完成的

    希望这会有所帮助,问候

    【讨论】:

      【解决方案2】:

      为什么不使用Process.Start Method 的以下重载?

      【讨论】:

      【解决方案3】:

      这篇文章为我解决了这个问题。不是输出部分,而是我让 CreateProcessWithLogonW 工作。

      http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-08
        • 2020-03-03
        • 2020-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-29
        • 2018-12-26
        相关资源
        最近更新 更多