From 620a60176f476523c5cb3184f20d3a306a1e75a7 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 00:08:09 +0200 Subject: [PATCH 01/19] Move remaining linker pragmas into CMakeLists file --- CMakeLists.txt | 2 +- src/wintoastlib.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35b5888..17df1d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(WINTOASTLIB_HEADERS ${CMAKE_CURRENT_LIST_DIR}/include/wintoastlib.h) set(WINTOASTLIB_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/wintoastlib.cpp) add_library(${WINTOASTLIB_LIBNAME} STATIC ${WINTOASTLIB_HEADERS} ${WINTOASTLIB_SOURCES}) target_include_directories(${WINTOASTLIB_LIBNAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) -target_link_libraries(${WINTOASTLIB_LIBNAME} psapi) +target_link_libraries(${WINTOASTLIB_LIBNAME} psapi shlwapi user32) if (${WINTOASTLIB_BUILD_EXAMPLES}) add_subdirectory(examples) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 2de25e8..6fc08de 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -29,9 +29,6 @@ #include #include -#pragma comment(lib, "shlwapi") -#pragma comment(lib, "user32") - #define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" #define DEFAULT_LINK_FORMAT L".lnk" #define STATUS_SUCCESS (0x00000000) From 6a8ab660a5a1d10dd2b4f688e29b4a25e1a0b0b9 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 02:49:36 +0200 Subject: [PATCH 02/19] Consistently use enum class instead of C-enums, ensure int32_t as default enum memory representation --- include/wintoastlib.h | 71 +++++++++++++++++++++---------------------- src/wintoastlib.cpp | 34 ++++++++++----------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index aa7a88a..cd90728 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -51,15 +51,14 @@ using namespace ABI::Windows::UI::Notifications; using namespace Windows::Foundation; namespace WinToastLib { - void setDebugOutputEnabled(bool enabled); class IWinToastHandler { public: - enum WinToastDismissalReason { - UserCanceled = ToastDismissalReason::ToastDismissalReason_UserCanceled, - ApplicationHidden = ToastDismissalReason::ToastDismissalReason_ApplicationHidden, - TimedOut = ToastDismissalReason::ToastDismissalReason_TimedOut + enum class WinToastDismissalReason : int32_t { + UserCanceled = ToastDismissalReason_UserCanceled, + ApplicationHidden = ToastDismissalReason_ApplicationHidden, + TimedOut = ToastDismissalReason_TimedOut }; virtual ~IWinToastHandler() = default; @@ -72,23 +71,23 @@ namespace WinToastLib { class WinToastTemplate { public: - enum class Scenario { Default, Alarm, IncomingCall, Reminder }; - enum Duration { System, Short, Long }; - enum AudioOption { Default = 0, Silent, Loop }; - enum TextField { FirstLine = 0, SecondLine, ThirdLine }; - - enum WinToastTemplateType { - ImageAndText01 = ToastTemplateType::ToastTemplateType_ToastImageAndText01, - ImageAndText02 = ToastTemplateType::ToastTemplateType_ToastImageAndText02, - ImageAndText03 = ToastTemplateType::ToastTemplateType_ToastImageAndText03, - ImageAndText04 = ToastTemplateType::ToastTemplateType_ToastImageAndText04, - Text01 = ToastTemplateType::ToastTemplateType_ToastText01, - Text02 = ToastTemplateType::ToastTemplateType_ToastText02, - Text03 = ToastTemplateType::ToastTemplateType_ToastText03, - Text04 = ToastTemplateType::ToastTemplateType_ToastText04 + enum class Scenario : int32_t { Default, Alarm, IncomingCall, Reminder }; + enum class Duration : int32_t { System, Short, Long }; + enum class AudioOption : int32_t { Default, Silent, Loop }; + enum class TextField : int32_t { FirstLine, SecondLine, ThirdLine }; + + enum class WinToastTemplateType : int32_t { + ImageAndText01 = ToastTemplateType_ToastImageAndText01, + ImageAndText02 = ToastTemplateType_ToastImageAndText02, + ImageAndText03 = ToastTemplateType_ToastImageAndText03, + ImageAndText04 = ToastTemplateType_ToastImageAndText04, + Text01 = ToastTemplateType_ToastText01, + Text02 = ToastTemplateType_ToastText02, + Text03 = ToastTemplateType_ToastText03, + Text04 = ToastTemplateType_ToastText04 }; - enum AudioSystemFile { + enum class AudioSystemFile : int32_t { DefaultSound, IM, Mail, @@ -117,7 +116,7 @@ namespace WinToastLib { Call10, }; - enum CropHint { + enum class CropHint : int32_t { Square, Circle, }; @@ -132,9 +131,9 @@ namespace WinToastLib { void setAttributionText(_In_ std::wstring const& attributionText); void setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint = CropHint::Square); void setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage = false); - void setAudioPath(_In_ WinToastTemplate::AudioSystemFile audio); + void setAudioPath(_In_ AudioSystemFile audio); void setAudioPath(_In_ std::wstring const& audioPath); - void setAudioOption(_In_ WinToastTemplate::AudioOption audioOption); + void setAudioOption(_In_ AudioOption audioOption); void setDuration(_In_ Duration duration); void setExpiration(_In_ INT64 millisecondsFromNow); void setScenario(_In_ Scenario scenario); @@ -155,7 +154,7 @@ namespace WinToastLib { std::wstring const& scenario() const; INT64 expiration() const; WinToastTemplateType type() const; - WinToastTemplate::AudioOption audioOption() const; + AudioOption audioOption() const; Duration duration() const; bool isToastGeneric() const; bool isInlineHeroImage() const; @@ -174,7 +173,7 @@ namespace WinToastLib { std::wstring _attributionText{}; std::wstring _scenario{L"Default"}; INT64 _expiration{0}; - AudioOption _audioOption{WinToastTemplate::AudioOption::Default}; + AudioOption _audioOption{AudioOption::Default}; WinToastTemplateType _type{WinToastTemplateType::Text01}; Duration _duration{Duration::System}; CropHint _cropHint{CropHint::Square}; @@ -182,8 +181,8 @@ namespace WinToastLib { class WinToast { public: - enum WinToastError { - NoError = 0, + enum class WinToastError : int32_t { + NoError, NotInitialized, SystemNotSupported, ShellLinkNotCreated, @@ -194,7 +193,7 @@ namespace WinToastLib { UnknownError }; - enum ShortcutResult { + enum class ShortcutResult : int32_t { SHORTCUT_UNCHANGED = 0, SHORTCUT_WAS_CHANGED = 1, SHORTCUT_WAS_CREATED = 2, @@ -205,16 +204,16 @@ namespace WinToastLib { SHORTCUT_CREATE_FAILED = -4 }; - enum ShortcutPolicy { + enum class ShortcutPolicy : int32_t { /* Don't check, create, or modify a shortcut. */ - SHORTCUT_POLICY_IGNORE = 0, + SHORTCUT_POLICY_IGNORE, /* Require a shortcut with matching AUMI, don't create or modify an existing one. */ - SHORTCUT_POLICY_REQUIRE_NO_CREATE = 1, + SHORTCUT_POLICY_REQUIRE_NO_CREATE, /* Require a shortcut with matching AUMI, create if missing, modify if not matching. This is the default. */ - SHORTCUT_POLICY_REQUIRE_CREATE = 2, + SHORTCUT_POLICY_REQUIRE_CREATE, }; - WinToast(void); + WinToast(); virtual ~WinToast(); static WinToast* instance(); static bool isCompatible(); @@ -230,7 +229,7 @@ namespace WinToastLib { virtual INT64 showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, _Out_opt_ WinToastError* error = nullptr); virtual void clear(); - virtual enum ShortcutResult createShortcut(); + virtual ShortcutResult createShortcut(); std::wstring const& appName() const; std::wstring const& appUserModelId() const; @@ -240,7 +239,7 @@ namespace WinToastLib { protected: struct NotifyData { - NotifyData() {}; + NotifyData() {} NotifyData(_In_ ComPtr notify, _In_ EventRegistrationToken activatedToken, _In_ EventRegistrationToken dismissedToken, _In_ EventRegistrationToken failedToken) : _notify(notify), _activatedToken(activatedToken), _dismissedToken(dismissedToken), _failedToken(failedToken) {} @@ -291,7 +290,7 @@ namespace WinToastLib { bool _isInitialized{false}; bool _hasCoInitialized{false}; - ShortcutPolicy _shortcutPolicy{SHORTCUT_POLICY_REQUIRE_CREATE}; + ShortcutPolicy _shortcutPolicy{ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE}; std::wstring _appName{}; std::wstring _aumi{}; std::map _buffer{}; diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 6fc08de..ab2a5ff 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -523,15 +523,15 @@ std::wstring const& WinToast::strerror(WinToastError error) { return iter->second; } -enum WinToast::ShortcutResult WinToast::createShortcut() { +WinToast::ShortcutResult WinToast::createShortcut() { if (_aumi.empty() || _appName.empty()) { DEBUG_MSG(L"Error: App User Model Id or Appname is empty!"); - return SHORTCUT_MISSING_PARAMETERS; + return ShortcutResult::SHORTCUT_MISSING_PARAMETERS; } if (!isCompatible()) { DEBUG_MSG(L"Your OS is not compatible with this library! =("); - return SHORTCUT_INCOMPATIBLE_OS; + return ShortcutResult::SHORTCUT_INCOMPATIBLE_OS; } if (!_hasCoInitialized) { @@ -539,7 +539,7 @@ enum WinToast::ShortcutResult WinToast::createShortcut() { if (initHr != RPC_E_CHANGED_MODE) { if (FAILED(initHr) && initHr != S_FALSE) { DEBUG_MSG(L"Error on COM library initialization!"); - return SHORTCUT_COM_INIT_FAILURE; + return ShortcutResult::SHORTCUT_COM_INIT_FAILURE; } else { _hasCoInitialized = true; } @@ -549,11 +549,11 @@ enum WinToast::ShortcutResult WinToast::createShortcut() { bool wasChanged; HRESULT hr = validateShellLinkHelper(wasChanged); if (SUCCEEDED(hr)) { - return wasChanged ? SHORTCUT_WAS_CHANGED : SHORTCUT_UNCHANGED; + return wasChanged ? ShortcutResult::SHORTCUT_WAS_CHANGED : ShortcutResult::SHORTCUT_UNCHANGED; } hr = createShellLinkHelper(); - return SUCCEEDED(hr) ? SHORTCUT_WAS_CREATED : SHORTCUT_CREATE_FAILED; + return SUCCEEDED(hr) ? ShortcutResult::SHORTCUT_WAS_CREATED : ShortcutResult::SHORTCUT_CREATE_FAILED; } bool WinToast::initialize(_Out_opt_ WinToastError* error) { @@ -572,8 +572,8 @@ bool WinToast::initialize(_Out_opt_ WinToastError* error) { return false; } - if (_shortcutPolicy != SHORTCUT_POLICY_IGNORE) { - if (createShortcut() < 0) { + if (_shortcutPolicy != ShortcutPolicy::SHORTCUT_POLICY_IGNORE) { + if (createShortcut() < ShortcutResult::SHORTCUT_UNCHANGED) { setError(error, WinToastError::ShellLinkNotCreated); DEBUG_MSG(L"Error while attaching the AUMI to the current proccess =("); return false; @@ -636,7 +636,7 @@ HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { hr = DllImporter::PropVariantToString(appIdPropVar, AUMI, MAX_PATH); wasChanged = false; if (FAILED(hr) || _aumi != AUMI) { - if (_shortcutPolicy == SHORTCUT_POLICY_REQUIRE_CREATE) { + if (_shortcutPolicy == ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE) { // AUMI Changed for the same app, let's update the current value! =) wasChanged = true; PropVariantClear(&appIdPropVar); @@ -665,7 +665,7 @@ HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { } HRESULT WinToast::createShellLinkHelper() { - if (_shortcutPolicy != SHORTCUT_POLICY_REQUIRE_CREATE) { + if (_shortcutPolicy != ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE) { return E_FAIL; } @@ -1278,14 +1278,14 @@ void WinToast::setError(_Out_opt_ WinToastError* error, _In_ WinToastError value WinToastTemplate::WinToastTemplate(_In_ WinToastTemplateType type) : _type(type) { constexpr static std::size_t TextFieldsCount[] = {1, 2, 2, 3, 1, 2, 2, 3}; - _textFields = std::vector(TextFieldsCount[type], L""); + _textFields = std::vector(TextFieldsCount[static_cast(type)], L""); } WinToastTemplate::~WinToastTemplate() { _textFields.clear(); } -void WinToastTemplate::setTextField(_In_ std::wstring const& txt, _In_ WinToastTemplate::TextField pos) { +void WinToastTemplate::setTextField(_In_ std::wstring const& txt, _In_ TextField pos) { auto const position = static_cast(pos); if (position >= _textFields.size()) { DEBUG_MSG("The selected template type supports only " << _textFields.size() << " text lines"); @@ -1342,20 +1342,20 @@ void WinToastTemplate::setAudioPath(_In_ AudioSystemFile file) { _audioPath = iter->second; } -void WinToastTemplate::setAudioOption(_In_ WinToastTemplate::AudioOption audioOption) { +void WinToastTemplate::setAudioOption(_In_ AudioOption audioOption) { _audioOption = audioOption; } void WinToastTemplate::setFirstLine(_In_ std::wstring const& text) { - setTextField(text, WinToastTemplate::FirstLine); + setTextField(text, TextField::FirstLine); } void WinToastTemplate::setSecondLine(_In_ std::wstring const& text) { - setTextField(text, WinToastTemplate::SecondLine); + setTextField(text, TextField::SecondLine); } void WinToastTemplate::setThirdLine(_In_ std::wstring const& text) { - setTextField(text, WinToastTemplate::ThirdLine); + setTextField(text, TextField::ThirdLine); } void WinToastTemplate::setDuration(_In_ Duration duration) { @@ -1463,7 +1463,7 @@ WinToastTemplate::Duration WinToastTemplate::duration() const { } bool WinToastTemplate::isToastGeneric() const { - return hasHeroImage() || _cropHint == WinToastTemplate::Circle; + return hasHeroImage() || _cropHint == CropHint::Circle; } bool WinToastTemplate::isInlineHeroImage() const { From bdad5b192caa93676ef7c4bc81392af8b0610441 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 02:55:16 +0200 Subject: [PATCH 03/19] Remove redundant noop FAR modifiers on function pointers --- src/wintoastlib.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index ab2a5ff..f581cfe 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -66,15 +66,15 @@ namespace DllImporter { return (func != nullptr) ? S_OK : E_FAIL; } - typedef HRESULT(FAR STDAPICALLTYPE* f_SetCurrentProcessExplicitAppUserModelID)(__in PCWSTR AppID); - typedef HRESULT(FAR STDAPICALLTYPE* f_PropVariantToString)(_In_ REFPROPVARIANT propvar, _Out_writes_(cch) PWSTR psz, _In_ UINT cch); - typedef HRESULT(FAR STDAPICALLTYPE* f_RoGetActivationFactory)(_In_ HSTRING activatableClassId, _In_ REFIID iid, + typedef HRESULT(STDAPICALLTYPE* f_SetCurrentProcessExplicitAppUserModelID)(__in PCWSTR AppID); + typedef HRESULT(STDAPICALLTYPE* f_PropVariantToString)(_In_ REFPROPVARIANT propvar, _Out_writes_(cch) PWSTR psz, _In_ UINT cch); + typedef HRESULT(STDAPICALLTYPE* f_RoGetActivationFactory)(_In_ HSTRING activatableClassId, _In_ REFIID iid, _COM_Outptr_ void** factory); - typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsCreateStringReference)(_In_reads_opt_(length + 1) PCWSTR sourceString, UINT32 length, + typedef HRESULT(STDAPICALLTYPE* f_WindowsCreateStringReference)(_In_reads_opt_(length + 1) PCWSTR sourceString, UINT32 length, _Out_ HSTRING_HEADER* hstringHeader, _Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string); - typedef PCWSTR(FAR STDAPICALLTYPE* f_WindowsGetStringRawBuffer)(_In_ HSTRING string, _Out_opt_ UINT32* length); - typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsDeleteString)(_In_opt_ HSTRING string); + typedef PCWSTR(STDAPICALLTYPE* f_WindowsGetStringRawBuffer)(_In_ HSTRING string, _Out_opt_ UINT32* length); + typedef HRESULT(STDAPICALLTYPE* f_WindowsDeleteString)(_In_opt_ HSTRING string); static f_SetCurrentProcessExplicitAppUserModelID SetCurrentProcessExplicitAppUserModelID; static f_PropVariantToString PropVariantToString; From c1ff224bd4893048ff86a144b5f0f460db609de9 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 02:56:57 +0200 Subject: [PATCH 04/19] Move top-level using namespace directives in API header into WinToastLib namespace to prevent global scope pollution --- include/wintoastlib.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index cd90728..73db7a3 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -44,13 +44,13 @@ #include #include -using namespace Microsoft::WRL; -using namespace ABI::Windows::Data::Xml::Dom; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::UI::Notifications; -using namespace Windows::Foundation; - namespace WinToastLib { + using namespace Microsoft::WRL; + using namespace ABI::Windows::Data::Xml::Dom; + using namespace ABI::Windows::Foundation; + using namespace ABI::Windows::UI::Notifications; + using namespace Windows::Foundation; + void setDebugOutputEnabled(bool enabled); class IWinToastHandler { From d546c2292ed9c24cccf7740fe679604d38530137 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 02:59:41 +0200 Subject: [PATCH 05/19] Remove redundant static casts --- src/wintoastlib.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index f581cfe..6940960 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -119,7 +119,7 @@ class WinToastStringWrapper { WinToastStringWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef, length, &_header, &_hstring); if (!SUCCEEDED(hr)) { - RaiseException(static_cast(STATUS_INVALID_PARAMETER), 0, 0, nullptr); + RaiseException(STATUS_INVALID_PARAMETER, 0, 0, nullptr); } } @@ -127,7 +127,7 @@ class WinToastStringWrapper { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef.c_str(), static_cast(stringRef.length()), &_header, &_hstring); if (FAILED(hr)) { - RaiseException(static_cast(STATUS_INVALID_PARAMETER), 0, 0, nullptr); + RaiseException(STATUS_INVALID_PARAMETER, 0, 0, nullptr); } } @@ -347,7 +347,7 @@ namespace Util { } if (arguments && *arguments) { - eventHandler->toastActivated(static_cast(wcstol(arguments, nullptr, 10))); + eventHandler->toastActivated(wcstol(arguments, nullptr, 10)); DllImporter::WindowsDeleteString(argumentsHandle); markAsReadyForDeletionFunc(); return S_OK; From 767ceea4a119e6824dcf48572df72002b0c625fc Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 03:01:07 +0200 Subject: [PATCH 06/19] Check for WIN32_LEAN_AND_MEAN in API header and define it if not already defined --- include/wintoastlib.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index 73db7a3..e1cdca8 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -24,6 +24,10 @@ #ifndef WINTOASTLIB_H #define WINTOASTLIB_H +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif //WIN32_LEAN_AND_MEAN + #include #include #include From d324ffc682b5e07e1cd2cf0cf00f776613c81e2e Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 03:06:15 +0200 Subject: [PATCH 07/19] Sort all includes and move ones only relevant to the implementation into cpp file --- include/wintoastlib.h | 19 ++++--------------- src/wintoastlib.cpp | 12 +++++++++++- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index e1cdca8..f47d0cc 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -28,25 +28,14 @@ #define WIN32_LEAN_AND_MEAN #endif //WIN32_LEAN_AND_MEAN +#include +#include +#include + #include -#include -#include -#include -#include #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include namespace WinToastLib { using namespace Microsoft::WRL; diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 6940960..420db2a 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -24,10 +24,20 @@ #include "wintoastlib.h" #include -#include #include #include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" #define DEFAULT_LINK_FORMAT L".lnk" From 5b3632c66f81ba06a74daff6a35f2eaf7e24d991 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 25 Jul 2025 03:17:20 +0200 Subject: [PATCH 08/19] Bump C++ standard to 17 for string_view and improved constexpr as that's fully support starting with Windows 8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17df1d5..f83ffca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.4...3.27) project(wintoastlib VERSION 1.3.2 LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) From ff0895704c6ee0ed7a42f52626aae70b2bdbdbfe Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sat, 26 Jul 2025 23:40:23 +0200 Subject: [PATCH 09/19] Rewrite defaultExecutablePath, defaultShellLinksDirectory and defaultShellLinkPath to use std::optional and std::filesystem::path --- src/wintoastlib.cpp | 101 +++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 420db2a..66448d5 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -39,9 +43,9 @@ #include #include -#define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" -#define DEFAULT_LINK_FORMAT L".lnk" -#define STATUS_SUCCESS (0x00000000) +constexpr std::wstring_view DEFAULT_SHELL_LINKS_PATH = L"\\Microsoft\\Windows\\Start Menu\\Programs\\"; +constexpr std::wstring_view DEFAULT_LINK_FORMAT = L".lnk"; +constexpr NTSTATUS STATUS_SUCCESS = 0x00000000; #ifdef NDEBUG static bool DebugOutputEnabled = false; @@ -94,12 +98,12 @@ namespace DllImporter { static f_WindowsDeleteString WindowsDeleteString; template - __inline _Check_return_ HRESULT _1_GetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ T** factory) { + _Check_return_ HRESULT _1_GetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ T** factory) { return RoGetActivationFactory(activatableClassId, IID_INS_ARGS(factory)); } template - inline HRESULT Wrap_GetActivationFactory(_In_ HSTRING activatableClassId, _Inout_ Details::ComPtrRef factory) noexcept { + HRESULT Wrap_GetActivationFactory(_In_ HSTRING activatableClassId, _Inout_ Details::ComPtrRef factory) noexcept { return _1_GetActivationFactory(activatableClassId, factory.ReleaseAndGetAddressOf()); } @@ -234,42 +238,36 @@ namespace Util { return rovi; } - inline HRESULT defaultExecutablePath(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { - DWORD written = GetModuleFileNameExW(GetCurrentProcess(), nullptr, path, nSize); - DEBUG_MSG("Default executable path: " << path); - return (written > 0) ? S_OK : E_FAIL; - } - - inline HRESULT defaultShellLinksDirectory(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { - DWORD written = GetEnvironmentVariableW(L"APPDATA", path, nSize); - HRESULT hr = written > 0 ? S_OK : E_INVALIDARG; - if (SUCCEEDED(hr)) { - errno_t result = wcscat_s(path, nSize, DEFAULT_SHELL_LINKS_PATH); - hr = (result == 0) ? S_OK : E_INVALIDARG; - DEBUG_MSG("Default shell link path: " << path); + inline std::optional defaultExecutablePath() { + std::array buffer; + const auto written = GetModuleFileNameExW(GetCurrentProcess(), nullptr, buffer.data(), MAX_PATH); + if (written <= 0) { + return std::nullopt; } - return hr; + std::wstring path{buffer.data(), written}; + DEBUG_MSG("Default executable path: " << path); + return std::filesystem::path{std::move(path)}; } - inline HRESULT defaultShellLinkPath(_In_ std::wstring const& appname, _In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { - HRESULT hr = defaultShellLinksDirectory(path, nSize); - if (SUCCEEDED(hr)) { - std::wstring const appLink(appname + DEFAULT_LINK_FORMAT); - errno_t result = wcscat_s(path, nSize, appLink.c_str()); - hr = (result == 0) ? S_OK : E_INVALIDARG; - DEBUG_MSG("Default shell link file path: " << path); + inline std::optional defaultShellLinksDirectory() { + std::array buffer; + const auto written = GetEnvironmentVariableW(L"APPDATA", buffer.data(), MAX_PATH); + if (written <= 0) { + return std::nullopt; } - return hr; + std::wstring path{buffer.data(), written}; + DEBUG_MSG("Default shell link path: " << path); + return std::filesystem::path{std::move(path)}; } - inline std::wstring parentDirectory(WCHAR* path, DWORD size) { - size_t lastSeparator = 0; - for (size_t i = 0; i < size; i++) { - if (path[i] == L'\\' || path[i] == L'/') { - lastSeparator = i; - } + inline std::optional defaultShellLinkPath(const std::wstring& appname) { + const auto path = defaultShellLinksDirectory(); + if (!path) { + return std::nullopt; } - return {path, lastSeparator}; + std::wstringstream appLink; + appLink << appname << DEFAULT_LINK_FORMAT; + return *path / appLink.str(); } inline PCWSTR AsString(_In_ ComPtr& xmlDocument) { @@ -302,7 +300,7 @@ namespace Util { } template - inline HRESULT setEventHandlers(_In_ IToastNotification* notification, _In_ std::shared_ptr eventHandler, + HRESULT setEventHandlers(_In_ IToastNotification* notification, _In_ std::shared_ptr eventHandler, _In_ INT64 expirationTime, _Out_ EventRegistrationToken& activatedToken, _Out_ EventRegistrationToken& dismissedToken, _Out_ EventRegistrationToken& failedToken, _In_ FunctorT&& markAsReadyForDeletionFunc) { @@ -613,12 +611,14 @@ std::wstring const& WinToast::appUserModelId() const { } HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { - WCHAR path[MAX_PATH] = {L'\0'}; - Util::defaultShellLinkPath(_appName, path); + const auto path = Util::defaultShellLinkPath(_appName); + if (!path) { + return E_FAIL; + } // Check if the file exist - DWORD attr = GetFileAttributesW(path); + const auto attr = GetFileAttributesW(path->c_str()); if (attr >= 0xFFFFFFF) { - DEBUG_MSG("Error, shell link not found. Try to create a new one in: " << path); + DEBUG_MSG("Error, shell link not found. Try to create a new one in: " << path->wstring()); return E_FAIL; } @@ -634,7 +634,7 @@ HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { ComPtr persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { - hr = persistFile->Load(path, STGM_READWRITE); + hr = persistFile->Load(path->c_str(), STGM_READWRITE); if (SUCCEEDED(hr)) { ComPtr propertyStore; hr = shellLink.As(&propertyStore); @@ -656,7 +656,7 @@ HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr) && SUCCEEDED(persistFile->IsDirty())) { - hr = persistFile->Save(path, TRUE); + hr = persistFile->Save(path->c_str(), TRUE); } } } @@ -678,16 +678,19 @@ HRESULT WinToast::createShellLinkHelper() { if (_shortcutPolicy != ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE) { return E_FAIL; } - - WCHAR exePath[MAX_PATH]{L'\0'}; - WCHAR slPath[MAX_PATH]{L'\0'}; - Util::defaultShellLinkPath(_appName, slPath); - Util::defaultExecutablePath(exePath); - std::wstring exeDir = Util::parentDirectory(exePath, sizeof(exePath) / sizeof(exePath[0])); + const auto slPath = Util::defaultShellLinkPath(_appName); + if (!slPath) { + return E_FAIL; + } + const auto exePath = Util::defaultExecutablePath(); + if (!exePath) { + return E_FAIL; + } + const auto exeDir = exePath->parent_path(); ComPtr shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { - hr = shellLink->SetPath(exePath); + hr = shellLink->SetPath(exePath->c_str()); if (SUCCEEDED(hr)) { hr = shellLink->SetArguments(L""); if (SUCCEEDED(hr)) { @@ -706,7 +709,7 @@ HRESULT WinToast::createShellLinkHelper() { ComPtr persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { - hr = persistFile->Save(slPath, TRUE); + hr = persistFile->Save(slPath->c_str(), TRUE); } } } From 8852def0d03f52d3d8a11f8cef7889a4dca7f9e5 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sat, 26 Jul 2025 23:59:30 +0200 Subject: [PATCH 10/19] Introduce WinToast::ThreadingMode enum --- include/wintoastlib.h | 11 ++++++++++- src/wintoastlib.cpp | 9 ++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index f47d0cc..e0507e9 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -206,6 +207,13 @@ namespace WinToastLib { SHORTCUT_POLICY_REQUIRE_CREATE, }; + enum class ThreadingMode : int32_t { + /* Don't synchronize the internal buffer and initialize COM for single-threaded use. */ + SINGLE_THREADED, + /* Synchronize the internal buffer and initialize COM for multithreaded use. */ + MULTI_THREADED + }; + WinToast(); virtual ~WinToast(); static WinToast* instance(); @@ -216,7 +224,8 @@ namespace WinToastLib { _In_ std::wstring const& subProduct = std::wstring(), _In_ std::wstring const& versionInformation = std::wstring()); static std::wstring const& strerror(_In_ WinToastError error); - virtual bool initialize(_Out_opt_ WinToastError* error = nullptr); + virtual bool initialize(_Out_opt_ WinToastError* error = nullptr, + _In_opt_ ThreadingMode threadingMode = ThreadingMode::MULTI_THREADED); virtual bool isInitialized() const; virtual bool hideToast(_In_ INT64 id); virtual INT64 showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 66448d5..ea37ff5 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -454,7 +454,7 @@ WinToast* WinToast::instance() { return &instance; } -WinToast::WinToast() : _isInitialized(false), _hasCoInitialized(false) { +WinToast::WinToast() { if (!isCompatible()) { DEBUG_MSG(L"Warning: Your system is not compatible with this library "); } @@ -462,7 +462,6 @@ WinToast::WinToast() : _isInitialized(false), _hasCoInitialized(false) { WinToast::~WinToast() { clear(); - if (_hasCoInitialized) { CoUninitialize(); } @@ -488,12 +487,12 @@ bool WinToast::isCompatible() { (DllImporter::WindowsDeleteString == nullptr)); } -bool WinToastLib::WinToast::isSupportingModernFeatures() { +bool WinToast::isSupportingModernFeatures() { constexpr auto MinimumSupportedVersion = 6; return Util::getRealOSVersion().dwMajorVersion > MinimumSupportedVersion; } -bool WinToastLib::WinToast::isWin10AnniversaryOrHigher() { +bool WinToast::isWin10AnniversaryOrHigher() { return Util::getRealOSVersion().dwBuildNumber >= 14393; } @@ -564,7 +563,7 @@ WinToast::ShortcutResult WinToast::createShortcut() { return SUCCEEDED(hr) ? ShortcutResult::SHORTCUT_WAS_CREATED : ShortcutResult::SHORTCUT_CREATE_FAILED; } -bool WinToast::initialize(_Out_opt_ WinToastError* error) { +bool WinToast::initialize(_Out_opt_ WinToastError* error, _In_opt_ ThreadingMode threadingMode) { _isInitialized = false; setError(error, WinToastError::NoError); From 51995f596262715313b2edef82512088de481669 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 00:21:02 +0200 Subject: [PATCH 11/19] Refactor out Windows specific includes into Platform.h, refactor out IWinToastHandler into its own header Refactor out Windows specific includes into Platform.h, refactor out IWinToastHandler into its own header --- include/IWinToastHandler.h | 50 ++++++++++++++++++++++++++++++++++++++ include/Platform.h | 44 +++++++++++++++++++++++++++++++++ include/wintoastlib.h | 33 ++----------------------- 3 files changed, 96 insertions(+), 31 deletions(-) create mode 100644 include/IWinToastHandler.h create mode 100644 include/Platform.h diff --git a/include/IWinToastHandler.h b/include/IWinToastHandler.h new file mode 100644 index 0000000..55be65c --- /dev/null +++ b/include/IWinToastHandler.h @@ -0,0 +1,50 @@ +/** +* MIT License + * + * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef IWINTOASTHANDLER_H +#define IWINTOASTHANDLER_H + +#include + +#include "Platform.h" + +namespace WinToastLib { + using namespace ABI::Windows::UI::Notifications; + + struct IWinToastHandler { + enum class WinToastDismissalReason : int32_t { + UserCanceled = ToastDismissalReason_UserCanceled, + ApplicationHidden = ToastDismissalReason_ApplicationHidden, + TimedOut = ToastDismissalReason_TimedOut + }; + + virtual ~IWinToastHandler() = default; + virtual void toastActivated() const = 0; + virtual void toastActivated(int actionIndex) const = 0; + virtual void toastActivated(std::wstring response) const = 0; + virtual void toastDismissed(WinToastDismissalReason state) const = 0; + virtual void toastFailed() const = 0; + }; +} + +#endif //IWINTOASTHANDLER_H \ No newline at end of file diff --git a/include/Platform.h b/include/Platform.h new file mode 100644 index 0000000..07eb92f --- /dev/null +++ b/include/Platform.h @@ -0,0 +1,44 @@ +/** + * MIT License + * + * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif //WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +namespace WinToastLib { + using namespace Microsoft::WRL; + using namespace ABI::Windows::Data::Xml::Dom; + using namespace ABI::Windows::Foundation; + using namespace ABI::Windows::UI::Notifications; + using namespace Windows::Foundation; +} + +#endif //PLATFORM_H \ No newline at end of file diff --git a/include/wintoastlib.h b/include/wintoastlib.h index e0507e9..8136c15 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -24,45 +24,16 @@ #ifndef WINTOASTLIB_H #define WINTOASTLIB_H -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif //WIN32_LEAN_AND_MEAN - #include #include #include -#include -#include -#include -#include -#include +#include "Platform.h" +#include "IWinToastHandler.h" namespace WinToastLib { - using namespace Microsoft::WRL; - using namespace ABI::Windows::Data::Xml::Dom; - using namespace ABI::Windows::Foundation; - using namespace ABI::Windows::UI::Notifications; - using namespace Windows::Foundation; - void setDebugOutputEnabled(bool enabled); - class IWinToastHandler { - public: - enum class WinToastDismissalReason : int32_t { - UserCanceled = ToastDismissalReason_UserCanceled, - ApplicationHidden = ToastDismissalReason_ApplicationHidden, - TimedOut = ToastDismissalReason_TimedOut - }; - - virtual ~IWinToastHandler() = default; - virtual void toastActivated() const = 0; - virtual void toastActivated(int actionIndex) const = 0; - virtual void toastActivated(std::wstring response) const = 0; - virtual void toastDismissed(WinToastDismissalReason state) const = 0; - virtual void toastFailed() const = 0; - }; - class WinToastTemplate { public: enum class Scenario : int32_t { Default, Alarm, IncomingCall, Reminder }; From dce26db4703b3a31f21a6c3ff5e5b268705a8fdf Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 00:24:36 +0200 Subject: [PATCH 12/19] Use file(GLOB_RECURSE) to find headers and sources automatically --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f83ffca..3ac88b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ option(WINTOASTLIB_BUILD_EXAMPLES "Compile the examples" ON) option(WINTOASTLIB_QT_ENABLED "Enable Qt support to build the GUI examples" OFF) set(WINTOASTLIB_LIBNAME WinToast) -set(WINTOASTLIB_HEADERS ${CMAKE_CURRENT_LIST_DIR}/include/wintoastlib.h) -set(WINTOASTLIB_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/wintoastlib.cpp) +file(GLOB_RECURSE WINTOASTLIB_HEADERS "${CMAKE_CURRENT_LIST_DIR}/include/*.h") +file(GLOB_RECURSE WINTOASTLIB_SOURCES "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp") add_library(${WINTOASTLIB_LIBNAME} STATIC ${WINTOASTLIB_HEADERS} ${WINTOASTLIB_SOURCES}) target_include_directories(${WINTOASTLIB_LIBNAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(${WINTOASTLIB_LIBNAME} psapi shlwapi user32) From a6d1c50235685c2bd641b369a84e1107e2277886 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 00:33:43 +0200 Subject: [PATCH 13/19] Update LICENSE.txt, add copyright profile for CLion --- .gitignore | 3 --- .idea/copyright/WinToast.xml | 7 +++++++ .idea/copyright/profiles_settings.xml | 3 +++ LICENSE.txt | 4 ++-- 4 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 .idea/copyright/WinToast.xml create mode 100644 .idea/copyright/profiles_settings.xml diff --git a/.gitignore b/.gitignore index 77487a9..242984e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,3 @@ enc_temp_folder/ build/ cmake-build-* CMakeLists.txt.user - -# CLion -.idea/ diff --git a/.idea/copyright/WinToast.xml b/.idea/copyright/WinToast.xml new file mode 100644 index 0000000..d16d728 --- /dev/null +++ b/.idea/copyright/WinToast.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..17ab555 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 0182078..7784ae9 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2016-2023 WinToast v1.3.0 - Mohammed Boujemaoui +Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file From 4b0c712f6b37d2cb2a2792e98b0705ddcc896487 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 00:34:00 +0200 Subject: [PATCH 14/19] Update copyright header in source files --- CMakeLists.txt | 2 +- include/IWinToastHandler.h | 57 +++++++++++++++++++------------------- include/Platform.h | 43 ++++++++++++++-------------- include/wintoastlib.h | 43 ++++++++++++++-------------- src/wintoastlib.cpp | 45 +++++++++++++++--------------- 5 files changed, 93 insertions(+), 97 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ac88b9..80c25c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.4...3.27) -project(wintoastlib VERSION 1.3.2 LANGUAGES CXX) +project(wintoastlib VERSION 2.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/include/IWinToastHandler.h b/include/IWinToastHandler.h index 55be65c..4971024 100644 --- a/include/IWinToastHandler.h +++ b/include/IWinToastHandler.h @@ -1,25 +1,24 @@ -/** -* MIT License - * - * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +// MIT License +// +// Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. #ifndef IWINTOASTHANDLER_H #define IWINTOASTHANDLER_H @@ -32,18 +31,18 @@ namespace WinToastLib { using namespace ABI::Windows::UI::Notifications; struct IWinToastHandler { - enum class WinToastDismissalReason : int32_t { + enum class DismissalReason : int32_t { UserCanceled = ToastDismissalReason_UserCanceled, ApplicationHidden = ToastDismissalReason_ApplicationHidden, TimedOut = ToastDismissalReason_TimedOut }; - virtual ~IWinToastHandler() = default; - virtual void toastActivated() const = 0; - virtual void toastActivated(int actionIndex) const = 0; - virtual void toastActivated(std::wstring response) const = 0; - virtual void toastDismissed(WinToastDismissalReason state) const = 0; - virtual void toastFailed() const = 0; + virtual ~IWinToastHandler() = default; + virtual void toastActivated() const = 0; + virtual void toastActivated(int actionIndex) const = 0; + virtual void toastActivated(std::wstring response) const = 0; + virtual void toastDismissed(DismissalReason state) const = 0; + virtual void toastFailed() const = 0; }; } diff --git a/include/Platform.h b/include/Platform.h index 07eb92f..259143c 100644 --- a/include/Platform.h +++ b/include/Platform.h @@ -1,25 +1,24 @@ -/** - * MIT License - * - * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +// MIT License +// +// Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. #ifndef PLATFORM_H #define PLATFORM_H diff --git a/include/wintoastlib.h b/include/wintoastlib.h index 8136c15..e57456f 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -1,25 +1,24 @@ -/** - * MIT License - * - * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +// MIT License +// +// Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. #ifndef WINTOASTLIB_H #define WINTOASTLIB_H diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index ea37ff5..d7d1ae0 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -1,25 +1,24 @@ -/** - * MIT License - * - * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ +// MIT License +// +// Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. #include "wintoastlib.h" @@ -380,7 +379,7 @@ namespace Util { InternalDateTime::Now() >= expirationTime) { reason = ToastDismissalReason_TimedOut; } - eventHandler->toastDismissed(static_cast(reason)); + eventHandler->toastDismissed(static_cast(reason)); } markAsReadyForDeletionFunc(); return S_OK; From 9b8838b96d9fc5dfa1c6d8451b491cbcef867467 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 01:01:26 +0200 Subject: [PATCH 15/19] Update examples --- examples/console-example/main.cpp | 16 ++++++------- examples/qt-gui-example/mainwindow.cpp | 33 ++++++++++++++------------ src/wintoastlib.cpp | 4 ++-- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/console-example/main.cpp b/examples/console-example/main.cpp index 1dbdaed..75c36d9 100644 --- a/examples/console-example/main.cpp +++ b/examples/console-example/main.cpp @@ -21,17 +21,17 @@ class CustomHandler : public IWinToastHandler { exit(0); } - void toastDismissed(WinToastDismissalReason state) const { + void toastDismissed(DismissalReason state) const { switch (state) { - case UserCanceled: + case DismissalReason::UserCanceled: std::wcout << L"The user dismissed this toast" << std::endl; exit(1); break; - case TimedOut: + case DismissalReason::TimedOut: std::wcout << L"The toast has timed out" << std::endl; exit(2); break; - case ApplicationHidden: + case DismissalReason::ApplicationHidden: std::wcout << L"The application hid the toast using ToastNotifier.hide()" << std::endl; exit(3); break; @@ -153,8 +153,8 @@ int wmain(int argc, LPWSTR* argv) { std::wcerr << L"--only-create-shortcut does not accept images/text/actions/expiration" << std::endl; return 9; } - enum WinToast::ShortcutResult result = WinToast::instance()->createShortcut(); - return result ? 16 + result : 0; + WinToast::ShortcutResult result = WinToast::instance()->createShortcut(); + return result != WinToast::ShortcutResult::SHORTCUT_UNCHANGED ? 16 + static_cast(result) : 0; } if (text.empty()) { @@ -166,8 +166,8 @@ int wmain(int argc, LPWSTR* argv) { return Results::InitializationFailure; } - WinToastTemplate templ(!imagePath.empty() ? WinToastTemplate::ImageAndText02 : WinToastTemplate::Text02); - templ.setTextField(text, WinToastTemplate::FirstLine); + WinToastTemplate templ(!imagePath.empty() ? WinToastTemplate::WinToastTemplateType::ImageAndText02 : WinToastTemplate::WinToastTemplateType::Text02); + templ.setTextField(text, WinToastTemplate::TextField::FirstLine); templ.setAudioOption(audioOption); templ.setAttributionText(attribute); templ.setImagePath(imagePath); diff --git a/examples/qt-gui-example/mainwindow.cpp b/examples/qt-gui-example/mainwindow.cpp index 58495b2..746039e 100644 --- a/examples/qt-gui-example/mainwindow.cpp +++ b/examples/qt-gui-example/mainwindow.cpp @@ -1,5 +1,8 @@ #include "mainwindow.h" #include "ui_mainwindow.h" +#include "wintoastlib.h" +#include "wintoastlib.h" + #include #include #include @@ -11,14 +14,14 @@ using namespace WinToastLib; MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); - ui->toastType->addItem("ImageAndText01", WinToastTemplate::ImageAndText01); - ui->toastType->addItem("ImageAndText02", WinToastTemplate::ImageAndText02); - ui->toastType->addItem("ImageAndText03", WinToastTemplate::ImageAndText03); - ui->toastType->addItem("ImageAndText04", WinToastTemplate::ImageAndText04); - ui->toastType->addItem("Text01", WinToastTemplate::Text01); - ui->toastType->addItem("Text02", WinToastTemplate::Text02); - ui->toastType->addItem("Text03", WinToastTemplate::Text03); - ui->toastType->addItem("Text04", WinToastTemplate::Text04); + ui->toastType->addItem("ImageAndText01", WinToastTemplate::WinToastTemplateType::ImageAndText01); + ui->toastType->addItem("ImageAndText02", WinToastTemplate::WinToastTemplateType::ImageAndText02); + ui->toastType->addItem("ImageAndText03", WinToastTemplate::WinToastTemplateType::ImageAndText03); + ui->toastType->addItem("ImageAndText04", WinToastTemplate::WinToastTemplateType::ImageAndText04); + ui->toastType->addItem("Text01", WinToastTemplate::WinToastTemplateType::Text01); + ui->toastType->addItem("Text02", WinToastTemplate::WinToastTemplateType::Text02); + ui->toastType->addItem("Text03", WinToastTemplate::WinToastTemplateType::Text03); + ui->toastType->addItem("Text04", WinToastTemplate::WinToastTemplateType::Text04); ui->audioMode->addItem("Default", WinToastTemplate::AudioOption::Default); ui->audioMode->addItem("Loop", WinToastTemplate::AudioOption::Loop); @@ -77,15 +80,15 @@ class CustomHandler : public IWinToastHandler { std::wcout << L"Error showing current toast" << std::endl; } - void toastDismissed(WinToastDismissalReason state) const { + void toastDismissed(DismissalReason state) const { switch (state) { - case UserCanceled: + case DismissalReason::UserCanceled: std::wcout << L"The user dismissed this toast" << std::endl; break; - case ApplicationHidden: + case DismissalReason::ApplicationHidden: std::wcout << L"The application hid the toast using ToastNotifier.hide()" << std::endl; break; - case TimedOut: + case DismissalReason::TimedOut: std::wcout << L"The toast has timed out" << std::endl; break; default: @@ -100,9 +103,9 @@ void MainWindow::on_showToast_clicked() { WinToastTemplate templ = WinToastTemplate(type); templ.setImagePath(ui->imagePath->text().toStdWString(), static_cast(ui->cropHint->currentData().toInt())); templ.setHeroImagePath(ui->heroPath->text().toStdWString(), ui->inlineHeroImage->isChecked()); - templ.setTextField(ui->firstLine->text().toStdWString(), WinToastTemplate::FirstLine); - templ.setTextField(ui->secondLine->text().toStdWString(), WinToastTemplate::SecondLine); - templ.setTextField(ui->thirdLine->text().toStdWString(), WinToastTemplate::ThirdLine); + templ.setTextField(ui->firstLine->text().toStdWString(), WinToastTemplate::TextField::FirstLine); + templ.setTextField(ui->secondLine->text().toStdWString(), WinToastTemplate::TextField::SecondLine); + templ.setTextField(ui->thirdLine->text().toStdWString(), WinToastTemplate::TextField::ThirdLine); templ.setExpiration(ui->spinBox->value() * 1000); templ.setAudioPath(static_cast(ui->audioSystemFile->currentData().toInt())); templ.setAudioOption(static_cast(ui->audioMode->currentData().toInt())); diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index d7d1ae0..dcf0f66 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -238,7 +238,7 @@ namespace Util { } inline std::optional defaultExecutablePath() { - std::array buffer; + std::array buffer{}; const auto written = GetModuleFileNameExW(GetCurrentProcess(), nullptr, buffer.data(), MAX_PATH); if (written <= 0) { return std::nullopt; @@ -249,7 +249,7 @@ namespace Util { } inline std::optional defaultShellLinksDirectory() { - std::array buffer; + std::array buffer{}; const auto written = GetEnvironmentVariableW(L"APPDATA", buffer.data(), MAX_PATH); if (written <= 0) { return std::nullopt; From a99fa5ec80e78307794affbf7dd28a43a6f68109 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Sun, 27 Jul 2025 01:14:31 +0200 Subject: [PATCH 16/19] Refactor out WinToastTemplate into its own header file --- examples/console-example/main.cpp | 5 +- examples/qt-gui-example/mainwindow.cpp | 18 ++-- include/WinToastTemplate.h | 143 +++++++++++++++++++++++++ include/wintoastlib.h | 114 +------------------- src/wintoastlib.cpp | 7 +- 5 files changed, 161 insertions(+), 126 deletions(-) create mode 100644 include/WinToastTemplate.h diff --git a/examples/console-example/main.cpp b/examples/console-example/main.cpp index 75c36d9..692a41c 100644 --- a/examples/console-example/main.cpp +++ b/examples/console-example/main.cpp @@ -1,6 +1,7 @@ #include "wintoastlib.h" + #include -#include +#include using namespace WinToastLib; @@ -166,7 +167,7 @@ int wmain(int argc, LPWSTR* argv) { return Results::InitializationFailure; } - WinToastTemplate templ(!imagePath.empty() ? WinToastTemplate::WinToastTemplateType::ImageAndText02 : WinToastTemplate::WinToastTemplateType::Text02); + WinToastTemplate templ(!imagePath.empty() ? WinToastTemplate::Type::ImageAndText02 : WinToastTemplate::Type::Text02); templ.setTextField(text, WinToastTemplate::TextField::FirstLine); templ.setAudioOption(audioOption); templ.setAttributionText(attribute); diff --git a/examples/qt-gui-example/mainwindow.cpp b/examples/qt-gui-example/mainwindow.cpp index 746039e..10a9c16 100644 --- a/examples/qt-gui-example/mainwindow.cpp +++ b/examples/qt-gui-example/mainwindow.cpp @@ -14,14 +14,14 @@ using namespace WinToastLib; MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); - ui->toastType->addItem("ImageAndText01", WinToastTemplate::WinToastTemplateType::ImageAndText01); - ui->toastType->addItem("ImageAndText02", WinToastTemplate::WinToastTemplateType::ImageAndText02); - ui->toastType->addItem("ImageAndText03", WinToastTemplate::WinToastTemplateType::ImageAndText03); - ui->toastType->addItem("ImageAndText04", WinToastTemplate::WinToastTemplateType::ImageAndText04); - ui->toastType->addItem("Text01", WinToastTemplate::WinToastTemplateType::Text01); - ui->toastType->addItem("Text02", WinToastTemplate::WinToastTemplateType::Text02); - ui->toastType->addItem("Text03", WinToastTemplate::WinToastTemplateType::Text03); - ui->toastType->addItem("Text04", WinToastTemplate::WinToastTemplateType::Text04); + ui->toastType->addItem("ImageAndText01", WinToastTemplate::Type::ImageAndText01); + ui->toastType->addItem("ImageAndText02", WinToastTemplate::Type::ImageAndText02); + ui->toastType->addItem("ImageAndText03", WinToastTemplate::Type::ImageAndText03); + ui->toastType->addItem("ImageAndText04", WinToastTemplate::Type::ImageAndText04); + ui->toastType->addItem("Text01", WinToastTemplate::Type::Text01); + ui->toastType->addItem("Text02", WinToastTemplate::Type::Text02); + ui->toastType->addItem("Text03", WinToastTemplate::Type::Text03); + ui->toastType->addItem("Text04", WinToastTemplate::Type::Text04); ui->audioMode->addItem("Default", WinToastTemplate::AudioOption::Default); ui->audioMode->addItem("Loop", WinToastTemplate::AudioOption::Loop); @@ -99,7 +99,7 @@ class CustomHandler : public IWinToastHandler { }; void MainWindow::on_showToast_clicked() { - auto const type = static_cast(ui->toastType->currentData().toInt()); + auto const type = static_cast(ui->toastType->currentData().toInt()); WinToastTemplate templ = WinToastTemplate(type); templ.setImagePath(ui->imagePath->text().toStdWString(), static_cast(ui->cropHint->currentData().toInt())); templ.setHeroImagePath(ui->heroPath->text().toStdWString(), ui->inlineHeroImage->isChecked()); diff --git a/include/WinToastTemplate.h b/include/WinToastTemplate.h new file mode 100644 index 0000000..ad3f8fc --- /dev/null +++ b/include/WinToastTemplate.h @@ -0,0 +1,143 @@ +// MIT License +// +// Copyright (C) 2016-2025 WinToast - Mohammed Boujemaoui +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef WINTOASTTEMPLATE_H +#define WINTOASTTEMPLATE_H + +#include +#include +#include + +#include "Platform.h" + +namespace WinToastLib { + struct WinToastTemplate final { + enum class Scenario : int32_t { Default, Alarm, IncomingCall, Reminder }; + enum class Duration : int32_t { System, Short, Long }; + enum class AudioOption : int32_t { Default, Silent, Loop }; + enum class TextField : int32_t { FirstLine, SecondLine, ThirdLine }; + + enum class Type : int32_t { + ImageAndText01 = ToastTemplateType_ToastImageAndText01, + ImageAndText02 = ToastTemplateType_ToastImageAndText02, + ImageAndText03 = ToastTemplateType_ToastImageAndText03, + ImageAndText04 = ToastTemplateType_ToastImageAndText04, + Text01 = ToastTemplateType_ToastText01, + Text02 = ToastTemplateType_ToastText02, + Text03 = ToastTemplateType_ToastText03, + Text04 = ToastTemplateType_ToastText04 + }; + + enum class AudioSystemFile : int32_t { + DefaultSound, + IM, + Mail, + Reminder, + SMS, + Alarm, + Alarm2, + Alarm3, + Alarm4, + Alarm5, + Alarm6, + Alarm7, + Alarm8, + Alarm9, + Alarm10, + Call, + Call1, + Call2, + Call3, + Call4, + Call5, + Call6, + Call7, + Call8, + Call9, + Call10, + }; + + enum class CropHint : int32_t { + Square, + Circle, + }; + + WinToastTemplate(_In_ Type type = Type::ImageAndText02); + ~WinToastTemplate(); + + void setFirstLine(_In_ std::wstring const& text); + void setSecondLine(_In_ std::wstring const& text); + void setThirdLine(_In_ std::wstring const& text); + void setTextField(_In_ std::wstring const& txt, _In_ TextField pos); + void setAttributionText(_In_ std::wstring const& attributionText); + void setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint = CropHint::Square); + void setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage = false); + void setAudioPath(_In_ AudioSystemFile audio); + void setAudioPath(_In_ std::wstring const& audioPath); + void setAudioOption(_In_ AudioOption audioOption); + void setDuration(_In_ Duration duration); + void setExpiration(_In_ INT64 millisecondsFromNow); + void setScenario(_In_ Scenario scenario); + void addAction(_In_ std::wstring const& label); + void addInput(); + + std::size_t textFieldsCount() const; + std::size_t actionsCount() const; + bool hasImage() const; + bool hasHeroImage() const; + std::vector const& textFields() const; + std::wstring const& textField(_In_ TextField pos) const; + std::wstring const& actionLabel(_In_ std::size_t pos) const; + std::wstring const& imagePath() const; + std::wstring const& heroImagePath() const; + std::wstring const& audioPath() const; + std::wstring const& attributionText() const; + std::wstring const& scenario() const; + INT64 expiration() const; + Type type() const; + AudioOption audioOption() const; + Duration duration() const; + bool isToastGeneric() const; + bool isInlineHeroImage() const; + bool isCropHintCircle() const; + bool isInput() const; + + private: + bool _hasInput{false}; + + std::vector _textFields{}; + std::vector _actions{}; + std::wstring _imagePath{}; + std::wstring _heroImagePath{}; + bool _inlineHeroImage{false}; + std::wstring _audioPath{}; + std::wstring _attributionText{}; + std::wstring _scenario{L"Default"}; + INT64 _expiration{0}; + AudioOption _audioOption{AudioOption::Default}; + Type _type{Type::Text01}; + Duration _duration{Duration::System}; + CropHint _cropHint{CropHint::Square}; + }; +} + +#endif //WINTOASTTEMPLATE_H \ No newline at end of file diff --git a/include/wintoastlib.h b/include/wintoastlib.h index e57456f..934e216 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -23,126 +23,16 @@ #ifndef WINTOASTLIB_H #define WINTOASTLIB_H -#include -#include #include +#include #include "Platform.h" #include "IWinToastHandler.h" +#include "WinToastTemplate.h" namespace WinToastLib { void setDebugOutputEnabled(bool enabled); - class WinToastTemplate { - public: - enum class Scenario : int32_t { Default, Alarm, IncomingCall, Reminder }; - enum class Duration : int32_t { System, Short, Long }; - enum class AudioOption : int32_t { Default, Silent, Loop }; - enum class TextField : int32_t { FirstLine, SecondLine, ThirdLine }; - - enum class WinToastTemplateType : int32_t { - ImageAndText01 = ToastTemplateType_ToastImageAndText01, - ImageAndText02 = ToastTemplateType_ToastImageAndText02, - ImageAndText03 = ToastTemplateType_ToastImageAndText03, - ImageAndText04 = ToastTemplateType_ToastImageAndText04, - Text01 = ToastTemplateType_ToastText01, - Text02 = ToastTemplateType_ToastText02, - Text03 = ToastTemplateType_ToastText03, - Text04 = ToastTemplateType_ToastText04 - }; - - enum class AudioSystemFile : int32_t { - DefaultSound, - IM, - Mail, - Reminder, - SMS, - Alarm, - Alarm2, - Alarm3, - Alarm4, - Alarm5, - Alarm6, - Alarm7, - Alarm8, - Alarm9, - Alarm10, - Call, - Call1, - Call2, - Call3, - Call4, - Call5, - Call6, - Call7, - Call8, - Call9, - Call10, - }; - - enum class CropHint : int32_t { - Square, - Circle, - }; - - WinToastTemplate(_In_ WinToastTemplateType type = WinToastTemplateType::ImageAndText02); - ~WinToastTemplate(); - - void setFirstLine(_In_ std::wstring const& text); - void setSecondLine(_In_ std::wstring const& text); - void setThirdLine(_In_ std::wstring const& text); - void setTextField(_In_ std::wstring const& txt, _In_ TextField pos); - void setAttributionText(_In_ std::wstring const& attributionText); - void setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint = CropHint::Square); - void setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage = false); - void setAudioPath(_In_ AudioSystemFile audio); - void setAudioPath(_In_ std::wstring const& audioPath); - void setAudioOption(_In_ AudioOption audioOption); - void setDuration(_In_ Duration duration); - void setExpiration(_In_ INT64 millisecondsFromNow); - void setScenario(_In_ Scenario scenario); - void addAction(_In_ std::wstring const& label); - void addInput(); - - std::size_t textFieldsCount() const; - std::size_t actionsCount() const; - bool hasImage() const; - bool hasHeroImage() const; - std::vector const& textFields() const; - std::wstring const& textField(_In_ TextField pos) const; - std::wstring const& actionLabel(_In_ std::size_t pos) const; - std::wstring const& imagePath() const; - std::wstring const& heroImagePath() const; - std::wstring const& audioPath() const; - std::wstring const& attributionText() const; - std::wstring const& scenario() const; - INT64 expiration() const; - WinToastTemplateType type() const; - AudioOption audioOption() const; - Duration duration() const; - bool isToastGeneric() const; - bool isInlineHeroImage() const; - bool isCropHintCircle() const; - bool isInput() const; - - private: - bool _hasInput{false}; - - std::vector _textFields{}; - std::vector _actions{}; - std::wstring _imagePath{}; - std::wstring _heroImagePath{}; - bool _inlineHeroImage{false}; - std::wstring _audioPath{}; - std::wstring _attributionText{}; - std::wstring _scenario{L"Default"}; - INT64 _expiration{0}; - AudioOption _audioOption{AudioOption::Default}; - WinToastTemplateType _type{WinToastTemplateType::Text01}; - Duration _duration{Duration::System}; - CropHint _cropHint{CropHint::Square}; - }; - class WinToast { public: enum class WinToastError : int32_t { diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index dcf0f66..390ecb9 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1287,7 +1288,7 @@ void WinToast::setError(_Out_opt_ WinToastError* error, _In_ WinToastError value } } -WinToastTemplate::WinToastTemplate(_In_ WinToastTemplateType type) : _type(type) { +WinToastTemplate::WinToastTemplate(_In_ Type type) : _type(type) { constexpr static std::size_t TextFieldsCount[] = {1, 2, 2, 3, 1, 2, 2, 3}; _textFields = std::vector(TextFieldsCount[static_cast(type)], L""); } @@ -1415,7 +1416,7 @@ std::size_t WinToastTemplate::actionsCount() const { } bool WinToastTemplate::hasImage() const { - return _type < WinToastTemplateType::Text01; + return _type < Type::Text01; } bool WinToastTemplate::hasHeroImage() const { @@ -1461,7 +1462,7 @@ INT64 WinToastTemplate::expiration() const { return _expiration; } -WinToastTemplate::WinToastTemplateType WinToastTemplate::type() const { +WinToastTemplate::Type WinToastTemplate::type() const { return _type; } From abe849c1cfc8232af2408945d3c24017c5d40496 Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Mon, 28 Jul 2025 05:07:13 +0200 Subject: [PATCH 17/19] Move COM initialiazation to initialize() function, use APARTMENT_THREADED to avoid JDK incompatibility issues due to JDK-8353140. Add nodiscard attributes, cleanup code further --- include/wintoastlib.h | 69 +++++++++++++++--------------------- src/wintoastlib.cpp | 82 +++++++++++++++++++++---------------------- 2 files changed, 69 insertions(+), 82 deletions(-) diff --git a/include/wintoastlib.h b/include/wintoastlib.h index 934e216..909a485 100644 --- a/include/wintoastlib.h +++ b/include/wintoastlib.h @@ -54,7 +54,6 @@ namespace WinToastLib { SHORTCUT_MISSING_PARAMETERS = -1, SHORTCUT_INCOMPATIBLE_OS = -2, - SHORTCUT_COM_INIT_FAILURE = -3, SHORTCUT_CREATE_FAILED = -4 }; @@ -67,34 +66,26 @@ namespace WinToastLib { SHORTCUT_POLICY_REQUIRE_CREATE, }; - enum class ThreadingMode : int32_t { - /* Don't synchronize the internal buffer and initialize COM for single-threaded use. */ - SINGLE_THREADED, - /* Synchronize the internal buffer and initialize COM for multithreaded use. */ - MULTI_THREADED - }; - WinToast(); virtual ~WinToast(); - static WinToast* instance(); - static bool isCompatible(); - static bool isSupportingModernFeatures(); - static bool isWin10AnniversaryOrHigher(); - static std::wstring configureAUMI(_In_ std::wstring const& companyName, _In_ std::wstring const& productName, + [[nodiscard]] static WinToast* instance(); + [[nodiscard]] static bool isCompatible(); + [[nodiscard]] static bool isSupportingModernFeatures(); + [[nodiscard]] static bool isWin10AnniversaryOrHigher(); + [[nodiscard]] static std::wstring configureAUMI(_In_ std::wstring const& companyName, _In_ std::wstring const& productName, _In_ std::wstring const& subProduct = std::wstring(), _In_ std::wstring const& versionInformation = std::wstring()); - static std::wstring const& strerror(_In_ WinToastError error); - virtual bool initialize(_Out_opt_ WinToastError* error = nullptr, - _In_opt_ ThreadingMode threadingMode = ThreadingMode::MULTI_THREADED); - virtual bool isInitialized() const; - virtual bool hideToast(_In_ INT64 id); - virtual INT64 showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, + [[nodiscard]] static std::wstring const& strerror(_In_ WinToastError error); + bool initialize(_Out_opt_ WinToastError* error = nullptr); + [[nodiscard]] bool isInitialized() const; + bool hideToast(_In_ INT64 id); + INT64 showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, _Out_opt_ WinToastError* error = nullptr); - virtual void clear(); - virtual ShortcutResult createShortcut(); + void clear(); + [[nodiscard]] ShortcutResult createShortcut(); - std::wstring const& appName() const; - std::wstring const& appUserModelId() const; + [[nodiscard]] std::wstring const& appName() const; + [[nodiscard]] std::wstring const& appUserModelId() const; void setAppUserModelId(_In_ std::wstring const& aumi); void setAppName(_In_ std::wstring const& appName); void setShortcutPolicy(_In_ ShortcutPolicy policy); @@ -133,11 +124,11 @@ namespace WinToastLib { _readyForDeletion = true; } - bool isReadyForDeletion() const { + [[nodiscard]] bool isReadyForDeletion() const { return _readyForDeletion; } - IToastNotification* notification() { + [[nodiscard]] IToastNotification* notification() { return _notify.Get(); } @@ -151,28 +142,26 @@ namespace WinToastLib { }; bool _isInitialized{false}; - bool _hasCoInitialized{false}; ShortcutPolicy _shortcutPolicy{ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE}; std::wstring _appName{}; std::wstring _aumi{}; std::map _buffer{}; void markAsReadyForDeletion(_In_ INT64 id); - HRESULT validateShellLinkHelper(_Out_ bool& wasChanged); - HRESULT createShellLinkHelper(); - HRESULT setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, bool isCropHintCircle); - HRESULT setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage); - HRESULT setBindToastGenericHelper(_In_ IXmlDocument* xml); - HRESULT - setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, + [[nodiscard]] HRESULT validateShellLinkHelper(_Out_ bool& wasChanged); + [[nodiscard]] HRESULT createShellLinkHelper(); + [[nodiscard]] HRESULT setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, bool isCropHintCircle); + [[nodiscard]] HRESULT setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage); + [[nodiscard]] HRESULT setBindToastGenericHelper(_In_ IXmlDocument* xml); + [[nodiscard]] HRESULT setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_opt_ WinToastTemplate::AudioOption option = WinToastTemplate::AudioOption::Default); - HRESULT setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos); - HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text); - HRESULT addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& action, _In_ std::wstring const& arguments); - HRESULT addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration); - HRESULT addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario); - HRESULT addInputHelper(_In_ IXmlDocument* xml); - ComPtr notifier(_In_ bool* succeded) const; + [[nodiscard]] HRESULT setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos); + [[nodiscard]] HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text); + [[nodiscard]] HRESULT addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& action, _In_ std::wstring const& arguments); + [[nodiscard]] HRESULT addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration); + [[nodiscard]] HRESULT addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario); + [[nodiscard]] HRESULT addInputHelper(_In_ IXmlDocument* xml); + [[nodiscard]] ComPtr notifier(_In_ bool* succeded) const; void setError(_Out_opt_ WinToastError* error, _In_ WinToastError value); }; } // namespace WinToastLib diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index 390ecb9..dd4e599 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -149,7 +149,7 @@ class WinToastStringWrapper { DllImporter::WindowsDeleteString(_hstring); } - inline HSTRING Get() const noexcept { + HSTRING Get() const noexcept { return _hstring; } @@ -403,7 +403,7 @@ namespace Util { } inline HRESULT addAttribute(_In_ IXmlDocument* xml, std::wstring const& name, IXmlNamedNodeMap* attributeMap) { - ComPtr srcAttribute; + ComPtr srcAttribute; HRESULT hr = xml->CreateAttribute(WinToastStringWrapper(name).Get(), &srcAttribute); if (SUCCEEDED(hr)) { ComPtr node; @@ -424,7 +424,7 @@ namespace Util { ComPtr root; hr = rootList->Item(0, &root); if (SUCCEEDED(hr)) { - ComPtr audioElement; + ComPtr audioElement; hr = xml->CreateElement(WinToastStringWrapper(element_name).Get(), &audioElement); if (SUCCEEDED(hr)) { ComPtr audioNodeTmp; @@ -450,19 +450,20 @@ namespace Util { } // namespace Util WinToast* WinToast::instance() { - thread_local static WinToast instance; + thread_local WinToast instance; return &instance; } WinToast::WinToast() { if (!isCompatible()) { - DEBUG_MSG(L"Warning: Your system is not compatible with this library "); + DEBUG_MSG(L"Warning: Your system is not compatible with this library"); + return; } } WinToast::~WinToast() { clear(); - if (_hasCoInitialized) { + if (_isInitialized) { CoUninitialize(); } } @@ -513,7 +514,7 @@ std::wstring WinToast::configureAUMI(_In_ std::wstring const& companyName, _In_ return aumi; } -std::wstring const& WinToast::strerror(WinToastError error) { +[[nodiscard]] std::wstring const& WinToast::strerror(WinToastError error) { static std::unordered_map const Labels = { {WinToastError::NoError, L"No error. The process was executed correctly" }, {WinToastError::NotInitialized, L"The library has not been initialized" }, @@ -530,7 +531,7 @@ std::wstring const& WinToast::strerror(WinToastError error) { return iter->second; } -WinToast::ShortcutResult WinToast::createShortcut() { +[[nodiscard]] WinToast::ShortcutResult WinToast::createShortcut() { if (_aumi.empty() || _appName.empty()) { DEBUG_MSG(L"Error: App User Model Id or Appname is empty!"); return ShortcutResult::SHORTCUT_MISSING_PARAMETERS; @@ -541,18 +542,6 @@ WinToast::ShortcutResult WinToast::createShortcut() { return ShortcutResult::SHORTCUT_INCOMPATIBLE_OS; } - if (!_hasCoInitialized) { - HRESULT initHr = CoInitializeEx(nullptr, COINIT::COINIT_MULTITHREADED); - if (initHr != RPC_E_CHANGED_MODE) { - if (FAILED(initHr) && initHr != S_FALSE) { - DEBUG_MSG(L"Error on COM library initialization!"); - return ShortcutResult::SHORTCUT_COM_INIT_FAILURE; - } else { - _hasCoInitialized = true; - } - } - } - bool wasChanged; HRESULT hr = validateShellLinkHelper(wasChanged); if (SUCCEEDED(hr)) { @@ -563,9 +552,14 @@ WinToast::ShortcutResult WinToast::createShortcut() { return SUCCEEDED(hr) ? ShortcutResult::SHORTCUT_WAS_CREATED : ShortcutResult::SHORTCUT_CREATE_FAILED; } -bool WinToast::initialize(_Out_opt_ WinToastError* error, _In_opt_ ThreadingMode threadingMode) { - _isInitialized = false; - setError(error, WinToastError::NoError); +bool WinToast::initialize(_Out_opt_ WinToastError* error) { + HRESULT initHr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (initHr != RPC_E_CHANGED_MODE) { + if (FAILED(initHr) && initHr != S_FALSE) { + DEBUG_MSG(L"Error on COM library initialization!"); + return false; + } + } if (!isCompatible()) { setError(error, WinToastError::SystemNotSupported); @@ -597,19 +591,19 @@ bool WinToast::initialize(_Out_opt_ WinToastError* error, _In_opt_ ThreadingMode return _isInitialized; } -bool WinToast::isInitialized() const { +[[nodiscard]] bool WinToast::isInitialized() const { return _isInitialized; } -std::wstring const& WinToast::appName() const { +[[nodiscard]] std::wstring const& WinToast::appName() const { return _appName; } -std::wstring const& WinToast::appUserModelId() const { +[[nodiscard]] std::wstring const& WinToast::appUserModelId() const { return _aumi; } -HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { +[[nodiscard]] HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { const auto path = Util::defaultShellLinkPath(_appName); if (!path) { return E_FAIL; @@ -673,7 +667,7 @@ HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { return hr; } -HRESULT WinToast::createShellLinkHelper() { +[[nodiscard]] HRESULT WinToast::createShellLinkHelper() { if (_shortcutPolicy != ShortcutPolicy::SHORTCUT_POLICY_REQUIRE_CREATE) { return E_FAIL; } @@ -726,7 +720,7 @@ INT64 WinToast::showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHand std::shared_ptr handler(eventHandler); setError(error, WinToastError::NoError); INT64 id = -1; - if (!isInitialized()) { + if (!_isInitialized) { setError(error, WinToastError::NotInitialized); DEBUG_MSG("Error when launching the toast. WinToast is not initialized."); return id; @@ -848,7 +842,7 @@ INT64 WinToast::showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHand return FAILED(hr) ? -1 : id; } -ComPtr WinToast::notifier(_In_ bool* succeded) const { +[[nodiscard]] ComPtr WinToast::notifier(_In_ bool* succeded) const { ComPtr notificationManager; ComPtr notifier; HRESULT hr = DllImporter::Wrap_GetActivationFactory( @@ -879,7 +873,7 @@ void WinToast::markAsReadyForDeletion(_In_ INT64 id) { } bool WinToast::hideToast(_In_ INT64 id) { - if (!isInitialized()) { + if (!_isInitialized) { DEBUG_MSG("Error when hiding the toast. WinToast is not initialized."); return false; } @@ -908,6 +902,10 @@ bool WinToast::hideToast(_In_ INT64 id) { } void WinToast::clear() { + if (!_isInitialized) { + DEBUG_MSG("Could not clear notifications, library not initialized"); + return; + } auto succeded = false; auto notify = notifier(&succeded); if (!succeded) { @@ -930,7 +928,7 @@ void WinToast::clear() { // NOTE: This will add a new text field, so be aware when iterating over // the toast's text fields or getting a count of them. // -HRESULT WinToast::setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text) { +[[nodiscard]] HRESULT WinToast::setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text) { Util::createElement(xml, L"binding", L"text", {L"placement"}); ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); @@ -964,7 +962,7 @@ HRESULT WinToast::setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std return hr; } -HRESULT WinToast::addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration) { +[[nodiscard]] HRESULT WinToast::addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration) { ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { @@ -985,7 +983,7 @@ HRESULT WinToast::addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring co return hr; } -HRESULT WinToast::addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario) { +[[nodiscard]] HRESULT WinToast::addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario) { ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { @@ -1006,7 +1004,7 @@ HRESULT WinToast::addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring co return hr; } -HRESULT WinToast::addInputHelper(_In_ IXmlDocument* xml) { +[[nodiscard]] HRESULT WinToast::addInputHelper(_In_ IXmlDocument* xml) { std::vector attrbs; attrbs.push_back(L"id"); attrbs.push_back(L"type"); @@ -1055,7 +1053,7 @@ HRESULT WinToast::addInputHelper(_In_ IXmlDocument* xml) { return hr; } -HRESULT WinToast::setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos) { +[[nodiscard]] HRESULT WinToast::setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos) { ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); if (SUCCEEDED(hr)) { @@ -1068,7 +1066,7 @@ HRESULT WinToast::setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring c return hr; } -HRESULT WinToast::setBindToastGenericHelper(_In_ IXmlDocument* xml) { +[[nodiscard]] HRESULT WinToast::setBindToastGenericHelper(_In_ IXmlDocument* xml) { ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { @@ -1089,7 +1087,7 @@ HRESULT WinToast::setBindToastGenericHelper(_In_ IXmlDocument* xml) { return hr; } -HRESULT WinToast::setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, +[[nodiscard]] HRESULT WinToast::setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, _In_ bool isCropHintCircle) { assert(path.size() < MAX_PATH); @@ -1126,7 +1124,7 @@ HRESULT WinToast::setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring return hr; } -HRESULT WinToast::setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, +[[nodiscard]] HRESULT WinToast::setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_opt_ WinToastTemplate::AudioOption option) { std::vector attrs; if (!path.empty()) { @@ -1248,7 +1246,7 @@ HRESULT WinToast::addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring cons return hr; } -HRESULT WinToast::setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage) { +[[nodiscard]] HRESULT WinToast::setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage) { ComPtr nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { @@ -1378,7 +1376,7 @@ void WinToastTemplate::setExpiration(_In_ INT64 millisecondsFromNow) { _expiration = millisecondsFromNow; } -void WinToastLib::WinToastTemplate::setScenario(_In_ Scenario scenario) { +void WinToastTemplate::setScenario(_In_ Scenario scenario) { switch (scenario) { case Scenario::Default: _scenario = L"Default"; @@ -1454,7 +1452,7 @@ std::wstring const& WinToastTemplate::attributionText() const { return _attributionText; } -std::wstring const& WinToastLib::WinToastTemplate::scenario() const { +std::wstring const& WinToastTemplate::scenario() const { return _scenario; } From ee9ba51cc80b319c51ef71928c451e1e488ed28d Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 1 Aug 2025 02:02:25 +0200 Subject: [PATCH 18/19] Add back static modifier on instance --- src/wintoastlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index dd4e599..bf37dd9 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -450,7 +450,7 @@ namespace Util { } // namespace Util WinToast* WinToast::instance() { - thread_local WinToast instance; + static thread_local WinToast instance; return &instance; } From 0ebe45919d8f31b6bdd246f35a0c031a27c566df Mon Sep 17 00:00:00 2001 From: KitsuneAlex Date: Fri, 1 Aug 2025 02:23:43 +0200 Subject: [PATCH 19/19] Use multithreaded initialization --- src/wintoastlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wintoastlib.cpp b/src/wintoastlib.cpp index bf37dd9..deec6d9 100644 --- a/src/wintoastlib.cpp +++ b/src/wintoastlib.cpp @@ -553,7 +553,7 @@ std::wstring WinToast::configureAUMI(_In_ std::wstring const& companyName, _In_ } bool WinToast::initialize(_Out_opt_ WinToastError* error) { - HRESULT initHr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + HRESULT initHr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (initHr != RPC_E_CHANGED_MODE) { if (FAILED(initHr) && initHr != S_FALSE) { DEBUG_MSG(L"Error on COM library initialization!");