/** * @file wfassoc++.h * @brief Windows File Association C++ API header * * This header provides C++ API for managing Windows file associations, * based on its C-compatible API. * The API is designed to work with at least C++17. */ #pragma once #ifndef WFASSOCPP_H_ #define WFASSOCPP_H_ #include "wfassoc.h" #include #include #include #include namespace wfassocpp { using wfassoc::CStyleString; using wfassoc::Token; using wfassoc::HICON; using wfassoc::INVALID_HICON; using wfassoc::INVALID_INDEX; using wfassoc::Scope; using wfassoc::View; /// @private inline void _Check(bool result) { if (!result) { throw std::runtime_error(wfassoc::WFGetLastError()); } } /// @private inline Token _INVALID_TOKEN() { static Token v = wfassoc::WFInvalidToken(); return v; } class Schema { public: Schema() { _Check(wfassoc::WFSchemaCreate(&_token)); } ~Schema() { if (_token != _INVALID_TOKEN()) { wfassoc::WFSchemaDestroy(_token); } } Schema(const Schema&) = delete; Schema& operator=(const Schema&) = delete; Schema(Schema&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } Schema& operator=(Schema&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { wfassoc::WFSchemaDestroy(_token); } _token = other._token; other._token = _INVALID_TOKEN(); } return *this; } void SetIdentifier(const char* value) { _Check(wfassoc::WFSchemaSetIdentifier(_token, value)); } void SetPath(const char* value) { _Check(wfassoc::WFSchemaSetPath(_token, value)); } void SetClsid(const char* value) { _Check(wfassoc::WFSchemaSetClsid(_token, value)); } void SetName(const char* value) { _Check(wfassoc::WFSchemaSetName(_token, value)); } void SetIcon(const char* value) { _Check(wfassoc::WFSchemaSetIcon(_token, value)); } void SetBehavior(const char* value) { _Check(wfassoc::WFSchemaSetBehavior(_token, value)); } void AddStr(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddStr(_token, name, value)); } void AddIcon(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddIcon(_token, name, value)); } void AddBehavior(const char* name, const char* value) { _Check(wfassoc::WFSchemaAddBehavior(_token, name, value)); } 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 Token Release() noexcept { Token t = _token; _token = _INVALID_TOKEN(); return t; } Token _token; }; class IconRc { public: explicit IconRc(Token token) : _token(token) {} ~IconRc() { if (_token != _INVALID_TOKEN()) { wfassoc::WFIconRcDestroy(_token); } } IconRc(const IconRc&) = delete; IconRc& operator=(const IconRc&) = delete; IconRc(IconRc&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } IconRc& operator=(IconRc&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { wfassoc::WFIconRcDestroy(_token); } _token = other._token; other._token = _INVALID_TOKEN(); } return *this; } HICON GetIcon() { HICON icon = nullptr; _Check(wfassoc::WFIconRcGetIcon(_token, &icon)); return icon; } private: Token _token; }; class ExtStatus { public: explicit ExtStatus(Token token) : _token(token) {} ~ExtStatus() { if (_token != _INVALID_TOKEN()) { wfassoc::WFExtStatusDestroy(_token); } } ExtStatus(const ExtStatus&) = delete; ExtStatus& operator=(const ExtStatus&) = delete; ExtStatus(ExtStatus&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } ExtStatus& operator=(ExtStatus&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { wfassoc::WFExtStatusDestroy(_token); } _token = other._token; other._token = _INVALID_TOKEN(); } return *this; } std::string GetName() { const char* name = nullptr; _Check(wfassoc::WFExtStatusGetName(_token, &name)); return name ? std::string(name) : std::string(); } HICON GetIcon() { HICON icon = nullptr; _Check(wfassoc::WFExtStatusGetIcon(_token, &icon)); return icon; } private: Token _token; }; class Ext { public: explicit Ext(Token token) : _token(token) {} ~Ext() { if (_token != _INVALID_TOKEN()) { wfassoc::WFExtDestroy(_token); } } Ext(const Ext&) = delete; Ext& operator=(const Ext&) = delete; Ext(Ext&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } Ext& operator=(Ext&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { wfassoc::WFExtDestroy(_token); } _token = other._token; other._token = _INVALID_TOKEN(); } return *this; } std::string GetInner() { const char* inner = nullptr; _Check(wfassoc::WFExtGetInner(_token, &inner)); return std::string(inner); } std::string GetDottedInner() { const char* inner = nullptr; _Check(wfassoc::WFExtGetDottedInner(_token, &inner)); return std::string(inner); } private: Token _token; }; class Program { public: explicit Program(std::unique_ptr&& schema) { _Check(wfassoc::WFProgramCreate(schema->Release(), &_token)); } ~Program() { if (_token != _INVALID_TOKEN()) { wfassoc::WFProgramDestroy(_token); } } Program(const Program&) = delete; Program& operator=(const Program&) = delete; Program(Program&& other) noexcept : _token(other._token) { other._token = _INVALID_TOKEN(); } Program& operator=(Program&& other) noexcept { if (this != &other) { if (_token != _INVALID_TOKEN()) { wfassoc::WFProgramDestroy(_token); } _token = other._token; other._token = _INVALID_TOKEN(); } return *this; } std::string ResolveName() { const char* name = nullptr; _Check(wfassoc::WFProgramResolveName(_token, &name)); return name ? std::string(name) : std::string(); } std::unique_ptr ResolveIcon() { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramResolveIcon(_token, &token)); if (token == _INVALID_TOKEN()) { return nullptr; } return std::make_unique(token); } size_t ExtsLen() { size_t len = 0; _Check(wfassoc::WFProgramExtsLen(_token, &len)); return len; } std::unique_ptr GetExt(size_t index) { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramGetExt(_token, index, &token)); return std::make_unique(token); } size_t FindExt(const char* body) { size_t index = INVALID_INDEX; _Check(wfassoc::WFProgramFindExt(_token, body, &index)); return index; } void Register(Scope scope) { _Check(wfassoc::WFProgramRegister(_token, scope)); } void Unregister(Scope scope) { _Check(wfassoc::WFProgramUnregister(_token, scope)); } bool IsRegistered(Scope scope) { bool result = false; _Check(wfassoc::WFProgramIsRegistered(_token, scope, &result)); return result; } void LinkExt(Scope scope, size_t index) { _Check(wfassoc::WFProgramLinkExt(_token, scope, index)); } void UnlinkExt(Scope scope, size_t index) { _Check(wfassoc::WFProgramUnlinkExt(_token, scope, index)); } std::unique_ptr QueryExt(View view, size_t index) { Token token = _INVALID_TOKEN(); _Check(wfassoc::WFProgramQueryExt(_token, view, index, &token)); if (token == _INVALID_TOKEN()) { return nullptr; } return std::make_unique(token); } private: Token _token; }; } // namespace wfassocpp #endif // WFASSOCPP_H_