Skip to content

Commit ad47657

Browse files
authored
Fix(windows): Resolve header conflicts and update tests (#123)
* Refactor: Isolate WinAPI declarations. This commit replaces the direct inclusion of `<windows.h>` with a minimal set of manual forward declarations. This is a deliberate architectural change to: - **Improve Compilation Speed:** Avoids parsing the notoriously large Windows header. - **Eliminate Naming Pollution:** Prevents name clashes with common names like `min`/`max` which conflict with the C++ standard library. - **Enhance Encapsulation:** Makes the library more self-contained by not exposing the entire Windows API. * fix(windows): Resolve header conflicts and update tests Previously, including both `subprocess.hpp` and `<Windows.h>` in the same file would cause compilation errors due to redefinitions of Windows API types and functions. This commit resolves these conflicts by wrapping the manual API declarations in `subprocess.hpp` with an `#ifndef _WINDEF_` guard. This ensures the library's lightweight declarations are only used if the official Windows headers haven't been included, making it safe to use both. The `test_ret_code.cc` unit test has been updated to include `<Windows.h>` directly for the `Sleep` function, which also serves to validate this fix. * fix(windows): Add platform-specific include for Windows.h Wraps the Windows.h include in a platform guard to prevent breaking non-Windows builds.
1 parent 60d4ad8 commit ad47657

2 files changed

Lines changed: 55 additions & 28 deletions

File tree

cpp-subprocess/subprocess.hpp

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ extern "C" {
7474

7575
#ifdef __USING_WINDOWS__
7676

77+
#ifndef _WINDEF_
78+
7779
#define CONST const
7880
#define WINAPI __stdcall
7981

@@ -133,20 +135,24 @@ extern "C" {
133135
typedef WCHAR* LPWSTR;
134136
typedef CONST WCHAR* LPCWSTR;
135137

136-
typedef struct _SECURITY_ATTRIBUTES {
138+
typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES, * LPSECURITY_ATTRIBUTES;
139+
typedef struct _PROCESS_INFORMATION PROCESS_INFORMATION, * LPPROCESS_INFORMATION;
140+
typedef struct _STARTUPINFOW STARTUPINFOW, * LPSTARTUPINFOW;
141+
142+
typedef struct _SP_SECURITY_ATTRIBUTES {
137143
DWORD nLength;
138144
LPVOID lpSecurityDescriptor;
139145
BOOL bInheritHandle;
140-
} SECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
146+
} SP_SECURITY_ATTRIBUTES, * SP_LPSECURITY_ATTRIBUTES;
141147

142-
typedef struct _PROCESS_INFORMATION {
148+
typedef struct _SP_PROCESS_INFORMATION {
143149
HANDLE hProcess;
144150
HANDLE hThread;
145151
DWORD dwProcessId;
146152
DWORD dwThreadId;
147-
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
153+
} SP_PROCESS_INFORMATION, * SP_LPPROCESS_INFORMATION;
148154

149-
typedef struct _STARTUPINFOW {
155+
typedef struct _SP_STARTUPINFOW {
150156
DWORD cb;
151157
LPWSTR lpReserved;
152158
LPWSTR lpDesktop;
@@ -165,24 +171,32 @@ extern "C" {
165171
HANDLE hStdInput;
166172
HANDLE hStdOutput;
167173
HANDLE hStdError;
168-
} STARTUPINFOW, * LPSTARTUPINFOW;
174+
} SP_STARTUPINFOW, * SP_LPSTARTUPINFOW;
169175

170-
BOOL WINAPI CloseHandle(HANDLE);
171-
BOOL WINAPI CreatePipe(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD);
172-
BOOL WINAPI CreateProcessW(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
173-
BOOL WINAPI FreeEnvironmentStringsW(LPWCH);
174-
BOOL WINAPI GetExitCodeProcess(HANDLE, LPDWORD);
175-
BOOL WINAPI SetHandleInformation(HANDLE, DWORD, DWORD);
176-
BOOL WINAPI TerminateProcess(HANDLE, UINT);
177-
DWORD WINAPI FormatMessageA(DWORD, LPCVOID, DWORD, DWORD, LPSTR, DWORD, va_list*);
178-
DWORD WINAPI GetLastError(VOID);
179-
DWORD WINAPI WaitForSingleObject(HANDLE, DWORD);
180-
HLOCAL WINAPI LocalFree(HLOCAL);
181-
LPWSTR WINAPI GetEnvironmentStringsW(VOID);
176+
__declspec(dllimport) BOOL WINAPI CloseHandle(HANDLE);
177+
__declspec(dllimport) BOOL WINAPI CreatePipe(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD);
178+
__declspec(dllimport) BOOL WINAPI CreateProcessW(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
179+
__declspec(dllimport) BOOL WINAPI FreeEnvironmentStringsW(LPWCH);
180+
__declspec(dllimport) BOOL WINAPI GetExitCodeProcess(HANDLE, LPDWORD);
181+
__declspec(dllimport) BOOL WINAPI SetHandleInformation(HANDLE, DWORD, DWORD);
182+
__declspec(dllimport) BOOL WINAPI TerminateProcess(HANDLE, UINT);
183+
__declspec(dllimport) DWORD WINAPI FormatMessageA(DWORD, LPCVOID, DWORD, DWORD, LPSTR, DWORD, va_list*);
184+
__declspec(dllimport) DWORD WINAPI GetLastError(VOID);
185+
__declspec(dllimport) DWORD WINAPI WaitForSingleObject(HANDLE, DWORD);
186+
__declspec(dllimport) HLOCAL WINAPI LocalFree(HLOCAL);
187+
__declspec(dllimport) LPWSTR WINAPI GetEnvironmentStringsW(VOID);
182188

183189
#define ZeroMemory(Destination,Length) memset((Destination),0,(Length))
184190
#define MAKELANGID(p, s) ((((WORD)(s)) << 10) | (WORD)(p))
185191

192+
#else
193+
194+
#define SP_SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES
195+
#define SP_PROCESS_INFORMATION PROCESS_INFORMATION
196+
#define SP_STARTUPINFOW STARTUPINFOW
197+
198+
#endif
199+
186200
#include <io.h>
187201
#include <cwchar>
188202
#else
@@ -417,15 +431,15 @@ namespace util
417431

418432
inline void configure_pipe(HANDLE* read_handle, HANDLE* write_handle, HANDLE* child_handle)
419433
{
420-
SECURITY_ATTRIBUTES saAttr;
434+
SP_SECURITY_ATTRIBUTES saAttr;
421435

422436
// Set the bInheritHandle flag so pipe handles are inherited.
423-
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
437+
saAttr.nLength = sizeof(SP_SECURITY_ATTRIBUTES);
424438
saAttr.bInheritHandle = TRUE;
425439
saAttr.lpSecurityDescriptor = NULL;
426440

427441
// Create a pipe for the child process's STDIN.
428-
if (!CreatePipe(read_handle, write_handle, &saAttr,0))
442+
if (!CreatePipe(read_handle, write_handle, reinterpret_cast<LPSECURITY_ATTRIBUTES>(&saAttr), 0))
429443
throw OSError("CreatePipe", 0);
430444

431445
// Ensure the write handle to the pipe for STDIN is not inherited.
@@ -1677,19 +1691,19 @@ inline void Popen::execute_process() noexcept(false)
16771691
// CreateProcessW can modify szCmdLine so we allocate needed memory
16781692
wchar_t *szCmdline = new wchar_t[command_line.size() + 1];
16791693
wcscpy_s(szCmdline, command_line.size() + 1, command_line.c_str());
1680-
PROCESS_INFORMATION piProcInfo;
1681-
STARTUPINFOW siStartInfo;
1694+
SP_PROCESS_INFORMATION piProcInfo;
1695+
SP_STARTUPINFOW siStartInfo;
16821696
BOOL bSuccess = FALSE;
16831697
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
16841698

16851699
// Set up members of the PROCESS_INFORMATION structure.
1686-
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
1700+
ZeroMemory(&piProcInfo, sizeof(SP_PROCESS_INFORMATION));
16871701

16881702
// Set up members of the STARTUPINFOW structure.
16891703
// This structure specifies the STDIN and STDOUT handles for redirection.
16901704

1691-
ZeroMemory(&siStartInfo, sizeof(STARTUPINFOW));
1692-
siStartInfo.cb = sizeof(STARTUPINFOW);
1705+
ZeroMemory(&siStartInfo, sizeof(SP_STARTUPINFOW));
1706+
siStartInfo.cb = sizeof(SP_STARTUPINFOW);
16931707

16941708
siStartInfo.hStdError = this->stream_.g_hChildStd_ERR_Wr;
16951709
siStartInfo.hStdOutput = this->stream_.g_hChildStd_OUT_Wr;
@@ -1708,8 +1722,8 @@ inline void Popen::execute_process() noexcept(false)
17081722
creation_flags, // creation flags
17091723
environment_string_table_ptr, // use provided environment
17101724
cwd_arg, // use provided current directory
1711-
&siStartInfo, // STARTUPINFOW pointer
1712-
&piProcInfo); // receives PROCESS_INFORMATION
1725+
reinterpret_cast<LPSTARTUPINFOW>(&siStartInfo), // STARTUPINFOW pointer
1726+
reinterpret_cast<LPPROCESS_INFORMATION>(&piProcInfo)); // receives PROCESS_INFORMATION
17131727

17141728
// If an error occurs, exit the application.
17151729
if (!bSuccess) {
@@ -2263,4 +2277,13 @@ OutBuffer pipeline(Args&&... args)
22632277

22642278
}
22652279

2280+
#ifdef __USING_WINDOWS__
2281+
#ifndef _WINDEF_
2282+
#undef ZeroMemory
2283+
#undef MAKELANGID
2284+
#undef STATUS_WAIT_0
2285+
#undef WAIT_OBJECT_0
2286+
#endif
2287+
#endif
2288+
22662289
#endif // SUBPROCESS_HPP

test/test_ret_code.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#include <iostream>
22
#include <cpp-subprocess/subprocess.hpp>
33

4+
#ifdef __USING_WINDOWS__
5+
#include <Windows.h>
6+
#endif
7+
48
namespace sp = subprocess;
59

610
void test_ret_code()

0 commit comments

Comments
 (0)