如何从CreateProcessWithLogonW获取标准输出?

时间:2009-12-29 07:27:22

标签: c# winapi

我正在使用http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw中的代码。如何将标准输出的输出作为字符串?就像在命令窗口中以交互方式运行它时出现的东西一样?

3 个答案:

答案 0 :(得分:3)

使用重定向的std input \ output \ error线程调用 CreateProcessWithLogonW 与使用 System.Diagnostics.Process 类并且指定了user \ domain \ password字段执行下面的代码相同重定向*字段设置为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字段。像这样的Smth:

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后,您可以从管道中读取std输出:

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方法中完成的。

希望这有帮助,尊重

答案 1 :(得分:2)

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

答案 2 :(得分:0)

这篇帖子为我解决了。不是输出部分,而是我让CreateProcessWithLogonW工作。

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