As part of my automated test suite, I have a C++ Program (A) that executes a command line Process (B) using CreateProcess()
.
The process only terminates when it receives a SIGINT signal (for reasons outside of my control).
I can terminate the process (B) from (A) using CloseHandle()
and/or TerminateProcess()
, however, this does not call the destructor of (B), preventing it from closing gracefully (writing stuff to disk and closing DB connections) and causing the tests to fail.
What is the best approach to gracefully close (B), allowing it clean up after itself? Should I be using a helper executable with IPC, a remote thread...?
I have tried the solutions in these SA questions:
- Can I send a ctrl-C (SIGINT) to an application on Windows? (If I detach my console the test suite fails)
- How do I send ctrl+c to a process in c#? (Modified for C+)
- How to get GenerateConsoleCtrlEvent to work with cmd.exe
Edit: @Remy Lebeau is right I should have posted some code:
Current Approach:
Close the process handle. This kills the process immediately.
PROCESS_INFORMATION process_info;
... // CreateProcess()
CloseHandle(process.hProcess);
CloseHandle(process.hThread);
Approach 2:
Detach the current console and then re-attach. This causes the initial test suite to fail.
PROCESS_INFORMATION process_info;
... // CreateProcess
DWORD thisConsoleId = GetCurrentProcessId();
bool consoleDetached = (FreeConsole() != FALSE);
if (AttachConsole(process_info.dwProcessId)) {
std::cout << "Attached process to console" << std::endl;
SetConsoleCtrlHandler(NULL, true);
if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
std::cout << "Ctrl-c sent to process" << std::endl;
} else {
std::cout << "Could not send ctrl-c (" << GetLastError() << ")" << std::endl;
}
FreeConsole();
} else {
std::cout << "Unable to attach process to console (" << GetLastError() << ")" << std::endl;
}
if (consoleDetached) {
// Create a new console if previous was deleted by OS
if (AttachConsole(thisConsoleId)) {
int errorCode = GetLastError();
// 31=ERROR_GEN_FAILURE
if (errorCode == 31) {
AllocConsole();
}
}
}
Approach 3:
Attach to console without freeing. This kills everything including the test suite.
PROCESS_INFORMATION process_info;
... // CreateProcess
AttachConsole(process_info.dwProcessId);
SetConsoleCtrlHandler(NULL, TRUE);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);