Мне нужно создать приложение, которое запускает разные команды (PowerShell.exe, ipconfig и т. д.), но когда вызывается ExecuteCommand, пользовательский интерфейс зависает до завершения работы.
Пытался запустить метод с помощью await proc.StandardOutput.ReadToEndAsync(), но не работает. (он висит на указанной строке и не продолжается на следующей строке)
Что я делаю не так?
Заранее спасибо.
ВыполнитьКоманду:
public static async Task<string> ExecuteCommand(string command)
{
try
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardInput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
var message = proc.StandardOutput.ReadToEndAsync();
//var error = await proc.StandardError.ReadToEndAsync();
proc.Close();
//var errorContent = error;
return message.Result;
}
catch (Exception objException)
{
return objException.Message;
}
}
Регистратор:
public void Logger(string value)
{
logtxt.AppendText("[" + DateTime.Now + "]: " + value + Environment.NewLine);
logtxt.SelectionStart = logtxt.Text.Length;
logtxt.ScrollToCaret();
}
Активен:
private async Task<bool> IsActive()
{
string text = await ExecuteCommand("PowerShell.exe -Command \"Get-VPNconnection -AllUserConnection\"");
Logger(text);
...more code...
}
Form1_Shown (я переместил приведенный ниже код из Form_Load, потому что до появления пользовательского интерфейса требуется время):
private void Form1_Shown(object sender, EventArgs e)
{
if (IsActive().Result)
{
...more code...
}
}
также отсутствует await
на ReadToEndAsync
Это распространенная проблема с winforms, если вы не разрешите запуск процесса в фоновом режиме. Не уверен, но у Джими может быть ответ.
Ни PowerShell.exe
, ни ipconfig
.exe не требуют какого-либо участия "cmd"
, поэтому я не понимаю, почему вы сначала используете cmd /c
, или, точнее, Environment.SystemDirectory
с \cmd.exe /S /D /C "command"
Вот ваша проблема:
private void Form1_Shown(object sender, EventArgs e)
{
if (IsActive().Result)
{
...more code...
}
}
Чтение свойства Результат является блокирующей операцией. Это не только блокирует поток пользовательского интерфейса, но, что еще хуже, вызывает взаимоблокировку, поскольку в асинхронном потоке есть await
, которые захватывают контекст пользовательского интерфейса, поскольку они не настроены с помощью .ConfiguredAwait(false)
. Правильный способ решить эту проблему — использовать полную асинхронность:
private async void Form1_Shown(object sender, EventArgs e)
{
if (await IsActive())
{
...more code...
}
}
Вы можете узнать больше об этой распространенной проблеме, прочитав знаменитую статью Стивена Клири Не блокируйте асинхронный код.
все работает так, как я хотел, спасибо
жду
[Process].WaitForExitAsync()