Skip to content

Commit

Permalink
fix: prevent unnecessary console windows
Browse files Browse the repository at this point in the history
fix #376
  • Loading branch information
geral-victor authored Oct 25, 2023
1 parent a40344e commit 6f8c26b
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 13 deletions.
1 change: 1 addition & 0 deletions source/matplot/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_library(matplot
util/handle_types.h
util/keywords.h
util/popen.h
util/popen.cpp
util/type_traits.h
util/world_cities.cpp
util/world_map_10m.cpp
Expand Down
12 changes: 1 addition & 11 deletions source/matplot/util/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <iostream>
#include <matplot/util/colors.h>
#include <matplot/util/common.h>
#include <matplot/util/popen.h>
#include <random>
#include <regex>
#include <set>
Expand All @@ -25,17 +26,6 @@
#pragma warning(pop)
#endif

#ifdef _WIN32
#include <windows.h>
#define PCLOSE _pclose
#define POPEN _popen
#define FILENO _fileno
#else
#define PCLOSE pclose
#define POPEN popen
#define FILENO fileno
#endif

namespace matplot {
bool iequals(std::string_view str1, std::string_view str2) {
if (str1.size() != str2.size()) {
Expand Down
102 changes: 102 additions & 0 deletions source/matplot/util/popen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <matplot/util/popen.h>

#ifdef _WIN32
#include <io.h>

namespace matplot::detail {
// Function to create a new process and return a FILE pointer for
// input/output. Mimics _popen behaviour, but does not open console windows
// in GUI apps
FILE *hiddenPopen(const char *command, const char *mode) {
SECURITY_ATTRIBUTES saAttr;
HANDLE hChildStdinRd, hChildStdinWr, hStdin, hStdout;
STARTUPINFO si;
PROCESS_INFORMATION pi;

// Set up security attributes for inheritable handles
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;

// Create a pipe for the child process's input
if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
return nullptr;
}

// Ensure the write handle to the pipe is not inherited by child
// processes
if (!SetHandleInformation(hChildStdinWr, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(hChildStdinRd);
return nullptr;
}

// Create a pipe for the child process's output
if (!CreatePipe(&hStdin, &hStdout, &saAttr, 0)) {
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdinWr);
return nullptr;
}

// Ensure the read handle to the output pipe is not inherited by child
// processes
if (!SetHandleInformation(hStdout, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdinWr);
CloseHandle(hStdin);
return nullptr;
}

// Configure STARTUPINFO structure for the new process
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdError = hStdout;
si.hStdOutput = hStdout;
si.hStdInput = hChildStdinRd;
si.dwFlags |= STARTF_USESTDHANDLES;

// Create the child process, while hiding the window
if (!CreateProcess(NULL, const_cast<char *>(command), NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdinWr);
CloseHandle(hStdin);
CloseHandle(hStdout);
return nullptr;
}

// Close unnecessary handles
CloseHandle(hChildStdinRd);
CloseHandle(hStdout);

// Create a FILE pointer from the write handle to the child process's
// input
FILE *file = _fdopen(_open_osfhandle((intptr_t)hChildStdinWr, 0), mode);

if (file == nullptr) {
CloseHandle(hChildStdinWr);
CloseHandle(hStdin);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return nullptr;
}

return file;
}

// Function to close the process and retrieve its exit code
int hiddenPclose(FILE *file) {
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
fclose(file);
DWORD exitCode;

// Wait for the process to finish and get its exit code
if (WaitForSingleObject(hFile, INFINITE) == WAIT_OBJECT_0 &&
GetExitCodeProcess(hFile, &exitCode)) {
CloseHandle(hFile);
return exitCode;
} else {
return -1; // Failed to get the exit code
}
}
} // namespace matplot::detail
#endif // _WIN32
14 changes: 12 additions & 2 deletions source/matplot/util/popen.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
#define MATPLOTPLUSPLUS_POPEN_H

#ifdef _WIN32
#include <stdio.h> //needed for FILE type
#include <windows.h>
#define PCLOSE _pclose
#define POPEN _popen

namespace matplot::detail {
// in a GUI application, _popen pops up a window. This version does not.
FILE *hiddenPopen(const char *command, const char *mode);

// close the handle opened by hiddenPopen
int hiddenPclose(FILE *file);
} // namespace matplot::detail

#define PCLOSE ::matplot::detail::hiddenPclose
#define POPEN ::matplot::detail::hiddenPopen
#define FILENO _fileno
#else
#define PCLOSE pclose
Expand Down

0 comments on commit 6f8c26b

Please sign in to comment.