diff options
Diffstat (limited to 'include/winapi')
-rw-r--r-- | include/winapi/buffer.hpp | 14 | ||||
-rw-r--r-- | include/winapi/cmd_line.hpp | 60 | ||||
-rw-r--r-- | include/winapi/error.hpp | 10 | ||||
-rw-r--r-- | include/winapi/file.hpp | 22 | ||||
-rw-r--r-- | include/winapi/handle.hpp | 32 | ||||
-rw-r--r-- | include/winapi/path.hpp | 2 | ||||
-rw-r--r-- | include/winapi/pipe.hpp | 6 | ||||
-rw-r--r-- | include/winapi/process.hpp | 34 | ||||
-rw-r--r-- | include/winapi/process_io.hpp | 16 | ||||
-rw-r--r-- | include/winapi/resource.hpp | 2 | ||||
-rw-r--r-- | include/winapi/shmem.hpp | 24 |
11 files changed, 218 insertions, 4 deletions
diff --git a/include/winapi/buffer.hpp b/include/winapi/buffer.hpp index 4d47930..10ff479 100644 --- a/include/winapi/buffer.hpp +++ b/include/winapi/buffer.hpp @@ -16,33 +16,45 @@ namespace winapi { +/** + * @brief Binary data container. + * + * This class wraps a blob of binary data. + */ class Buffer : public std::vector<unsigned char> { public: typedef std::vector<unsigned char> Parent; Buffer() = default; + /** Construct a buffer from an explicit list of byte values. */ Buffer(std::initializer_list<unsigned char> lst) : Parent{lst} {} + /** Construct a buffer from an instance of `std::vector<unsigned char>`. */ explicit Buffer(Parent&& src) : Parent{std::move(src)} {} + /** Construct a buffer from an instance of `std::basic_string`. */ template <typename CharT> explicit Buffer(const std::basic_string<CharT>& src) { set(src); } + /** Construct a buffer from a memory region. */ Buffer(const void* src, std::size_t nb) { set(src, nb); } + /** Replace the buffer's contents with the data from `std::basic_string`. */ template <typename CharT> void set(const std::basic_string<CharT>& src) { set(src.c_str(), src.length() * sizeof(std::basic_string<CharT>::char_type)); } + /** Replace the buffer's contents with the data from a memory region. */ void set(const void* src, std::size_t nb) { resize(nb); std::memcpy(data(), src, nb); } + /** Interpret the buffer's contents as a `std::string`. */ std::string as_utf8() const { const auto c_str = reinterpret_cast<const char*>(data()); const auto nb = size(); @@ -50,6 +62,7 @@ public: return {c_str, nch}; } + /** Interpret the buffer's contents as a `std::wstring`. */ std::wstring as_utf16() const { const auto c_str = reinterpret_cast<const wchar_t*>(data()); const auto nb = size(); @@ -62,6 +75,7 @@ public: return {c_str, nch}; } + /** Append another buffer to the end of this one. */ void add(const Buffer& src) { const auto nb = size(); resize(nb + src.size()); diff --git a/include/winapi/cmd_line.hpp b/include/winapi/cmd_line.hpp index 8735660..d1a4a7e 100644 --- a/include/winapi/cmd_line.hpp +++ b/include/winapi/cmd_line.hpp @@ -11,38 +11,94 @@ namespace winapi { +/** + * @brief Command line for the current process or for launching new processes. + * + * This class takes care of proper parsing and stringifying command line + * arguments so that they are safe to use with CreateProcess, ShellExecute, + * etc. + */ class CommandLine { public: + /** Get the command line used to launch this process. */ static CommandLine query(); - static CommandLine parse(const std::string&); - + /** + * Parse a command line from a string. + * @param src UTF-8 encoded string. + */ + static CommandLine parse(const std::string& src); + + /** + * Build a command line from main() arguments. + * @param argc Length of the argv array. + * @param argv UTF-16 encoded strings. + */ static CommandLine from_main(int argc, wchar_t* argv[]); + /** + * Build an empty command line. + * It won't have neither argv[0], nor any other args. + */ CommandLine() = default; + /** + * Build a command line. + * @param argv0 UTF-8 string, argv[0]. + * @param args List of UTF-8 strings, other arguments. + */ explicit CommandLine(const std::string& argv0, const std::vector<std::string>& args = {}) : m_argv0{argv0}, m_args{args} {} + /** + * Build a command line. + * @param argv0 UTF-8 string, argv[0]. + * @param args List of UTF-8 strings, other arguments. + */ explicit CommandLine(std::string&& argv0, std::vector<std::string>&& args = {}) : m_argv0{std::move(argv0)}, m_args{std::move(args)} {} + /** + * Build a command line. + * @param argv List of UTF-8 strings, including argv[0]. + */ explicit CommandLine(std::vector<std::string> argv); static std::string escape(const std::string&); static std::string escape_cmd(const std::string&); + /** + * Build a string that represents this command line. + * @return UTF-8 string. + */ std::string to_string() const; + /** + * Build a string that represents this command line, but omit argv[0]. + * @return UTF-8 string. + */ std::string args_to_string() const; + /** + * Get argv[0] for this command line. + * @return UTF-8 string. + */ std::string get_argv0() const { return m_argv0; } + /** Test if this command line has any additional arguments besides argv[0]. */ bool has_args() const { return !get_args().empty(); } + /** + * Get list of arguments for this command line beyond argv[0]. + * @return List of UTF-8 strings. + */ const std::vector<std::string>& get_args() const { return m_args; } + /** + * Get list of arguments for this command line. + * @return List of UTF-8 strings. + */ std::vector<std::string> get_argv() const; private: diff --git a/include/winapi/error.hpp b/include/winapi/error.hpp index 8ecd720..35e10f0 100644 --- a/include/winapi/error.hpp +++ b/include/winapi/error.hpp @@ -3,6 +3,11 @@ // For details, see https://github.com/egor-tensin/winapi-common. // Distributed under the MIT License. +/** + * @file + * @brief Make `std::system_error` work with `GetLastError()`. + */ + #pragma once #include <windows.h> @@ -30,6 +35,11 @@ inline const CategoryWindows& category_windows() { return instance; } +/** + * Build a `std::system_error` from the value of `GetLastError()`. + * @param code Value of `GetLastError()`. + * @param function Name of the function that failed, like "CreateFile". + */ std::system_error windows(DWORD code, const char* function); template <typename Ret> diff --git a/include/winapi/file.hpp b/include/winapi/file.hpp index 7d0126c..b1c8ce3 100644 --- a/include/winapi/file.hpp +++ b/include/winapi/file.hpp @@ -21,6 +21,11 @@ namespace winapi { bool operator==(const FILE_ID_128& a, const FILE_ID_128& b); +/** + * @brief File I/O. + * + * Easily open, read & write files. + */ class File : public Handle { public: struct ID { @@ -32,20 +37,37 @@ public: } }; + /** Open file for reading. */ static File open_r(const std::string&); + /** @overload */ static File open_r(const CanonicalPath&); + /** Open file for reading (inc. ability to read its attributes). */ static File open_read_attributes(const std::string&); + /** @overload */ static File open_read_attributes(const CanonicalPath&); + /** Open file for writing. */ static File open_w(const std::string&); + /** @overload */ static File open_w(const CanonicalPath&); + /** Delete a file. */ static void remove(const std::string&); + /** @overload */ static void remove(const CanonicalPath&); + /** Make a File instance from an open handle. */ explicit File(Handle&& handle) : Handle{std::move(handle)} {} + /** + * Get file size. + * @return File size, bytes. + */ std::size_t get_size() const; + /** + * Get file ID. + * File ID is a unique representation of a file, suitable for hashing. + */ ID query_id() const; }; diff --git a/include/winapi/handle.hpp b/include/winapi/handle.hpp index 8ea90aa..b5a7547 100644 --- a/include/winapi/handle.hpp +++ b/include/winapi/handle.hpp @@ -16,6 +16,12 @@ namespace winapi { +/** + * @brief HANDLE wrapper. + * + * This class wraps HANDLE, allowing for painless reads and writes from a + * random handle. + */ class Handle { public: Handle() = default; @@ -29,21 +35,45 @@ public: bool is_valid() const; static bool is_valid(HANDLE); + /** Close this handle. */ void close(); + /** Check if this is a standard console handle. */ bool is_std() const; + /** Check if this is the stdin handle. */ static Handle std_in(); + /** Check if this is the stdout handle. */ static Handle std_out(); + /** Check if this is the stderr handle. */ static Handle std_err(); + /** Read everything from this handle. */ Buffer read() const; static constexpr std::size_t max_chunk_size = 16 * 1024; + /** + * Read a chunk from this handle. + * @param read_chunk Receives the data read. + * @return `true` if there's more data, `false` otherwise. + */ bool read_chunk(Buffer& read_chunk) const; - void write(const void*, std::size_t nb) const; + /** + * Write data to this handle. + * @param data Pointer to binary data. + * @param nb Data size. + */ + void write(const void* data, std::size_t nb) const; + /** + * Write data to this handle. + * @param buffer Binary data to write. + */ void write(const Buffer& buffer) const; + /** + * Write data to this handle. + * @param src Binary data to write. + */ template <typename CharT> void write(const std::basic_string<CharT>& src) const { write(src.c_str(), src.size() * sizeof(CharT)); diff --git a/include/winapi/path.hpp b/include/winapi/path.hpp index f2b0aa9..26d89ce 100644 --- a/include/winapi/path.hpp +++ b/include/winapi/path.hpp @@ -9,8 +9,10 @@ namespace winapi { +/** @brief Absolute, canonical path. */ class CanonicalPath { public: + /** Make an absolute, canonical path. */ static std::string canonicalize(const std::string&); explicit CanonicalPath(const std::string&); diff --git a/include/winapi/pipe.hpp b/include/winapi/pipe.hpp index aec87cd..e4f8624 100644 --- a/include/winapi/pipe.hpp +++ b/include/winapi/pipe.hpp @@ -11,13 +11,19 @@ namespace winapi { +/** @brief Anonymous pipe wrapper. */ class Pipe { public: + /** Create a new pipe. */ Pipe(); + /** Get the read end of the pipe. */ Handle& read_end() { return m_read_end; } + /** @overload */ const Handle& read_end() const { return m_read_end; } + /** Get the write end of the pipe. */ Handle& write_end() { return m_write_end; } + /** @overload */ const Handle& write_end() const { return m_write_end; } private: diff --git a/include/winapi/process.hpp b/include/winapi/process.hpp index d5a4ed5..92d9da5 100644 --- a/include/winapi/process.hpp +++ b/include/winapi/process.hpp @@ -20,6 +20,7 @@ namespace winapi { +/** @brief Process parameters for Process::create(). */ struct ProcessParameters { enum ConsoleCreationMode { ConsoleNone, @@ -34,6 +35,7 @@ struct ProcessParameters { ConsoleCreationMode console_mode = ConsoleNew; }; +/** @brief Process parameters for Process::shell(). */ struct ShellParameters : ProcessParameters { static ShellParameters runas(const CommandLine& cmd_line) { ShellParameters params{cmd_line}; @@ -46,36 +48,66 @@ struct ShellParameters : ProcessParameters { boost::optional<std::string> verb; }; +/** + * @brief Create a new process or open an existing process. + */ class Process { public: using ID = DWORD; + /** Create a new process using ProcessParameters. */ static Process create(ProcessParameters); + /** Create a new process using the given command line. */ static Process create(const CommandLine&); + /** Create a new process using the given command line and IO settings. */ static Process create(const CommandLine&, process::IO); + /** Create a new shell process using ShellParameters. */ static Process shell(const ShellParameters&); + /** Create a new shell process using the given command line. */ static Process shell(const CommandLine&); + /** Open the current process. */ static Process current(); - static Process open(ID, DWORD permissions = default_permissions()); + /** + * Open an existing process. + * @param id Process ID. + * @param permissions Required permissions. + */ + static Process open(ID id, DWORD permissions = default_permissions()); + /** Open an existing process with read permissions. */ static Process open_r(ID); + /** Permissions that allow to query process's status. */ static DWORD default_permissions(); + /** Permissions that allows to read process's memory. */ static DWORD read_permissions(); + /** Get this process's ID. */ ID get_id() const { return m_id; } + /** Get this process's handle. */ const Handle& get_handle() const { return m_handle; } + /** Check if this process is running (i.e. not terminated). */ bool is_running() const; + /** Wait for the process to terminate. */ void wait() const; + /** Make this process terminate with an exit code. */ void terminate(int ec = 0) const; + /** Same as calling terminate() and wait(). */ void shut_down(int ec = 0) const; + /** Get terminated process's exit code. */ int get_exit_code() const; + /** Get this process's executable path. */ std::string get_exe_path() const; + /** Get a binary resource from the process's executable. */ static Resource get_resource(uint32_t id); + /** + * Get a string resource from the process's executable. + * @return UTF-8 string. + */ static std::string get_resource_string(uint32_t id); private: diff --git a/include/winapi/process_io.hpp b/include/winapi/process_io.hpp index 805ada8..9df145c 100644 --- a/include/winapi/process_io.hpp +++ b/include/winapi/process_io.hpp @@ -21,27 +21,43 @@ struct Stream { Handle handle; }; +/** @brief Redirect child process's stdin. */ struct Stdin : Stream { + /** No redirection. */ Stdin(); + /** Make child process read form a file. */ explicit Stdin(const std::string& file); + /** @overload */ explicit Stdin(const CanonicalPath& file); + /** Make child process read form a pipe. */ explicit Stdin(Pipe&); }; +/** @brief Redirect child process's stdout. */ struct Stdout : Stream { + /** No redirection. */ Stdout(); + /** Redirect child process's stdout to a file. */ explicit Stdout(const std::string& file); + /** @overload */ explicit Stdout(const CanonicalPath& file); + /** Redirect child process's stdout to a pipe. */ explicit Stdout(Pipe&); }; +/** @brief Redirect child process's stderr. */ struct Stderr : Stream { + /** No redirection. */ Stderr(); + /** Redirect child process's stderr to a file. */ explicit Stderr(const std::string& file); + /** @overload */ explicit Stderr(const CanonicalPath& file); + /** Redirect child process's stderr to a pipe. */ explicit Stderr(Pipe&); }; +/** @brief Child process IO settings. */ struct IO { IO() = default; diff --git a/include/winapi/resource.hpp b/include/winapi/resource.hpp index 2f77d3e..8b6e41b 100644 --- a/include/winapi/resource.hpp +++ b/include/winapi/resource.hpp @@ -11,6 +11,7 @@ namespace winapi { +/** @brief Resources embedded in a PE (Portable Executable). */ struct Resource { // This is just a pointer to static data. @@ -18,6 +19,7 @@ struct Resource { Resource(const void* data, std::size_t nb) : data{data}, nb{nb} {} + /** Extract resource data into a Buffer instance. */ Buffer copy() const { return {data, nb}; } const void* data = nullptr; diff --git a/include/winapi/shmem.hpp b/include/winapi/shmem.hpp index 4fc5ac7..d1ad997 100644 --- a/include/winapi/shmem.hpp +++ b/include/winapi/shmem.hpp @@ -15,12 +15,24 @@ namespace winapi { +/** @brief Named shared memory region. */ class SharedMemory { public: + /** + * Creates a shared memory region. + * @param name UTF-8 string. + * @param nb Number of bytes. + */ static SharedMemory create(const std::string& name, std::size_t nb); + /** + * Opens a shared memory region. + * @param name UTF-8 string. + */ static SharedMemory open(const std::string& name); + /** Get pointer to the data. */ void* get() const { return m_addr.get(); } + /** @overload */ void* ptr() const { return get(); } private: @@ -36,11 +48,17 @@ private: std::unique_ptr<void, Unmap> m_addr; }; +/** @brief Easy way to represent a C++ object as a shared memory region. */ template <typename T> class SharedObject { public: typedef typename std::aligned_storage<sizeof(T), __alignof(T)>::type AlignedType; + /** + * Create the object & construct a shared memory region to store it. + * @param name UTF-8 string, name of the shared memory region. + * @param args Arguments to construct the object. + */ template <typename... Args> static SharedObject create(const std::string& name, Args&&... args) { SharedObject obj{SharedMemory::create(name, sizeof(AlignedType))}; @@ -49,6 +67,10 @@ public: return obj; } + /** + * Open a shared memory region that stores the object. + * @param name UTF-8 string, name of the shared memory region. + */ static SharedObject open(const std::string& name) { SharedObject obj{SharedMemory::open(name)}; return obj; @@ -64,7 +86,9 @@ public: } } + /** Get pointer to the object. */ T* ptr() const { return reinterpret_cast<T*>(m_shmem.ptr()); } + /** Get reference to the object. */ T& get() const { return *ptr(); } T* operator->() const { return ptr(); } |