24#include <winpr/assert.h>
25#include <winpr/cast.h>
27#include <freerdp/config.h>
29#include <freerdp/freerdp.h>
30#include <freerdp/gdi/gdi.h>
31#include <freerdp/client/cmdline.h>
33#include <freerdp/server/proxy/proxy_log.h>
34#include <freerdp/channels/drdynvc.h>
35#include <freerdp/channels/encomsp.h>
36#include <freerdp/channels/rdpdr.h>
37#include <freerdp/channels/rdpsnd.h>
38#include <freerdp/channels/cliprdr.h>
39#include <freerdp/channels/channels.h>
43#include "pf_channel.h"
44#include <freerdp/server/proxy/proxy_context.h>
47#include <freerdp/server/proxy/proxy_config.h>
48#include "proxy_modules.h"
50#include "channels/pf_channel_rdpdr.h"
51#include "channels/pf_channel_smartcard.h"
53#define TAG PROXY_TAG("client")
55static void channel_data_free(
void* obj);
58static BOOL proxy_server_reactivate(rdpContext* ps,
const rdpContext* pc)
63 if (!pf_context_copy_settings(ps->settings, pc->settings))
70 WINPR_ASSERT(ps->update);
71 return (ps->update->DesktopResize(ps));
74static void pf_client_on_error_info(
void* ctx,
const ErrorInfoEventArgs* e)
76 pClientContext* pc = (pClientContext*)ctx;
78 WINPR_ASSERT(pc->pdata);
81 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
84 if (e->code == ERRINFO_NONE)
87 PROXY_LOG_WARN(TAG, pc,
"received ErrorInfo PDU. code=0x%08" PRIu32
", message: %s", e->code,
88 freerdp_get_error_info_string(e->code));
91 freerdp_set_error_info(ps->context.rdp, e->code);
92 if (!freerdp_send_error_info(ps->context.rdp))
94 PROXY_LOG_WARN(TAG, pc,
"[fail] reply ErrorInfo PDU. code=0x%08" PRIu32
", message: %s",
95 e->code, freerdp_get_error_info_string(e->code));
99static void pf_client_on_activated(WINPR_ATTR_UNUSED
void* ctx,
100 WINPR_ATTR_UNUSED
const ActivatedEventArgs* e)
105static BOOL pf_client_load_rdpsnd(pClientContext* pc)
107 rdpContext* context = (rdpContext*)pc;
110 WINPR_ASSERT(pc->pdata);
115 if (!freerdp_static_channel_collection_find(context->settings, RDPSND_CHANNEL_NAME))
117 const char* params[2] = { RDPSND_CHANNEL_NAME,
"sys:fake" };
119 if (!freerdp_client_add_static_channel(context->settings, ARRAYSIZE(params), params))
127static BOOL pf_client_use_peer_load_balance_info(pClientContext* pc)
130 WINPR_ASSERT(pc->pdata);
132 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
134 rdpSettings* settings = pc->cctx.context.settings;
135 WINPR_ASSERT(settings);
137 DWORD lb_info_len = 0;
138 const char* lb_info = freerdp_nego_get_routing_token(&ps->context, &lb_info_len);
147static BOOL str_is_empty(
const char* str)
151 if (strlen(str) == 0)
157static BOOL pf_client_use_proxy_smartcard_auth(
const rdpSettings* settings)
166 if (str_is_empty(key))
169 if (str_is_empty(cert))
176static BOOL pf_client_pre_connect(freerdp* instance)
178 WINPR_ASSERT(instance);
179 pClientContext* pc = (pClientContext*)instance->context;
181 WINPR_ASSERT(pc->pdata);
183 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
185 WINPR_ASSERT(ps->pdata);
187 const proxyConfig* config = ps->pdata->config;
188 WINPR_ASSERT(config);
190 rdpSettings* settings = instance->context->settings;
191 WINPR_ASSERT(settings);
204 ZeroMemory(OrderSupport, 32);
206 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, DRDYNVC_SVC_CHANNEL_NAME))
220 config->DeviceRedirection) ||
224 if (config->RemoteApp)
226 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RAIL_SVC_CHANNEL_NAME))
233 if (config->DeviceRedirection)
235 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RDPDR_SVC_CHANNEL_NAME))
246 config->DisplayControl))
249 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, ENCOMSP_SVC_CHANNEL_NAME))
255 if (config->Clipboard)
257 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, CLIPRDR_SVC_CHANNEL_NAME))
267 if (PubSub_SubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info) < 0)
269 if (PubSub_SubscribeActivated(instance->context->pubSub, pf_client_on_activated) < 0)
271 if (!pf_client_use_peer_load_balance_info(pc))
274 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_PRE_CONNECT, pc->pdata, pc);
286static BOOL updateBackIdFn(WINPR_ATTR_UNUSED
const void* key,
void* value,
void* arg)
288 pServerStaticChannelContext* current = (pServerStaticChannelContext*)value;
289 UpdateBackIdArgs* updateArgs = (UpdateBackIdArgs*)arg;
291 if (strcmp(updateArgs->name, current->channel_name) != 0)
294 current->back_channel_id = updateArgs->backId;
295 if (!HashTable_Insert(updateArgs->ps->channelsByBackId, ¤t->back_channel_id, current))
297 WLog_ERR(TAG,
"error inserting channel in channelsByBackId table");
303static BOOL pf_client_update_back_id(pServerContext* ps,
const char* name, UINT32 backId)
305 UpdateBackIdArgs res = { ps, name, backId };
307 return HashTable_Foreach(ps->channelsByFrontId, updateBackIdFn, &res) == FALSE;
311static BOOL pf_client_load_channels(freerdp* instance)
313 WINPR_ASSERT(instance);
315 pClientContext* pc = (pClientContext*)instance->context;
317 WINPR_ASSERT(pc->pdata);
319 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
321 WINPR_ASSERT(ps->pdata);
323 const proxyConfig* config = ps->pdata->config;
324 WINPR_ASSERT(config);
326 rdpSettings* settings = instance->context->settings;
327 WINPR_ASSERT(settings);
332 PROXY_LOG_INFO(TAG, pc,
"Loading addins");
334 if (!pf_client_load_rdpsnd(pc))
336 PROXY_LOG_ERR(TAG, pc,
"Failed to load rdpsnd client");
340 if (!pf_utils_is_passthrough(config))
342 if (!freerdp_client_load_addins(instance->context->channels, settings))
344 PROXY_LOG_ERR(TAG, pc,
"Failed to load addins");
350 if (!pf_channel_rdpdr_client_new(pc))
352#if defined(WITH_PROXY_EMULATE_SMARTCARD)
353 if (!pf_channel_smartcard_client_new(pc))
357 if (!freerdp_channels_from_mcs(settings, &ps->context))
363 settings, FreeRDP_ChannelDefArray, 0);
365 UINT32
id = MCS_GLOBAL_CHANNEL_ID + 1;
367 WINPR_ASSERT(channels || (size == 0));
375 dev.channel_name = cur->name;
376 dev.flags = cur->options;
379 if (!pf_modules_run_filter(pc->pdata->module,
380 FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE, pc->pdata,
383 const size_t s = size - MIN(size, x + 1);
389 if (!pf_client_update_back_id(ps, cur->name,
id++))
391 WLog_ERR(TAG,
"unable to update backid for channel %s", cur->name);
402 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOAD_CHANNELS, pc->pdata, pc);
406static BOOL pf_client_receive_channel_data_hook(freerdp* instance, UINT16 channelId,
407 const BYTE* xdata,
size_t xsize, UINT32 flags,
410 UINT64 channelId64 = channelId;
412 WINPR_ASSERT(instance);
413 WINPR_ASSERT(xdata || (xsize == 0));
415 pClientContext* pc = (pClientContext*)instance->context;
417 WINPR_ASSERT(pc->pdata);
419 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
422 proxyData* pdata = ps->pdata;
425 pServerStaticChannelContext* channel =
426 HashTable_GetItemValue(ps->channelsByBackId, &channelId64);
430 WINPR_ASSERT(channel->onBackData);
431 switch (channel->onBackData(pdata, channel, xdata, xsize, flags, totalSize))
433 case PF_CHANNEL_RESULT_PASS:
437 if (channel->front_channel_id == 0)
440 return ps->context.peer->SendChannelPacket(
441 ps->context.peer, WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id),
442 totalSize, flags, xdata, xsize);
443 case PF_CHANNEL_RESULT_DROP:
445 case PF_CHANNEL_RESULT_ERROR:
452static BOOL pf_client_on_server_heartbeat(freerdp* instance, BYTE period, BYTE count1, BYTE count2)
454 WINPR_ASSERT(instance);
455 pClientContext* pc = (pClientContext*)instance->context;
457 WINPR_ASSERT(pc->pdata);
459 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
462 return freerdp_heartbeat_send_heartbeat_pdu(ps->context.peer, period, count1, count2);
471 return Queue_Enqueue(pc->cached_server_channel_data, ev);
475static BOOL sendQueuedChannelData(pClientContext* pc)
485 Queue_Lock(pc->cached_server_channel_data);
486 while (rc && (ev = Queue_Dequeue(pc->cached_server_channel_data)))
488 UINT16 channelId = 0;
489 WINPR_ASSERT(pc->cctx.context.instance);
492 freerdp_channels_get_id_by_name(pc->cctx.context.instance, ev->channel_name);
494 if ((channelId == 0) || (channelId == UINT16_MAX))
498 WINPR_ASSERT(pc->cctx.context.instance->SendChannelPacket);
499 rc = pc->cctx.context.instance->SendChannelPacket(
500 pc->cctx.context.instance, channelId, ev->total_size, ev->flags, ev->data,
503 channel_data_free(ev);
506 Queue_Unlock(pc->cached_server_channel_data);
522static BOOL pf_client_post_connect(freerdp* instance)
524 WINPR_ASSERT(instance);
525 rdpContext* context = instance->context;
526 WINPR_ASSERT(context);
527 rdpUpdate* update = context->update;
528 WINPR_ASSERT(update);
529 pClientContext* pc = (pClientContext*)context;
531 WINPR_ASSERT(pc->pdata);
533 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
536 if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata, pc))
539 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
544 pf_client_register_update_callbacks(update);
547 pc->client_receive_channel_data_original = instance->ReceiveChannelData;
548 instance->ReceiveChannelData = pf_client_receive_channel_data_hook;
550 instance->heartbeat->ServerHeartbeat = pf_client_on_server_heartbeat;
552 pc->connected = TRUE;
555 if (!sendQueuedChannelData(pc))
563 return proxy_server_reactivate(&ps->context, context);
569static void pf_client_post_disconnect(freerdp* instance)
571 pClientContext* pc =
nullptr;
572 proxyData* pdata =
nullptr;
577 if (!instance->context)
580 pc = (pClientContext*)instance->context;
585#if defined(WITH_PROXY_EMULATE_SMARTCARD)
586 pf_channel_smartcard_client_free(pc);
589 pf_channel_rdpdr_client_free(pc);
591 pc->connected = FALSE;
592 (void)pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_DISCONNECT, pc->pdata, pc);
594 PubSub_UnsubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info);
598 if (!pc->allow_next_conn_failure)
599 proxy_data_abort_connect(pdata);
603static BOOL pf_client_redirect(freerdp* instance)
608 if (!instance->context)
611 pClientContext* pc = (pClientContext*)instance->context;
614#if defined(WITH_PROXY_EMULATE_SMARTCARD)
615 pf_channel_smartcard_client_reset(pc);
617 pf_channel_rdpdr_client_reset(pc);
619 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_REDIRECT, pc->pdata, pc);
629static BOOL pf_client_should_retry_without_nla(pClientContext* pc)
631 rdpSettings* settings =
nullptr;
632 const proxyConfig* config =
nullptr;
635 WINPR_ASSERT(pc->pdata);
636 settings = pc->cctx.context.settings;
637 WINPR_ASSERT(settings);
638 config = pc->pdata->config;
639 WINPR_ASSERT(config);
641 if (!config->ClientAllowFallbackToTls ||
646 return config->ClientTlsSecurity || config->ClientRdpSecurity;
650static BOOL pf_client_set_security_settings(pClientContext* pc)
653 WINPR_ASSERT(pc->pdata);
654 rdpSettings* settings = pc->cctx.context.settings;
655 WINPR_ASSERT(settings);
656 const proxyConfig* config = pc->pdata->config;
657 WINPR_ASSERT(config);
668 if (pf_client_use_proxy_smartcard_auth(settings))
685static BOOL pf_client_connect_without_nla(pClientContext* pc)
687 freerdp* instance =
nullptr;
688 rdpSettings* settings =
nullptr;
691 instance = pc->cctx.context.instance;
692 WINPR_ASSERT(instance);
694 if (!freerdp_context_reset(instance))
697 settings = pc->cctx.context.settings;
698 WINPR_ASSERT(settings);
712 pc->allow_next_conn_failure = FALSE;
713 return freerdp_connect(instance);
717static BOOL pf_client_connect(freerdp* instance)
719 pClientContext* pc =
nullptr;
720 rdpSettings* settings =
nullptr;
724 WINPR_ASSERT(instance);
725 pc = (pClientContext*)instance->context;
727 settings = instance->context->settings;
728 WINPR_ASSERT(settings);
730 if (!pf_client_set_security_settings(pc))
733 if (pf_client_should_retry_without_nla(pc))
734 retry = pc->allow_next_conn_failure = TRUE;
736 PROXY_LOG_INFO(TAG, pc,
"connecting using client info: Username: %s, Domain: %s",
739 PROXY_LOG_INFO(TAG, pc,
"connecting using security settings: rdp=%d, tls=%d, nla=%d, ext=%d",
745 if (!freerdp_connect(instance))
747 if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata, pc))
753 PROXY_LOG_ERR(TAG, pc,
"failed to connect with NLA. retrying to connect without NLA");
754 if (!pf_client_connect_without_nla(pc))
756 PROXY_LOG_ERR(TAG, pc,
"pf_client_connect_without_nla failed!");
763 pc->allow_next_conn_failure = FALSE;
773static DWORD WINAPI pf_client_thread_proc(pClientContext* pc)
775 freerdp* instance =
nullptr;
776 proxyData* pdata =
nullptr;
779 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
783 instance = pc->cctx.context.instance;
784 WINPR_ASSERT(instance);
795 handles[nCount++] = pdata->abort_event;
797 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_INIT_CONNECT, pdata, pc))
799 proxy_data_abort_connect(pdata);
803 if (!pf_client_connect(instance))
805 proxy_data_abort_connect(pdata);
808 handles[nCount++] = Queue_Event(pc->cached_server_channel_data);
810 while (!freerdp_shall_disconnect_context(instance->context))
812 UINT32 tmp = freerdp_get_event_handles(instance->context, &handles[nCount],
813 ARRAYSIZE(handles) - nCount);
817 PROXY_LOG_ERR(TAG, pc,
"freerdp_get_event_handles failed!");
821 status = WaitForMultipleObjects(nCount + tmp, handles, FALSE, INFINITE);
823 if (status == WAIT_FAILED)
825 WLog_ERR(TAG,
"WaitForMultipleObjects failed with %" PRIu32
"", status);
830 if (status == WAIT_OBJECT_0)
833 if (freerdp_shall_disconnect_context(instance->context))
836 if (proxy_data_shall_disconnect(pdata))
839 if (!freerdp_check_event_handles(instance->context))
841 if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
842 WLog_ERR(TAG,
"Failed to check FreeRDP event handles");
846 if (!sendQueuedChannelData(pc))
850 freerdp_disconnect(instance);
853 (void)pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_UNINIT_CONNECT, pdata, pc);
859static int pf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
861 const char* str_data = freerdp_get_logon_error_info_data(data);
862 const char* str_type = freerdp_get_logon_error_info_type(type);
864 if (!instance || !instance->context)
867 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
871static void pf_client_context_free(freerdp* instance, rdpContext* context)
873 pClientContext* pc = (pClientContext*)context;
874 WINPR_UNUSED(instance);
879 pc->sendChannelData =
nullptr;
880 Queue_Free(pc->cached_server_channel_data);
881 Stream_Free(pc->remote_pem, TRUE);
882 free(pc->remote_hostname);
883 free(pc->computerName.v);
884 HashTable_Free(pc->interceptContextMap);
888static int pf_client_verify_X509_certificate(freerdp* instance,
const BYTE* data,
size_t length,
889 const char* hostname, UINT16 port, DWORD flags)
891 pClientContext* pc =
nullptr;
893 WINPR_ASSERT(instance);
895 WINPR_ASSERT(length > 0);
896 WINPR_ASSERT(hostname);
898 pc = (pClientContext*)instance->context;
901 if (!Stream_EnsureCapacity(pc->remote_pem, length))
903 Stream_ResetPosition(pc->remote_pem);
905 free(pc->remote_hostname);
906 pc->remote_hostname =
nullptr;
909 Stream_Write(pc->remote_pem, data, length);
912 pc->remote_hostname = _strdup(hostname);
913 pc->remote_port = port;
914 pc->remote_flags = flags;
916 Stream_SealLength(pc->remote_pem);
917 if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_VERIFY_X509, pc->pdata, pc))
923static BOOL pf_client_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
925 WINPR_ATTR_UNUSED DWORD count, DWORD* choice,
926 WINPR_ATTR_UNUSED BOOL gateway)
935static BOOL pf_client_authenticate_ex(WINPR_ATTR_UNUSED freerdp* instance,
936 WINPR_ATTR_UNUSED
char** username,
937 WINPR_ATTR_UNUSED
char** password,
938 WINPR_ATTR_UNUSED
char** domain, rdp_auth_reason reason)
940 WINPR_ASSERT(instance);
941 WINPR_ASSERT(username);
942 WINPR_ASSERT(password);
943 WINPR_ASSERT(domain);
953 case AUTH_SMARTCARD_PIN:
964static BOOL pf_client_present_gateway_message(WINPR_ATTR_UNUSED freerdp* instance,
965 WINPR_ATTR_UNUSED UINT32 type,
966 WINPR_ATTR_UNUSED BOOL isDisplayMandatory,
967 WINPR_ATTR_UNUSED BOOL isConsentMandatory,
968 WINPR_ATTR_UNUSED
size_t length,
969 WINPR_ATTR_UNUSED
const WCHAR* message)
971 WLog_WARN(TAG,
"TODO: Implement gateway message forwarding");
975void channel_data_free(
void* obj)
988 cnv.cpv = dst->channel_name;
994WINPR_ATTR_MALLOC(channel_data_free, 1)
996static
void* channel_data_copy(const
void* obj)
1013 if (src->channel_name)
1015 dst->channel_name = _strdup(src->channel_name);
1016 if (!dst->channel_name)
1019 dst->data = malloc(src->data_len);
1023 cnv.cpv = dst->data;
1024 memcpy(cnv.pv, src->data, src->data_len);
1028 channel_data_free(dst);
1033static BOOL pf_client_client_new(freerdp* instance, rdpContext* context)
1036 pClientContext* pc = (pClientContext*)context;
1038 if (!instance || !context)
1041 instance->LoadChannels = pf_client_load_channels;
1042 instance->PreConnect = pf_client_pre_connect;
1043 instance->PostConnect = pf_client_post_connect;
1044 instance->PostDisconnect = pf_client_post_disconnect;
1045 instance->Redirect = pf_client_redirect;
1046 instance->LogonErrorInfo = pf_logon_error_info;
1047 instance->GetAccessToken =
nullptr;
1048 instance->RetryDialog =
nullptr;
1049 instance->VerifyCertificateEx =
nullptr;
1050 instance->VerifyChangedCertificateEx =
nullptr;
1051 instance->VerifyX509Certificate = pf_client_verify_X509_certificate;
1052 instance->AuthenticateEx = pf_client_authenticate_ex;
1053 instance->ChooseSmartcard = pf_client_choose_smartcard;
1054 instance->PresentGatewayMessage = pf_client_present_gateway_message;
1056 pc->remote_pem = Stream_New(
nullptr, 4096);
1057 if (!pc->remote_pem)
1060 pc->sendChannelData = pf_client_send_channel_data;
1061 pc->cached_server_channel_data = Queue_New(TRUE, -1, -1);
1062 if (!pc->cached_server_channel_data)
1064 obj = Queue_Object(pc->cached_server_channel_data);
1069 pc->interceptContextMap = HashTable_New(FALSE);
1070 if (!pc->interceptContextMap)
1073 if (!HashTable_SetupForStringData(pc->interceptContextMap, FALSE))
1076 obj = HashTable_ValueObject(pc->interceptContextMap);
1084static int pf_client_client_stop(rdpContext* context)
1086 pClientContext* pc = (pClientContext*)context;
1087 proxyData* pdata =
nullptr;
1091 WINPR_ASSERT(pdata);
1093 PROXY_LOG_DBG(TAG, pc,
"aborting client connection");
1094 proxy_data_abort_connect(pdata);
1095 freerdp_abort_connect_context(context);
1100int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1102 WINPR_ASSERT(pEntryPoints);
1104 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
1105 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1106 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1107 pEntryPoints->ContextSize =
sizeof(pClientContext);
1109 pEntryPoints->ClientNew = pf_client_client_new;
1110 pEntryPoints->ClientFree = pf_client_context_free;
1111 pEntryPoints->ClientStop = pf_client_client_stop;
1118DWORD WINAPI pf_client_start(LPVOID arg)
1121 pClientContext* pc = (pClientContext*)arg;
1124 if (freerdp_client_start(&pc->cctx.context) == 0)
1125 rc = pf_client_thread_proc(pc);
1126 freerdp_client_stop(&pc->cctx.context);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_NEW_FN fnObjectNew