diff --git a/client/SDL/SDL2/dialogs/sdl_dialogs.cpp b/client/SDL/SDL2/dialogs/sdl_dialogs.cpp index 62cb17f1c..1d44c288b 100644 --- a/client/SDL/SDL2/dialogs/sdl_dialogs.cpp +++ b/client/SDL/SDL2/dialogs/sdl_dialogs.cpp @@ -119,6 +119,7 @@ BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password, ch size_t titlesize = 0; winpr_asprintf(&title, &titlesize, "Credentials required for %s", target); + std::unique_ptr scope(title, free); char* u = nullptr; char* d = nullptr; char* p = nullptr; @@ -132,26 +133,22 @@ BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password, ch p = *password; if (!sdl_push_user_event(SDL_USEREVENT_AUTH_DIALOG, title, u, d, p, reason)) - goto fail; + return res; if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_AUTH_RESULT, &event)) - goto fail; - else - { - auto arg = reinterpret_cast(event.padding); + return res; - res = arg->result > 0 ? TRUE : FALSE; + auto arg = reinterpret_cast(event.padding); - free(*username); - free(*domain); - free(*password); - *username = arg->user; - *domain = arg->domain; - *password = arg->password; - } + res = arg->result > 0 ? TRUE : FALSE; + + free(*username); + free(*domain); + free(*password); + *username = arg->user; + *domain = arg->domain; + *password = arg->password; -fail: - free(title); return res; } @@ -195,15 +192,14 @@ BOOL sdl_choose_smartcard(freerdp* instance, SmartcardCertInfo** cert_list, DWOR if (gateway) title = "Select a gateway logon smartcard certificate"; if (!sdl_push_user_event(SDL_USEREVENT_SCARD_DIALOG, title, list.data(), count)) - goto fail; + return res; if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_SCARD_RESULT, &event)) - goto fail; + return res; res = (event.user.code >= 0) ? TRUE : FALSE; *choice = static_cast(event.user.code); -fail: return res; } diff --git a/client/SDL/SDL2/sdl_freerdp.cpp b/client/SDL/SDL2/sdl_freerdp.cpp index 3f0f5b033..3568d71bd 100644 --- a/client/SDL/SDL2/sdl_freerdp.cpp +++ b/client/SDL/SDL2/sdl_freerdp.cpp @@ -59,6 +59,7 @@ #include "sdl_pointer.hpp" #include "sdl_prefs.hpp" #include "dialogs/sdl_dialogs.hpp" +#include "scoped_guard.hpp" #include @@ -703,7 +704,6 @@ static BOOL sdl_create_windows(SdlContext* sdl) auto settings = sdl->context()->settings; auto title = sdl_window_get_title(settings); - BOOL rc = FALSE; UINT32 windowCount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); @@ -755,8 +755,11 @@ static BOOL sdl_create_windows(SdlContext* sdl) static_cast(w), static_cast(h), flags }; + + ScopeGuard guard([&]() { sdl->windows_created.set(); }); + if (!window.window()) - goto fail; + return FALSE; if (freerdp_settings_get_bool(settings, FreeRDP_UseMultimon)) { @@ -768,11 +771,7 @@ static BOOL sdl_create_windows(SdlContext* sdl) sdl->windows.insert({ window.id(), std::move(window) }); } - rc = TRUE; -fail: - - sdl->windows_created.set(); - return rc; + return TRUE; } static BOOL sdl_wait_create_windows(SdlContext* sdl) @@ -1168,19 +1167,56 @@ static void sdl_post_final_disconnect(freerdp* instance) return; } -/* RDP main loop. - * Connects RDP, loops while running and handles event and dispatch, cleans up - * after the connection ends. */ -static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) +static void sdl_client_cleanup(SdlContext* sdl, int exit_code, const std::string& error_msg) { - DWORD nCount = 0; - DWORD status = 0; - int exit_code = SDL_EXIT_SUCCESS; - char* error_msg = nullptr; - size_t error_msg_len = 0; + WINPR_ASSERT(sdl); - HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {}; + rdpContext* context = sdl->context(); + WINPR_ASSERT(context); + rdpSettings* settings = context->settings; + WINPR_ASSERT(settings); + + sdl->rdp_thread_running = false; + bool showError = false; + if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly)) + WLog_Print(sdl->log, WLOG_INFO, "Authentication only, exit status %s [%" PRId32 "]", + sdl_map_to_code_tag(exit_code), exit_code); + else + { + switch (exit_code) + { + case SDL_EXIT_SUCCESS: + case SDL_EXIT_DISCONNECT: + case SDL_EXIT_LOGOFF: + case SDL_EXIT_DISCONNECT_BY_USER: + case SDL_EXIT_CONNECT_CANCELLED: + break; + default: + { + std::lock_guard lock(sdl->critical); + if (sdl->connection_dialog && !error_msg.empty()) + { + sdl->connection_dialog->showError(error_msg.c_str()); + showError = true; + } + } + break; + } + } + + if (!showError) + sdl_hide_connection_dialog(sdl); + + sdl->exit_code = exit_code; + sdl_push_user_event(SDL_USEREVENT_QUIT); +#if SDL_VERSION_ATLEAST(2, 0, 16) + SDL_TLSCleanup(); +#endif +} + +static int sdl_client_thread_connect(SdlContext* sdl, std::string& error_msg) +{ WINPR_ASSERT(sdl); auto instance = sdl->context()->instance; @@ -1190,9 +1226,12 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) BOOL rc = freerdp_connect(instance); rdpContext* context = sdl->context(); + WINPR_ASSERT(context); + rdpSettings* settings = context->settings; WINPR_ASSERT(settings); + int exit_code = SDL_EXIT_SUCCESS; if (!rc) { UINT32 error = freerdp_get_last_error(context); @@ -1205,21 +1244,33 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) freerdp_abort_connect_context(context); WLog_Print(sdl->log, WLOG_ERROR, "Authentication only, %s [0x%08" PRIx32 "] %s", freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code)); - goto terminate; + return exit_code; } if (!rc) { DWORD code = freerdp_error_info(instance); if (exit_code == SDL_EXIT_SUCCESS) - exit_code = error_info_to_error(instance, &code, &error_msg, &error_msg_len); + { + char* msg = nullptr; + size_t len = 0; + exit_code = error_info_to_error(instance, &code, &msg, &len); + if (msg) + error_msg = msg; + free(msg); + } auto last = freerdp_get_last_error(context); - if (!error_msg) + if (error_msg.empty()) { - winpr_asprintf(&error_msg, &error_msg_len, "%s [0x%08" PRIx32 "]\n%s", + char* msg = nullptr; + size_t len = 0; + winpr_asprintf(&msg, &len, "%s [0x%08" PRIx32 "]\n%s", freerdp_get_last_error_name(last), last, freerdp_get_last_error_string(last)); + if (msg) + error_msg = msg; + free(msg); } if (exit_code == SDL_EXIT_SUCCESS) @@ -1231,11 +1282,24 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) } sdl_hide_connection_dialog(sdl); - goto terminate; } + return exit_code; +} +static int sdl_client_thread_run(SdlContext* sdl, std::string& error_msg) +{ + WINPR_ASSERT(sdl); + + auto context = sdl->context(); + WINPR_ASSERT(context); + + auto instance = context->instance; + WINPR_ASSERT(instance); + + int exit_code = SDL_EXIT_SUCCESS; while (!freerdp_shall_disconnect_context(context)) { + HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {}; /* * win8 and server 2k12 seem to have some timing issue/race condition * when a initial sync request is send to sync the keyboard indicators @@ -1251,7 +1315,7 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) break; } - nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles)); + const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles)); if (nCount == 0) { @@ -1259,7 +1323,7 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) break; } - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); + const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (status == WAIT_FAILED) break; @@ -1294,18 +1358,26 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) if (exit_code == SDL_EXIT_SUCCESS) { DWORD code = 0; - exit_code = error_info_to_error(instance, &code, &error_msg, &error_msg_len); + { + char* msg = nullptr; + size_t len = 0; + exit_code = error_info_to_error(instance, &code, &msg, &len); + if (msg) + error_msg = msg; + free(msg); + } if ((code == ERRINFO_LOGOFF_BY_USER) && (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested)) { const char* msg = "Error info says user did not initiate but disconnect ultimatum says " "they did; treat this as a user logoff"; - free(error_msg); - error_msg = nullptr; - error_msg_len = 0; - winpr_asprintf(&error_msg, &error_msg_len, "%s", msg); - + char* emsg = nullptr; + size_t len = 0; + winpr_asprintf(&emsg, &len, "%s", msg); + if (emsg) + error_msg = emsg; + free(emsg); /* This situation might be limited to Windows XP. */ WLog_Print(sdl->log, WLOG_INFO, "%s", msg); exit_code = SDL_EXIT_LOGOFF; @@ -1313,45 +1385,26 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) } freerdp_disconnect(instance); + return exit_code; +} -terminate: - sdl->rdp_thread_running = false; - bool showError = false; - if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly)) - WLog_Print(sdl->log, WLOG_INFO, "Authentication only, exit status %s [%" PRId32 "]", - sdl_map_to_code_tag(exit_code), exit_code); - else - { - switch (exit_code) - { - case SDL_EXIT_SUCCESS: - case SDL_EXIT_DISCONNECT: - case SDL_EXIT_LOGOFF: - case SDL_EXIT_DISCONNECT_BY_USER: - case SDL_EXIT_CONNECT_CANCELLED: - break; - default: - { - std::lock_guard lock(sdl->critical); - if (sdl->connection_dialog && error_msg) - { - sdl->connection_dialog->showError(error_msg); - showError = true; - } - } - break; - } - } - free(error_msg); - if (!showError) - sdl_hide_connection_dialog(sdl); +/* RDP main loop. + * Connects RDP, loops while running and handles event and dispatch, cleans up + * after the connection ends. */ +static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) +{ + WINPR_ASSERT(sdl); - sdl->exit_code = exit_code; - sdl_push_user_event(SDL_USEREVENT_QUIT); -#if SDL_VERSION_ATLEAST(2, 0, 16) - SDL_TLSCleanup(); -#endif - return 0; + auto instance = sdl->context()->instance; + WINPR_ASSERT(instance); + + std::string error_msg; + int exit_code = sdl_client_thread_connect(sdl, error_msg); + if (exit_code == SDL_EXIT_SUCCESS) + exit_code = sdl_client_thread_run(sdl, error_msg); + sdl_client_cleanup(sdl, exit_code, error_msg); + + return static_cast(exit_code); } /* Optional global initializer. diff --git a/client/SDL/SDL3/dialogs/sdl_dialogs.cpp b/client/SDL/SDL3/dialogs/sdl_dialogs.cpp index 3ca42fab8..99ba96289 100644 --- a/client/SDL/SDL3/dialogs/sdl_dialogs.cpp +++ b/client/SDL/SDL3/dialogs/sdl_dialogs.cpp @@ -119,6 +119,7 @@ BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password, ch size_t titlesize = 0; winpr_asprintf(&title, &titlesize, "Credentials required for %s", target); + std::unique_ptr guard(title, free); char* u = nullptr; char* d = nullptr; char* p = nullptr; @@ -132,26 +133,22 @@ BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password, ch p = *password; if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason)) - goto fail; + return res; if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_AUTH_RESULT, &event)) - goto fail; - else - { - auto arg = reinterpret_cast(event.padding); + return res; - res = arg->result > 0 ? TRUE : FALSE; + auto arg = reinterpret_cast(event.padding); - free(*username); - free(*domain); - free(*password); - *username = arg->user; - *domain = arg->domain; - *password = arg->password; - } + res = arg->result > 0 ? TRUE : FALSE; + + free(*username); + free(*domain); + free(*password); + *username = arg->user; + *domain = arg->domain; + *password = arg->password; -fail: - free(title); return res; } @@ -195,15 +192,14 @@ BOOL sdl_choose_smartcard(freerdp* instance, SmartcardCertInfo** cert_list, DWOR if (gateway) title = "Select a gateway logon smartcard certificate"; if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count)) - goto fail; + return res; if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event)) - goto fail; + return res; res = (event.user.code >= 0) ? TRUE : FALSE; *choice = static_cast(event.user.code); -fail: return res; } diff --git a/client/SDL/SDL3/sdl_freerdp.cpp b/client/SDL/SDL3/sdl_freerdp.cpp index 32f7fbdf6..6145bfd15 100644 --- a/client/SDL/SDL3/sdl_freerdp.cpp +++ b/client/SDL/SDL3/sdl_freerdp.cpp @@ -60,6 +60,7 @@ #include "sdl_pointer.hpp" #include "sdl_prefs.hpp" #include "dialogs/sdl_dialogs.hpp" +#include "scoped_guard.hpp" #include @@ -701,7 +702,6 @@ static BOOL sdl_create_windows(SdlContext* sdl) auto settings = sdl->context()->settings; auto title = sdl_window_get_title(settings); - BOOL rc = FALSE; UINT32 windowCount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); @@ -752,8 +752,9 @@ static BOOL sdl_create_windows(SdlContext* sdl) static_cast(w), static_cast(h), flags }; + ScopeGuard guard1([&]() { sdl->windows_created.set(); }); if (!window.window()) - goto fail; + return FALSE; if (freerdp_settings_get_bool(settings, FreeRDP_UseMultimon)) { @@ -765,11 +766,7 @@ static BOOL sdl_create_windows(SdlContext* sdl) sdl->windows.insert({ window.id(), std::move(window) }); } - rc = TRUE; -fail: - - sdl->windows_created.set(); - return rc; + return TRUE; } static BOOL sdl_wait_create_windows(SdlContext* sdl) @@ -1155,19 +1152,53 @@ static void sdl_post_final_disconnect(freerdp* instance) return; } -/* RDP main loop. - * Connects RDP, loops while running and handles event and dispatch, cleans up - * after the connection ends. */ -static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) +static void sdl_client_cleanup(SdlContext* sdl, int exit_code, const std::string& error_msg) { - DWORD nCount = 0; - DWORD status = 0; - int exit_code = SDL_EXIT_SUCCESS; - char* error_msg = nullptr; - size_t error_msg_len = 0; + WINPR_ASSERT(sdl); - HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {}; + rdpContext* context = sdl->context(); + WINPR_ASSERT(context); + rdpSettings* settings = context->settings; + WINPR_ASSERT(settings); + sdl->rdp_thread_running = false; + bool showError = false; + if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly)) + WLog_Print(sdl->log, WLOG_INFO, "Authentication only, exit status %s [%" PRId32 "]", + sdl_map_to_code_tag(exit_code), exit_code); + else + { + switch (exit_code) + { + case SDL_EXIT_SUCCESS: + case SDL_EXIT_DISCONNECT: + case SDL_EXIT_LOGOFF: + case SDL_EXIT_DISCONNECT_BY_USER: + case SDL_EXIT_CONNECT_CANCELLED: + break; + default: + { + std::lock_guard lock(sdl->critical); + if (sdl->connection_dialog && !error_msg.empty()) + { + sdl->connection_dialog->showError(error_msg.c_str()); + showError = true; + } + } + break; + } + } + + if (!showError) + sdl_hide_connection_dialog(sdl); + + sdl->exit_code = exit_code; + sdl_push_user_event(SDL_EVENT_USER_QUIT); + SDL_CleanupTLS(); +} + +static int sdl_client_thread_connect(SdlContext* sdl, std::string& error_msg) +{ WINPR_ASSERT(sdl); auto instance = sdl->context()->instance; @@ -1180,6 +1211,7 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) rdpSettings* settings = context->settings; WINPR_ASSERT(settings); + int exit_code = SDL_EXIT_SUCCESS; if (!rc) { UINT32 error = freerdp_get_last_error(context); @@ -1192,21 +1224,33 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) freerdp_abort_connect_context(context); WLog_Print(sdl->log, WLOG_ERROR, "Authentication only, %s [0x%08" PRIx32 "] %s", freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code)); - goto terminate; + return exit_code; } if (!rc) { DWORD code = freerdp_error_info(instance); if (exit_code == SDL_EXIT_SUCCESS) - exit_code = error_info_to_error(instance, &code, &error_msg, &error_msg_len); + { + char* msg = nullptr; + size_t len = 0; + exit_code = error_info_to_error(instance, &code, &msg, &len); + if (msg) + error_msg = msg; + free(msg); + } auto last = freerdp_get_last_error(context); - if (!error_msg) + if (error_msg.empty()) { - winpr_asprintf(&error_msg, &error_msg_len, "%s [0x%08" PRIx32 "]\n%s", + char* msg = nullptr; + size_t len = 0; + winpr_asprintf(&msg, &len, "%s [0x%08" PRIx32 "]\n%s", freerdp_get_last_error_name(last), last, freerdp_get_last_error_string(last)); + if (msg) + error_msg = msg; + free(msg); } if (exit_code == SDL_EXIT_SUCCESS) @@ -1218,11 +1262,25 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) } sdl_hide_connection_dialog(sdl); - goto terminate; } + return exit_code; +} + +static int sdl_client_thread_run(SdlContext* sdl, std::string& error_msg) +{ + WINPR_ASSERT(sdl); + + auto context = sdl->context(); + WINPR_ASSERT(context); + + auto instance = context->instance; + WINPR_ASSERT(instance); + + int exit_code = SDL_EXIT_SUCCESS; while (!freerdp_shall_disconnect_context(context)) { + HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {}; /* * win8 and server 2k12 seem to have some timing issue/race condition * when a initial sync request is send to sync the keyboard indicators @@ -1238,7 +1296,7 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) break; } - nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles)); + const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles)); if (nCount == 0) { @@ -1246,7 +1304,7 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) break; } - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); + const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (status == WAIT_FAILED) break; @@ -1281,17 +1339,27 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) if (exit_code == SDL_EXIT_SUCCESS) { DWORD code = 0; - exit_code = error_info_to_error(instance, &code, &error_msg, &error_msg_len); + { + char* emsg = nullptr; + size_t elen = 0; + exit_code = error_info_to_error(instance, &code, &emsg, &elen); + if (emsg) + error_msg = emsg; + free(emsg); + } if ((code == ERRINFO_LOGOFF_BY_USER) && (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested)) { const char* msg = "Error info says user did not initiate but disconnect ultimatum says " "they did; treat this as a user logoff"; - free(error_msg); - error_msg = nullptr; - error_msg_len = 0; - winpr_asprintf(&error_msg, &error_msg_len, "%s", msg); + + char* emsg = nullptr; + size_t elen = 0; + winpr_asprintf(&emsg, &elen, "%s", msg); + if (emsg) + error_msg = emsg; + free(emsg); /* This situation might be limited to Windows XP. */ WLog_Print(sdl->log, WLOG_INFO, "%s", msg); @@ -1301,44 +1369,28 @@ static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) freerdp_disconnect(instance); -terminate: - sdl->rdp_thread_running = false; - bool showError = false; - if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly)) - WLog_Print(sdl->log, WLOG_INFO, "Authentication only, exit status %s [%" PRId32 "]", - sdl_map_to_code_tag(exit_code), exit_code); - else - { - switch (exit_code) - { - case SDL_EXIT_SUCCESS: - case SDL_EXIT_DISCONNECT: - case SDL_EXIT_LOGOFF: - case SDL_EXIT_DISCONNECT_BY_USER: - case SDL_EXIT_CONNECT_CANCELLED: - break; - default: - { - std::lock_guard lock(sdl->critical); - if (sdl->connection_dialog && error_msg) - { - sdl->connection_dialog->showError(error_msg); - showError = true; - } - } - break; - } - } - free(error_msg); - if (!showError) - sdl_hide_connection_dialog(sdl); - - sdl->exit_code = exit_code; - sdl_push_user_event(SDL_EVENT_USER_QUIT); - SDL_CleanupTLS(); return 0; } +/* RDP main loop. + * Connects RDP, loops while running and handles event and dispatch, cleans up + * after the connection ends. */ +static DWORD WINAPI sdl_client_thread_proc(SdlContext* sdl) +{ + WINPR_ASSERT(sdl); + + auto instance = sdl->context()->instance; + WINPR_ASSERT(instance); + + std::string error_msg; + int exit_code = sdl_client_thread_connect(sdl, error_msg); + if (exit_code == SDL_EXIT_SUCCESS) + exit_code = sdl_client_thread_run(sdl, error_msg); + sdl_client_cleanup(sdl, exit_code, error_msg); + + return static_cast(exit_code); +} + /* Optional global initializer. * Here we just register a signal handler to print out stack traces * if available. */ diff --git a/client/SDL/common/CMakeLists.txt b/client/SDL/common/CMakeLists.txt index 9da9feb8a..d19bdc152 100644 --- a/client/SDL/common/CMakeLists.txt +++ b/client/SDL/common/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(res) add_library(sdl-common-prefs STATIC sdl_prefs.hpp sdl_prefs.cpp + scoped_guard.hpp ) target_link_libraries(sdl-common-prefs winpr freerdp) diff --git a/client/SDL/common/scoped_guard.hpp b/client/SDL/common/scoped_guard.hpp new file mode 100644 index 000000000..9a5f43c73 --- /dev/null +++ b/client/SDL/common/scoped_guard.hpp @@ -0,0 +1,56 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * SDL ScopeGuard + * + * Copyright 2024 Armin Novak + * Copyright 2024 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class ScopeGuard +{ + public: + template explicit ScopeGuard(Callable&& cleanupFunction) + try : f(std::forward(cleanupFunction)) + { + } + catch (...) + { + cleanupFunction(); + throw; + } + + ~ScopeGuard() + { + if (f) + f(); + } + + void dismiss() noexcept + { + f = nullptr; + } + + ScopeGuard(const ScopeGuard&) = delete; + ScopeGuard(ScopeGuard&& other) noexcept = delete; + auto operator=(const ScopeGuard&) = delete; + auto operator=(const ScopeGuard&&) = delete; + + private: + std::function f; +};