diff --git a/wfassoc-cdylib/codegen/wfassoc.h b/wfassoc-cdylib/codegen/wfassoc.h index 3c99452..816739b 100644 --- a/wfassoc-cdylib/codegen/wfassoc.h +++ b/wfassoc-cdylib/codegen/wfassoc.h @@ -1,3 +1,12 @@ +/** + * @file wfassoc.h + * @brief Windows File Association C API header + * + * This header provides a C-compatible API for managing Windows file associations, + * including schema creation, program registration, and extension management. + * The API is designed to work with both C and C++ compilers. + */ + #pragma once #ifndef __WFASSOC_H__ #define __WFASSOC_H__ @@ -13,8 +22,25 @@ #ifdef __cplusplus +namespace wfassoc { +#endif // __cplusplus + + +#ifdef __cplusplus +/** Type representing a null-terminated UTF-8 C-style string */ using CStyleString = const char*; +/** + * @brief Type representing a handle/token for managed objects + * + * This library use object pool to manage any objects created during calling. + * And we expose this type as an opaque handle for visiting your created object. + */ using Token = uint64_t; +/** + * @brief Type representing an icon handle (opaque pointer) + * + * This type is equivalent with Win32 HICON type. + */ using HICON = void*; #else // __cplusplus typedef const char *CStyleString; @@ -24,7 +50,9 @@ typedef void *HICON; #ifdef __cplusplus +/** Invalid icon handle value */ constexpr HICON INVALID_HICON = nullptr; +/** Invalid index value used for error conditions */ constexpr size_t INVALID_INDEX = static_cast(-1); #else // __cplusplus static const HICON INVALID_HICON = NULL; @@ -33,113 +61,479 @@ static const size_t INVALID_INDEX = ((size_t)-1); #ifdef __cplusplus +/** + * @brief Registration scope for file associations + * + * Determines whether a program is registered for the current user or system-wide. + */ enum class Scope : uint32_t { + /** Current user scope */ User = 0u, + /** System-wide scope */ System = 1u }; +/** + * @brief View mode for querying file association status + * + * Determines how the association status is viewed/queried. + */ enum class View : uint32_t { + /** User-level view */ User = 0u, + /** System-level view */ System = 1u, + /** Combined hybrid view of both user and system */ Hybrid = 2u }; #else // __cplusplus typedef uint32_t Scope; +/** Current user scope */ static const Scope SCOPE_USER = 0u; +/** System-wide scope */ static const Scope SCOPE_SYSTEM = 1u; typedef uint32_t View; +/** User-level view */ static const View VIEW_USER = 0u; +/** System-level view */ static const View VIEW_SYSTEM = 1u; +/** Combined hybrid view of both user and system */ static const View VIEW_HYBRID = 2u; #endif // __cplusplus #ifdef __cplusplus -namespace wfassoc { extern "C" { #endif // __cplusplus +/** + * @brief Initialize the wfassoc library + * + * This function must be called before using the MOST of any other wfassoc functions. + * + * @return true on success, false on failure. + */ bool WFStartup(void); +/** + * @brief Shutdown the wfassoc library + * + * Cleans up all allocated resources and object pools. + * Should be called when done using the library. + * + * @return true on success, false on failure. + */ bool WFShutdown(void); +/** + * @brief Get the last error message + * + * Returns a human-readable error message describing the last error that occurred. + * The returned error message string is valid until the next API call. + * + * For most functions located in this library, except some special function indicated in their notes, + * they return boolean value indicating whether function is successful or not. + * Once they fail, you can call this function to get a human-readable error message. + * + * The execution of this function do not need to be wrapped by WFStartup() and WFShutdown(). + * + * @return Null-terminated UTF-8 string containing the error message. + * If no error has occurred, the string is empty. + * There is no possibility of a NULL return value. + */ CStyleString WFGetLastError(void); +/** + * @brief Check if the current process has administrative privileges + * + * This function will not throw any error. + * There is no necessity to call WFGetLastError() after this function. + * The return value only indicates whether the current process has administrative privileges or not. + * + * The execution of this function do not need to be wrapped by WFStartup() and WFShutdown(). + * + * @return true if running with admin privileges, false otherwise + */ bool WFHasPrivilege(void); +/** + * @brief Get an invalid token value + * + * In theory, invalid token value should be a constant value. + * However, due to the library I used in Rust side, this value only can be fetched at runtime. + * So I expose this function to make programmer can fetch this constant value. + * Theoretically, you just need to fetch this function only once at the beginning of your program. + * + * The execution of this function do not need to be wrapped by WFStartup() and WFShutdown(). + * + * @return An invalid token value + */ Token WFInvalidToken(void); +/** + * @brief Create a new Schema object + * + * A Schema is a sketchpad of a complete program. + * For the user of this library, they should create a Schema object first. + * Then convert it to a Program object for following operations. + * + * @param[out] out_schema Pointer to receive the Schema token. + * The receiver take the ownership of this Schema object. + * And it should be freed by calling WFSchemaDestroy() when it is no longer needed, + * or consumed by creating a Program object via WFProgramCreate(). + * @return true on success, false on failure + */ bool WFSchemaCreate(Token *out_schema); +/** + * @brief Destroy a Schema object + * + * Releases resources associated with the Schema object. + * + * Usually you do not need to call this function, + * because the convertion function from Schema to Program will consume given Schema object to produce Program object. + * + * @param[in] in_schema Schema token to destroy + * @return true on success, false on failure + */ bool WFSchemaDestroy(Token in_schema); +/** + * @brief Set the program identifier for a Schema + * + * @param[in] in_schema Schema token + * @param[in] 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. + * @return true on success, false on failure + */ bool WFSchemaSetIdentifier(Token in_schema, CStyleString in_value); +/** + * @brief Set the program path for a Schema + * + * @param[in] in_schema Schema token + * @param[in] in_value Null-terminated UTF-8 string containing the program path. + * This path should be the fully qualified path to the application. + * @return true on success, false on failure + */ bool WFSchemaSetPath(Token in_schema, CStyleString in_value); +/** + * @brief Set the program CLSID for a Schema + * + * @param[in] in_schema Schema token + * @param[in] 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. + * @return true on success, false on failure + */ bool WFSchemaSetClsid(Token in_schema, CStyleString in_value); +/** + * @brief Set the program name for a Schema (optional) + * + * @param[in] in_schema Schema token + * @param[in] in_value Null-terminated UTF-8 string containing the name, or NULL to clear + * @return true on success, false on failure + */ bool WFSchemaSetName(Token in_schema, CStyleString in_value); +/** + * @brief Set the program icon for a Schema (optional) + * + * @param[in] in_schema Schema token + * @param[in] in_value Null-terminated UTF-8 string containing the icon path, or NULL to clear + * @return true on success, false on failure + */ bool WFSchemaSetIcon(Token in_schema, CStyleString in_value); +/** + * @brief Set the program behavior for a Schema (optional) + * + * @param[in] in_schema Schema token + * @param[in] in_value Null-terminated UTF-8 string containing the behavior command, or NULL to clear + * @return true on success, false on failure + */ bool WFSchemaSetBehavior(Token in_schema, CStyleString in_value); +/** + * @brief Add a string resource entry to a Schema + * + * @param[in] in_schema Schema token + * @param[in] in_name Null-terminated UTF-8 string containing the name of this entry + * @param[in] 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. + * @return true on success, false on failure + */ bool WFSchemaAddStr(Token in_schema, CStyleString in_name, CStyleString in_value); +/** + * @brief Add an icon registry entry to a Schema + * + * @param[in] in_schema Schema token + * @param[in] in_name Null-terminated UTF-8 string containing the name of this entry + * @param[in] 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. + * @return true on success, false on failure + */ bool WFSchemaAddIcon(Token in_schema, CStyleString in_name, CStyleString in_value); +/** + * @brief Add a behavior registry entry to a Schema + * + * @param[in] in_schema Schema token + * @param[in] in_name Null-terminated UTF-8 string containing the name of this entry + * @param[in] in_value Null-terminated UTF-8 string containing the value of this entry. + * It should be a valid command line string which use \c %1, \c %2, etc. to represent parameters. + * @return true on success, false on failure + */ bool WFSchemaAddBehavior(Token in_schema, CStyleString in_name, CStyleString in_value); +/** + * @brief Add a file extension to a Schema + * + * @param[in] in_schema Schema token + * @param[in] in_ext Null-terminated UTF-8 string containing the file extension name (without leading dot). + * @param[in] 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 WFSchemaAddStr(). + * @param[in] 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 WFSchemaAddIcon(). + * @param[in] 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 WFSchemaAddBehavior(). + * @return true on success, false on failure + */ bool WFSchemaAddExt(Token in_schema, CStyleString in_ext, CStyleString in_ext_name, CStyleString in_ext_icon, CStyleString in_ext_behavior); +/** + * @brief Create a Program object from a Schema + * + * Please note that this function will consume the Schema object. + * It means that the Schema object cannot be used after this call. + * And you do not need to call WFSchemaDestroy() for this Schema object after this call. + * + * @param[in] in_schema Schema token (will be consumed) + * @param[out] out_program Pointer to receive the Program token. + * The receiver take the ownership of this Program object. + * And it should be freed by calling WFProgramDestroy() when it is no longer needed. + * @return true on success, false on failure + */ bool WFProgramCreate(Token in_schema, Token *out_program); +/** + * @brief Destroy a Program object + * + * Releases resources associated with the Program. + * + * @param[in] in_program Program token to destroy + * @return true on success, false on failure + */ bool WFProgramDestroy(Token in_program); +/** + * @brief Resolve the provided program name of this Program + * + * @param[in] in_program Program token + * @param[out] out_name Pointer to receive the resolved name, or NULL if not found. + * This string will be freed at the next API call. Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFProgramResolveName(Token in_program, CStyleString *out_name); +/** + * @brief Resolve the Program icon resource + * + * @param[in] in_program Program token + * @param[out] out_icon_rc Pointer to receive the icon resource token, or invalid token if not found. + * The caller take the ownership of created icon resource object. + * And it should be freed by calling WFIconRcDestroy() when it is no longer needed. + * @return true on success, false on failure + */ bool WFProgramResolveIcon(Token in_program, Token *out_icon_rc); +/** + * @brief Get the number of file extensions in the Program + * + * @param[in] in_program Program token + * @param[out] out_len Pointer to receive the number of extensions + * @return true on success, false on failure + */ bool WFProgramExtsLen(Token in_program, size_t *out_len); +/** + * @brief Get a file extension by index + * + * @param[in] in_program Program token + * @param[in] in_index Index of the extension to retrieve + * @param[out] out_ext Pointer to receive the file extension token. + * The caller take the ownership of created file extension object. + * And it should be freed by calling WFExtDestroy() when it is no longer needed. + * @return true on success, false on failure + */ bool WFProgramGetExt(Token in_program, size_t in_index, Token *out_ext); +/** + * @brief Find a file extension by its body (extension string) + * + * @param[in] in_program Program token + * @param[in] in_body Null-terminated UTF-8 string containing the file extension name (without leading dot) to find. + * @param[out] out_index Pointer to receive the file extension index, or INVALID_INDEX if not found. + * @return true on success, false on failure + */ bool WFProgramFindExt(Token in_program, CStyleString in_body, size_t *out_index); +/** + * @brief Register the Program in the specified scope + * + * @param[in] in_program Program token + * @param[in] in_scope Registration scope + * @return true on success, false on failure + */ bool WFProgramRegister(Token in_program, Scope in_scope); +/** + * @brief Unregister the Program from the specified scope + * + * @param[in] in_program Program token + * @param[in] in_scope Registration scope + * @return true on success, false on failure + */ bool WFProgramUnregister(Token in_program, Scope in_scope); +/** + * @brief Check if the Program is registered in the specified scope + * + * @param[in] in_program Program token + * @param[in] in_scope Registration scope for checking + * @param[out] out_is_registered Pointer to receive the registration status. + * True if the Program is registered in the specified scope, false otherwise. + * @return true on success, false on failure + */ bool WFProgramIsRegistered(Token in_program, Scope in_scope, bool *out_is_registered); +/** + * @brief Link a file extension in the specified scope + * + * @param[in] in_program Program token + * @param[in] in_scope Registration scope + * @param[in] in_index Index of the extension to link + * @return true on success, false on failure + */ bool WFProgramLinkExt(Token in_program, Scope in_scope, size_t in_index); +/** + * @brief Unlink a file extension in the specified scope + * + * @param[in] in_program Program token + * @param[in] in_scope Registration scope + * @param[in] in_index Index of the extension to unlink + * @return true on success, false on failure + */ bool WFProgramUnlinkExt(Token in_program, Scope in_scope, size_t in_index); +/** + * @brief Query the status of a file extension + * + * @param[in] in_program Program token + * @param[in] in_view View viewpoint. + * @param[in] in_index Index of the extension to query + * @param[out] out_ext_status Pointer to receive the extension status token, or invalid token if not found. + * If the extension is not found, it usually means that this extension is not registered in the specified scope. + * The caller take the ownership of created extension status object. + * And it should be freed by calling WFExtStatusDestroy() when it is no longer needed. + * @return true on success, false on failure + */ bool WFProgramQueryExt(Token in_program, View in_view, size_t in_index, Token *out_ext_status); +/** + * @brief Destroy an extension status object + * + * @param[in] in_ext_status Extension status token to destroy + * @return true on success, false on failure + */ bool WFExtStatusDestroy(Token in_ext_status); +/** + * @brief Get the name from an extension status object + * + * @param[in] in_ext_status Extension status token + * @param[out] out_name Pointer to receive the name. + * There is no possibility that this value is NULL. + * We will try to use localized name first, then use raw ProgId name if localized name is not available. + * This string will be freed at the next API call. Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFExtStatusGetName(Token in_ext_status, CStyleString *out_name); +/** + * @brief Get the icon from an extension status object + * + * @param[in] in_ext_status Extension status token + * @param[out] out_icon Pointer to receive the icon handle, or INVALID_HICON if not available. + * This icon handle will be freed once this icon resource object is destroyed. + * Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFExtStatusGetIcon(Token in_ext_status, HICON *out_icon); +/** + * @brief Destroy an icon resource object + * + * @param[in] in_icon_rc Icon resource token to destroy + * @return true on success, false on failure + */ bool WFIconRcDestroy(Token in_icon_rc); +/** + * @brief Get the icon handle from an icon resource object + * + * @param[in] in_icon_rc Icon resource token + * @param[out] out_icon Pointer to receive the icon handle. + * There is no possibility that this value is INVALID_HICON. + * This icon handle will be freed once this icon resource object is destroyed. + * Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFIconRcGetIcon(Token in_icon_rc, HICON *out_icon); +/** + * @brief Destroy a file extension object + * + * @param[in] in_ext Extension token to destroy + * @return true on success, false on failure + */ bool WFExtDestroy(Token in_ext); +/** + * @brief Get the inner extension string without dot + * + * @param[in] in_ext Extension token + * @param[out] out_inner Pointer to receive the file extension name (without leading dot). + * There is no possibility that this value is NULL. + * This string will be freed at the next API call. Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFExtGetInner(Token in_ext, CStyleString *out_inner); +/** + * @brief Get the inner extension string with dot prefix + * + * @param[in] in_ext Extension token + * @param[out] out_inner Pointer to receive the file extension string (with leading dot). + * There is no possibility that this value is NULL. + * This string will be freed at the next API call. Please make a copy immediately if you need to use it longer. + * @return true on success, false on failure + */ bool WFExtGetDottedInner(Token in_ext, CStyleString *out_inner); #ifdef __cplusplus } // extern "C" +#endif // __cplusplus + +#ifdef __cplusplus } // namespace wfassoc #endif // __cplusplus