PipedProcess 2.1.3
dotnet add package PipedProcess --version 2.1.3
NuGet\Install-Package PipedProcess -Version 2.1.3
<PackageReference Include="PipedProcess" Version="2.1.3" />
<PackageVersion Include="PipedProcess" Version="2.1.3" />
<PackageReference Include="PipedProcess" />
paket add PipedProcess --version 2.1.3
#r "nuget: PipedProcess, 2.1.3"
#:package PipedProcess@2.1.3
#addin nuget:?package=PipedProcess&version=2.1.3
#tool nuget:?package=PipedProcess&version=2.1.3
PipedProcess
C++ helper class to create a child process with redirected std in/out/error streams using the Windows API.
What it does
It can be used to pass arbitrary binary input data to the child process via stdin and retrieve the result data via stdout. Errors can be received via stderr.
What it does not
Currently the class can not be used for asynchronous communication (e.g. messages) to and from the child process.
Public Interface
The PipedProcess class provides a simple, exception-free public API that returns error codes for all operations.
Core Methods
// Basic execution
DWORD Run(const char* program, const char* arguments);
// Execution with abort capability
template<class T>
DWORD Run(const char* program, const char* arguments, T& abortEvent);
// Execution with user token (run as different user)
DWORD RunAs(const HANDLE& token, const char* program, const char* arguments);
template<class T>
DWORD RunAs(const HANDLE& token, const char* program, const char* arguments, T& abortEvent);
Input/Output Methods
// Set data to send to child process stdin
void SetStdInData(const char* pData, size_t len);
// Check if output data is available
bool HasStdOutData() const;
bool HasStdErrData() const;
// Retrieve output data (moves data out of internal buffers)
std::string FetchStdOutData();
std::string FetchStdErrData();
Configuration
// Control child process window visibility
enum class WindowMode { Visible = 0, Hidden = 1 };
void SetWindowMode(WindowMode mode); // Default is Hidden
Return Values
All Run methods return DWORD error codes:
0= Success (child process completed successfully)ERROR_INVALID_PARAMETER= Null parameters providedERROR_FILE_NOT_FOUND= Program executable not foundERROR_PATH_NOT_FOUND= Empty program path- Other Windows error codes for various failure conditions
Error details are available via FetchStdErrData() when errors occur.
Usage Examples
Basic Usage
#include "PipedProcess/PipedProcess.h"
// Simple command execution
PipedProcess process;
DWORD exitCode = process.Run("cmd.exe", "/c echo Hello World");
if (exitCode == 0 && process.HasStdOutData()) {
std::string output = process.FetchStdOutData();
std::cout << "Output: " << output << std::endl;
}
Sending Input Data
// Execute a program that reads from stdin
PipedProcess process;
std::string input = "Hello from parent process\n";
process.SetStdInData(input.c_str(), input.length());
DWORD exitCode = process.Run("sort.exe", "");
if (exitCode == 0) {
std::string output = process.FetchStdOutData();
std::cout << "Sorted output: " << output << std::endl;
}
Error Handling
PipedProcess process;
DWORD exitCode = process.Run("nonexistent.exe", "");
if (exitCode != 0) {
std::cout << "Process failed with exit code: " << exitCode << std::endl;
if (process.HasStdErrData()) {
std::string errorMsg = process.FetchStdErrData();
std::cout << "Error details: " << errorMsg << std::endl;
}
}
Using Abort Events
// Custom abort event
struct MyAbortEvent {
std::atomic<bool> shouldAbort{false};
bool IsSet() const { return shouldAbort.load(); }
void Set() { shouldAbort = true; }
};
PipedProcess process;
MyAbortEvent abortEvent;
// Start long-running process in another thread
auto future = std::async(std::launch::async, [&]() {
return process.Run("long-running-program.exe", "", abortEvent);
});
// Later, signal abort if needed
abortEvent.Set();
DWORD exitCode = future.get();
Hidden vs Visible Windows
PipedProcess process;
// Show the child process window (useful for debugging)
process.SetWindowMode(PipedProcess::WindowMode::Visible);
// Or keep it hidden (default behavior)
process.SetWindowMode(PipedProcess::WindowMode::Hidden);
DWORD exitCode = process.Run("notepad.exe", "test.txt");
Security Considerations
Important: This library does not validate input parameters. It is the caller's responsibility to ensure:
- Program paths are trusted and do not contain malicious executable paths
- Arguments do not contain command injection vectors (e.g.,
|,&,;,>,<when used with shell commands) - Input data size is reasonable to prevent memory exhaustion
- Program execution is limited to trusted executables in secure environments
For applications handling untrusted input, implement validation before calling PipedProcess methods.
MIT License
Feel free to use. See LICENSE file for further information.
How to build
The project is a Visual Studio 2022 solution. It should be possible to build it with other compilers, but I have not tested it.
Creating NuGet Package
Prerequisites
- NuGet CLI or dotnet CLI
- Visual Studio 2022 (for building)
Package Creation Steps
Build the solution to ensure all tests pass:
msbuild PipedProcess.sln -p:Configuration=Release -p:Platform=x64Create the NuGet package using the modern nuspec file:
nuget pack PipedProcess.nuspecOr with dotnet CLI:
dotnet pack PipedProcess.nuspecPublish to NuGet.org (optional):
nuget push PipedProcess.{version}.nupkg -Source https://api.nuget.org/v3/index.json -ApiKey {your-api-key}
Package Contents
The NuGet package includes:
- Headers:
PipedProcess.h,StdPipe.h,UniqueHandle.hininclude/PipedProcess/directory - MSBuild targets: Automatic include path configuration and preprocessor definitions
- Documentation: Inline comments and usage examples
Using the Package
After installing the package in a project, simply include the headers:
#include <PipedProcess/PipedProcess.h>
#include <PipedProcess/StdPipe.h>
The MSBuild targets automatically configure include paths and preprocessor definitions.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| native | native is compatible. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.1.3: Major robustness and reliability improvements:
Enhanced StdPipe Write Operations:
- Robust partial write handling for large data chunks (supports multi-GB transfers)
- Automatic retry logic for incomplete writes with proper progress tracking
- Fixed edge cases in Write() method preventing data loss
Security and Safety Enhancements:
- Added comprehensive null pointer validation with ERROR_INVALID_PARAMETER returns
- Enhanced RAII handle management with UniqueHandle wrapper preventing resource leaks
- Added input validation and security documentation for safe API usage
Performance and Maintainability:
- Simplified argument handling from std::vector to std::string (reduced complexity)
- Fixed incorrect std::move usage in Read() method improving performance
- Added defensive programming patterns with early returns for edge cases
Testing Excellence:
- Comprehensive test suite with 49 test cases and 136 assertions
- Added stress testing with 1MB data transfers validating partial write robustness
- Enhanced binary data handling and multithreaded access testing
- Migrated to modern doctest framework with superior error reporting
All improvements maintain full backward compatibility while significantly improving reliability and performance.