【发布时间】:2009-12-29 07:27:21
【问题描述】:
我正在使用来自http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw 的代码。如何从标准输出中获取输出作为字符串?就像您在命令窗口中以交互方式运行它时显示的内容一样?
【问题讨论】:
我正在使用来自http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw 的代码。如何从标准输出中获取输出作为字符串?就像您在命令窗口中以交互方式运行它时显示的内容一样?
【问题讨论】:
使用重定向的 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方法中完成的
希望这会有所帮助,问候
【讨论】:
为什么不使用Process.Start Method 的以下重载?
【讨论】:
这篇文章为我解决了这个问题。不是输出部分,而是我让 CreateProcessWithLogonW 工作。
【讨论】: