-2

I am building a program that would open Sublime text and after a period of time would close the application itself . I can't figure out how to close the application using the existing code .

This is what I have so far :

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);
VLL
  • 9,634
  • 1
  • 29
  • 54
Seinfeld
  • 680
  • 1
  • 8
  • 13
  • Remove "==FALSE" from line `&piProcessInfo) == FALSE)` - according to [doc](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx) `CreateProcess` returns nonzero if it succeeded (i.e. not FALSE) – mvidelgauz Jun 28 '16 at 16:04
  • And to forcibly close that process use [BOOL WINAPI TerminateProcess(_In_ HANDLE hProcess, _In_ UINT uExitCode);](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx) – mvidelgauz Jun 28 '16 at 16:19
  • http://stackoverflow.com/questions/9428456/how-to-terminate-a-process-created-by-createprocess – theB Jun 28 '16 at 16:32
  • 1
    Why do you need to forcibly terminate the process? Normally, you use `WaitForSingleObject` to wait for the process to exit on its own. For an interactive process, "exit on its own" would really be "the user to exit it." It would be quite user-hostile if I started typing into that Sublime Text window, then you killed the process out from underneath me before I had a chance to save. – Cody Gray - on strike Jun 28 '16 at 16:37
  • @CodyGray the program is sort of time bounded in a sense that I need to kill the application after a certain period of time . Could you help in that direction ? – Seinfeld Jun 28 '16 at 16:41
  • Does this answer your question? [how to terminate a process created by CreateProcess()?](https://stackoverflow.com/questions/9428456/how-to-terminate-a-process-created-by-createprocess) – VLL May 11 '23 at 11:29

1 Answers1

7

First, you are calling WaitForSingleObject() and CloseHandle() if CreateProcess() fails, which is useless. Don't call those functions unless it succeeds instead.

Second, you are calling the Unicode version of CreateProcess(), which has a caveat that your code is not handling. Per the CreateProcess() documentation:

lpCommandLine [in, out, optional]
The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

Third, if you want to terminate the process after a timeout, you could use TerminateProcess(), but that is brute force and should be avoided when possible. Sublime has a UI, so the preferred solution is to ask the UI to close itself down and then wait for it to do so, as documented on MSDN:

How To Terminate an Application "Cleanly" in Win32.

If you absolutely must shut down a process, follow these steps:

  1. Post a WM_CLOSE to all Top-Level windows owned by the process that you want to shut down. Many Windows applications respond to this message by shutting down.

NOTE: A console application's response to WM_CLOSE depends on whether or not it has installed a control handler.

Use EnumWindows() to find the handles to your target windows. In your callback function, check to see if the windows' process ID matches the process you want to shut down. You can do this by calling GetWindowThreadProcessId(). Once you have established a match, use PostMessage() or SendMessageTimeout() to post the WM_CLOSE message to the window.

  1. Use WaitForSingleObject() to wait for the handle of the process. Make sure you wait with a timeout value, because there are many situations in which the WM_CLOSE will not shut down the application. Remember to make the timeout long enough (either with WaitForSingleObject(), or with SendMessageTimeout()) so that a user can respond to any dialog boxes that were created in response to the WM_CLOSE message.

  2. If the return value is WAIT_OBJECT_0, then the application closed itself down cleanly. If the return value is WAIT_TIMEOUT, then you must use TerminateProcess() to shutdown the application.

NOTE: If you are getting a return value from WaitForSingleObject() other then WAIT_OBJECT_0 or WAIT_TIMEOUT, use GetLastError() to determine the cause.

By following these steps, you give the application the best possible chance to shutdown cleanly (aside from IPC or user-intervention).

With that said, try something more like this:

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(&SendWMCloseMsg, 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);
}
VLL
  • 9,634
  • 1
  • 29
  • 54
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770