2010-01-23 2 views
15

Мне нужно иметь возможность запускать процессы (как консольные, так и оконные) без кражи фокуса. Единственный способ в .NET Framework, который я нашел для этого, - это Microsoft.VisualBasic.Interaction.Shell с Microsoft.VisualBasic.AppWinStyle. [Минимизированный | Нормальный] NoFocus (который отображается в SW_SHOWMINNOACTIVE/SW_SHOWMA, который передается в ShellExecute).Запуск процесса без кражи фокуса (C#)

В текущей версии моего кода (который делает кражу фокуса) я использую System.Diagnostics.Process и полагаюсь на некоторые функции, которые дают мне, что метод Interaction.Shell этого не делает.

2 вопроса (один серьезный и один вентилирующего мое разочарование, что я не ожидал хороший ответ)

1.) Я правильно, что у меня нет выбора, кроме как обернуть CreateProcess или ShellExecuteEx себя, или я пропустил какое-то другое решение? Я действительно надеялся избежать этого, так как Process - это такая полная и полезная оболочка, кроме этого, и было бы так много возможностей для реализации, P/Invoke вызовы для отладки и всевозможные разнообразные боли.

2.) Почему одна команда в Microsoft создала такую ​​(в противном случае) полную оболочку, а затем исключила бы половину возможных значений из ProcessWindowStyle, в то время как другая команда создала аналогичную оболочку, которая была намного менее полной, но при условии, что все полезные стили окна?

+0

Вы кодируете то, что вы не хотите, чтобы пользователь знал об этом или не хотел беспокоить пользователя? LOL nevermind ...: -/ – jasonco

+1

Нет выбора? Пространство имен Microsoft.VisualBasic является частью платформы .NET и доступно для любой установки .NET. Не использовать его было бы ошибкой.У него много других полезных свойств, но вы не можете узнать, не можете ли вы пройти мимо имени пространства имен. –

+0

Привет nobugz, прошу прощения, если у меня сложилось впечатление, что у меня возникла проблема с пространством имен. Это не моя проблема, на самом деле я использую хороший парсер из Microsoft.VisualBasic в другой части кода. Проблема в том, что Microsoft.VisualBasic.Interaction.Shell не дает мне возможности быть уведомленным о выходе или прервать процесс. Мне пришлось бы каким-то образом обернуть его, чтобы получить эту функциональность, если класс Process даст мне обоим эти вещи. – psm321

ответ

11

Команда VB.Net сделала гораздо больше, чтобы облегчить работу разработчика в отношении аппаратуры окон, и я не вижу проблемы с добавлением ссылки на библиотеку VB и ее использования в вашей программе на C#.

Это две команды с разным фокусом, вот и все. И вы не должны плохо относиться к использованию Microsoft.VisualBasic.Interaction.Shell, если он решает вашу проблему.

Вы также можете использовать Reflector, чтобы увидеть фактическую реализацию и реализовать код самостоятельно, если вы не хотите ссылаться на dll.

[Редактировать - добавлен пример кода после комментария, чтобы показать, вы можете объединить Interaction.Shell и процесс]

int pid = Interaction.Shell("notepad.exe", AppWinStyle.NormalFocus); 
Process p = Process.GetProcessById(pid); 
p.Exited += ((o, e) => Console.WriteLine("Exit")); 
p.EnableRaisingEvents = true; 
Console.ReadLine(); 

Здесь я использую метод Shell, чтобы начать процесс, получить дескриптор процесса от pid и зацепить события. Вы можете даже сделать p.Kill(), чтобы прервать процесс.

[Edit - обходной путь для cmd.exe]

Это начинает становиться немного хаком на мой вкус, но это работает. Замените «NEWWINDOW» на случайное руководство или что-то, чтобы сделать его уникальным.

Microsoft.VisualBasic.Interaction.Shell(@"cmd.exe /c ""start cmd.exe /k title NEWWINDOW""", AppWinStyle.NormalFocus); 
foreach (var process in Process.GetProcessesByName("cmd")) 
{ 
    if (process.MainWindowTitle.EndsWith("NEWWINDOW")) 
    { 
     process.Exited += ((o, e) => Console.WriteLine("Exit")); 
     process.EnableRaisingEvents = true; 
    } 
} 
+0

У меня нет проблема с использованием пространства имен Microsoft.VisualBasic. Моя проблема связана с отсутствием других функций в этом методе (отсутствие события Exited и возможность прервать процесс). Я посмотрел на источник отладки, который Microsoft предоставляет для обоих методов ... вот как я узнал о базовых вызовах и переданных флагах, чтобы сделать эту работу. Это также то, как я решил, что попытка справиться с некоторыми функциями, которые я хочу сам по себе, будет очень болезненной, поскольку, похоже, существуют сложные проблемы с блокировкой, и я не могу просто скопировать код, так как это нарушит лицензию. – psm321

+0

отличная идея! Я попробую в понедельник и, скорее всего, приму ответ. благодаря! – psm321

+0

Это сработало, но есть сложность ... похоже, что вызов Interaction.Shell() из консольного приложения, запуск консольного приложения, повторное использование того же консольного окна, а не запуск нового, например, Console.Start. Любая идея, если это можно избежать? – psm321

2

Посмотрите здесь:

 
System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(); 
procInfo.CreateNoWindow = true; 
procInfo.UseShellExecute = true; 
procInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
proc.StartInfo = procInfo; 
proc.EnableRaisingEvents = true; 
proc.Exited += new EventHandler(proc_Exited); 
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); 
proc.Start(...) 
// Do something with proc.Handle... 
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    /* Do something here... */ 
} 

void proc_Exited(object sender, EventArgs e) 
{ 
/* Do something here... */ 
} 

Edit: Я изменил код, чтобы показать средства повышения событий и обращения с ними, а также, я показал использование в Handle имущества, которое является дескриптор выполняемого процесса.

+0

Спасибо за указатель. К сожалению, Hidden не делает то, что я хочу, так как 1.) из того, что я собираю, это только рекомендация для запущенного приложения и 2.), даже если это не так, мне нужно, чтобы приложение было видимым для пользователя, если он/она хочет сосредоточиться на ней, просто не краду фокус по умолчанию. Так что я действительно хочу, чтобы это было эквивалентное поведение для SW_SHOWMINNOACTIVE или SW_SHOWMA (http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx), которые используют метод Shell() действительно, но это, к сожалению, не возвращает мне дескриптор процесса, на который я могу установить выходное событие и т. д. – psm321

+0

@ psm321: Во-первых, код, который я вставлял, есть обработчик обработанного события для объекта proc, как показано выше! Зачем изобретать колесо? Во-вторых, я подозреваю, что это глобальная системная настройка, возможно, у вас есть аддон где-то, где по умолчанию фокус по умолчанию - это поведение в окнах. Подобно автоматическому поднятию окна без нажатия на него, которое выводит его на передний план. – t0mm13b

+0

И, кстати, Handle является свойством объекта proc, в котором у вас есть дескриптор процесса ... – t0mm13b

Смежные вопросы