Как закрыть (а не убить) приложение, которое свернуто в системный трей? - PullRequest
2 голосов
/ 27 июня 2011

Я пишу приложение, которое закрывает программу, изменяет файл данных, а затем снова открывает его.Я заметил, что если я использую process.Kill(), некоторые данные не записываются в файл.

Если я использую process.CloseMainWindow(), главное окно закрывается, но процесс сворачивается в начальный лоток.

Есть ли какой-нибудь способ, которым я могу отправить изящное сообщение о закрытии процесса?

Если это важно, я пытаюсь закрыть это Grindstone.

Ответы [ 4 ]

3 голосов
/ 27 июня 2011

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

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

Следующий шаг должен быть немного более жестким и отправить сообщение WM_QUIT потоку.Это немного проблематично, потому что вы должны найти обсуждаемый поток, используя некоторую форму перечисления процесса / потока и PInvoke PostThreadMessage для публикации WM_QUIT.Однако MSDN предлагает , чтобы вы не делали этого (ищите WM_QUIT).На практике это должно сработать.

Если это не сработает, то Process.Kill - это все, что у вас осталось.

Обновление: Выше я понимаю, но есть статья Microsoft KB на эту же тему.Он работает с Win32 (не управляемый код), но идеи могут быть адаптированы без особых проблем.

1 голос
/ 08 октября 2013

Объект EventWaitHandle в решении BackgroundWorker предоставил здесь работал для меня довольно хорошо, и я думаю, что его легче кодировать, чем использовать сообщения win API.

По сути, вы получили поток фонового работника, ожидающего определенного именованного события с помощью метода myEventWaitHandle.WaitOne.

Другое приложение просто создает одноименное событие и вызывает myEventWaitHandle.Set(), чтобы вызвать его. Это приводит к продолжению метода WaitOne() в фоновом режиме и, следовательно, к запуску RunWorkerCompleted. В этот момент вы можете безопасно закрыть свое приложение.

Ваше основное приложение:

private void evtBgWorker_DoWork(object sender, DoWorkEventArgs e) { 
   string evtName = "MyExitRequest" + Process.GetCurrentProcess().Id.ToString(); 
   EventWaitHandle evt = new EventWaitHandle(false, EventResetMode.ManualReset, evtName); 
   evt.WaitOne(); // the worker stops here until the event is triggered
 } 

private void evtBgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
  this.Close(); 
} 

Ваше приложение "Изящный убийца":

private void CloseMainApp() 
{
   Process[] processes = Process.GetProcessesByName("MyProcessName");
   Process myprocess= null;
   if (processes.Length > 0)
   {
      myprocess = processes[0];
      string evtName = "MyExitRequest" + myprocess.Id; // the same event name
      EventWaitHandle evt = new EventWaitHandle(false, EventResetMode.ManualReset, evtName);
      evt.Set(); // triggers the event at the main app

      if (!myprocess.WaitForExit(10000)) // waits until the process ends gracefuly
      {
         // if don't...
         myprocess.Kill();
      }
   }
}
0 голосов
/ 09 апреля 2013

Для моего приложения я пытался завершить процесс Python и его порожденные процессы открывались с помощью «subprocess.Popen». Я попробовал TerminateProcess, и это слишком зло. :) Наконец-то я решил, что могу использовать консольную команду taskkill . Я сделал это в программе на C ++:

    // standard kill process call
    void stopProcess(DWORD pid)
    {
        STARTUPINFO startupInfo;
        LPPROCESS_INFORMATION processInfo = new PROCESS_INFORMATION;

        // clear the memory to prevent garbage
        ZeroMemory(&startupInfo, sizeof(startupInfo));

        // set size of structure (not using Ex version)
        startupInfo.cb = sizeof(STARTUPINFO);
        // tell the application that we are setting the window display 
        // information within this structure
        startupInfo.dwFlags = STARTF_USESHOWWINDOW;    
        // hide process
        startupInfo.wShowWindow = SW_HIDE;

        //TerminateProcess(itr->second->hProcess, 0);  // not friendly to process, and does not kill child processes
        std::stringstream comStream;       
        comStream << "taskkill /pid ";
        comStream << pid;
        //comStream << " /t /f";  // to be more like TerminateProcess
        _MESSAGE("%s", comStream.str().c_str());             
        //system(comStream.str().c_str()); // works, but pops up a window momentarilly when called        

        //LPSTR s = const_cast<char *>(comStream.str().c_str());  
        LPSTR cString = strdup( comStream.str().c_str() );
        if(!CreateProcess(NULL,cString,NULL,NULL,false,NORMAL_PRIORITY_CLASS,NULL,NULL,&startupInfo,processInfo)){
            _MESSAGE("Could not launch '%s'",cString);
            SAFE_DELETE(processInfo);
        }else{
            // clean up
            CloseHandle(processInfo);
            SAFE_DELETE(processInfo);
        }
        // clean up 
        free(cString);
    }

Вы увидите, что мои другие эксперименты закомментированы. Я наконец остановился на этом методе, потому что он скрывает все всплывающие окна, которые могут появиться. Я также обнаружил, что это позволяет приложению Python правильно вызывать atexit. Однако даже без моего явного завершения подпроцессов они все равно отключаются с помощью метода taskkill. Я предполагаю, что это связано с тем, как разработан код Python.

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

0 голосов
/ 27 июня 2011

Вам необходимо отправить WM_CLOSE сообщение в главное окно приложения.Предположительно, это то, что CloseMainWindow реферат для вас.Это будет хорошо работать каждый раз.

К сожалению, похоже, что рассматриваемое приложение обрабатывает сообщение WM_CLOSE, минимизируя себя до области уведомлений панели задач.В этом случае он будет делать то же самое, если вы попытаетесь выйти из приложения любым другим способом, включая File -> Exit или нажав кнопку «X» в строке заголовка.

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

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

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

...