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

StackOverflow https://stackoverflow.com/questions/110336

  •  02-07-2019
  •  | 
  •  

Вопрос

Вот моя проблема:Мне нужно закрыть уже запущенный процесс из программы 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 когда окно было свернуто.Удаление если не помогает.Ни ЗакрытьMainWindow() ни Закрывать() работа.А Убийство() есть, но как уже говорилось выше - это не то, что мне нужно.

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

Это было полезно?

Решение 3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top