Закрытие свернутого / иконизированного процесса из C#

Вот моя проблема: мне нужно закрыть уже запущенный процесс из программы 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!
                }
            }
        }

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
3 939
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

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

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

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

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

[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-битной версиях.

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

Это не ответ. Это должен быть комментарий под вопросом.

rory.ap 02.04.2018 15:05

Принято к сведению. Спасибо за совет. Хотя, может быть, в 2008 году, когда я спросил, что такого не было. / пожимать плечами

Craig Eddy 04.05.2018 03:22

Никакие ответы и вопросы никогда не смешивались, даже в 2008 году.

rory.ap 04.05.2018 21:59

В ПОРЯДКЕ. Еще раз спасибо.

Craig Eddy 07.05.2018 20:42
Ответ принят как подходящий

Вот некоторые ответы и пояснения:

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

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

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

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

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

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

Я знаю, что этому вопросу больше шести лет, но вы когда-нибудь находили решение на C#? Я закончил тем, что использовал язык сценариев под названием AutoIt, в котором есть функция ProcessClose, которая не «убивает» ее, но не выполняет ее с помощью C#.

kayleeFrye_onDeck 23.11.2014 06:39

Нет @kayleeFrye_onDeck, я не трогал это уже много лет :)

Traveling Tech Guy 23.11.2014 06:55

Хорошо! Спасибо, что ответили на этот код-археолог! : P Я сам сейчас работаю над решением, чтобы закрыть постоянное имя exe для процесса. Я дам вам знать, если я нанесу удар!

kayleeFrye_onDeck 23.11.2014 07:09

kayleeFrye_onDeck <== Вы сделали рабочее решение, если да, не могли бы вы поделиться им в этой ветке?

oakman 27.04.2015 13:29

Другие вопросы по теме