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"
48 WLog_ERR(TAG,
"remdesk was null!");
50 return CHANNEL_RC_INVALID_INSTANCE;
53 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelWriteEx);
54 status = remdesk->channelEntryPoints.pVirtualChannelWriteEx(
55 remdesk->InitHandle, remdesk->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
57 if (status != CHANNEL_RC_OK)
60 WLog_ERR(TAG,
"pVirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
61 WTSErrorToString(status), status);
71static UINT remdesk_generate_expert_blob(
remdeskPlugin* remdesk)
73 const char* name =
nullptr;
75 const char* password =
nullptr;
76 rdpSettings* settings =
nullptr;
78 WINPR_ASSERT(remdesk);
80 WINPR_ASSERT(remdesk->rdpcontext);
81 settings = remdesk->rdpcontext->settings;
82 WINPR_ASSERT(settings);
84 if (remdesk->ExpertBlob)
93 WLog_ERR(TAG,
"password was not set!");
94 return ERROR_INTERNAL_ERROR;
103 remdesk->EncryptedPassStub =
104 freerdp_assistance_encrypt_pass_stub(password, stub, &(remdesk->EncryptedPassStubSize));
106 if (!remdesk->EncryptedPassStub)
108 WLog_ERR(TAG,
"freerdp_assistance_encrypt_pass_stub failed!");
109 return ERROR_INTERNAL_ERROR;
112 pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub,
113 remdesk->EncryptedPassStubSize);
117 WLog_ERR(TAG,
"freerdp_assistance_bin_to_hex_string failed!");
118 return ERROR_INTERNAL_ERROR;
121 remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass);
124 if (!remdesk->ExpertBlob)
126 WLog_ERR(TAG,
"freerdp_assistance_construct_expert_blob failed!");
127 return ERROR_INTERNAL_ERROR;
130 return CHANNEL_RC_OK;
138static UINT remdesk_recv_ctl_server_announce_pdu(WINPR_ATTR_UNUSED
remdeskPlugin* remdesk,
142 WINPR_ASSERT(remdesk);
144 WINPR_ASSERT(header);
146 WLog_ERR(
"TODO",
"TODO: implement");
147 return CHANNEL_RC_OK;
158 WINPR_ASSERT(remdesk);
160 WINPR_ASSERT(header);
162 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
163 return ERROR_INVALID_DATA;
165 const UINT32 versionMajor = Stream_Get_UINT32(s);
166 const UINT32 versionMinor = Stream_Get_UINT32(s);
168 if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
170 WLog_ERR(TAG,
"Unsupported protocol version %" PRIu32
".%" PRIu32, versionMajor,
174 remdesk->Version = versionMinor;
175 return CHANNEL_RC_OK;
183static UINT remdesk_send_ctl_version_info_pdu(
remdeskPlugin* remdesk)
187 WINPR_ASSERT(remdesk);
189 UINT error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
193 pdu.versionMajor = 1;
194 pdu.versionMinor = 2;
195 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
199 WLog_ERR(TAG,
"Stream_New failed!");
200 return CHANNEL_RC_NO_MEMORY;
203 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
206 Stream_Free(s, TRUE);
209 Stream_Write_UINT32(s, pdu.versionMajor);
210 Stream_Write_UINT32(s, pdu.versionMinor);
211 Stream_SealLength(s);
213 if ((error = remdesk_virtual_channel_write(remdesk, s)))
214 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
230 WINPR_ASSERT(remdesk);
232 WINPR_ASSERT(header);
233 WINPR_ASSERT(pResult);
235 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
236 return ERROR_INVALID_DATA;
238 Stream_Read_UINT32(s, result);
243 case REMDESK_ERROR_HELPEESAIDNO:
244 WLog_DBG(TAG,
"remote assistance connection request was denied");
245 return ERROR_CONNECTION_REFUSED;
251 return CHANNEL_RC_OK;
259static UINT remdesk_send_ctl_authenticate_pdu(
remdeskPlugin* remdesk)
261 UINT error = ERROR_INTERNAL_ERROR;
262 size_t cbExpertBlobW = 0;
263 WCHAR* expertBlobW =
nullptr;
264 size_t cbRaConnectionStringW = 0;
267 WINPR_ASSERT(remdesk);
269 if ((error = remdesk_generate_expert_blob(remdesk)))
271 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"", error);
275 const char* expertBlob = remdesk->ExpertBlob;
276 WINPR_ASSERT(remdesk->rdpcontext);
277 rdpSettings* settings = remdesk->rdpcontext->settings;
278 WINPR_ASSERT(settings);
280 const char* raConnectionString =
282 WCHAR* raConnectionStringW =
283 ConvertUtf8ToWCharAlloc(raConnectionString, &cbRaConnectionStringW);
285 if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX /
sizeof(WCHAR)))
288 cbRaConnectionStringW = cbRaConnectionStringW *
sizeof(WCHAR);
290 expertBlobW = ConvertUtf8ToWCharAlloc(expertBlob, &cbExpertBlobW);
295 cbExpertBlobW = cbExpertBlobW *
sizeof(WCHAR);
296 error = remdesk_prepare_ctl_header(&(ctlHeader), REMDESK_CTL_AUTHENTICATE,
297 cbRaConnectionStringW + cbExpertBlobW);
302 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
305 WLog_ERR(TAG,
"Stream_New failed!");
306 error = CHANNEL_RC_NO_MEMORY;
310 error = remdesk_write_ctl_header(s, &ctlHeader);
313 Stream_Free(s, TRUE);
316 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
317 Stream_Write(s, expertBlobW, cbExpertBlobW);
318 Stream_SealLength(s);
320 error = remdesk_virtual_channel_write(remdesk, s);
323 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
326 free(raConnectionStringW);
337static UINT remdesk_send_ctl_remote_control_desktop_pdu(
remdeskPlugin* remdesk)
342 WINPR_ASSERT(remdesk);
343 WINPR_ASSERT(remdesk->rdpcontext);
344 rdpSettings* settings = remdesk->rdpcontext->settings;
345 WINPR_ASSERT(settings);
347 const char* raConnectionString =
349 WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
350 size_t cbRaConnectionStringW = length *
sizeof(WCHAR);
352 if (!raConnectionStringW)
353 return ERROR_INTERNAL_ERROR;
356 error = remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
357 cbRaConnectionStringW);
358 if (error != CHANNEL_RC_OK)
362 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
366 WLog_ERR(TAG,
"Stream_New failed!");
367 error = CHANNEL_RC_NO_MEMORY;
371 error = remdesk_write_ctl_header(s, &ctlHeader);
374 Stream_Free(s, TRUE);
377 Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
378 Stream_SealLength(s);
380 if ((error = remdesk_virtual_channel_write(remdesk, s)))
381 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
385 free(raConnectionStringW);
395static UINT remdesk_send_ctl_verify_password_pdu(
remdeskPlugin* remdesk)
397 size_t cbExpertBlobW = 0;
400 WINPR_ASSERT(remdesk);
402 UINT error = remdesk_generate_expert_blob(remdesk);
405 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"!", error);
409 pdu.expertBlob = remdesk->ExpertBlob;
410 WCHAR* expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
415 cbExpertBlobW = cbExpertBlobW *
sizeof(WCHAR);
417 remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
423 Stream_New(
nullptr, 1ULL * REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
427 WLog_ERR(TAG,
"Stream_New failed!");
428 error = CHANNEL_RC_NO_MEMORY;
432 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
435 Stream_Free(s, TRUE);
438 Stream_Write(s, expertBlobW, cbExpertBlobW);
439 Stream_SealLength(s);
441 error = remdesk_virtual_channel_write(remdesk, s);
444 WLog_ERR(TAG,
"remdesk_virtual_channel_write failed with error %" PRIu32
"!", error);
457static UINT remdesk_send_ctl_expert_on_vista_pdu(
remdeskPlugin* remdesk)
461 WINPR_ASSERT(remdesk);
463 UINT error = remdesk_generate_expert_blob(remdesk);
466 WLog_ERR(TAG,
"remdesk_generate_expert_blob failed with error %" PRIu32
"!", error);
469 if (remdesk->EncryptedPassStubSize > UINT32_MAX)
470 return ERROR_INTERNAL_ERROR;
472 pdu.EncryptedPasswordLength = (UINT32)remdesk->EncryptedPassStubSize;
473 pdu.EncryptedPassword = remdesk->EncryptedPassStub;
474 error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
475 pdu.EncryptedPasswordLength);
479 wStream* s = Stream_New(
nullptr, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
483 WLog_ERR(TAG,
"Stream_New failed!");
484 return CHANNEL_RC_NO_MEMORY;
487 error = remdesk_write_ctl_header(s, &(pdu.ctlHeader));
490 Stream_Free(s, TRUE);
493 Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
494 Stream_SealLength(s);
495 return remdesk_virtual_channel_write(remdesk, s);
505 UINT error = CHANNEL_RC_OK;
509 WINPR_ASSERT(remdesk);
511 WINPR_ASSERT(header);
513 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
514 return ERROR_INVALID_DATA;
516 Stream_Read_UINT32(s, msgType);
522 case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
525 case REMDESK_CTL_RESULT:
526 if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
527 WLog_ERR(TAG,
"remdesk_recv_ctl_result_pdu failed with error %" PRIu32
"", error);
531 case REMDESK_CTL_AUTHENTICATE:
534 case REMDESK_CTL_SERVER_ANNOUNCE:
535 if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
536 WLog_ERR(TAG,
"remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32
"",
541 case REMDESK_CTL_DISCONNECT:
544 case REMDESK_CTL_VERSIONINFO:
545 if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
547 WLog_ERR(TAG,
"remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32
"",
552 if (remdesk->Version == 1)
554 if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
556 WLog_ERR(TAG,
"remdesk_send_ctl_version_info_pdu failed with error %" PRIu32
"",
561 if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
563 WLog_ERR(TAG,
"remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32
"",
568 if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
572 "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32
"",
577 else if (remdesk->Version == 2)
579 if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
582 "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32
"",
587 if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
590 "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32
"",
598 case REMDESK_CTL_ISCONNECTED:
601 case REMDESK_CTL_VERIFY_PASSWORD:
604 case REMDESK_CTL_EXPERT_ON_VISTA:
607 case REMDESK_CTL_RANOVICE_NAME:
610 case REMDESK_CTL_RAEXPERT_NAME:
613 case REMDESK_CTL_TOKEN:
617 WLog_ERR(TAG,
"unknown msgType: %" PRIu32
"", msgType);
618 error = ERROR_INVALID_DATA;
635 WINPR_ASSERT(remdesk);
638 if ((status = remdesk_read_channel_header(s, &header)))
640 WLog_ERR(TAG,
"remdesk_read_channel_header failed with error %" PRIu32
"", status);
644 if (strcmp(header.ChannelName,
"RC_CTL") == 0)
646 status = remdesk_recv_ctl_pdu(remdesk, s, &header);
648 else if (strcmp(header.ChannelName,
"70") == 0)
651 else if (strcmp(header.ChannelName,
"71") == 0)
654 else if (strcmp(header.ChannelName,
".") == 0)
657 else if (strcmp(header.ChannelName,
"1000.") == 0)
660 else if (strcmp(header.ChannelName,
"RA_FX") == 0)
670static void remdesk_process_connect(WINPR_ATTR_UNUSED
remdeskPlugin* remdesk)
672 WINPR_ASSERT(remdesk);
673 WLog_ERR(
"TODO",
"TODO: implement");
681static UINT remdesk_virtual_channel_event_data_received(
remdeskPlugin* remdesk,
const void* pData,
682 UINT32 dataLength, UINT32 totalLength,
685 WINPR_ASSERT(remdesk);
687 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
689 return CHANNEL_RC_OK;
692 if (dataFlags & CHANNEL_FLAG_FIRST)
694 if (remdesk->firstFlagReceived)
695 return ERROR_INVALID_DATA;
697 if (remdesk->data_in)
698 Stream_Free(remdesk->data_in, TRUE);
700 remdesk->data_in = Stream_New(
nullptr, dataLength);
702 if (!remdesk->data_in)
704 WLog_ERR(TAG,
"Stream_New failed!");
705 return CHANNEL_RC_NO_MEMORY;
707 remdesk->firstFlagReceived = TRUE;
708 remdesk->totalLength = totalLength;
711 wStream* data_in = remdesk->data_in;
713 return ERROR_INVALID_DATA;
715 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
717 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
718 return CHANNEL_RC_NO_MEMORY;
721 Stream_Write(data_in, pData, dataLength);
722 if ((Stream_GetPosition(data_in) > totalLength) || (remdesk->totalLength != totalLength))
723 return ERROR_INVALID_DATA;
725 if (dataFlags & CHANNEL_FLAG_LAST)
727 if (!remdesk->firstFlagReceived)
728 return ERROR_INVALID_DATA;
729 remdesk->firstFlagReceived = FALSE;
731 if (remdesk->totalLength != Stream_GetPosition(data_in))
733 WLog_ERR(TAG,
"read error");
734 return ERROR_INTERNAL_ERROR;
737 remdesk->totalLength = 0;
738 remdesk->data_in =
nullptr;
739 Stream_SealLength(data_in);
740 Stream_ResetPosition(data_in);
742 if (!MessageQueue_Post(remdesk->queue,
nullptr, 0, (
void*)data_in,
nullptr))
744 WLog_ERR(TAG,
"MessageQueue_Post failed!");
745 return ERROR_INTERNAL_ERROR;
749 return CHANNEL_RC_OK;
752static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
753 UINT event, LPVOID pData,
754 UINT32 dataLength, UINT32 totalLength,
757 UINT error = CHANNEL_RC_OK;
762 case CHANNEL_EVENT_INITIALIZED:
765 case CHANNEL_EVENT_DATA_RECEIVED:
766 if (!remdesk || (remdesk->OpenHandle != openHandle))
768 WLog_ERR(TAG,
"error no match");
771 if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
772 totalLength, dataFlags)))
774 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
780 case CHANNEL_EVENT_WRITE_CANCELLED:
781 case CHANNEL_EVENT_WRITE_COMPLETE:
784 Stream_Free(s, TRUE);
788 case CHANNEL_EVENT_USER:
792 WLog_ERR(TAG,
"unhandled event %" PRIu32
"!", event);
793 error = ERROR_INTERNAL_ERROR;
797 if (error && remdesk && remdesk->rdpcontext)
798 setChannelError(remdesk->rdpcontext, error,
799 "remdesk_virtual_channel_open_event_ex reported an error");
802static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
805 wMessage message = WINPR_C_ARRAY_INIT;
807 UINT error = CHANNEL_RC_OK;
809 WINPR_ASSERT(remdesk);
811 remdesk_process_connect(remdesk);
815 if (!MessageQueue_Wait(remdesk->queue))
817 WLog_ERR(TAG,
"MessageQueue_Wait failed!");
818 error = ERROR_INTERNAL_ERROR;
822 if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
824 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
825 error = ERROR_INTERNAL_ERROR;
829 if (message.id == WMQ_QUIT)
834 data = (
wStream*)message.wParam;
836 if ((error = remdesk_process_receive(remdesk, data)))
838 WLog_ERR(TAG,
"remdesk_process_receive failed with error %" PRIu32
"!", error);
839 Stream_Free(data, TRUE);
843 Stream_Free(data, TRUE);
847 if (error && remdesk->rdpcontext)
848 setChannelError(remdesk->rdpcontext, error,
849 "remdesk_virtual_channel_client_thread reported an error");
860static UINT remdesk_virtual_channel_event_connected(
remdeskPlugin* remdesk,
861 WINPR_ATTR_UNUSED LPVOID pData,
862 WINPR_ATTR_UNUSED UINT32 dataLength)
866 WINPR_ASSERT(remdesk);
868 remdesk->queue = MessageQueue_New(
nullptr);
872 WLog_ERR(TAG,
"MessageQueue_New failed!");
873 error = CHANNEL_RC_NO_MEMORY;
878 CreateThread(
nullptr, 0, remdesk_virtual_channel_client_thread, (
void*)remdesk, 0,
nullptr);
880 if (!remdesk->thread)
882 WLog_ERR(TAG,
"CreateThread failed");
883 error = ERROR_INTERNAL_ERROR;
887 return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
888 remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
889 remdesk_virtual_channel_open_event_ex);
891 MessageQueue_Free(remdesk->queue);
892 remdesk->queue =
nullptr;
901static UINT remdesk_virtual_channel_event_disconnected(
remdeskPlugin* remdesk)
903 UINT rc = CHANNEL_RC_OK;
905 WINPR_ASSERT(remdesk);
907 if (remdesk->queue && remdesk->thread)
909 if (MessageQueue_PostQuit(remdesk->queue, 0) &&
910 (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
913 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", rc);
918 if (remdesk->OpenHandle != 0)
920 WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
921 rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
922 remdesk->OpenHandle);
924 if (CHANNEL_RC_OK != rc)
926 WLog_ERR(TAG,
"pVirtualChannelCloseEx failed with %s [%08" PRIX32
"]",
927 WTSErrorToString(rc), rc);
930 remdesk->OpenHandle = 0;
932 MessageQueue_Free(remdesk->queue);
933 (void)CloseHandle(remdesk->thread);
934 Stream_Free(remdesk->data_in, TRUE);
935 remdesk->data_in =
nullptr;
936 remdesk->queue =
nullptr;
937 remdesk->thread =
nullptr;
941static void remdesk_virtual_channel_event_terminated(
remdeskPlugin* remdesk)
943 WINPR_ASSERT(remdesk);
945 remdesk->InitHandle =
nullptr;
946 free(remdesk->context);
950static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
951 UINT event, LPVOID pData,
954 UINT error = CHANNEL_RC_OK;
957 if (!remdesk || (remdesk->InitHandle != pInitHandle))
959 WLog_ERR(TAG,
"error no match");
965 case CHANNEL_EVENT_CONNECTED:
966 if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
968 "remdesk_virtual_channel_event_connected failed with error %" PRIu32
"",
973 case CHANNEL_EVENT_DISCONNECTED:
974 if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
976 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32
"",
981 case CHANNEL_EVENT_TERMINATED:
982 remdesk_virtual_channel_event_terminated(remdesk);
985 case CHANNEL_EVENT_ATTACHED:
986 case CHANNEL_EVENT_DETACHED:
991 if (error && remdesk->rdpcontext)
992 setChannelError(remdesk->rdpcontext, error,
993 "remdesk_virtual_channel_init_event reported an error");
997#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
999FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
1016 WLog_ERR(TAG,
"calloc failed!");
1020 remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1021 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1022 (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1023 REMDESK_SVC_CHANNEL_NAME);
1024 remdesk->Version = 2;
1028 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1034 WLog_ERR(TAG,
"calloc failed!");
1038 context->handle = (
void*)remdesk;
1039 remdesk->context = context;
1040 remdesk->rdpcontext = pEntryPointsEx->context;
1043 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1045 remdesk->InitHandle = pInitHandle;
1046 rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1047 remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1048 remdesk_virtual_channel_init_event_ex);
1050 if (CHANNEL_RC_OK != rc)
1052 WLog_ERR(TAG,
"pVirtualChannelInitEx failed with %s [%08" PRIX32
"]", WTSErrorToString(rc),
1057 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.