23#include "rail_common.h"
26#include <freerdp/channels/log.h>
28#define TAG CHANNELS_TAG("rail.common")
30const char* rail_get_order_type_string(UINT16 orderType)
34 case TS_RAIL_ORDER_EXEC:
35 return "TS_RAIL_ORDER_EXEC";
36 case TS_RAIL_ORDER_ACTIVATE:
37 return "TS_RAIL_ORDER_ACTIVATE";
38 case TS_RAIL_ORDER_SYSPARAM:
39 return "TS_RAIL_ORDER_SYSPARAM";
40 case TS_RAIL_ORDER_SYSCOMMAND:
41 return "TS_RAIL_ORDER_SYSCOMMAND";
42 case TS_RAIL_ORDER_HANDSHAKE:
43 return "TS_RAIL_ORDER_HANDSHAKE";
44 case TS_RAIL_ORDER_NOTIFY_EVENT:
45 return "TS_RAIL_ORDER_NOTIFY_EVENT";
46 case TS_RAIL_ORDER_WINDOWMOVE:
47 return "TS_RAIL_ORDER_WINDOWMOVE";
48 case TS_RAIL_ORDER_LOCALMOVESIZE:
49 return "TS_RAIL_ORDER_LOCALMOVESIZE";
50 case TS_RAIL_ORDER_MINMAXINFO:
51 return "TS_RAIL_ORDER_MINMAXINFO";
52 case TS_RAIL_ORDER_CLIENTSTATUS:
53 return "TS_RAIL_ORDER_CLIENTSTATUS";
54 case TS_RAIL_ORDER_SYSMENU:
55 return "TS_RAIL_ORDER_SYSMENU";
56 case TS_RAIL_ORDER_LANGBARINFO:
57 return "TS_RAIL_ORDER_LANGBARINFO";
58 case TS_RAIL_ORDER_GET_APPID_REQ:
59 return "TS_RAIL_ORDER_GET_APPID_REQ";
60 case TS_RAIL_ORDER_GET_APPID_RESP:
61 return "TS_RAIL_ORDER_GET_APPID_RESP";
62 case TS_RAIL_ORDER_TASKBARINFO:
63 return "TS_RAIL_ORDER_TASKBARINFO";
64 case TS_RAIL_ORDER_LANGUAGEIMEINFO:
65 return "TS_RAIL_ORDER_LANGUAGEIMEINFO";
66 case TS_RAIL_ORDER_COMPARTMENTINFO:
67 return "TS_RAIL_ORDER_COMPARTMENTINFO";
68 case TS_RAIL_ORDER_HANDSHAKE_EX:
69 return "TS_RAIL_ORDER_HANDSHAKE_EX";
70 case TS_RAIL_ORDER_ZORDER_SYNC:
71 return "TS_RAIL_ORDER_ZORDER_SYNC";
72 case TS_RAIL_ORDER_CLOAK:
73 return "TS_RAIL_ORDER_CLOAK";
74 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
75 return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST";
76 case TS_RAIL_ORDER_SNAP_ARRANGE:
77 return "TS_RAIL_ORDER_SNAP_ARRANGE";
78 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
79 return "TS_RAIL_ORDER_GET_APPID_RESP_EX";
80 case TS_RAIL_ORDER_EXEC_RESULT:
81 return "TS_RAIL_ORDER_EXEC_RESULT";
82 case TS_RAIL_ORDER_TEXTSCALEINFO:
83 return "TS_RAIL_ORDER_TEXTSCALEINFO";
84 case TS_RAIL_ORDER_CARETBLINKINFO:
85 return "TS_RAIL_ORDER_CARETBLINKINFO";
87 return "TS_RAIL_ORDER_UNKNOWN";
91const char* rail_get_order_type_string_full(UINT16 orderType,
char* buffer,
size_t length)
93 (void)_snprintf(buffer, length,
"%s[0x%04" PRIx16
"]", rail_get_order_type_string(orderType),
103UINT rail_read_pdu_header(
wStream* s, UINT16* orderType, UINT16* orderLength)
105 if (!s || !orderType || !orderLength)
106 return ERROR_INVALID_PARAMETER;
108 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
109 return ERROR_INVALID_DATA;
111 Stream_Read_UINT16(s, *orderType);
112 Stream_Read_UINT16(s, *orderLength);
113 if (*orderLength < RAIL_PDU_HEADER_LENGTH)
115 WLog_ERR(TAG,
"invalid order length %" PRIu16
" < RAIL_PDU_HEADER_LENGTH(%u)", *orderLength,
116 RAIL_PDU_HEADER_LENGTH);
117 return ERROR_INVALID_DATA;
120 if (!Stream_CheckAndLogRequiredLength(TAG, s, *orderLength - RAIL_PDU_HEADER_LENGTH))
121 return ERROR_INVALID_DATA;
123 if (*orderLength > RAIL_PDU_MAX_LENGTH)
125 WLog_ERR(TAG,
"invalid order length %" PRIu16
" < RAIL_PDU_MAX_LENGTH(%llu)", *orderLength,
126 RAIL_PDU_MAX_LENGTH);
127 return ERROR_INVALID_DATA;
130 return CHANNEL_RC_OK;
133BOOL rail_write_pdu_header(
wStream* s, UINT16 orderType, UINT16 orderLength)
135 if (!Stream_EnsureRemainingCapacity(s, 4))
137 Stream_Write_UINT16(s, orderType);
138 Stream_Write_UINT16(s, orderLength);
142wStream* rail_pdu_init(
size_t length)
144 wStream* s = Stream_New(
nullptr, length + RAIL_PDU_HEADER_LENGTH);
149 Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
160 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
161 return ERROR_INVALID_DATA;
163 Stream_Read_UINT32(s, handshake->buildNumber);
164 return CHANNEL_RC_OK;
170 WINPR_ASSERT(handshake);
171 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, 4));
172 Stream_Write_UINT32(s, handshake->buildNumber);
182 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
183 return ERROR_INVALID_DATA;
185 Stream_Read_UINT32(s, handshakeEx->buildNumber);
186 Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags);
187 return CHANNEL_RC_OK;
193 WINPR_ASSERT(handshakeEx);
194 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, 8));
196 Stream_Write_UINT32(s, handshakeEx->buildNumber);
197 Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags);
207 if (!s || !highContrast)
208 return ERROR_INVALID_PARAMETER;
210 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
211 return ERROR_INVALID_DATA;
213 Stream_Read_UINT32(s, highContrast->flags);
214 Stream_Read_UINT32(s, highContrast->colorSchemeLength);
216 if (!rail_read_unicode_string(s, &highContrast->colorScheme))
217 return ERROR_INTERNAL_ERROR;
218 return CHANNEL_RC_OK;
228 UINT32 colorSchemeLength = 0;
230 if (!s || !highContrast)
231 return ERROR_INVALID_PARAMETER;
233 if (!Stream_EnsureRemainingCapacity(s, 8))
234 return CHANNEL_RC_NO_MEMORY;
236 colorSchemeLength = highContrast->colorScheme.length + 2;
237 Stream_Write_UINT32(s, highContrast->flags);
238 Stream_Write_UINT32(s, colorSchemeLength);
239 return rail_write_unicode_string(s, &highContrast->colorScheme);
249 if (!s || !filterKeys)
250 return ERROR_INVALID_PARAMETER;
252 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
253 return ERROR_INVALID_DATA;
255 Stream_Read_UINT32(s, filterKeys->Flags);
256 Stream_Read_UINT32(s, filterKeys->WaitTime);
257 Stream_Read_UINT32(s, filterKeys->DelayTime);
258 Stream_Read_UINT32(s, filterKeys->RepeatTime);
259 Stream_Read_UINT32(s, filterKeys->BounceTime);
260 return CHANNEL_RC_OK;
270 if (!s || !filterKeys)
271 return ERROR_INVALID_PARAMETER;
273 if (!Stream_EnsureRemainingCapacity(s, 20))
274 return CHANNEL_RC_NO_MEMORY;
276 Stream_Write_UINT32(s, filterKeys->Flags);
277 Stream_Write_UINT32(s, filterKeys->WaitTime);
278 Stream_Write_UINT32(s, filterKeys->DelayTime);
279 Stream_Write_UINT32(s, filterKeys->RepeatTime);
280 Stream_Write_UINT32(s, filterKeys->BounceTime);
281 return CHANNEL_RC_OK;
292 UINT error = CHANNEL_RC_OK;
295 return ERROR_INVALID_PARAMETER;
297 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
298 return ERROR_INVALID_DATA;
300 Stream_Read_UINT32(s, sysparam->param);
302 sysparam->params = 0;
304 switch (sysparam->param)
307 case SPI_SET_DRAG_FULL_WINDOWS:
308 sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
309 Stream_Read_UINT8(s, body);
310 sysparam->dragFullWindows = body != 0;
313 case SPI_SET_KEYBOARD_CUES:
314 sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
315 Stream_Read_UINT8(s, body);
316 sysparam->keyboardCues = body != 0;
319 case SPI_SET_KEYBOARD_PREF:
320 sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
321 Stream_Read_UINT8(s, body);
322 sysparam->keyboardPref = body != 0;
325 case SPI_SET_MOUSE_BUTTON_SWAP:
326 sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
327 Stream_Read_UINT8(s, body);
328 sysparam->mouseButtonSwap = body != 0;
331 case SPI_SET_WORK_AREA:
332 sysparam->params |= SPI_MASK_SET_WORK_AREA;
334 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
335 return ERROR_INVALID_DATA;
337 Stream_Read_UINT16(s, sysparam->workArea.left);
338 Stream_Read_UINT16(s, sysparam->workArea.top);
339 Stream_Read_UINT16(s, sysparam->workArea.right);
340 Stream_Read_UINT16(s, sysparam->workArea.bottom);
343 case SPI_DISPLAY_CHANGE:
344 sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
346 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
347 return ERROR_INVALID_DATA;
349 Stream_Read_UINT16(s, sysparam->displayChange.left);
350 Stream_Read_UINT16(s, sysparam->displayChange.top);
351 Stream_Read_UINT16(s, sysparam->displayChange.right);
352 Stream_Read_UINT16(s, sysparam->displayChange.bottom);
355 case SPI_TASKBAR_POS:
356 sysparam->params |= SPI_MASK_TASKBAR_POS;
358 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
359 return ERROR_INVALID_DATA;
361 Stream_Read_UINT16(s, sysparam->taskbarPos.left);
362 Stream_Read_UINT16(s, sysparam->taskbarPos.top);
363 Stream_Read_UINT16(s, sysparam->taskbarPos.right);
364 Stream_Read_UINT16(s, sysparam->taskbarPos.bottom);
367 case SPI_SET_HIGH_CONTRAST:
368 sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
369 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
370 return ERROR_INVALID_DATA;
372 error = rail_read_high_contrast(s, &sysparam->highContrast);
375 case SPI_SETCARETWIDTH:
376 sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
378 if (!extendedSpiSupported)
379 return ERROR_INVALID_DATA;
381 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
382 return ERROR_INVALID_DATA;
384 Stream_Read_UINT32(s, sysparam->caretWidth);
386 if (sysparam->caretWidth < 0x0001)
387 return ERROR_INVALID_DATA;
391 case SPI_SETSTICKYKEYS:
392 sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
394 if (!extendedSpiSupported)
395 return ERROR_INVALID_DATA;
397 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
398 return ERROR_INVALID_DATA;
400 Stream_Read_UINT32(s, sysparam->stickyKeys);
403 case SPI_SETTOGGLEKEYS:
404 sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
406 if (!extendedSpiSupported)
407 return ERROR_INVALID_DATA;
409 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
410 return ERROR_INVALID_DATA;
412 Stream_Read_UINT32(s, sysparam->toggleKeys);
415 case SPI_SETFILTERKEYS:
416 sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
418 if (!extendedSpiSupported)
419 return ERROR_INVALID_DATA;
421 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
422 return ERROR_INVALID_DATA;
424 error = rail_read_filterkeys(s, &sysparam->filterKeys);
428 case SPI_SETSCREENSAVEACTIVE:
429 sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
431 Stream_Read_UINT8(s, body);
432 sysparam->setScreenSaveActive = body != 0;
435 case SPI_SETSCREENSAVESECURE:
436 sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
438 Stream_Read_UINT8(s, body);
439 sysparam->setScreenSaveSecure = body != 0;
450 BOOL extendedSpiSupported)
453 UINT error = CHANNEL_RC_OK;
456 return ERROR_INVALID_PARAMETER;
458 if (!Stream_EnsureRemainingCapacity(s, 12))
459 return CHANNEL_RC_NO_MEMORY;
461 Stream_Write_UINT32(s, sysparam->param);
463 switch (sysparam->param)
466 case SPI_SET_DRAG_FULL_WINDOWS:
467 body = sysparam->dragFullWindows ? 1 : 0;
468 Stream_Write_UINT8(s, body);
471 case SPI_SET_KEYBOARD_CUES:
472 body = sysparam->keyboardCues ? 1 : 0;
473 Stream_Write_UINT8(s, body);
476 case SPI_SET_KEYBOARD_PREF:
477 body = sysparam->keyboardPref ? 1 : 0;
478 Stream_Write_UINT8(s, body);
481 case SPI_SET_MOUSE_BUTTON_SWAP:
482 body = sysparam->mouseButtonSwap ? 1 : 0;
483 Stream_Write_UINT8(s, body);
486 case SPI_SET_WORK_AREA:
487 Stream_Write_UINT16(s, sysparam->workArea.left);
488 Stream_Write_UINT16(s, sysparam->workArea.top);
489 Stream_Write_UINT16(s, sysparam->workArea.right);
490 Stream_Write_UINT16(s, sysparam->workArea.bottom);
493 case SPI_DISPLAY_CHANGE:
494 Stream_Write_UINT16(s, sysparam->displayChange.left);
495 Stream_Write_UINT16(s, sysparam->displayChange.top);
496 Stream_Write_UINT16(s, sysparam->displayChange.right);
497 Stream_Write_UINT16(s, sysparam->displayChange.bottom);
500 case SPI_TASKBAR_POS:
501 Stream_Write_UINT16(s, sysparam->taskbarPos.left);
502 Stream_Write_UINT16(s, sysparam->taskbarPos.top);
503 Stream_Write_UINT16(s, sysparam->taskbarPos.right);
504 Stream_Write_UINT16(s, sysparam->taskbarPos.bottom);
507 case SPI_SET_HIGH_CONTRAST:
508 error = rail_write_high_contrast(s, &sysparam->highContrast);
511 case SPI_SETCARETWIDTH:
512 if (!extendedSpiSupported)
513 return ERROR_INVALID_DATA;
515 if (sysparam->caretWidth < 0x0001)
516 return ERROR_INVALID_DATA;
518 Stream_Write_UINT32(s, sysparam->caretWidth);
521 case SPI_SETSTICKYKEYS:
522 if (!extendedSpiSupported)
523 return ERROR_INVALID_DATA;
525 Stream_Write_UINT32(s, sysparam->stickyKeys);
528 case SPI_SETTOGGLEKEYS:
529 if (!extendedSpiSupported)
530 return ERROR_INVALID_DATA;
532 Stream_Write_UINT32(s, sysparam->toggleKeys);
535 case SPI_SETFILTERKEYS:
536 if (!extendedSpiSupported)
537 return ERROR_INVALID_DATA;
539 error = rail_write_filterkeys(s, &sysparam->filterKeys);
543 case SPI_SETSCREENSAVEACTIVE:
544 body = sysparam->setScreenSaveActive ? 1 : 0;
545 Stream_Write_UINT8(s, body);
548 case SPI_SETSCREENSAVESECURE:
549 body = sysparam->setScreenSaveSecure ? 1 : 0;
550 Stream_Write_UINT8(s, body);
554 return ERROR_INVALID_PARAMETER;
560BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
562 return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) != 0;
565const char* rail_handshake_ex_flags_to_string(UINT32 flags,
char* buffer,
size_t len)
570 (void)_snprintf(buffer, len,
"{");
571 char* fbuffer = &buffer[1];
574 if (flags & TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF)
575 winpr_str_append(
"HIDEF", fbuffer, len,
"|");
576 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED)
577 winpr_str_append(
"EXTENDED_SPI_SUPPORTED", fbuffer, len,
"|");
578 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED)
579 winpr_str_append(
"SNAP_ARRANGE_SUPPORTED", fbuffer, len,
"|");
580 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED)
581 winpr_str_append(
"TEXT_SCALE_SUPPORTED", fbuffer, len,
"|");
582 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED)
583 winpr_str_append(
"CARET_BLINK_SUPPORTED", fbuffer, len,
"|");
584 if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED)
585 winpr_str_append(
"EXTENDED_SPI_2_SUPPORTED", fbuffer, len,
"|");
587 char number[16] = WINPR_C_ARRAY_INIT;
588 (void)_snprintf(number,
sizeof(number),
"[0x%08" PRIx32
"]", flags);
589 winpr_str_append(number, buffer, len,
"}");