26#include <freerdp/config.h>
30#include <freerdp/types.h>
31#include <freerdp/constants.h>
32#include <freerdp/freerdp.h>
34#include "rail_orders.h"
37#include "../../../channels/client/addin.h"
39RailClientContext* rail_get_client_interface(
railPlugin* rail)
41 RailClientContext* pInterface =
nullptr;
46 pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
62 return CHANNEL_RC_BAD_INIT_HANDLE;
65 status = rail->channelEntryPoints.pVirtualChannelWriteEx(
66 rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
68 if (status != CHANNEL_RC_OK)
71 WLog_ERR(TAG,
"pVirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
72 WTSErrorToString(status), status);
87 Stream_Free(src, TRUE);
88 return ERROR_INVALID_PARAMETER;
91 return rail_send(rail, src);
103static UINT rail_client_execute(RailClientContext* context,
const RAIL_EXEC_ORDER* exec)
105 const char* exeOrFile =
nullptr;
113 if (!context || !exec)
114 return ERROR_INVALID_PARAMETER;
117 exeOrFile = exec->RemoteApplicationProgram;
121 return ERROR_INVALID_PARAMETER;
123 if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
125 !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
127 !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
129 error = ERROR_INTERNAL_ERROR;
131 error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
133 free(ruExeOrFile.string);
134 free(ruWorkingDir.string);
135 free(ruArguments.string);
144static UINT rail_client_activate(RailClientContext* context,
const RAIL_ACTIVATE_ORDER* activate)
148 if (!context || !activate)
149 return ERROR_INVALID_PARAMETER;
152 return rail_send_client_activate_order(rail, activate);
160static UINT rail_send_client_sysparam(RailClientContext* context,
163 size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
165 if (!context || !sysparam)
166 return ERROR_INVALID_PARAMETER;
170 switch (sysparam->param)
172 case SPI_SET_DRAG_FULL_WINDOWS:
173 case SPI_SET_KEYBOARD_CUES:
174 case SPI_SET_KEYBOARD_PREF:
175 case SPI_SET_MOUSE_BUTTON_SWAP:
179 case SPI_SET_WORK_AREA:
180 case SPI_DISPLAY_CHANGE:
181 case SPI_TASKBAR_POS:
185 case SPI_SET_HIGH_CONTRAST:
186 length += sysparam->highContrast.colorSchemeLength + 10;
189 case SPI_SETFILTERKEYS:
193 case SPI_SETSTICKYKEYS:
194 case SPI_SETCARETWIDTH:
195 case SPI_SETTOGGLEKEYS:
200 return ERROR_BAD_ARGUMENTS;
203 wStream* s = rail_pdu_init(length);
207 WLog_ERR(TAG,
"rail_pdu_init failed!");
208 return CHANNEL_RC_NO_MEMORY;
211 const BOOL extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
212 const UINT error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported);
215 WLog_ERR(TAG,
"rail_write_client_sysparam_order failed with error %" PRIu32
"!", error);
216 Stream_Free(s, TRUE);
220 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
228static UINT rail_client_system_param(RailClientContext* context,
231 UINT error = CHANNEL_RC_OK;
233 if (!context || !sysInParam)
234 return ERROR_INVALID_PARAMETER;
238 if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
240 sysparam.param = SPI_SET_HIGH_CONTRAST;
242 if ((error = rail_send_client_sysparam(context, &sysparam)))
244 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
249 if (sysparam.params & SPI_MASK_TASKBAR_POS)
251 sysparam.param = SPI_TASKBAR_POS;
253 if ((error = rail_send_client_sysparam(context, &sysparam)))
255 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
260 if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
262 sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
264 if ((error = rail_send_client_sysparam(context, &sysparam)))
266 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
271 if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
273 sysparam.param = SPI_SET_KEYBOARD_PREF;
275 if ((error = rail_send_client_sysparam(context, &sysparam)))
277 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
282 if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
284 sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
286 if ((error = rail_send_client_sysparam(context, &sysparam)))
288 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
293 if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
295 sysparam.param = SPI_SET_KEYBOARD_CUES;
297 if ((error = rail_send_client_sysparam(context, &sysparam)))
299 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
304 if (sysparam.params & SPI_MASK_SET_WORK_AREA)
306 sysparam.param = SPI_SET_WORK_AREA;
308 if ((error = rail_send_client_sysparam(context, &sysparam)))
310 WLog_ERR(TAG,
"rail_send_client_sysparam failed with error %" PRIu32
"!", error);
323static UINT rail_client_system_command(RailClientContext* context,
328 if (!context || !syscommand)
329 return ERROR_INVALID_PARAMETER;
332 return rail_send_client_syscommand_order(rail, syscommand);
340static UINT rail_client_handshake(RailClientContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
342 if (!context || !handshake)
343 return ERROR_INVALID_PARAMETER;
347 WLog_Print(rail->log, WLOG_DEBUG,
"build=0x%08" PRIx32, handshake->buildNumber);
348 return rail_send_handshake_order(rail, handshake);
351static UINT rail_server_handshake(RailClientContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
353 WINPR_ASSERT(context);
354 WINPR_ASSERT(handshake);
359 WLog_Print(rail->log, WLOG_DEBUG,
"build=0x%08" PRIx32, handshake->buildNumber);
361 const UINT32 buildnumber =
364 return context->ClientHandshake(context, &clientHandshake);
367static UINT rail_server_handshake_ex(RailClientContext* context,
370 WINPR_ASSERT(context);
371 WINPR_ASSERT(handshakeEx);
378 char buffer[128] = WINPR_C_ARRAY_INIT;
380 rail->log, WLOG_DEBUG,
"build=0x%08" PRIx32
", flags=%s", handshakeEx->buildNumber,
381 rail_handshake_ex_flags_to_string(handshakeEx->railHandshakeFlags, buffer,
sizeof(buffer)));
382 return rail_server_handshake(context, &handshake);
390static UINT rail_client_notify_event(RailClientContext* context,
395 if (!context || !notifyEvent)
396 return ERROR_INVALID_PARAMETER;
399 return rail_send_client_notify_event_order(rail, notifyEvent);
407static UINT rail_client_window_move(RailClientContext* context,
412 if (!context || !windowMove)
413 return ERROR_INVALID_PARAMETER;
416 return rail_send_client_window_move_order(rail, windowMove);
424static UINT rail_client_information(RailClientContext* context,
429 if (!context || !clientStatus)
430 return ERROR_INVALID_PARAMETER;
433 return rail_send_client_status_order(rail, clientStatus);
441static UINT rail_client_system_menu(RailClientContext* context,
const RAIL_SYSMENU_ORDER* sysmenu)
445 if (!context || !sysmenu)
446 return ERROR_INVALID_PARAMETER;
449 return rail_send_client_sysmenu_order(rail, sysmenu);
457static UINT rail_client_language_bar_info(RailClientContext* context,
462 if (!context || !langBarInfo)
463 return ERROR_INVALID_PARAMETER;
466 return rail_send_client_langbar_info_order(rail, langBarInfo);
469static UINT rail_client_language_ime_info(RailClientContext* context,
474 if (!context || !langImeInfo)
475 return ERROR_INVALID_PARAMETER;
478 return rail_send_client_languageime_info_order(rail, langImeInfo);
486static UINT rail_client_get_appid_request(RailClientContext* context,
491 if (!context || !getAppIdReq || !context->handle)
492 return ERROR_INVALID_PARAMETER;
495 return rail_send_client_get_appid_req_order(rail, getAppIdReq);
498static UINT rail_client_compartment_info(RailClientContext* context,
503 if (!context || !compartmentInfo || !context->handle)
504 return ERROR_INVALID_PARAMETER;
507 return rail_send_client_compartment_info_order(rail, compartmentInfo);
510static UINT rail_client_cloak(RailClientContext* context,
const RAIL_CLOAK* cloak)
514 if (!context || !cloak || !context->handle)
515 return ERROR_INVALID_PARAMETER;
518 return rail_send_client_cloak_order(rail, cloak);
521static UINT rail_client_snap_arrange(RailClientContext* context,
const RAIL_SNAP_ARRANGE* snap)
525 if (!context || !snap || !context->handle)
526 return ERROR_INVALID_PARAMETER;
529 return rail_send_client_snap_arrange_order(rail, snap);
532static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
534 if (!context || !context->handle)
535 return ERROR_INVALID_PARAMETER;
538 return rail_send_client_text_scale_order(rail, textScale);
541static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
543 if (!context || !context->handle)
544 return ERROR_INVALID_PARAMETER;
547 return rail_send_client_caret_blink_rate_order(rail, rate);
550static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
551 UINT event, LPVOID pData,
552 UINT32 dataLength, UINT32 totalLength,
555 UINT error = CHANNEL_RC_OK;
560 case CHANNEL_EVENT_DATA_RECEIVED:
561 if (!rail || (rail->OpenHandle != openHandle))
563 WLog_ERR(TAG,
"error no match");
567 if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
568 totalLength, dataFlags)))
571 "rail_virtual_channel_event_data_received"
572 " failed with error %" PRIu32
"!",
578 case CHANNEL_EVENT_WRITE_CANCELLED:
579 case CHANNEL_EVENT_WRITE_COMPLETE:
582 Stream_Free(s, TRUE);
586 case CHANNEL_EVENT_USER:
592 if (error && rail && rail->rdpcontext)
593 setChannelError(rail->rdpcontext, error,
594 "rail_virtual_channel_open_event reported an error");
602static UINT rail_virtual_channel_event_connected(
railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
603 WINPR_ATTR_UNUSED UINT32 dataLength)
607 rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
608 RAIL_SVC_CHANNEL_NAME);
609 if (!rail->MsgsHandle)
610 return ERROR_INTERNAL_ERROR;
612 return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
613 rail->channelDef.name,
614 rail_virtual_channel_open_event_ex);
622static UINT rail_virtual_channel_event_disconnected(
railPlugin* rail)
626 channel_client_quit_handler(rail->MsgsHandle);
627 if (rail->OpenHandle == 0)
628 return CHANNEL_RC_OK;
630 WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
631 rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
633 if (CHANNEL_RC_OK != rc)
635 WLog_ERR(TAG,
"pVirtualChannelCloseEx failed with %s [%08" PRIX32
"]", WTSErrorToString(rc),
640 rail->OpenHandle = 0;
642 return CHANNEL_RC_OK;
645static void rail_virtual_channel_event_terminated(
railPlugin* rail)
647 rail->InitHandle =
nullptr;
652static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
653 UINT event, LPVOID pData, UINT dataLength)
655 UINT error = CHANNEL_RC_OK;
658 if (!rail || (rail->InitHandle != pInitHandle))
660 WLog_ERR(TAG,
"error no match");
666 case CHANNEL_EVENT_CONNECTED:
667 if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
668 WLog_ERR(TAG,
"rail_virtual_channel_event_connected failed with error %" PRIu32
"!",
673 case CHANNEL_EVENT_DISCONNECTED:
674 if ((error = rail_virtual_channel_event_disconnected(rail)))
676 "rail_virtual_channel_event_disconnected failed with error %" PRIu32
"!",
681 case CHANNEL_EVENT_TERMINATED:
682 rail_virtual_channel_event_terminated(rail);
685 case CHANNEL_EVENT_ATTACHED:
686 case CHANNEL_EVENT_DETACHED:
691 if (error && rail->rdpcontext)
692 setChannelError(rail->rdpcontext, error,
693 "rail_virtual_channel_init_event_ex reported an error");
697#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
699FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
704 RailClientContext* context =
nullptr;
706 BOOL isFreerdp = FALSE;
711 WLog_ERR(TAG,
"calloc failed!");
715 rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
716 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
717 (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
721 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
723 context = (RailClientContext*)calloc(1,
sizeof(RailClientContext));
727 WLog_ERR(TAG,
"calloc failed!");
732 context->handle = (
void*)rail;
733 context->custom =
nullptr;
734 context->ClientExecute = rail_client_execute;
735 context->ClientActivate = rail_client_activate;
736 context->ClientSystemParam = rail_client_system_param;
737 context->ClientSystemCommand = rail_client_system_command;
738 context->ClientHandshake = rail_client_handshake;
739 context->ServerHandshake = rail_server_handshake;
740 context->ServerHandshakeEx = rail_server_handshake_ex;
741 context->ClientNotifyEvent = rail_client_notify_event;
742 context->ClientWindowMove = rail_client_window_move;
743 context->ClientInformation = rail_client_information;
744 context->ClientSystemMenu = rail_client_system_menu;
745 context->ClientLanguageBarInfo = rail_client_language_bar_info;
746 context->ClientLanguageIMEInfo = rail_client_language_ime_info;
747 context->ClientGetAppIdRequest = rail_client_get_appid_request;
748 context->ClientSnapArrange = rail_client_snap_arrange;
749 context->ClientCloak = rail_client_cloak;
750 context->ClientCompartmentInfo = rail_client_compartment_info;
751 context->ClientTextScale = rail_client_text_scale;
752 context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
753 rail->rdpcontext = pEntryPointsEx->context;
754 rail->context = context;
758 rail->log = WLog_Get(
"com.freerdp.channels.rail.client");
759 WLog_Print(rail->log, WLOG_DEBUG,
"VirtualChannelEntryEx");
761 rail->InitHandle = pInitHandle;
762 rc = rail->channelEntryPoints.pVirtualChannelInitEx(
763 rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
764 rail_virtual_channel_init_event_ex);
766 if (CHANNEL_RC_OK != rc)
768 WLog_ERR(TAG,
"failed with %s [%08" PRIX32
"]", WTSErrorToString(rc), rc);
772 rail->channelEntryPoints.pInterface = context;
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.