From 6ab3d3e8fc6aa62ed1acce3f17a950eff2b968fc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 22 Nov 2018 10:22:40 +0100 Subject: [PATCH] Fix #5052: Updated client sample --- client/Sample/CMakeLists.txt | 5 +- client/Sample/freerdp.c | 212 ------------------------- client/Sample/tf_channels.c | 127 +++++++++++++++ client/Sample/tf_channels.h | 37 +++++ client/Sample/tf_freerdp.c | 362 +++++++++++++++++++++++++++++++++++++++++++ client/Sample/tf_freerdp.h | 43 +++++ 6 files changed, 573 insertions(+), 213 deletions(-) delete mode 100644 client/Sample/freerdp.c create mode 100644 client/Sample/tf_channels.c create mode 100644 client/Sample/tf_channels.h create mode 100644 client/Sample/tf_freerdp.c create mode 100644 client/Sample/tf_freerdp.h diff --git a/client/Sample/CMakeLists.txt b/client/Sample/CMakeLists.txt index 1e64733..a3392c9 100644 --- a/client/Sample/CMakeLists.txt +++ b/client/Sample/CMakeLists.txt @@ -19,7 +19,10 @@ set(MODULE_NAME "sfreerdp") set(MODULE_PREFIX "FREERDP_CLIENT_SAMPLE") set(${MODULE_PREFIX}_SRCS - freerdp.c) + tf_channels.c + tf_channels.h + tf_freerdp.h + tf_freerdp.c) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt diff --git a/client/Sample/freerdp.c b/client/Sample/freerdp.c deleted file mode 100644 index cfbc30e..0000000 --- a/client/Sample/freerdp.c +++ /dev/null @@ -1,212 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Test UI - * - * Copyright 2011 Marc-Andre Moreau - * Copyright 2016 Armin Novak - * Copyright 2016 Thincast Technologies GmbH - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define TAG CLIENT_TAG("sample") - -struct tf_context -{ - rdpContext _p; -}; -typedef struct tf_context tfContext; - -static BOOL tf_context_new(freerdp* instance, rdpContext* context) -{ - return TRUE; -} - -static void tf_context_free(freerdp* instance, rdpContext* context) -{ -} - -static BOOL tf_begin_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - gdi->primary->hdc->hwnd->invalid->null = TRUE; - return TRUE; -} - -static BOOL tf_end_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - - if (gdi->primary->hdc->hwnd->invalid->null) - return TRUE; - - return TRUE; -} - -static BOOL tf_pre_connect(freerdp* instance) -{ - rdpSettings* settings; - settings = instance->settings; - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = TRUE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = TRUE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = TRUE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = TRUE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = TRUE; - return TRUE; -} - -static BOOL tf_post_connect(freerdp* instance) -{ - if (!gdi_init(instance, PIXEL_FORMAT_XRGB32)) - return FALSE; - - instance->update->BeginPaint = tf_begin_paint; - instance->update->EndPaint = tf_end_paint; - return TRUE; -} - -static DWORD WINAPI tf_client_thread_proc(LPVOID arg) -{ - freerdp* instance = (freerdp*)arg; - DWORD nCount; - DWORD status; - HANDLE handles[64]; - - if (!freerdp_connect(instance)) - { - WLog_ERR(TAG, "connection failure"); - return 0; - } - - while (!freerdp_shall_disconnect(instance)) - { - nCount = freerdp_get_event_handles(instance->context, &handles[0], 64); - - if (nCount == 0) - { - WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__); - break; - } - - status = WaitForMultipleObjects(nCount, handles, FALSE, 100); - - if (status == WAIT_FAILED) - { - WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__, - status); - break; - } - - if (!freerdp_check_event_handles(instance->context)) - { - if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) - WLog_ERR(TAG, "Failed to check FreeRDP event handles"); - - break; - } - } - - freerdp_disconnect(instance); - ExitThread(0); - return 0; -} - -int main(int argc, char* argv[]) -{ - int status; - HANDLE thread; - freerdp* instance; - instance = freerdp_new(); - - if (!instance) - { - WLog_ERR(TAG, "Couldn't create instance"); - return 1; - } - - instance->PreConnect = tf_pre_connect; - instance->PostConnect = tf_post_connect; - instance->ContextSize = sizeof(tfContext); - instance->ContextNew = tf_context_new; - instance->ContextFree = tf_context_free; - freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); - - if (!freerdp_context_new(instance)) - { - WLog_ERR(TAG, "Couldn't create context"); - return 1; - } - - status = freerdp_client_settings_parse_command_line(instance->settings, argc, - argv, FALSE); - - if (status < 0) - { - return 0; - } - - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) - return -1; - - if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL))) - { - WLog_ERR(TAG, "Failed to create client thread"); - } - else - { - WaitForSingleObject(thread, INFINITE); - } - - freerdp_context_free(instance); - freerdp_free(instance); - return 0; -} diff --git a/client/Sample/tf_channels.c b/client/Sample/tf_channels.c new file mode 100644 index 0000000..91e13bc --- /dev/null +++ b/client/Sample/tf_channels.c @@ -0,0 +1,127 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client Channels + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include "tf_channels.h" +#include "tf_freerdp.h" + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT tf_encomsp_participant_created(EncomspClientContext* context, + ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +{ + return CHANNEL_RC_OK; +} + +static void tf_encomsp_init(tfContext* tf, EncomspClientContext* encomsp) +{ + tf->encomsp = encomsp; + encomsp->custom = (void*) tf; + encomsp->ParticipantCreated = tf_encomsp_participant_created; +} + +static void tf_encomsp_uninit(tfContext* tf, EncomspClientContext* encomsp) +{ + if (encomsp) + { + encomsp->custom = NULL; + encomsp->ParticipantCreated = NULL; + } + + if (tf) + tf->encomsp = NULL; +} + + +void tf_OnChannelConnectedEventHandler(void* context, + ChannelConnectedEventArgs* e) +{ + tfContext* tf = (tfContext*) context; + rdpSettings* settings; + settings = tf->context.settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = (RdpeiClientContext*) e->pInterface; + } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + gdi_graphics_pipeline_init(tf->context.gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + tf_encomsp_init(tf, (EncomspClientContext*) e->pInterface); + } +} + +void tf_OnChannelDisconnectedEventHandler(void* context, + ChannelDisconnectedEventArgs* e) +{ + tfContext* tf = (tfContext*) context; + rdpSettings* settings; + settings = tf->context.settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = NULL; + } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + gdi_graphics_pipeline_uninit(tf->context.gdi, + (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + tf_encomsp_uninit(tf, (EncomspClientContext*) e->pInterface); + } +} diff --git a/client/Sample/tf_channels.h b/client/Sample/tf_channels.h new file mode 100644 index 0000000..5cb3202 --- /dev/null +++ b/client/Sample/tf_channels.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client Channels + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifndef FREERDP_CLIENT_SAMPLE_CHANNELS_H +#define FREERDP_CLIENT_SAMPLE_CHANNELS_H + +#include +#include + +int tf_on_channel_connected(freerdp* instance, const char* name, + void* pInterface); +int tf_on_channel_disconnected(freerdp* instance, const char* name, + void* pInterface); + +void tf_OnChannelConnectedEventHandler(void* context, + ChannelConnectedEventArgs* e); +void tf_OnChannelDisconnectedEventHandler(void* context, + ChannelDisconnectedEventArgs* e); + +#endif /* FREERDP_CLIENT_SAMPLE_CHANNELS_H */ diff --git a/client/Sample/tf_freerdp.c b/client/Sample/tf_freerdp.c new file mode 100644 index 0000000..cf0d966 --- /dev/null +++ b/client/Sample/tf_freerdp.c @@ -0,0 +1,362 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Test UI + * + * Copyright 2011 Marc-Andre Moreau + * Copyright 2016,2018 Armin Novak + * Copyright 2016,2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tf_channels.h" +#include "tf_freerdp.h" + +#define TAG CLIENT_TAG("sample") + +/* This function is called whenever a new frame starts. + * It can be used to reset invalidated areas. */ +static BOOL tf_begin_paint(rdpContext* context) +{ + rdpGdi* gdi = context->gdi; + gdi->primary->hdc->hwnd->invalid->null = TRUE; + return TRUE; +} + +/* This function is called when the library completed composing a new + * frame. Read out the changed areas and blit them to your output device. + * The image buffer will have the format specified by gdi_init + */ +static BOOL tf_end_paint(rdpContext* context) +{ + rdpGdi* gdi = context->gdi; + + if (gdi->primary->hdc->hwnd->invalid->null) + return TRUE; + + return TRUE; +} + +/* This function is called to output a System BEEP */ +static BOOL tf_play_sound(rdpContext* context, + const PLAY_SOUND_UPDATE* play_sound) +{ + /* TODO: Implement */ + return TRUE; +} + +/* This function is called to update the keyboard indocator LED */ +static BOOL tf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags) +{ + /* TODO: Set local keyboard indicator LED status */ + return TRUE; +} + +/* This function is called to set the IME state */ +static BOOL tf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState, + UINT32 imeConvMode) +{ + if (!context) + return FALSE; + + WLog_WARN(TAG, + "KeyboardSetImeStatus(unitId=%04"PRIx16", imeState=%08"PRIx32", imeConvMode=%08"PRIx32") ignored", + imeId, imeState, imeConvMode); + return TRUE; +} + +/* Called before a connection is established. + * Set all configuration options to support and load channels here. */ +static BOOL tf_pre_connect(freerdp* instance) +{ + rdpSettings* settings; + settings = instance->settings; + /* Optional OS identifier sent to server */ + settings->OsMajorType = OSMAJORTYPE_UNIX; + settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; + /* Base protocol feature support mask */ + ZeroMemory(settings->OrderSupport, 32); + settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; + settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; + settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; + settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; + settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; + settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; + settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; + settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; + settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; + settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; + settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; + settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; + settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled; + settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled; + settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; + settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled; + settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; + settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; + settings->OrderSupport[NEG_FAST_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; + settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; + settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; + settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; + settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; + settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; + /* Register the channel listeners. + * They are required to set up / tear down channels if they are loaded. */ + PubSub_SubscribeChannelConnected(instance->context->pubSub, + tf_OnChannelConnectedEventHandler); + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + tf_OnChannelDisconnectedEventHandler); + + /* Load all required plugins / channels / libraries specified by current + * settings. */ + if (!freerdp_client_load_addins(instance->context->channels, + instance->settings)) + return FALSE; + + /* TODO: Any code your client requires */ + return TRUE; +} + +/* Called after a RDP connection was successfully established. + * Settings might have changed during negociation of client / server feature + * support. + * + * Set up local framebuffers and paing callbacks. + * If required, register pointer callbacks to change the local mouse cursor + * when hovering over the RDP window + */ +static BOOL tf_post_connect(freerdp* instance) +{ + if (!gdi_init(instance, PIXEL_FORMAT_XRGB32)) + return FALSE; + + instance->update->BeginPaint = tf_begin_paint; + instance->update->EndPaint = tf_end_paint; + instance->update->PlaySound = tf_play_sound; + instance->update->SetKeyboardIndicators = tf_keyboard_set_indicators; + instance->update->SetKeyboardImeStatus = tf_keyboard_set_ime_status; + return TRUE; +} + +/* This function is called whether a session ends by failure or success. + * Clean up everything allocated by pre_connect and post_connect. + */ +static void tf_post_disconnect(freerdp* instance) +{ + tfContext* context; + + if (!instance) + return; + + if (!instance->context) + return; + + context = (tfContext*) instance->context; + PubSub_UnsubscribeChannelConnected(instance->context->pubSub, + tf_OnChannelConnectedEventHandler); + PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, + tf_OnChannelDisconnectedEventHandler); + gdi_free(instance); + /* TODO : Clean up custom stuff */ +} + +/* RDP main loop. + * Connects RDP, loops while running and handles event and dispatch, cleans up + * after the connection ends. */ +static DWORD WINAPI tf_client_thread_proc(LPVOID arg) +{ + freerdp* instance = (freerdp*)arg; + DWORD nCount; + DWORD status; + HANDLE handles[64]; + + if (!freerdp_connect(instance)) + { + WLog_ERR(TAG, "connection failure"); + return 0; + } + + while (!freerdp_shall_disconnect(instance)) + { + nCount = freerdp_get_event_handles(instance->context, &handles[0], 64); + + if (nCount == 0) + { + WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__); + break; + } + + status = WaitForMultipleObjects(nCount, handles, FALSE, 100); + + if (status == WAIT_FAILED) + { + WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__, + status); + break; + } + + if (!freerdp_check_event_handles(instance->context)) + { + if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) + WLog_ERR(TAG, "Failed to check FreeRDP event handles"); + + break; + } + } + + freerdp_disconnect(instance); + return 0; +} + +/* Optional global initializer. + * Here we just register a signal handler to print out stack traces + * if available. */ +static BOOL tf_client_global_init(void) +{ + if (freerdp_handle_signals() != 0) + return FALSE; + + return TRUE; +} + +/* Optional global tear down */ +static void tf_client_global_uninit(void) +{ +} + +static int tf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) +{ + tfContext* tf; + const char* str_data = freerdp_get_logon_error_info_data(data); + const char* str_type = freerdp_get_logon_error_info_type(type); + + if (!instance || !instance->context) + return -1; + + tf = (tfContext*) instance->context; + WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + return 1; +} + +static BOOL tf_client_new(freerdp* instance, rdpContext* context) +{ + tfContext* tf = (tfContext*) context; + + if (!instance || !context) + return FALSE; + + instance->PreConnect = tf_pre_connect; + instance->PostConnect = tf_post_connect; + instance->PostDisconnect = tf_post_disconnect; + instance->Authenticate = client_cli_authenticate; + instance->GatewayAuthenticate = client_cli_gw_authenticate; + instance->VerifyCertificate = client_cli_verify_certificate; + instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; + instance->LogonErrorInfo = tf_logon_error_info; + /* TODO: Client display set up */ + return TRUE; +} + + +static void tf_client_free(freerdp* instance, rdpContext* context) +{ + tfContext* tf = (tfContext*) instance->context; + + if (!context) + return; + + /* TODO: Client display tear down */ +} + +static int tf_client_start(rdpContext* context) +{ + /* TODO: Start client related stuff */ + return 0; +} + +static int tf_client_stop(rdpContext* context) +{ + /* TODO: Stop client related stuff */ + return 0; +} + +static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) +{ + ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); + pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION; + pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); + pEntryPoints->GlobalInit = tf_client_global_init; + pEntryPoints->GlobalUninit = tf_client_global_uninit; + pEntryPoints->ContextSize = sizeof(tfContext); + pEntryPoints->ClientNew = tf_client_new; + pEntryPoints->ClientFree = tf_client_free; + pEntryPoints->ClientStart = tf_client_start; + pEntryPoints->ClientStop = tf_client_stop; + return 0; +} + +int main(int argc, char* argv[]) +{ + int rc = -1; + DWORD status; + RDP_CLIENT_ENTRY_POINTS clientEntryPoints; + rdpContext* context; + RdpClientEntry(&clientEntryPoints); + context = freerdp_client_context_new(&clientEntryPoints); + + if (!context) + goto fail; + + status = freerdp_client_settings_parse_command_line(context->settings, argc, + argv, FALSE); + status = freerdp_client_settings_command_line_status_print(context->settings, + status, argc, argv); + + if (status) + return 0; + + if (freerdp_client_start(context) != 0) + goto fail; + + rc = tf_client_thread_proc(context->instance); + + if (freerdp_client_stop(context) != 0) + rc = -1; + +fail: + freerdp_client_context_free(context); + return rc; +} diff --git a/client/Sample/tf_freerdp.h b/client/Sample/tf_freerdp.h new file mode 100644 index 0000000..de0580f --- /dev/null +++ b/client/Sample/tf_freerdp.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifndef FREERDP_CLIENT_SAMPLE_H +#define FREERDP_CLIENT_SAMPLE_H + +#include +#include +#include +#include +#include +#include +#include + +struct tf_context +{ + rdpContext context; + + /* Channels */ + RdpeiClientContext* rdpei; + RdpgfxClientContext* gfx; + EncomspClientContext* encomsp; +}; +typedef struct tf_context tfContext; + +#endif /* FREERDP_CLIENT_SAMPLE_H */ -- 2.7.4