2016-06-28 3 views
-4

Я создаю программу, которая откроет текст Sublime и через некоторое время закроет приложение. Я не могу понять, как закрыть приложение, используя существующий код.Использование CreateProcess() для выхода/закрытия открытого приложения

Это то, что я до сих пор:

STARTUPINFO   siStartupInfo; 
PROCESS_INFORMATION piProcessInfo; 

memset(&siStartupInfo, 0, sizeof(siStartupInfo)); 
memset(&piProcessInfo, 0, sizeof(piProcessInfo)); 

siStartupInfo.cb = sizeof(siStartupInfo); 

if (CreateProcess(L"C:\\Program Files\\Sublime Text 2\\sublime_text.exe",  
    L" source.cpp",     
    NULL, 
    NULL, 
    FALSE, 
    CREATE_DEFAULT_ERROR_MODE, 
    NULL, 
    NULL, 
    &siStartupInfo, 
    &piProcessInfo) == FALSE) 

    WaitForSingleObject(piProcessInfo.hProcess, INFINITE); 

::CloseHandle(piProcessInfo.hThread); 
::CloseHandle(piProcessInfo.hProcess); 
+0

Удалить "== FALSE" из строки '& piProcessInfo) == FALSE)' - в соответствии с [док] (https: // MSDN .microsoft.com/en-us/library/windows/desktop/ms682425 (v = vs.85) .aspx) 'CreateProcess' возвращает ненулевое значение, если оно выполнено успешно (т.е. не FALSE) – mvidelgauz

+0

И принудительно закрыть этот процесс [BOOL WINAPI TerminateProcess (_In_ HANDLE hProcess, _In_ UINT uExitCode);] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714 (v = vs.85) .aspx) – mvidelgauz

+0

http: // stackoverflow .com/вопросы/9428456/как-к-terminate-a-process-created-by-createprocess – theB

ответ

3

Во-первых, вы звоните WaitForSingleObject() и CloseHandle() если CreateProcess()терпит неудачу, что бесполезно. Не вызывайте эти функции, если только не подходит вместо.

Во-вторых, вы вызываете версию Unicode CreateProcess(), в которой есть предостережение, что ваш код не обрабатывается. Согласно CreateProcess() documentation:

lpCommandLine [в, из, опционально]
Командная строка должна быть выполнена. Максимальная длина этой строки - 32 768 символов, включая нули-символ Unicode. Если lpApplicationName NULL, часть имени модуля lpCommandLine ограничена символами MAX_PATH.

Unicode-версия этой функции CreateProcessW может изменять содержимое этой строки. Поэтому этот параметр не может быть указателем на постоянную память (например, константную переменную или литеральную строку). Если этот параметр является константой, функция может вызвать нарушение доступа.

В-третьих, если вы хотите, чтобы завершить процесс после тайм-аута, вы могли использования TerminateProcess(), но это грубая сила и его следует избегать, если это возможно. Sublime имеет пользовательский интерфейс, поэтому предпочтительным решением является попросить пользовательский интерфейс закрыть его, а затем ждать, пока он это сделает, как описано в MSDN:

.

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

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

    ПРИМЕЧАНИЕ. Ответ консольного приложения на WM_CLOSE зависит от того, установлен ли он для управления обработчиком.

    Используйте EnumWindows(), чтобы найти ручки в целевых окнах. В своей функции обратного вызова проверьте, совпадает ли идентификатор процесса Windows с процессом, который вы хотите отключить. Вы можете сделать это, вызвав GetWindowThreadProcessId(). После того, как вы установили соответствие, используйте PostMessage() или SendMessageTimeout(), чтобы отправить сообщение WM_CLOSE в окно.

  2. Используйте WaitForSingleObject(), чтобы дождаться дескриптора процесса. Удостоверьтесь, что вы ждали с тайм-аутом, потому что есть много ситуаций, когда WM_CLOSE не будет закрывать приложение. Не забудьте сделать тайм-аут достаточно долго (либо с помощью WaitForSingleObject(), либо с помощью SendMessageTimeout()), чтобы пользователь мог отвечать на любые диалоговые окна, созданные в ответ на сообщение WM_CLOSE.

  3. Если возвращаемое значение WAIT_OBJECT_0, приложение автоматически закрывается. Если возвращаемое значение WAIT_TIMEOUT, вы должны использовать TerminateProcess() для выключения приложения.

    ПРИМЕЧАНИЕ. Если вы получаете возвращаемое значение из WaitForSingleObject() другого, то WAIT_OBJECT_0 или WAIT_TIMEOUT, используйте GetLastError(), чтобы определить причину.

Следуя этим шагам, вы предоставляете приложению наилучшую возможную остановку (кроме IPC или вмешательства пользователя).

С учетом сказанного, попробовать что-то больше, как это:

BOOL CALLBACK SendWMCloseMsg(HWND hwnd, LPARAM lParam) 
{ 
    DWORD dwProcessId = 0; 
    GetWindowThreadProcessId(hwnd, &dwProcessId); 
    if (dwProcessId == lParam) 
     SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_ABORTIFHUNG, 30000, NULL); 
    return TRUE; 
} 

... 

STARTUPINFO   siStartupInfo; 
PROCESS_INFORMATION piProcessInfo; 

memset(&siStartupInfo, 0, sizeof(siStartupInfo)); 
memset(&piProcessInfo, 0, sizeof(piProcessInfo)); 

siStartupInfo.cb = sizeof(siStartupInfo); 

WCHAR szFilename[] = L"C:\\full path to\\source.cpp"; 

if (CreateProcess(L"C:\\Program Files\\Sublime Text 2\\sublime_text.exe",  
    szFileName,     
    NULL, 
    NULL, 
    FALSE, 
    CREATE_DEFAULT_ERROR_MODE, 
    NULL, 
    NULL, 
    &siStartupInfo, 
    &piProcessInfo)) 
{ 
    CloseHandle(piProcessInfo.hThread); 
    WaitForInputIdle(piProcessInfo.hProcess, INFINITE); 

    if (WaitForSingleObject(piProcessInfo.hProcess, SomeTimeoutHere) == WAIT_TIMEOUT) 
    { 
     EnumWindows(&PostWMCloseMsg, piProcessInfo.dwProcessId); 
     if (WaitForSingleObject(piProcessInfo.hProcess, AnotherTimeoutHere) == WAIT_TIMEOUT) 
     { 
      // application did not close in a timely manner, do something... 

      // in this example, just kill it. In a real world 
      // app, you should ask the user what to do... 
      TerminateProcess(piProcessInfo.hProcess, 0); 
     } 
    } 

    CloseHandle(piProcessInfo.hProcess); 
} 
Смежные вопросы