Закрытие свернутого / иконизированного процесса из C # - PullRequest
3 голосов
/ 21 сентября 2008

Вот моя проблема: мне нужно закрыть уже запущенный процесс из программы на C #. Проблема в том, что процесс теперь выполняется в виде значка (свернутого на панель задач), и если пользователь не откроет его хотя бы один раз (что никогда не произойдет на автоматических машинах), он никогда не будет есть главное окно.

Другое требование, которое у меня есть, заключается в том, чтобы приложение было закрыто , а не убито . Мне нужно, чтобы он записал свои буферы памяти на диск - и его уничтожение приводит к потере данных.

Вот что я попробовал до сих пор:

        foreach (Process proc in Process.GetProcesses())
        {
            if (proc.ProcessName.ToLower().StartsWith("myapp"))
            {
                if (proc.MainWindowHandle.ToInt32() != 0)
                {
                    proc.CloseMainWindow();
                    proc.Close();
                    //proc.Kill();  <--- not good!
                }
            }
        }

Я добавил предложение if , обнаружив, что MainWindowHandle == 0 , когда окно было свернуто. Удаление , если не помогает. Ни CloseMainWindow () , ни Close () не работают. Kill () делает, но, как упоминалось выше - это не то, что мне нужно.

Любая идея будет принята, включая использование тайных функций Win32 API:)

Ответы [ 4 ]

2 голосов
/ 21 сентября 2008

Это должно работать:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr FindWindow(string className, string windowName);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

private const int WM_CLOSE = 0x10;
private const int WM_QUIT = 0x12;

public void SearchAndDestroy(string windowName) 
{
    IntPtr hWnd = FindWindow(null, windowName);
    if (hWnd == IntPtr.Zero)
        throw new Exception("Couldn't find window!");
    SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

Поскольку некоторые окна не отвечают на WM_CLOSE, вместо этого может потребоваться отправка WM_QUIT. Эти объявления должны работать как на 32, так и на 64 битах.

1 голос
/ 21 сентября 2008

Если он находится на панели задач, у него будет окно. Или вы имели в виду, что он находится в области уведомлений панели задач (он же SysTray)? В этом случае у него все еще будет окно.

Приложения Win32 на самом деле не имеют «главного окна», кроме как по соглашению (главное окно - это то, которое вызывает PostQuitMessage в ответ на WM_DESTROY, вызывая выход из цикла сообщений).

Запустив программу, запустите Spy ++. Чтобы найти все окна, принадлежащие процессу, вы должны выбрать Spy -> Processes в главном меню. Это отобразит дерево процессов. Оттуда вы можете перейти к потокам, а затем к окнам. Это скажет вам, какие окна имеет процесс. Запишите класс окна и заголовок. С их помощью вы можете использовать FindWindow (или EnumWindows), чтобы найти дескриптор окна в будущем.

С помощью дескриптора окна вы можете отправить сообщение WM_CLOSE или WM_SYSCOMMAND / SC_CLOSE (что эквивалентно нажатию на «X» в заголовке окна). Это должно привести к хорошему завершению программы.

Обратите внимание, что я говорю с точки зрения Win32 здесь. Возможно, вам придется использовать P / Invoke или другие приемы, чтобы заставить это работать из программы .NET.

0 голосов
/ 21 сентября 2008

Вот некоторые ответы и разъяснения:

rpetrich : Пробовал ваш метод раньше, и проблема в том, что я не знаю имя окна, оно отличается от пользователя к пользователю, от версии к версии - только имя exe остается неизменным. Все, что у меня есть, это имя процесса. И, как вы можете видеть в коде выше, MainWindowHandle процесса равна 0.

Роджер : Да, я имел в виду область уведомлений панели задач - спасибо за разъяснения. Мне НУЖНО , чтобы вызвать PostQuitMessage. Я просто не знаю как, учитывая только процессы, а не окно.

Craig : Я был бы рад объяснить ситуацию: приложение имеет интерфейс командной строки, позволяющий вам указать параметры, которые определяют, что он будет делать и где будет сохранять результаты. Но как только он запустится, единственный способ остановить его и получить результаты - щелкнуть его правой кнопкой мыши в области уведомлений и выбрать «Выход».

Теперь мои пользователи хотят создать скрипт / пакет приложения. У них не было абсолютно никаких проблем с запуском его из пакета (просто укажите exe-имя и несколько флагов), но затем они застряли с запущенным процессом. Предполагая, что никто не изменит процесс для предоставления API, чтобы остановить его во время работы (он довольно старый), мне нужен способ искусственно закрыть его.

Аналогично, на автоматических компьютерах сценарий запуска процесса может быть запущен программой планирования задач или управления операциями, но нет способа остановить процесс.

Надеюсь, что прояснит мою ситуацию, и еще раз, спасибо всем, кто пытается помочь!

0 голосов
/ 21 сентября 2008

Вопрос, чтобы уточнить, почему вы пытаетесь это сделать: если единственным пользовательским интерфейсом в процессе является значок на панели задач, почему вы хотите убить это и оставить процесс запущенным? Как бы пользователь получил доступ к процессу? А если аппарат «без присмотра», зачем беспокоиться о значке в трее?

...