From e3a1195c041d8bc4c553fe720793241fa91cbc16 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Fri, 26 Jun 2026 14:59:14 +0800 Subject: [PATCH] doc: add the doc for c++ binding according to c binding --- wfassoc-cdylib/cbindgen/wfassoc++.h | 409 +++++++++++++++++++++++++++- wfassoc-cdylib/cbindgen/wfassoc.h | 6 + 2 files changed, 412 insertions(+), 3 deletions(-) diff --git a/wfassoc-cdylib/cbindgen/wfassoc++.h b/wfassoc-cdylib/cbindgen/wfassoc++.h index ac468b2..cbdc4ff 100644 --- a/wfassoc-cdylib/cbindgen/wfassoc++.h +++ b/wfassoc-cdylib/cbindgen/wfassoc++.h @@ -17,40 +17,108 @@ #include #include +/** + * @brief Windows File Association C++ API namespace + * + * Provides C++ RAII wrappers around the C-compatible wfassoc API. + */ namespace wfassocpp { +/** @brief Type representing a null-terminated UTF-8 C-style string */ using CString = wfassoc::WFCString; +/** + * @brief Type representing a handle/token for managed objects + * + * This library uses an object pool to manage any objects created during calling. + * This type is exposed as an opaque handle for visiting your created object. + */ using Token = wfassoc::WFToken; +/** + * @brief Type representing an icon handle (opaque pointer) + * + * This type is equivalent to the Win32 HICON type. + */ using HICON = wfassoc::WFHICON; +/** @brief Invalid icon handle value */ using INVALID_HICON = wfassoc::WF_INVALID_HICON; +/** @brief Invalid index value used for error conditions */ using INVALID_INDEX = wfassoc::WF_INVALID_INDEX; +/** + * @brief Registration scope for file associations + * + * Determines whether a program is registered for the current user or system-wide. + */ using Scope = wfassoc::WFScope; +/** + * @brief View mode for querying file association status + * + * Determines how the association status is viewed/queried. + */ using View = wfassoc::WFView; -/// @private +/** + * @private + * @brief Check the result of a C API call and throw on failure + * + * @param[in] result Boolean result from a C API call + * @throws std::runtime_error if result is false, with the error message from WFGetLastError() + */ inline void _Check(bool result) { if (!result) { throw std::runtime_error(wfassoc::WFGetLastError()); } } -/// @private +/** + * @private + * @brief Get the invalid token value + * + * In theory, invalid token value should be a constant value. + * However, due to the library used in Rust side, this value can only be fetched at runtime. + * This function caches the value on first call for subsequent use. + * + * @return An invalid token value + */ inline Token _INVALID_TOKEN() { static Token v = wfassoc::WFInvalidToken(); return v; } +/** + * @brief Schema object for defining a program's file association configuration + * + * A Schema is a sketchpad of a complete program. + * Create a Schema object first, then convert it to a Program object for following operations. + * + * This class is move-only (non-copyable). + */ class Schema { public: + /** + * @brief Construct a new Schema object + * @throws std::runtime_error if schema creation fails + */ Schema() { _Check(wfassoc::WFSchemaCreate(&_token)); } + + /** + * @brief Destroy the Schema object + * + * Releases resources associated with the Schema object. + */ ~Schema() { if (_token != _INVALID_TOKEN()) { wfassoc::WFSchemaDestroy(_token); } } + + /** @brief Non-copyable */ Schema(const Schema&) = delete; + /** @brief Non-copyable */ Schema& operator=(const Schema&) = delete; + + /** @brief Move constructor */ Schema(Schema&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } + /** @brief Move assignment operator */ Schema& operator=(Schema&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { @@ -62,41 +130,159 @@ public: return *this; } + /** + * @brief Set the program identifier for this Schema + * + * @param[in] value Null-terminated UTF-8 string containing the identifier. + * This identifier should not be empty, must start with alphabet character, + * and follow with alphabet characters, digits, underline, or hyphens. + * @throws std::runtime_error if the operation fails + */ void SetIdentifier(const char* value) { _Check(wfassoc::WFSchemaSetIdentifier(_token, value)); } + + /** + * @brief Set the program path for this Schema + * + * @param[in] value Null-terminated UTF-8 string containing the program path. + * This path should be the fully qualified path to the application. + * @throws std::runtime_error if the operation fails + */ void SetPath(const char* value) { _Check(wfassoc::WFSchemaSetPath(_token, value)); } + + /** + * @brief Set the program CLSID for this Schema + * + * @param[in] value Null-terminated UTF-8 string containing the CLSID. + * This CLSID string should be in the format of @c {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. + * Please note that curly braces are required. + * @throws std::runtime_error if the operation fails + */ void SetClsid(const char* value) { _Check(wfassoc::WFSchemaSetClsid(_token, value)); } + + /** + * @brief Set the program name for this Schema (optional) + * + * @param[in] value Null-terminated UTF-8 string containing the name, or nullptr to clear + * @throws std::runtime_error if the operation fails + */ void SetName(const char* value) { _Check(wfassoc::WFSchemaSetName(_token, value)); } + + /** + * @brief Set the program icon for this Schema (optional) + * + * @param[in] value Null-terminated UTF-8 string containing the icon path, or nullptr to clear + * @throws std::runtime_error if the operation fails + */ void SetIcon(const char* value) { _Check(wfassoc::WFSchemaSetIcon(_token, value)); } + + /** + * @brief Set the program behavior for this Schema (optional) + * + * @param[in] value Null-terminated UTF-8 string containing the behavior command, or nullptr to clear + * @throws std::runtime_error if the operation fails + */ void SetBehavior(const char* value) { _Check(wfassoc::WFSchemaSetBehavior(_token, value)); } + + /** + * @brief Add a string resource entry to this Schema + * + * @param[in] name Null-terminated UTF-8 string containing the name of this entry + * @param[in] value Null-terminated UTF-8 string containing the value of this entry. + * It can be a plain string or a reference string to resource. + * @throws std::runtime_error if the operation fails + */ void AddStr(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddStr(_token, name, value)); } + + /** + * @brief Add an icon registry entry to this Schema + * + * @param[in] name Null-terminated UTF-8 string containing the name of this entry + * @param[in] value Null-terminated UTF-8 string containing the value of this entry. + * It can be a path to icon or a reference string to resource. + * @throws std::runtime_error if the operation fails + */ void AddIcon(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddIcon(_token, name, value)); } + + /** + * @brief Add a behavior registry entry to this Schema + * + * @param[in] name Null-terminated UTF-8 string containing the name of this entry + * @param[in] value Null-terminated UTF-8 string containing the value of this entry. + * It should be a valid command line string which uses @c %1, @c %2, etc. to represent parameters. + * @throws std::runtime_error if the operation fails + */ void AddBehavior(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddBehavior(_token, name, value)); } + + /** + * @brief Add a file extension to this Schema + * + * @param[in] ext Null-terminated UTF-8 string containing the file extension name (without leading dot) + * @param[in] ext_name Null-terminated UTF-8 string containing the name pointing to associated name for this extension. + * This name should be registered by calling AddStr(). + * @param[in] ext_icon Null-terminated UTF-8 string containing the name pointing to associated icon for this extension. + * This name should be registered by calling AddIcon(). + * @param[in] ext_behavior Null-terminated UTF-8 string containing the name pointing to associated behavior for this extension. + * This name should be registered by calling AddBehavior(). + * @throws std::runtime_error if the operation fails + */ void AddExt(const char* ext, const char* ext_name, const char* ext_icon, const char* ext_behavior) { _Check(wfassoc::WFSchemaAddExt(_token, ext, ext_name, ext_icon, ext_behavior)); } private: friend class Program; - /// @private + + /** + * @private + * @brief Release ownership of the token + * + * @return The released token + */ Token Release() noexcept { Token t = _token; _token = _INVALID_TOKEN(); return t; } + Token _token; }; +/** + * @brief Icon resource object for managing icon handles + * + * This class wraps an icon resource token and provides access to the icon handle. + * The icon handle will be freed when this object is destroyed. + * + * This class is move-only (non-copyable). + */ class IconRc { public: + /** + * @brief Construct an IconRc from an existing token + * + * @param[in] token The icon resource token to wrap + */ explicit IconRc(Token token) : _token(token) {} + + /** + * @brief Destroy the IconRc object + * + * Releases resources associated with the icon resource. + */ ~IconRc() { if (_token != _INVALID_TOKEN()) { wfassoc::WFIconRcDestroy(_token); } } + + /** @brief Non-copyable */ IconRc(const IconRc&) = delete; + /** @brief Non-copyable */ IconRc& operator=(const IconRc&) = delete; + + /** @brief Move constructor */ IconRc(IconRc&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } + /** @brief Move assignment operator */ IconRc& operator=(IconRc&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { @@ -108,6 +294,13 @@ public: return *this; } + /** + * @brief Get the icon handle from this icon resource + * + * @return The icon handle. This handle will be freed when this object is destroyed. + * Please make a copy immediately if you need to use it longer. + * @throws std::runtime_error if the operation fails + */ HICON GetIcon() { HICON icon = nullptr; _Check(wfassoc::WFIconRcGetIcon(_token, &icon)); @@ -118,17 +311,42 @@ private: Token _token; }; +/** + * @brief Extension status object for querying file extension registration status + * + * This class wraps an extension status token and provides access to extension details. + * The extension status object will be freed when this object is destroyed. + * + * This class is move-only (non-copyable). + */ class ExtStatus { public: + /** + * @brief Construct an ExtStatus from an existing token + * + * @param[in] token The extension status token to wrap + */ explicit ExtStatus(Token token) : _token(token) {} + + /** + * @brief Destroy the ExtStatus object + * + * Releases resources associated with the extension status. + */ ~ExtStatus() { if (_token != _INVALID_TOKEN()) { wfassoc::WFExtStatusDestroy(_token); } } + + /** @brief Non-copyable */ ExtStatus(const ExtStatus&) = delete; + /** @brief Non-copyable */ ExtStatus& operator=(const ExtStatus&) = delete; + + /** @brief Move constructor */ ExtStatus(ExtStatus&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } + /** @brief Move assignment operator */ ExtStatus& operator=(ExtStatus&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { @@ -140,12 +358,30 @@ public: return *this; } + /** + * @brief Get the display name from this extension status + * + * The display name will be user specified first, then fallback to its ProgId verbatim. + * The library will try to use localized name first, then use raw ProgId name if localized name is not available. + * + * @return The display name string. There is no possibility that this value is empty. + * @throws std::runtime_error if the operation fails + */ std::string GetName() { const char* name = nullptr; _Check(wfassoc::WFExtStatusGetName(_token, &name)); return std::string(name); } + /** + * @brief Get the icon from this extension status + * + * The icon will be user specified first, then fallback to the system default file icon. + * + * @return The icon handle. This handle will be freed when this object is destroyed. + * Please make a copy immediately if you need to use it longer. + * @throws std::runtime_error if the operation fails + */ HICON GetIcon() { HICON icon = nullptr; _Check(wfassoc::WFExtStatusGetIcon(_token, &icon)); @@ -156,17 +392,42 @@ private: Token _token; }; +/** + * @brief Self extension status object for accessing program-provided extension details + * + * This class wraps a self extension status token and provides access to extension details + * as defined by the program itself. + * + * This class is move-only (non-copyable). + */ class SelfExtStatus { public: + /** + * @brief Construct a SelfExtStatus from an existing token + * + * @param[in] token The self extension status token to wrap + */ explicit SelfExtStatus(Token token) : _token(token) {} + + /** + * @brief Destroy the SelfExtStatus object + * + * Releases resources associated with the self extension status. + */ ~SelfExtStatus() { if (_token != _INVALID_TOKEN()) { wfassoc::WFSelfExtStatusDestroy(_token); } } + + /** @brief Non-copyable */ SelfExtStatus(const SelfExtStatus&) = delete; + /** @brief Non-copyable */ SelfExtStatus& operator=(const SelfExtStatus&) = delete; + + /** @brief Move constructor */ SelfExtStatus(SelfExtStatus&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } + /** @brief Move assignment operator */ SelfExtStatus& operator=(SelfExtStatus&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { @@ -178,24 +439,53 @@ public: return *this; } + /** + * @brief Get the display name from this self extension status + * + * The display name will be user specified first, then fallback to its ProgId verbatim. + * + * @return The display name string. There is no possibility that this value is empty. + * @throws std::runtime_error if the operation fails + */ std::string GetName() { const char* name = nullptr; _Check(wfassoc::WFSelfExtStatusGetName(_token, &name)); return std::string(name); } + /** + * @brief Get the icon from this self extension status + * + * The icon will be user specified first, then fallback to the system default file icon. + * + * @return The icon handle. This handle will be freed when this object is destroyed. + * Please make a copy immediately if you need to use it longer. + * @throws std::runtime_error if the operation fails + */ HICON GetIcon() { HICON icon = nullptr; _Check(wfassoc::WFSelfExtStatusGetIcon(_token, &icon)); return icon; } + /** + * @brief Get the extension string (without leading dot) from this self extension status + * + * @return The file extension name (without leading dot). There is no possibility that this value is empty. + * @throws std::runtime_error if the operation fails + */ std::string GetExt() { const char* inner = nullptr; _Check(wfassoc::WFSelfExtStatusGetExt(_token, &inner)); return std::string(inner); } + /** + * @brief Get the dotted extension string (with leading dot) from this self extension status + * + * @return The file extension string (with leading dot). There is no possibility that this value is empty. + * @throws std::runtime_error if the operation fails + */ std::string GetDottedExt() { const char* inner = nullptr; _Check(wfassoc::WFSelfExtStatusGetDottedExt(_token, &inner)); @@ -206,19 +496,48 @@ private: Token _token; }; +/** + * @brief Program object for managing file association registration + * + * A Program is created from a Schema and provides methods for registering, + * unregistering, and querying file associations. + * + * This class is move-only (non-copyable). + */ class Program { public: + /** + * @brief Construct a Program from a Schema + * + * This constructor consumes the Schema object. + * The Schema object cannot be used after this call. + * + * @param[in] schema The Schema to create the Program from (will be consumed) + * @throws std::runtime_error if program creation fails + */ explicit Program(Schema&& schema) { _Check(wfassoc::WFProgramCreate(schema.Release(), &_token)); } + + /** + * @brief Destroy the Program object + * + * Releases resources associated with the Program. + */ ~Program() { if (_token != _INVALID_TOKEN()) { wfassoc::WFProgramDestroy(_token); } } + + /** @brief Non-copyable */ Program(const Program&) = delete; + /** @brief Non-copyable */ Program& operator=(const Program&) = delete; + + /** @brief Move constructor */ Program(Program&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } + /** @brief Move assignment operator */ Program& operator=(Program&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { @@ -230,48 +549,132 @@ public: return *this; } + /** + * @brief Resolve the provided program name of this Program + * + * The name will be user specified first, + * then fallback to program manifest file specified name, + * and finally fallback to the file name of executable. + * + * @return The resolved program name. There is no possibility that this value is empty. + * @throws std::runtime_error if the operation fails + */ std::string ResolveName() { const char* name = nullptr; _Check(wfassoc::WFProgramResolveName(_token, &name)); return std::string(name); } + /** + * @brief Resolve the Program icon resource + * + * The icon will be user specified first, + * then fallback to the first icon of program, + * and finally fallback to the system default executable icon. + * + * @return An IconRc object containing the resolved icon + * @throws std::runtime_error if the operation fails + */ IconRc ResolveIcon() { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramResolveIcon(_token, &token)); return IconRc(token); } + /** + * @brief Get the number of file extensions in the Program + * + * @return The number of extensions + * @throws std::runtime_error if the operation fails + */ size_t ExtsLen() { size_t len = 0; _Check(wfassoc::WFProgramExtsLen(_token, &len)); return len; } + /** + * @brief Find a file extension by its body (extension string) + * + * @param[in] body Null-terminated UTF-8 string containing the file extension name (without leading dot) to find + * @return The index of the extension, or INVALID_INDEX if not found + * @throws std::runtime_error if the operation fails + */ size_t FindExt(const char* body) { size_t index = INVALID_INDEX; _Check(wfassoc::WFProgramFindExt(_token, body, &index)); return index; } + /** + * @brief Resolve this program provided extension's details by index + * + * @param[in] index Index of the extension to resolve + * @return A SelfExtStatus object containing the extension details + * @throws std::runtime_error if the operation fails + */ SelfExtStatus ResolveExt(size_t index) { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramResolveExt(_token, index, &token)); return SelfExtStatus(token); } + /** + * @brief Register the Program in the specified scope + * + * @param[in] scope Registration scope + * @throws std::runtime_error if the operation fails + */ void Register(Scope scope) { _Check(wfassoc::WFProgramRegister(_token, scope)); } + + /** + * @brief Unregister the Program from the specified scope + * + * @param[in] scope Registration scope + * @throws std::runtime_error if the operation fails + */ void Unregister(Scope scope) { _Check(wfassoc::WFProgramUnregister(_token, scope)); } + /** + * @brief Check if the Program is registered in the specified scope + * + * @param[in] scope Registration scope for checking + * @return true if the Program is registered in the specified scope, false otherwise + * @throws std::runtime_error if the operation fails + */ bool IsRegistered(Scope scope) { bool result = false; _Check(wfassoc::WFProgramIsRegistered(_token, scope, &result)); return result; } + /** + * @brief Link a file extension in the specified scope + * + * @param[in] scope Registration scope + * @param[in] index Index of the extension to link + * @throws std::runtime_error if the operation fails + */ void LinkExt(Scope scope, size_t index) { _Check(wfassoc::WFProgramLinkExt(_token, scope, index)); } + + /** + * @brief Unlink a file extension in the specified scope + * + * @param[in] scope Registration scope + * @param[in] index Index of the extension to unlink + * @throws std::runtime_error if the operation fails + */ void UnlinkExt(Scope scope, size_t index) { _Check(wfassoc::WFProgramUnlinkExt(_token, scope, index)); } + /** + * @brief Query the status of a file extension + * + * @param[in] view View viewpoint + * @param[in] index Index of the extension to query + * @return An optional ExtStatus object. Returns std::nullopt if the extension is not found + * (usually means that this extension is not registered in the specified scope). + * @throws std::runtime_error if the operation fails + */ std::optional QueryExt(View view, size_t index) { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramQueryExt(_token, view, index, &token)); diff --git a/wfassoc-cdylib/cbindgen/wfassoc.h b/wfassoc-cdylib/cbindgen/wfassoc.h index ff03d7e..13f2ae4 100644 --- a/wfassoc-cdylib/cbindgen/wfassoc.h +++ b/wfassoc-cdylib/cbindgen/wfassoc.h @@ -22,6 +22,12 @@ #ifdef __cplusplus +/** + * @brief Windows File Association C/C++ API namespace + * + * This namespace only provide the raw binding to C-compatible wfassoc API in C++. + * For the C++ RAII wrappers of this, please see @ref wfassocpp namespace. + */ namespace wfassoc { #endif // __cplusplus