Проблема, с которой вы сталкиваетесь, заключается в том, что имя исполняемого файла и некоторые аргументы уже содержатся в вашей переменной commandPath
(которая представляет собой не только путь, но и некоторые параметры). Если бы первая часть состояла только из символов (без пробелов), было бы не сложно отделить исполняемый файл от параметров, но это Windows, поэтому у вас могут быть пробелы, поэтому вы застряли. Так кажется.
Решение в не с использованием Process.Start
и не с использованием ShellExecute
. Process.Start
, независимо от того, просите ли вы использовать ShellExecute
или CreateProcess
, в обоих случаях требуется задать параметр / элемент FileName
, который передается как есть в CreateProcess и ShellExecute.
Так что тогда? Скорее просто: используйте CreateProcess
самостоятельно. Менее известная особенность этой функции API заключается в том, что вы можете передать ей полную командную строку, так же, как и в WinKey + R (Windows Run). "магия" , которую вы запрашиваете, может быть достигнута путем установки ее первого параметра на null
и его второго параметра на полный путь, включая все параметры. Подобно следующему, которое запустит Windows Photo Gallery для вас, при использовании той же строки с параметрами с Process.Start
любым способом, который приведет к ошибке «Файл не найден» :
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(
/* app name */ null,
/* cmd line */ @"C:\Program Files\Windows Photo Gallery\WindowsPhotoGallery.exe testBogusParam",
/* proc atts */ IntPtr.Zero,
/* thread atts */ IntPtr.Zero,
/* inh handles */ false,
/* create flags */ 0,
/* env ptr */ IntPtr.Zero,
/* current dir */ null,
/* startupinfo */ ref si,
/* processinfo */ out pi);
Обратите внимание, что я намеренно не включал кавычки вокруг пути к исполняемому файлу. Но если путь к исполняемому файлу заключен в кавычки, как в приведенном выше коде, он все равно будет работать, все magic есть. Добавьте к этому фрагмент кода, следующий процесс запустится так, как вы хотите:
/* with your code */
String commandPath = ReadFromRegistry();
String fullCommand = commandPath + " " + fileName; // assuming not %1
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(
null,
fullCommand,
IntPtr.Zero,
IntPtr.Zero,
false,
0,
IntPtr.Zero,
null,
ref si,
out pi);
Декларации - это то, что вы можете получить из http://www.pinvoke.net,, но для удобства вот часть, которая должна быть вставлена в секцию класса, чтобы приведенное выше работало. Справочник этих функций, как проверить результат (успех / сбой) и структуры STARTUPINFO
и PROCESS_INFORMATION
можно найти по адресу MSDN корпорации Майкрософт здесь . для удобства я рекомендую сделать вызов CreateProcess
в служебной функции.
/* place the following at the class level */
[DllImport("kernel32.dll")]
static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
Надеюсь, я правильно понял вашу проблему. Дайте мне знать, если у вас возникли проблемы с реализацией вышеуказанного кода.