2011-08-12 12:15:04 +04:00
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2011-08-12 12:15:04 +04:00
|
|
|
* Remote Applications Integrated Locally (RAIL) Orders
|
|
|
|
*
|
|
|
|
* Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
|
|
* Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
|
2015-06-08 19:04:05 +03:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2017-02-20 20:31:58 +03:00
|
|
|
* Copyright 2017 Armin Novak <armin.novak@thincast.com>
|
|
|
|
* Copyright 2017 Thincast Technologies GmbH
|
2011-08-12 12:15:04 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2012-08-15 01:09:01 +04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2012-10-09 07:21:26 +04:00
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
2014-08-11 11:12:01 +04:00
|
|
|
#include <freerdp/channels/log.h>
|
2011-08-11 00:33:15 +04:00
|
|
|
|
|
|
|
#include "rail_orders.h"
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
|
2015-05-18 12:28:00 +03:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !unicode_string)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2014-11-12 18:18:53 +03:00
|
|
|
|
|
|
|
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
|
|
|
|
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2014-11-12 18:18:53 +03:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
|
2014-11-12 18:18:53 +03:00
|
|
|
{
|
2018-09-14 11:04:16 +03:00
|
|
|
size_t length;
|
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !unicode_string)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
length = unicode_string->length;
|
|
|
|
|
|
|
|
if (length > 0)
|
2014-11-12 18:18:53 +03:00
|
|
|
{
|
2018-09-14 11:04:16 +03:00
|
|
|
if (!Stream_EnsureRemainingCapacity(s, length))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
Stream_Write(s, unicode_string->string, length); /* string */
|
2014-11-12 18:18:53 +03:00
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2014-11-12 18:18:53 +03:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
UINT16 orderLength;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !s)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2014-02-10 10:06:11 +04:00
|
|
|
orderLength = (UINT16) Stream_GetPosition(s);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(s, 0);
|
2011-08-11 00:33:15 +04:00
|
|
|
rail_write_pdu_header(s, orderType, orderLength);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(s, orderLength);
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %"PRIu16"",
|
2017-02-20 20:31:58 +03:00
|
|
|
RAIL_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], orderLength);
|
2019-02-19 16:13:34 +03:00
|
|
|
return rail_send_channel_data(rail, s);
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT32 colorSchemeLength;
|
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !highContrast)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
colorSchemeLength = highContrast->colorScheme.length + 2;
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
|
2018-09-14 11:04:16 +03:00
|
|
|
Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
|
2015-05-18 12:28:00 +03:00
|
|
|
return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
|
|
|
|
{
|
|
|
|
if (!s || !filterKeys)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, filterKeys->Flags);
|
|
|
|
Stream_Write_UINT32(s, filterKeys->WaitTime);
|
|
|
|
Stream_Write_UINT32(s, filterKeys->DelayTime);
|
|
|
|
Stream_Write_UINT32(s, filterKeys->RepeatTime);
|
|
|
|
Stream_Write_UINT32(s, filterKeys->BounceTime);
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* execResult)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !execResult)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 8)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
|
|
|
Stream_Read_UINT16(s, execResult->flags); /* flags (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, execResult->execResult); /* execResult (2 bytes) */
|
|
|
|
Stream_Read_UINT32(s, execResult->rawResult); /* rawResult (4 bytes) */
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek_UINT16(s); /* padding (2 bytes) */
|
2017-02-20 20:31:58 +03:00
|
|
|
return rail_read_unicode_string(s,
|
|
|
|
&execResult->exeOrFile) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; /* exeOrFile */
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE body;
|
2013-01-11 04:31:48 +04:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !sysparam)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 5)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
|
|
|
|
Stream_Read_UINT8(s, body); /* body (1 byte) */
|
2011-08-18 05:33:22 +04:00
|
|
|
|
|
|
|
switch (sysparam->param)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
case SPI_SETSCREENSAVEACTIVE:
|
2012-10-09 10:31:28 +04:00
|
|
|
sysparam->setScreenSaveActive = (body != 0) ? TRUE : FALSE;
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
case SPI_SETSCREENSAVESECURE:
|
2012-10-09 10:31:28 +04:00
|
|
|
sysparam->setScreenSaveSecure = (body != 0) ? TRUE : FALSE;
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !minmaxinfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 20)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(s, minmaxinfo->windowId); /* windowId (4 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxWidth); /* maxWidth (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxHeight); /* maxHeight (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxPosX); /* maxPosX (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxPosY); /* maxPosY (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->minTrackWidth); /* minTrackWidth (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->minTrackHeight); /* minTrackHeight (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxTrackWidth); /* maxTrackWidth (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, minmaxinfo->maxTrackHeight); /* maxTrackHeight (2 bytes) */
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_server_localmovesize_order(wStream* s,
|
|
|
|
RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
UINT16 isMoveSizeStart;
|
2013-10-10 06:38:26 +04:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !localMoveSize)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 12)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
|
|
|
Stream_Read_UINT32(s, localMoveSize->windowId); /* windowId (4 bytes) */
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT16(s, isMoveSizeStart); /* isMoveSizeStart (2 bytes) */
|
2013-10-10 06:38:26 +04:00
|
|
|
localMoveSize->isMoveSizeStart = (isMoveSizeStart != 0) ? TRUE : FALSE;
|
|
|
|
Stream_Read_UINT16(s, localMoveSize->moveSizeType); /* moveSizeType (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, localMoveSize->posX); /* posX (2 bytes) */
|
|
|
|
Stream_Read_UINT16(s, localMoveSize->posY); /* posY (2 bytes) */
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_server_get_appid_resp_order(wStream* s,
|
|
|
|
RAIL_GET_APPID_RESP_ORDER* getAppidResp)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !getAppidResp)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 516)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */
|
2017-02-20 20:31:58 +03:00
|
|
|
Stream_Read(s, (BYTE*) & (getAppidResp->applicationId),
|
|
|
|
512); /* applicationId (256 UNICODE chars) */
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !langbarInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
if (Stream_GetRemainingLength(s) < 4)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
|
|
|
Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !clientStatus)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, clientStatus->flags); /* flags (4 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_exec_order(wStream* s, UINT16 flags,
|
|
|
|
const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir,
|
|
|
|
const RAIL_UNICODE_STRING* arguments)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if (!s || !exeOrFile || !workingDir || !arguments)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
/* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC)
|
|
|
|
* Check argument limits */
|
|
|
|
if ((exeOrFile->length > 520) || (workingDir->length > 520) ||
|
|
|
|
(arguments->length > 16000))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG,
|
|
|
|
"TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%"PRIu16" [max=520], WorkingDir=%"PRIu16" [max=520], Arguments=%"PRIu16" [max=16000]",
|
|
|
|
exeOrFile->length, workingDir->length, arguments->length);
|
|
|
|
return ERROR_BAD_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Write_UINT16(s, flags); /* flags (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if ((error = rail_write_unicode_string_value(s, exeOrFile)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2017-02-20 20:31:58 +03:00
|
|
|
WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if ((error = rail_write_unicode_string_value(s, workingDir)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2017-02-20 20:31:58 +03:00
|
|
|
WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if ((error = rail_write_unicode_string_value(s, arguments)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2017-02-20 20:31:58 +03:00
|
|
|
WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
UINT rail_write_client_sysparam_order(railPlugin* rail, wStream* s,
|
|
|
|
const RAIL_SYSPARAM_ORDER* sysparam)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE body;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!s || !sysparam)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2011-08-18 05:33:22 +04:00
|
|
|
switch (sysparam->param)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
|
|
|
case SPI_SET_DRAG_FULL_WINDOWS:
|
2018-09-14 11:04:16 +03:00
|
|
|
body = sysparam->dragFullWindows ? 1 : 0;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT8(s, body);
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
case SPI_SET_KEYBOARD_CUES:
|
2018-09-14 11:04:16 +03:00
|
|
|
body = sysparam->keyboardCues ? 1 : 0;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT8(s, body);
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
case SPI_SET_KEYBOARD_PREF:
|
2018-09-14 11:04:16 +03:00
|
|
|
body = sysparam->keyboardPref ? 1 : 0;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT8(s, body);
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
case SPI_SET_MOUSE_BUTTON_SWAP:
|
2018-09-14 11:04:16 +03:00
|
|
|
body = sysparam->mouseButtonSwap ? 1 : 0;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT8(s, body);
|
2011-08-11 00:33:15 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SET_WORK_AREA:
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
case SPI_DISPLAY_CHANGE:
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
|
2011-08-18 05:33:22 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
case SPI_TASKBAR_POS:
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
|
2011-08-11 00:33:15 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SET_HIGH_CONTRAST:
|
2015-06-08 19:04:05 +03:00
|
|
|
error = rail_write_high_contrast(s, &sysparam->highContrast);
|
2011-08-11 00:33:15 +04:00
|
|
|
break;
|
2019-05-08 16:36:20 +03:00
|
|
|
|
|
|
|
case SPI_SETCARETWIDTH:
|
|
|
|
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
error = rail_write_high_contrast(s, &sysparam->caretWidth);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SETSTICKYKEYS:
|
|
|
|
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, sysparam->stickyKeys);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SETTOGGLEKEYS:
|
|
|
|
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, sysparam->toggleKeys);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SETFILTERKEYS:
|
|
|
|
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
error = rail_write_filterkeys(s, &sysparam->filterKeys);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE enabled;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!s || !activate)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */
|
2018-09-14 11:04:16 +03:00
|
|
|
enabled = activate->enabled ? 1 : 0;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER* sysmenu)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !sysmenu)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysmenu->left); /* left (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, sysmenu->top); /* top (2 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND_ORDER* syscommand)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !syscommand)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */
|
|
|
|
Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_notify_event_order(wStream* s,
|
|
|
|
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !notifyEvent)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */
|
|
|
|
Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_window_move_order(wStream* s,
|
|
|
|
const RAIL_WINDOW_MOVE_ORDER* windowMove)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !windowMove)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */
|
|
|
|
Stream_Write_UINT16(s, windowMove->left); /* left (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, windowMove->top); /* top (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, windowMove->right); /* right (2 bytes) */
|
|
|
|
Stream_Write_UINT16(s, windowMove->bottom); /* bottom (2 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_client_get_appid_req_order(wStream* s,
|
|
|
|
const RAIL_GET_APPID_REQ_ORDER* getAppidReq)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !getAppidReq)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, getAppidReq->windowId); /* windowId (4 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!s || !langbarInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-10 06:38:26 +04:00
|
|
|
Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_SUCCESS;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_write_languageime_info_order(wStream* s,
|
|
|
|
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
|
|
|
|
{
|
|
|
|
if (!s || !langImeInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, langImeInfo->ProfileType);
|
|
|
|
Stream_Write_UINT32(s, langImeInfo->LanguageID);
|
|
|
|
Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID));
|
|
|
|
Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID));
|
|
|
|
Stream_Write_UINT32(s, langImeInfo->KeyboardLayout);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
|
2011-08-12 00:27:16 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_HANDSHAKE_ORDER serverHandshake = { 0 };
|
2019-02-19 16:13:34 +03:00
|
|
|
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-15 07:16:40 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_handshake_order(s, &serverHandshake)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_handshake_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-12 00:27:16 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
rail->channelBuildNumber = serverHandshake.buildNumber;
|
2019-02-19 16:13:34 +03:00
|
|
|
clientHandshake.buildNumber = 0x00001DB0;
|
|
|
|
/* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
|
|
|
|
* Client response is really a Handshake PDU */
|
|
|
|
error = context->ClientHandshake(context, &clientHandshake);
|
|
|
|
|
|
|
|
if (error != CHANNEL_RC_OK)
|
|
|
|
return error;
|
|
|
|
|
2013-10-21 05:59:03 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerHandshake, error, context, &serverHandshake);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerHandshake failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-10-21 05:59:03 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2013-10-21 05:59:03 +04:00
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
|
|
|
|
{
|
|
|
|
UINT32 supported, masked;
|
|
|
|
|
|
|
|
if (!context || !context->settings)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
supported = context->settings->RemoteApplicationSupportLevel &
|
|
|
|
context->settings->RemoteApplicationSupportMask;
|
|
|
|
masked = (supported & featureMask);
|
|
|
|
|
|
|
|
if (masked != featureMask)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
|
2013-10-21 05:59:03 +04:00
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_HANDSHAKE_EX_ORDER serverHandshake = { 0 };
|
2019-02-19 16:13:34 +03:00
|
|
|
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-21 05:59:03 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!rail || !context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED))
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
if ((error = rail_read_handshake_ex_order(s, &serverHandshake)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-10-21 05:59:03 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
rail->channelBuildNumber = serverHandshake.buildNumber;
|
|
|
|
rail->channelFlags = serverHandshake.railHandshakeFlags;
|
2019-02-19 16:13:34 +03:00
|
|
|
clientHandshake.buildNumber = 0x00001DB0;
|
|
|
|
/* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
|
|
|
|
* Client response is really a Handshake PDU */
|
|
|
|
error = context->ClientHandshake(context, &clientHandshake);
|
|
|
|
|
|
|
|
if (error != CHANNEL_RC_OK)
|
|
|
|
return error;
|
|
|
|
|
2013-10-15 07:16:40 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake);
|
2015-07-30 16:49:21 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
if (error)
|
2019-04-25 11:55:24 +03:00
|
|
|
WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %"PRIu32"", error);
|
2017-02-20 20:31:58 +03:00
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-12 00:27:16 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s)
|
2011-08-19 18:10:08 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_EXEC_RESULT_ORDER execResult = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_server_exec_result_order(s, &execResult)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %"PRIu32"!", error);
|
2019-05-08 16:36:20 +03:00
|
|
|
goto fail;
|
2015-06-08 19:04:05 +03:00
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-15 07:16:40 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerExecuteResult, error, context, &execResult);
|
2015-07-30 16:49:21 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerExecuteResult failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
fail:
|
|
|
|
free(execResult.exeOrFile.string);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-20 02:46:10 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
|
2011-08-20 02:46:10 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_SYSPARAM_ORDER sysparam;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-15 07:16:40 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_server_sysparam_order(s, &sysparam)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_server_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-15 07:16:40 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerSystemParam failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-20 02:46:10 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
|
2011-08-20 02:46:10 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_MINMAXINFO_ORDER minMaxInfo = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-16 23:32:33 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-16 23:32:33 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-20 02:46:10 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
|
2011-08-20 02:46:10 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_LOCALMOVESIZE_ORDER localMoveSize = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-16 23:32:33 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-16 23:32:33 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-20 02:46:10 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
|
2011-08-20 02:46:10 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_GET_APPID_RESP_ORDER getAppIdResp = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-16 23:32:33 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context || !s)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-16 23:32:33 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-20 02:46:10 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
|
2011-08-20 02:46:10 +04:00
|
|
|
{
|
2013-10-16 23:32:33 +04:00
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_LANGBAR_INFO_ORDER langBarInfo = { 0 };
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2013-10-16 23:32:33 +04:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %"PRIu32"!", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->custom)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
|
|
|
|
{
|
|
|
|
if (!s || !taskbarInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 12)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
|
|
|
|
Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
|
|
|
|
Stream_Read_UINT32(s, taskbarInfo->Body);
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
|
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
|
|
|
RAIL_TASKBAR_INFO_ORDER taskBarInfo = { 0 };
|
|
|
|
UINT error;
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
|
|
|
|
* server -> client message only supported if announced. */
|
|
|
|
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2013-10-16 23:32:33 +04:00
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %"PRIu32"", error);
|
|
|
|
}
|
2013-03-29 04:23:16 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-19 18:10:08 +04:00
|
|
|
}
|
|
|
|
|
2019-04-26 14:14:30 +03:00
|
|
|
static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
if (!s || !zorder)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 4)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, zorder->windowIdMarker);
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_ZORDER_SYNC zorder = { 0 };
|
2019-02-19 16:13:34 +03:00
|
|
|
UINT error;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context)
|
2019-02-19 16:13:34 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if ((error = rail_read_zorder_sync_order(s, &zorder)))
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %"PRIu32"!", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerZOrderSync failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT rail_read_order_cloak(wStream* s, RAIL_CLOAK* cloak)
|
|
|
|
{
|
|
|
|
if (!s || !cloak)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 5)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, cloak->windowId);
|
|
|
|
Stream_Read_UINT8(s, cloak->cloak);
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s)
|
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
|
|
|
RAIL_CLOAK cloak = { 0 };
|
|
|
|
UINT error;
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
|
|
|
|
* server -> client message only supported if announced. */
|
|
|
|
if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if ((error = rail_read_order_cloak(s, &cloak)))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %"PRIu32"!", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->custom)
|
|
|
|
{
|
|
|
|
IFCALLRET(context->ServerCloak, error, context, &cloak);
|
2019-02-19 16:13:34 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerZOrderSync failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
|
|
|
|
{
|
|
|
|
if (!s || !power)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 4)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, power->active);
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_POWER_DISPLAY_REQUEST power = { 0 };
|
2019-02-19 16:13:34 +03:00
|
|
|
UINT error;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context)
|
2019-02-19 16:13:34 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
/* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
|
|
|
|
*/
|
|
|
|
if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if ((error = rail_read_power_display_request_order(s, &power)))
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %"PRIu32"!", error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
|
2019-02-19 16:13:34 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static UINT rail_read_get_application_id_extended_response_order(wStream* s,
|
|
|
|
RAIL_GET_APPID_RESP_EX* id)
|
|
|
|
{
|
|
|
|
if (!s || !id)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 4)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, id->windowID);
|
|
|
|
|
|
|
|
if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) < 4)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, id->processId);
|
|
|
|
|
|
|
|
if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
if (_wcsnlen(id->applicationID, ARRAYSIZE(id->processImageName)) >= ARRAYSIZE(id->processImageName))
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail,
|
|
|
|
wStream* s)
|
|
|
|
{
|
|
|
|
RailClientContext* context = rail_get_client_interface(rail);
|
2019-05-08 16:36:20 +03:00
|
|
|
RAIL_GET_APPID_RESP_EX id = { 0 };
|
2019-02-19 16:13:34 +03:00
|
|
|
UINT error;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!context)
|
2019-02-19 16:13:34 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
|
2019-02-19 16:13:34 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_read_get_application_id_extended_response_order failed with error %"PRIu32"!",
|
|
|
|
error);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->custom)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
|
2019-02-19 16:13:34 +03:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %"PRIu32"", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
|
|
|
UINT rail_order_recv(railPlugin* rail, wStream* s)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
UINT16 orderType;
|
|
|
|
UINT16 orderLength;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!rail || !s)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_read_pdu_header failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%"PRIu16"",
|
2017-02-20 20:31:58 +03:00
|
|
|
RAIL_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], orderLength);
|
2011-08-11 02:08:44 +04:00
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
switch (orderType)
|
|
|
|
{
|
2019-05-08 16:36:20 +03:00
|
|
|
case TS_RAIL_ORDER_HANDSHAKE:
|
|
|
|
return rail_recv_handshake_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_HANDSHAKE_EX:
|
|
|
|
return rail_recv_handshake_ex_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_EXEC_RESULT:
|
|
|
|
return rail_recv_exec_result_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_SYSPARAM:
|
|
|
|
return rail_recv_server_sysparam_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_MINMAXINFO:
|
|
|
|
return rail_recv_server_minmaxinfo_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_LOCALMOVESIZE:
|
|
|
|
return rail_recv_server_localmovesize_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_GET_APPID_RESP:
|
|
|
|
return rail_recv_server_get_appid_resp_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_LANGBARINFO:
|
|
|
|
return rail_recv_langbar_info_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_TASKBARINFO:
|
|
|
|
return rail_recv_taskbar_info_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_ZORDER_SYNC:
|
|
|
|
return rail_recv_zorder_sync_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_CLOAK:
|
|
|
|
return rail_recv_order_cloak(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
|
|
|
|
return rail_recv_power_display_request_order(rail, s);
|
|
|
|
|
|
|
|
case TS_RAIL_ORDER_GET_APPID_RESP_EX:
|
|
|
|
return rail_recv_get_application_id_extended_response_order(rail, s);
|
2019-02-19 16:13:34 +03:00
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
default:
|
2014-09-12 18:19:32 +04:00
|
|
|
WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
|
2015-06-08 19:04:05 +03:00
|
|
|
return ERROR_INVALID_DATA;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
2013-10-10 06:38:26 +04:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return CHANNEL_RC_OK;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !handshake)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
rail_write_handshake_order(s, handshake);
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE);
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
|
2013-10-21 05:59:03 +04:00
|
|
|
{
|
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !handshakeEx)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-21 05:59:03 +04:00
|
|
|
s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2013-10-21 05:59:03 +04:00
|
|
|
rail_write_handshake_ex_order(s, handshakeEx);
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX);
|
2013-10-21 05:59:03 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2013-10-21 05:59:03 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !clientStatus)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
rail->clientStatus = *clientStatus;
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_status_order(s, clientStatus);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
|
|
|
|
const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir,
|
|
|
|
const RAIL_UNICODE_STRING* arguments)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2015-06-08 19:04:05 +03:00
|
|
|
size_t length;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if (!rail || !exeOrFile || !workingDir || !arguments)
|
2017-12-20 17:00:21 +03:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
length = RAIL_EXEC_ORDER_LENGTH +
|
2018-09-14 11:04:16 +03:00
|
|
|
exeOrFile->length +
|
|
|
|
workingDir->length +
|
|
|
|
arguments->length;
|
2015-05-18 12:28:00 +03:00
|
|
|
s = rail_pdu_init(length);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2018-09-14 11:04:16 +03:00
|
|
|
if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_write_client_exec_order failed with error %"PRIu32"!", error);
|
2018-08-17 13:51:19 +03:00
|
|
|
goto out;
|
2015-06-08 19:04:05 +03:00
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error);
|
2018-08-17 13:51:19 +03:00
|
|
|
goto out;
|
2015-06-08 19:04:05 +03:00
|
|
|
}
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2018-08-17 13:51:19 +03:00
|
|
|
out:
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARAM_ORDER* sysparam)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2017-12-20 17:00:21 +03:00
|
|
|
size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !sysparam)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2011-08-11 00:33:15 +04:00
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
switch (sysparam->param)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
|
|
|
case SPI_SET_DRAG_FULL_WINDOWS:
|
|
|
|
case SPI_SET_KEYBOARD_CUES:
|
|
|
|
case SPI_SET_KEYBOARD_PREF:
|
|
|
|
case SPI_SET_MOUSE_BUTTON_SWAP:
|
|
|
|
length += 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SET_WORK_AREA:
|
|
|
|
case SPI_DISPLAY_CHANGE:
|
|
|
|
case SPI_TASKBAR_POS:
|
|
|
|
length += 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_SET_HIGH_CONTRAST:
|
2013-10-16 22:58:45 +04:00
|
|
|
length += sysparam->highContrast.colorSchemeLength + 10;
|
2011-08-11 00:33:15 +04:00
|
|
|
break;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
|
|
|
default:
|
|
|
|
length += 8;
|
|
|
|
break;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
s = rail_pdu_init(length);
|
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_write_client_sysparam_order(rail, s, sysparam)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %"PRIu32"!", error);
|
2018-08-17 13:51:19 +03:00
|
|
|
goto out;
|
2015-06-08 19:04:05 +03:00
|
|
|
}
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM)))
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error);
|
2018-08-17 13:51:19 +03:00
|
|
|
goto out;
|
2015-06-08 19:04:05 +03:00
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2018-08-17 13:51:19 +03:00
|
|
|
out:
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2017-12-20 17:00:21 +03:00
|
|
|
static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!rail || !sysparam)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_HIGH_CONTRAST;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_TASKBAR_POS)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_TASKBAR_POS;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_MOUSE_BUTTON_SWAP;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_KEYBOARD_PREF)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_KEYBOARD_PREF;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_DRAG_FULL_WINDOWS;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_KEYBOARD_CUES)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_KEYBOARD_CUES;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:58:45 +04:00
|
|
|
if (sysparam->params & SPI_MASK_SET_WORK_AREA)
|
2011-08-18 05:33:22 +04:00
|
|
|
{
|
2013-10-16 22:58:45 +04:00
|
|
|
sysparam->param = SPI_SET_WORK_AREA;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
|
|
|
}
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-18 05:33:22 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
if (!rail || !activate)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2017-12-23 12:26:25 +03:00
|
|
|
s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_activate_order(s, activate);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !sysmenu)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_sysmenu_order(s, sysmenu);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !syscommand)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_syscommand_order(s, syscommand);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_notify_event_order(railPlugin* rail,
|
|
|
|
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !notifyEvent)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_notify_event_order(s, notifyEvent);
|
|
|
|
|
|
|
|
if (ERROR_SUCCESS == error)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !windowMove)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_window_move_order(s, windowMove);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_get_appid_req_order(railPlugin* rail,
|
|
|
|
const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !getAppIdReq)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_client_get_appid_req_order(s, getAppIdReq);
|
|
|
|
|
|
|
|
if (error == ERROR_SUCCESS)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
|
|
|
|
2015-08-27 15:25:09 +03:00
|
|
|
/**
|
|
|
|
* Function description
|
|
|
|
*
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
*/
|
2018-09-14 11:04:16 +03:00
|
|
|
UINT rail_send_client_langbar_info_order(railPlugin* rail,
|
|
|
|
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
|
2011-08-11 00:33:15 +04:00
|
|
|
{
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2015-08-27 15:25:09 +03:00
|
|
|
UINT error;
|
2017-12-20 17:00:21 +03:00
|
|
|
|
|
|
|
if (!rail || !langBarInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
2011-08-11 00:33:15 +04:00
|
|
|
s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-18 12:28:00 +03:00
|
|
|
if (!s)
|
2015-06-08 19:04:05 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
2015-05-18 12:28:00 +03:00
|
|
|
|
2017-12-20 17:00:21 +03:00
|
|
|
error = rail_write_langbar_info_order(s, langBarInfo);
|
|
|
|
|
|
|
|
if (ERROR_SUCCESS == error)
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO);
|
|
|
|
|
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT rail_send_client_languageime_info_order(railPlugin* rail,
|
|
|
|
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
|
|
|
|
{
|
|
|
|
wStream* s;
|
|
|
|
UINT error;
|
|
|
|
|
|
|
|
if (!rail || !langImeInfo)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
|
|
|
|
return ERROR_BAD_CONFIGURATION;
|
|
|
|
|
|
|
|
s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH);
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = rail_write_languageime_info_order(s, langImeInfo);
|
|
|
|
|
|
|
|
if (ERROR_SUCCESS == error)
|
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO);
|
2017-12-20 17:00:21 +03:00
|
|
|
|
2013-05-09 01:48:30 +04:00
|
|
|
Stream_Free(s, TRUE);
|
2015-06-08 19:04:05 +03:00
|
|
|
return error;
|
2011-08-11 00:33:15 +04:00
|
|
|
}
|
2019-02-19 16:13:34 +03:00
|
|
|
|
|
|
|
UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
|
|
|
|
{
|
|
|
|
wStream* s;
|
|
|
|
UINT error;
|
|
|
|
|
|
|
|
if (!rail || !cloak)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
s = rail_pdu_init(5);
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, cloak->windowId);
|
|
|
|
Stream_Write_UINT8(s, cloak->cloak ? 1 : 0);
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK);
|
2019-02-19 16:13:34 +03:00
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT rail_send_client_order_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
|
|
|
|
{
|
|
|
|
wStream* s;
|
|
|
|
UINT error;
|
|
|
|
|
|
|
|
if (!rail)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2019-05-08 16:36:20 +03:00
|
|
|
/* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */
|
|
|
|
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0)
|
|
|
|
{
|
|
|
|
RAIL_WINDOW_MOVE_ORDER move = { 0 };
|
|
|
|
move.top = snap->top;
|
|
|
|
move.left = snap->left;
|
|
|
|
move.right = snap->right;
|
|
|
|
move.bottom = snap->bottom;
|
|
|
|
move.windowId = snap->windowId;
|
|
|
|
return rail_send_client_window_move_order(rail, &move);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:13:34 +03:00
|
|
|
s = rail_pdu_init(12);
|
|
|
|
|
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rail_pdu_init failed!");
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Write_UINT32(s, snap->windowId);
|
|
|
|
Stream_Write_UINT16(s, snap->left);
|
|
|
|
Stream_Write_UINT16(s, snap->top);
|
|
|
|
Stream_Write_UINT16(s, snap->right);
|
|
|
|
Stream_Write_UINT16(s, snap->bottom);
|
2019-05-08 16:36:20 +03:00
|
|
|
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE);
|
2019-02-19 16:13:34 +03:00
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
return error;
|
|
|
|
}
|