22#include <freerdp/config.h>
25#include <winpr/assert.h>
26#include <winpr/print.h>
28#include <freerdp/freerdp.h>
29#include <freerdp/assistance.h>
31#include <freerdp/channels/log.h>
32#include <freerdp/client/remdesk.h>
34#include "remdesk_main.h"
35#include "remdesk_common.h"
49 WLog_ERR(TAG,
"remdesk was null!");
51 return CHANNEL_RC_INVALID_INSTANCE;
54 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelWriteEx);
55 status = remdesk->channelEntryPoints.pVirtualChannelWriteEx(
56 remdesk->InitHandle, remdesk->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
58 if (status != CHANNEL_RC_OK)
61 WLog_ERR(TAG,
"pVirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
62 WTSErrorToString(status), status);
73static UINT remdesk_generate_expert_blob(
remdeskPlugin* remdesk)
75 const char* name =
nullptr;
77 const char* password =
nullptr;
78 rdpSettings* settings =
nullptr;
80 WINPR_ASSERT(remdesk);
82 WINPR_ASSERT(remdesk->rdpcontext);
83 settings = remdesk->rdpcontext->settings;
84 WINPR_ASSERT(settings);
86 if (remdesk->ExpertBlob)
95 WLog_ERR(TAG,
"password was not set!");
96 return ERROR_INTERNAL_ERROR;
105 remdesk->EncryptedPassStub =
106 freerdp_assistance_encrypt_pass_stub(password, stub, &(remdesk->EncryptedPassStubSize));
108 if (!remdesk->EncryptedPassStub)
110 WLog_ERR(TAG,
"freerdp_assistance_encrypt_pass_stub failed!");
111 return ERROR_INTERNAL_ERROR;
114 pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub,
115 remdesk->EncryptedPassStubSize);
119 WLog_ERR(TAG,
"freerdp_assistance_bin_to_hex_string failed!");
120 return ERROR_INTERNAL_ERROR;
123 remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass);
126 if (!remdesk->ExpertBlob)
128 WLog_ERR(TAG,
"freerdp_assistance_construct_expert_blob failed!");
129 return ERROR_INTERNAL_ERROR;
132 return CHANNEL_RC_OK;
142remdesk_recv_ctl_server_announce_pdu(WINPR_ATTR_UNUSED
remdeskPlugin* remdesk,
146 WINPR_ASSERT(remdesk);
148 WINPR_ASSERT(header);
150 WLog_ERR(
"TODO",
"TODO: implement");
151 return CHANNEL_RC_OK;
164 WINPR_ASSERT(remdesk);
166 WINPR_ASSERT(header);
168 if (header->DataLength < 12ull)
170 WLog_ERR(TAG,
"remdesk: HEADER::DataLength=%" PRIu32
", but expected >= 12",
172 return ERROR_INVALID_DATA;
175 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
176 return ERROR_INVALID_DATA;
178 const UINT32 versionMajor = Stream_Get_UINT32(s);
179 const UINT32 versionMinor = Stream_Get_UINT32(s);
181 if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
183 WLog_ERR(TAG,
"Unsupported protocol version %" PRIu32
".%" PRIu32, versionMajor,
187 remdesk->Version = versionMinor;
188 return CHANNEL_RC_OK;
197static UINT remdesk_send_ctl_version_info_pdu(
remdeskPlugin* remdesk)
201 WINPR_ASSERT(remdesk);
203 UINT error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
207 pdu.versionMajor = 1;
208 pdu.versionMinor = 2;
209 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
213 WLog_ERR(TAG,
"Stream_New failed!");
214 return CHANNEL_RC_NO_MEMORY;
217 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
220 Stream_Free(s, TRUE);
223 Stream_Write_UINT32(s, pdu.versionMajor);
224 Stream_Write_UINT32(s, pdu.versionMinor);
225 Stream_SealLength(s);
227 if ((error = remdesk_virtual_channel_write(remdesk, s)))
228 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
245 WINPR_ASSERT(remdesk);
247 WINPR_ASSERT(header);
248 WINPR_ASSERT(pResult);
250 if (header->DataLength < 8ull)
252 WLog_ERR(TAG,
"remdesk: HEADER::DataLength=%" PRIu32
", but expected >= 8",
254 return ERROR_INVALID_DATA;
257 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
258 return ERROR_INVALID_DATA;
260 Stream_Read_UINT32(s, result);
265 case REMDESK_ERROR_HELPEESAIDNO:
266 WLog_DBG(TAG,
"remote assistance connection request was denied");
267 return ERROR_CONNECTION_REFUSED;
273 return CHANNEL_RC_OK;
282static UINT remdesk_send_ctl_authenticate_pdu(
remdeskPlugin* remdesk)
284 UINT error = ERROR_INTERNAL_ERROR;
285 size_t cbExpertBlobW = 0;
286 WCHAR* expertBlobW =
nullptr;
287 size_t cbRaConnectionStringW = 0;
290 WINPR_ASSERT(remdesk);
292 if ((error = remdesk_generate_expert_blob(remdesk)))
294 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"", error);
298 const char* expertBlob = remdesk->ExpertBlob;
299 WINPR_ASSERT(remdesk->rdpcontext);
300 rdpSettings* settings = remdesk->rdpcontext->settings;
301 WINPR_ASSERT(settings);
303 const char* raConnectionString =
305 WCHAR* raConnectionStringW =
306 ConvertUtf8ToWCharAlloc(raConnectionString, &cbRaConnectionStringW);
308 if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX /
sizeof(WCHAR)))
311 cbRaConnectionStringW = cbRaConnectionStringW *
sizeof(WCHAR);
313 expertBlobW = ConvertUtf8ToWCharAlloc(expertBlob, &cbExpertBlobW);
318 cbExpertBlobW = cbExpertBlobW *
sizeof(WCHAR);
319 error = remdesk_prepare_ctl_header(&(ctlHeader), REMDESK_CTL_AUTHENTICATE,
320 cbRaConnectionStringW + cbExpertBlobW);
325 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
328 WLog_ERR(TAG,
"Stream_New failed!");
329 error = CHANNEL_RC_NO_MEMORY;
333 error = remdesk_write_ctl_header(s, &ctlHeader);
336 Stream_Free(s, TRUE);
339 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
340 Stream_Write(s, expertBlobW, cbExpertBlobW);
341 Stream_SealLength(s);
343 error = remdesk_virtual_channel_write(remdesk, s);
346 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
349 free(raConnectionStringW);
361static UINT remdesk_send_ctl_remote_control_desktop_pdu(
remdeskPlugin* remdesk)
366 WINPR_ASSERT(remdesk);
367 WINPR_ASSERT(remdesk->rdpcontext);
368 rdpSettings* settings = remdesk->rdpcontext->settings;
369 WINPR_ASSERT(settings);
371 const char* raConnectionString =
373 WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
374 size_t cbRaConnectionStringW = length *
sizeof(WCHAR);
376 if (!raConnectionStringW)
377 return ERROR_INTERNAL_ERROR;
380 error = remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
381 cbRaConnectionStringW);
382 if (error != CHANNEL_RC_OK)
386 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
390 WLog_ERR(TAG,
"Stream_New failed!");
391 error = CHANNEL_RC_NO_MEMORY;
395 error = remdesk_write_ctl_header(s, &ctlHeader);
398 Stream_Free(s, TRUE);
401 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
402 Stream_SealLength(s);
404 if ((error = remdesk_virtual_channel_write(remdesk, s)))
405 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
409 free(raConnectionStringW);
420static UINT remdesk_send_ctl_verify_password_pdu(
remdeskPlugin* remdesk)
422 size_t cbExpertBlobW = 0;
425 WINPR_ASSERT(remdesk);
427 UINT error = remdesk_generate_expert_blob(remdesk);
430 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"!", error);
434 pdu.expertBlob = remdesk->ExpertBlob;
435 WCHAR* expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
440 cbExpertBlobW = cbExpertBlobW *
sizeof(WCHAR);
442 remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
448 Stream_New(
nullptr, 1ULL * REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
452 WLog_ERR(TAG,
"Stream_New failed!");
453 error = CHANNEL_RC_NO_MEMORY;
457 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
460 Stream_Free(s, TRUE);
463 Stream_Write(s, expertBlobW, cbExpertBlobW);
464 Stream_SealLength(s);
466 error = remdesk_virtual_channel_write(remdesk, s);
469 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
483static UINT remdesk_send_ctl_expert_on_vista_pdu(
remdeskPlugin* remdesk)
487 WINPR_ASSERT(remdesk);
489 UINT error = remdesk_generate_expert_blob(remdesk);
492 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"!", error);
495 if (remdesk->EncryptedPassStubSize > UINT32_MAX)
496 return ERROR_INTERNAL_ERROR;
498 pdu.EncryptedPasswordLength = (UINT32)remdesk->EncryptedPassStubSize;
499 pdu.EncryptedPassword = remdesk->EncryptedPassStub;
500 error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
501 pdu.EncryptedPasswordLength);
505 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
509 WLog_ERR(TAG,
"Stream_New failed!");
510 return CHANNEL_RC_NO_MEMORY;
513 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
516 Stream_Free(s, TRUE);
519 Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
520 Stream_SealLength(s);
521 return remdesk_virtual_channel_write(remdesk, s);
533 UINT error = CHANNEL_RC_OK;
537 WINPR_ASSERT(remdesk);
539 WINPR_ASSERT(header);
541 if (header->DataLength < 4)
543 WLog_ERR(TAG,
"remdesk: HEADER::DataLength=%" PRIu32
", but expected >= 4",
545 return ERROR_INVALID_DATA;
548 if (!Stream_CheckAndLogRequiredLength(TAG, s, header->DataLength))
549 return ERROR_INVALID_DATA;
551 Stream_Read_UINT32(s, msgType);
557 case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
560 case REMDESK_CTL_RESULT:
561 if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
562 WLog_ERR(TAG,
"remdesk_recv_ctl_result_pdu failed with error %" PRIu32
"", error);
566 case REMDESK_CTL_AUTHENTICATE:
569 case REMDESK_CTL_SERVER_ANNOUNCE:
570 if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
571 WLog_ERR(TAG,
"remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32
"",
576 case REMDESK_CTL_DISCONNECT:
579 case REMDESK_CTL_VERSIONINFO:
580 if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
582 WLog_ERR(TAG,
"remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32
"",
587 if (remdesk->Version == 1)
589 if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
591 WLog_ERR(TAG,
"remdesk_send_ctl_version_info_pdu failed with error %" PRIu32
"",
596 if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
598 WLog_ERR(TAG,
"remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32
"",
603 if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
607 "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32
"",
612 else if (remdesk->Version == 2)
614 if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
617 "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32
"",
622 if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
625 "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32
"",
633 case REMDESK_CTL_ISCONNECTED:
636 case REMDESK_CTL_VERIFY_PASSWORD:
639 case REMDESK_CTL_EXPERT_ON_VISTA:
642 case REMDESK_CTL_RANOVICE_NAME:
645 case REMDESK_CTL_RAEXPERT_NAME:
648 case REMDESK_CTL_TOKEN:
652 WLog_ERR(TAG,
"unknown msgType: %" PRIu32
"", msgType);
653 error = ERROR_INVALID_DATA;
670 WINPR_ASSERT(remdesk);
673 UINT status = remdesk_read_channel_header(s, &header);
676 WLog_ERR(TAG,
"remdesk_read_channel_header failed with error %" PRIu32
"", status);
680 if (strcmp(header.ChannelName,
"RC_CTL") == 0)
682 status = remdesk_recv_ctl_pdu(remdesk, s, &header);
684 else if (strcmp(header.ChannelName,
"70") == 0)
687 else if (strcmp(header.ChannelName,
"71") == 0)
690 else if (strcmp(header.ChannelName,
".") == 0)
693 else if (strcmp(header.ChannelName,
"1000.") == 0)
696 else if (strcmp(header.ChannelName,
"RA_FX") == 0)
706static void remdesk_process_connect(WINPR_ATTR_UNUSED
remdeskPlugin* remdesk)
708 WINPR_ASSERT(remdesk);
709 WLog_ERR(
"TODO",
"TODO: implement");
718static UINT remdesk_virtual_channel_event_data_received(
remdeskPlugin* remdesk,
const void* pData,
719 UINT32 dataLength, UINT32 totalLength,
722 WINPR_ASSERT(remdesk);
724 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
726 return CHANNEL_RC_OK;
729 if (dataFlags & CHANNEL_FLAG_FIRST)
731 if (remdesk->firstFlagReceived)
732 return ERROR_INVALID_DATA;
734 if (remdesk->data_in)
735 Stream_Free(remdesk->data_in, TRUE);
737 remdesk->data_in = Stream_New(
nullptr, dataLength);
739 if (!remdesk->data_in)
741 WLog_ERR(TAG,
"Stream_New failed!");
742 return CHANNEL_RC_NO_MEMORY;
744 remdesk->firstFlagReceived = TRUE;
745 remdesk->totalLength = totalLength;
748 wStream* data_in = remdesk->data_in;
750 return ERROR_INVALID_DATA;
752 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
754 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
755 return CHANNEL_RC_NO_MEMORY;
758 Stream_Write(data_in, pData, dataLength);
759 if ((Stream_GetPosition(data_in) > totalLength) || (remdesk->totalLength != totalLength))
760 return ERROR_INVALID_DATA;
762 if (dataFlags & CHANNEL_FLAG_LAST)
764 if (!remdesk->firstFlagReceived)
765 return ERROR_INVALID_DATA;
766 remdesk->firstFlagReceived = FALSE;
768 if (remdesk->totalLength != Stream_GetPosition(data_in))
770 WLog_ERR(TAG,
"read error");
771 return ERROR_INTERNAL_ERROR;
774 remdesk->totalLength = 0;
775 remdesk->data_in =
nullptr;
776 Stream_SealLength(data_in);
777 Stream_ResetPosition(data_in);
779 if (!MessageQueue_Post(remdesk->queue,
nullptr, 0, (
void*)data_in,
nullptr))
781 WLog_ERR(TAG,
"MessageQueue_Post failed!");
782 return ERROR_INTERNAL_ERROR;
786 return CHANNEL_RC_OK;
789static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
790 UINT event, LPVOID pData,
791 UINT32 dataLength, UINT32 totalLength,
794 UINT error = CHANNEL_RC_OK;
799 case CHANNEL_EVENT_INITIALIZED:
802 case CHANNEL_EVENT_DATA_RECEIVED:
803 if (!remdesk || (remdesk->OpenHandle != openHandle))
805 WLog_ERR(TAG,
"error no match");
808 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
809 totalLength, dataFlags)))
811 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
817 case CHANNEL_EVENT_WRITE_CANCELLED:
818 case CHANNEL_EVENT_WRITE_COMPLETE:
821 Stream_Free(s, TRUE);
825 case CHANNEL_EVENT_USER:
829 WLog_ERR(TAG,
"unhandled event %" PRIu32
"!", event);
830 error = ERROR_INTERNAL_ERROR;
834 if (error && remdesk && remdesk->rdpcontext)
835 setChannelError(remdesk->rdpcontext, error,
836 "remdesk_virtual_channel_open_event_ex reported an error");
840static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
843 wMessage message = WINPR_C_ARRAY_INIT;
845 UINT error = CHANNEL_RC_OK;
847 WINPR_ASSERT(remdesk);
849 remdesk_process_connect(remdesk);
853 if (!MessageQueue_Wait(remdesk->queue))
855 WLog_ERR(TAG,
"MessageQueue_Wait failed!");
856 error = ERROR_INTERNAL_ERROR;
860 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
862 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
863 error = ERROR_INTERNAL_ERROR;
867 if (message.id == WMQ_QUIT)
872 data = (
wStream*)message.wParam;
874 if ((error = remdesk_process_receive(remdesk, data)))
876 WLog_ERR(TAG,
"remdesk_process_receive failed with error %" PRIu32
"!", error);
877 Stream_Free(data, TRUE);
881 Stream_Free(data, TRUE);
885 if (error && remdesk->rdpcontext)
886 setChannelError(remdesk->rdpcontext, error,
887 "remdesk_virtual_channel_client_thread reported an error");
899static UINT remdesk_virtual_channel_event_connected(
remdeskPlugin* remdesk,
900 WINPR_ATTR_UNUSED LPVOID pData,
901 WINPR_ATTR_UNUSED UINT32 dataLength)
905 WINPR_ASSERT(remdesk);
907 remdesk->queue = MessageQueue_New(
nullptr);
911 WLog_ERR(TAG,
"MessageQueue_New failed!");
912 error = CHANNEL_RC_NO_MEMORY;
917 CreateThread(
nullptr, 0, remdesk_virtual_channel_client_thread, (
void*)remdesk, 0,
nullptr);
919 if (!remdesk->thread)
921 WLog_ERR(TAG,
"CreateThread failed");
922 error = ERROR_INTERNAL_ERROR;
926 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
927 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
928 remdesk_virtual_channel_open_event_ex);
930 MessageQueue_Free(remdesk->queue);
931 remdesk->queue =
nullptr;
941static UINT remdesk_virtual_channel_event_disconnected(
remdeskPlugin* remdesk)
943 UINT rc = CHANNEL_RC_OK;
945 WINPR_ASSERT(remdesk);
947 if (remdesk->queue && remdesk->thread)
949 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
950 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
953 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", rc);
958 if (remdesk->OpenHandle != 0)
960 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
961 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
962 remdesk->OpenHandle);
964 if (CHANNEL_RC_OK != rc)
966 WLog_ERR(TAG,
"pVirtualChannelCloseEx failed with %s [%08" PRIX32
"]",
967 WTSErrorToString(rc), rc);
970 remdesk->OpenHandle = 0;
972 MessageQueue_Free(remdesk->queue);
973 (void)CloseHandle(remdesk->thread);
974 Stream_Free(remdesk->data_in, TRUE);
975 remdesk->data_in =
nullptr;
976 remdesk->queue =
nullptr;
977 remdesk->thread =
nullptr;
981static void remdesk_virtual_channel_event_terminated(
remdeskPlugin* remdesk)
983 WINPR_ASSERT(remdesk);
985 remdesk->InitHandle =
nullptr;
986 free(remdesk->context);
990static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
991 UINT event, LPVOID pData,
994 UINT error = CHANNEL_RC_OK;
997 if (!remdesk || (remdesk->InitHandle != pInitHandle))
999 WLog_ERR(TAG,
"error no match");
1005 case CHANNEL_EVENT_CONNECTED:
1006 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
1008 "remdesk_virtual_channel_event_connected failed with error %" PRIu32
"",
1013 case CHANNEL_EVENT_DISCONNECTED:
1014 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
1016 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32
"",
1021 case CHANNEL_EVENT_TERMINATED:
1022 remdesk_virtual_channel_event_terminated(remdesk);
1025 case CHANNEL_EVENT_ATTACHED:
1026 case CHANNEL_EVENT_DETACHED:
1031 if (error && remdesk->rdpcontext)
1032 setChannelError(remdesk->rdpcontext, error,
1033 "remdesk_virtual_channel_init_event reported an error");
1037#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
1039FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1056 WLog_ERR(TAG,
"calloc failed!");
1060 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1061 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1062 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1063 REMDESK_SVC_CHANNEL_NAME);
1064 remdesk->Version = 2;
1068 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1074 WLog_ERR(TAG,
"calloc failed!");
1078 context->handle = (
void*)remdesk;
1079 remdesk->context = context;
1080 remdesk->rdpcontext = pEntryPointsEx->context;
1083 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1085 remdesk->InitHandle = pInitHandle;
1086 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1087 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1088 remdesk_virtual_channel_init_event_ex);
1090 if (CHANNEL_RC_OK != rc)
1092 WLog_ERR(TAG,
"pVirtualChannelInitEx failed with %s [%08" PRIX32
"]", WTSErrorToString(rc),
1097 remdesk->channelEntryPoints.pInterface = context;
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.