看起来不是。
如果我将文件名转换为其短值,则Process.Start()可以正常工作。
Process runScripts = new Process();
runScripts.StartInfo.FileName = @"C:\long file path\run.cmd";
runScripts.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
runScripts.StartInfo.UseShellExecute = true;
runScripts.StartInfo.RedirectStandardOutput = false;
runScripts.Start();
上述代码失败。但...
Process runScripts = new Process();
runScripts.StartInfo.FileName = @"C:\short\file\path\run.cmd";
runScripts.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
runScripts.StartInfo.UseShellExecute = true;
runScripts.StartInfo.RedirectStandardOutput = false;
runScripts.Start();
成功。
我设法通过将长路径名转换为短路径名来解决这个问题。 但我发现这一点有点惊讶。 关于此的任何原因或背景信息?
感谢。
更新1
Microsoft .NET Framework版本2.0.50727
答案 0 :(得分:5)
很奇怪,我重现了这个行为,实际上,它没有像你说的那样执行,但修改它,它起作用了:
System.Diagnostics.Process runScripts = new System.Diagnostics.Process();
runScripts.StartInfo.FileName = @"run.cmd";
// new
runScripts.StartInfo.WorkingDirectory = @"C:\long file path";
runScripts.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
runScripts.StartInfo.UseShellExecute = true;
runScripts.StartInfo.RedirectStandardOutput = false;
runScripts.Start();
答案 1 :(得分:4)
我无法重现您所描述的行为。以下代码适用于我。
string path = @"X:\Temp\long file path\run.cmd";
Process p = new Process();
p.StartInfo.FileName = path;
// Works with both true (default) and false.
p.StartInfo.UseShellExecute = true;
p.Start();
修改强>
我可以使用以下代码重现
string path = @"X:\Temp\long file path";
string file = "run.cmd";
Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.WorkingDirectory = path;
p.StartInfo.UseShellExecute = false; // only fails with false.
p.Start();
return;
此节目(使用进程监视器),ConsoleApplication.vshost.exe尝试在project \ bin \ Release,System32,System,Windows,System32 \ Wbem中找到run.cmd,然后进一步进入某些(我猜)路径变量。但是,如果我设置UseShellExecute = true。
答案 2 :(得分:3)
为了重现您的问题,我使用了以下程序:
// file test.cs
using System;
using System.ComponentModel;
using System.Diagnostics;
public class Test
{
public static int Main()
{
string error;
try {
ProcessStartInfo i = new ProcessStartInfo();
i.FileName = @"C:\long file path\run.cmd";
i.WindowStyle = ProcessWindowStyle.Hidden;
i.UseShellExecute = true;
i.RedirectStandardOutput = false;
using (Process p = Process.Start(i)) {
error = "No process object was returned from Process.Start";
if (p != null) {
p.WaitForExit();
if (p.ExitCode == 0) {
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("OK");
Console.ResetColor();
return 0;
}
error = "Process exit code was " + p.ExitCode;
}
}
}
catch (Win32Exception ex) {
error = "(Win32Exception) " + ex.Message;
}
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Whooops: " + error);
Console.ResetColor();
return 1;
}
}
代码启动一个新进程(根据您的代码示例)并报告它可能无法执行的不同方式。您可以从命令行编译程序:
c:\windows\Microsoft.NET\Framework\v2.0.50727\csc test.cs
(假设test.cs在当前目录中;它将在与test.cs相同的目录中创建test.exe)
正如预期的那样,当“C:\ long file path \ run.cmd”不存在时,程序将失败并显示:
Whooops: (Win32Exception) The system cannot find the file specified
现在让我们创建一个目录“C:\ long file path”并在其中放一个非常简单的run.cmd:
rem file run.cmd
echo I ran at %Time% > "%~dp0\run.out.txt"
但是,此时我无法重现您的失败。一旦上面的run.cmd到位,test.exe就会成功运行(即run.cmd正确执行 - 您可以通过查找新创建的文件“C:\ long file path \ run.out.txt”来验证这一点。
我在Vista x64(我的主开发机器),Windows XP SP3 x86(虚拟机),Windows Server 2008 x64(虚拟机)上运行了test.exe,它可以在任何地方运行。
您是否可以尝试在您的环境中运行上述代码并报告它是否失败?这样我们至少会建立相同的测试上下文(相同的.NET程序将尝试在同一位置为您运行相同的批处理文件)。
答案 3 :(得分:2)
我设法通过使用以下行为来实际运行它。
private string StartProcessAndGetResult(string executableFile, string arguments)
//NOTE executable file should be passed as string with a full path
//For example: C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe
//Without """ and @ signs
{
var result = String.Empty;
var workingDirectory = Path.GetDirectoryName(executableFile);
var processStartInfo = new ProcessStartInfo(executableFile, arguments)
{
WorkingDirectory = workingDirectory,
UseShellExecute = false,
ErrorDialog = false,
CreateNoWindow = true,
RedirectStandardOutput = true
};
var process = Process.Start(processStartInfo);
if (process != null)
{
using (var streamReader = process.StandardOutput)
{
result = streamReader.ReadToEnd();
}
}
return result;
}
使用@或将字符串引用到引号(“”“)的解决方案在我的案例中并没有被忽略。
答案 4 :(得分:1)
尝试
runScripts.StartInfo.FileName = @"""C:\long file path\run.cmd""";
虽然我确信它是由Process类自动完成的。您确定提供了正确的路径吗?
答案 5 :(得分:1)
我有一个假设。 Win32有一个限制,用于描述文件名的字符串不能超过MAX_PATH(260字节),包括终止'\ 0'。
也许这个问题已泄露到C#中?
(我所做的测试表明,但我无法确认哪些错误。)
因此,尝试在路径前添加“\\?\”。 (反斜杠,反斜杠,问号,反斜杠) 即。
runScripts.StartInfo.FileName = @"\\?\C:\long file path\run.cmd";
有关MAX_PATH的更多详细信息:http://msdn.microsoft.com/en-us/library/aa365247.aspx
/雷夫
答案 6 :(得分:1)
我认为我从Process.Start方法的逆向工程中发现了一个问题。我是在正确的路线上,在没有设置WorkingDirectory的情况下失败。
所以换句话说,CreateProcess需要一个有效的工作目录,而不是.NET(它应该真的从文件名中推断出它,但显然不是)
以下是证据:
namespace SoTest
{
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, StringBuilder lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, STARTUPINFO lpStartupInfo, PROCESS_INFORMATION lpProcessInformation);
static void Main(string[] args)
{
Process process = new Process();
process.StartInfo.FileName = @"C:\my test folder\my test.bat";
StringBuilder cmdLine = new StringBuilder();
cmdLine.Append(process.StartInfo.FileName);
STARTUPINFO lpStartupInfo = new STARTUPINFO();
PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION();
// This fails
//string workingDirectory = process.StartInfo.WorkingDirectory;
string workingDirectory = @"C:\my test folder\";
CreateProcess(null, cmdLine, null, null, true, 0, IntPtr.Zero, workingDirectory, lpStartupInfo, lpProcessInformation);
}
}
[StructLayout(LayoutKind.Sequential)]
internal class PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
public PROCESS_INFORMATION()
{
this.hProcess = IntPtr.Zero;
this.hThread = IntPtr.Zero;
}
}
[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES
{
public int nLength;
public long lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
internal class 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;
public STARTUPINFO()
{
this.lpReserved = IntPtr.Zero;
this.lpDesktop = IntPtr.Zero;
this.lpTitle = IntPtr.Zero;
this.lpReserved2 = IntPtr.Zero;
this.hStdInput = IntPtr.Zero;
this.hStdOutput = IntPtr.Zero;
this.hStdError = IntPtr.Zero;
this.cb = Marshal.SizeOf(this);
}
}
}
我已从原始代码中删除了SafeFileHandle,因为我们正在执行的操作不需要它。此外,没有设置启动标志,但无窗口版本需要这些标志。
答案 7 :(得分:0)
试试这个:
Process runScripts = new Process();
runScripts.StartInfo.FileName = @"""C:\long file path\run.cmd""";
runScripts.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
runScripts.StartInfo.UseShellExecute = true;
runScripts.StartInfo.RedirectStandardOutput = false;
runScripts.Start();
即。当FileName有空格时,使用FileName的带引号的字符串。
答案 8 :(得分:0)
您的代码可能因各种原因而失败,这些原因与长/短路径问题无关。您应该在问题中添加确切的异常描述(包括调用堆栈)。