6#undef PEN_FLAG_INVERTED
7#include "freerdp/client.h"
8#include "freerdp/client/channels.h"
9#include "freerdp/channels/rdpei.h"
10#include "freerdp/channels/rdpdr.h"
11#include "freerdp/channels/disp.h"
12#include "freerdp/channels/tsmf.h"
13#include "freerdp/channels/rdpsnd.h"
14#include "freerdp/client/encomsp.h"
15#include "freerdp/gdi/gfx.h"
16#include "freerdp/settings.h"
17#include "freerdp/locale/keyboard.h"
18#include "freerdp/channels/rdpgfx.h"
19#include "freerdp/channels/cliprdr.h"
20#include "freerdp/client/cmdline.h"
21#include "freerdp/gdi/video.h"
22#include "winpr/winsock.h"
24#include "ConnectFreeRDP.h"
25#include "RabbitCommonTools.h"
26#include "ConvertKeyCode.h"
30#include <QApplication>
32#include <QSslCertificate>
33#include <QInputDialog>
34#include <QMutexLocker>
36#include <QPrinterInfo>
38#include <QSerialPortInfo>
39#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
40 #include <QSoundEffect>
45#ifdef WINPR_HAVE_POLL_H
52#include <sys/select.h>
56#if FREERDP_VERSION_MAJOR >= 3
57#include "ConnectLayerQTcpSocket.h"
59#include "ConnectLayerSSHTunnel.h"
63static Q_LOGGING_CATEGORY(log,
"FreeRDP.Connect")
64static Q_LOGGING_CATEGORY(logKey, "FreeRDP.Connect.Key")
65static Q_LOGGING_CATEGORY(logMouse, "FreeRDP.Connect.Mouse")
69 , m_pConnecter(pConnecter)
71 , m_pParameter(
nullptr)
74 , m_writeEvent(
nullptr)
75#if FREERDP_VERSION_MAJOR >= 3
76 , m_pConnectLayer(
nullptr)
79 , m_pThreadSSH(
nullptr)
82 qDebug(log) << Q_FUNC_INFO;
83 m_pParameter = qobject_cast<CParameterFreeRDP*>(pConnecter->GetParameter());
84 Q_ASSERT(m_pParameter);
87CConnectFreeRDP::~CConnectFreeRDP()
89 qDebug(log) << Q_FUNC_INFO;
100 qDebug(log) << Q_FUNC_INFO;
103 m_writeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
105 qCritical(log) <<
"CreateEvent failed";
106 return OnInitReturnValue::Fail;
108 ZeroMemory(&m_ClientEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
109 m_ClientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
110 m_ClientEntryPoints.Size =
sizeof(RDP_CLIENT_ENTRY_POINTS);
112 m_ClientEntryPoints.GlobalInit = cbGlobalInit;
113 m_ClientEntryPoints.GlobalUninit = cbGlobalUninit;
114 m_ClientEntryPoints.ClientNew = cbClientNew;
115 m_ClientEntryPoints.ClientFree = cbClientFree;
116 m_ClientEntryPoints.ClientStart = cbClientStart;
117 m_ClientEntryPoints.ClientStop = cbClientStop;
120 auto pRdpContext = freerdp_client_context_new(&m_ClientEntryPoints);
124 m_pContext->pThis =
this;
126 qCritical(log) <<
"freerdp_client_context_new fail";
127 return OnInitReturnValue::Fail;
130 rdpSettings* settings = pRdpContext->settings;
132 qCritical(log) <<
"settings is null";
133 return OnInitReturnValue::Fail;
146 char* argv[]= {(
char*)QApplication::applicationFilePath().toStdString().c_str()};
147 int argc =
sizeof(argv) /
sizeof(
char*);
148 nRet = freerdp_client_settings_parse_command_line(settings, argc, argv, TRUE);
151 nRet = freerdp_client_settings_command_line_status_print(settings, nRet, argc, argv);
152 return OnInitReturnValue::Fail;
155#if FREERDP_VERSION_MAJOR >= 3
156 if (!stream_dump_register_handlers(pRdpContext,
157 CONNECTION_STATE_MCS_CREATE_REQUEST,
159 return OnInitReturnValue::Fail;
162 auto &user = m_pParameter->m_Net.
m_User;
163 if(!user.GetUser().isEmpty())
164 freerdp_settings_set_string(
165 settings, FreeRDP_Username,
166 user.GetUser().toStdString().c_str());
167 if(!user.GetPassword().isEmpty())
168 freerdp_settings_set_string(
169 settings, FreeRDP_Password,
170 user.GetPassword().toStdString().c_str());
172 freerdp_settings_set_bool(
173 settings, FreeRDP_RedirectClipboard, m_pParameter->GetClipboard());
175#if FREERDP_VERSION_MAJOR >= 3
176 bool bOnlyView = m_pParameter->GetOnlyView();
177 freerdp_settings_set_bool(
178 settings, FreeRDP_SuspendInput, bOnlyView);
181 freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth,
182 m_pParameter->GetDesktopWidth());
183 freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight,
184 m_pParameter->GetDesktopHeight());
185 freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
186 m_pParameter->GetColorDepth());
188 freerdp_settings_set_bool(settings, FreeRDP_UseMultimon,
189 m_pParameter->GetUseMultimon());
191 if(m_pParameter->GetReconnectInterval()) {
192 freerdp_settings_set_bool(
193 settings, FreeRDP_AutoReconnectionEnabled,
true);
194 freerdp_settings_set_uint32(
196 FreeRDP_AutoReconnectMaxRetries,
197 m_pParameter->GetReconnectInterval());
200 freerdp_settings_set_bool(
201 settings, FreeRDP_AutoReconnectionEnabled,
false);
205 RedirectionMicrophone();
207 RedirectionPrinter();
212 switch(m_pParameter->m_Proxy.GetUsedType())
214 case CParameterProxy::TYPE::System:
216 case CParameterProxy::TYPE::Http:
217 case CParameterProxy::TYPE::SockesV5:
220 if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS))
221 return OnInitReturnValue::Fail;
222 if(CParameterProxy::TYPE::Http == m_pParameter->m_Proxy.GetUsedType()) {
223 net = &m_pParameter->m_Proxy.m_Http;
224 if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP))
225 return OnInitReturnValue::Fail;
228 if (!freerdp_settings_set_string(settings, FreeRDP_ProxyHostname,
229 net->GetHost().toStdString().c_str()))
230 return OnInitReturnValue::Fail;
231 if (!freerdp_settings_set_uint16(settings, FreeRDP_ProxyPort, net->GetPort()))
232 return OnInitReturnValue::Fail;
234 if(((user.GetUsedType() == CParameterUser::TYPE::UserPassword)
235 && (user.GetPassword().isEmpty() || user.GetUser().isEmpty()))
236 || ((user.GetUsedType() == CParameterUser::TYPE::PublicKey)
237 && user.GetPassphrase().isEmpty())) {
238 int nRet = QDialog::Rejected;
240 if(QDialog::Accepted != nRet)
242 return OnInitReturnValue::Fail;
245 if (!freerdp_settings_set_string(settings, FreeRDP_ProxyUsername,
246 user.GetUser().toStdString().c_str()))
247 return OnInitReturnValue::Fail;
248 if (!freerdp_settings_set_string(settings, FreeRDP_ProxyPassword,
249 user.GetPassword().toStdString().c_str()))
250 return OnInitReturnValue::Fail;
261 case CParameterProxy::TYPE::None:
263 if(!m_pParameter->GetDomain().isEmpty())
264 freerdp_settings_set_string(
265 settings, FreeRDP_Domain,
266 m_pParameter->GetDomain().toStdString().c_str());
267 if(m_pParameter->m_Net.GetHost().isEmpty())
270 szErr = tr(
"The server is empty, please input it");
271 qCritical(log) << szErr;
273 emit
sigError(-1, szErr.toStdString().c_str());
274 return OnInitReturnValue::Fail;
276 auto &net = m_pParameter->m_Net;
277 freerdp_settings_set_string(
278 settings, FreeRDP_ServerHostname,
279 net.GetHost().toStdString().c_str());
280 freerdp_settings_set_uint32(
281 settings, FreeRDP_ServerPort,
284 nRet = freerdp_client_start(pRdpContext);
287 qCritical(log) <<
"freerdp_client_start fail";
288 return OnInitReturnValue::Fail;
293 case CParameterProxy::TYPE::SSHTunnel:
295#if FREERDP_VERSION_MAJOR >= 3
297 if(!m_pConnectLayer)
return OnInitReturnValue::Fail;
298 nRet = m_pConnectLayer->Initialize(pRdpContext);
299 if(nRet)
return OnInitReturnValue::Fail;
302 return InitSSHTunnelPipe();
307 qCritical(log) <<
"Don't support proxy type:" << m_pParameter->m_Proxy.GetUsedType();
311 return OnInitReturnValue::UseOnProcess;
316 qDebug(log) << Q_FUNC_INFO;
320 CloseHandle(m_writeEvent);
321 m_writeEvent =
nullptr;
325 rdpContext* pRdpContext = (rdpContext*)m_pContext;
326 if(!freerdp_disconnect(pRdpContext->instance))
327 qCritical(log) <<
"freerdp_disconnect fail";
329 if(freerdp_client_stop(pRdpContext))
330 qCritical(log) <<
"freerdp_client_stop fail";
332 freerdp_client_context_free(pRdpContext);
333 m_pContext =
nullptr;
336#if FREERDP_VERSION_MAJOR >= 3
337 if(m_pConnectLayer) {
338 m_pConnectLayer->Clean();
339 m_pConnectLayer->deleteLater();
340 m_pConnectLayer =
nullptr;
345 CleanSSHTunnelPipe();
387 rdpContext* pRdpContext = (rdpContext*)m_pContext;
389 if(
nullptr == freerdp_settings_get_string(pRdpContext->settings, FreeRDP_ServerHostname))
397 nCount += freerdp_get_event_handles(pRdpContext, &handles[nCount],
398 ARRAYSIZE(handles) - nCount);
401 qCritical(log) <<
"freerdp_get_event_handles failed";
407 handles[nCount++] = m_writeEvent;
409 DWORD waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, nTimeout);
412 ResetEvent(m_writeEvent);
414 if (waitStatus == WAIT_FAILED)
416 qCritical(log) <<
"WaitForMultipleObjects: WAIT_FAILED";
421 if(waitStatus == WAIT_TIMEOUT)
428 if (!freerdp_check_event_handles(pRdpContext))
432 UINT32 err = freerdp_get_last_error(pRdpContext);
434 szErr =
"freerdp_check_event_handles fail.";
436 szErr += QString::number(err);
438 szErr += freerdp_get_last_error_category(err);
440 szErr += freerdp_get_last_error_name(err);
442 szErr += freerdp_get_last_error_string(err);
443 qCritical(log) << szErr;
467#if FREERDP_VERSION_MAJOR >= 3
468 if(freerdp_shall_disconnect_context(pRdpContext))
470 if(freerdp_shall_disconnect(pRdpContext->instance))
473 qCritical(log) <<
"freerdp_shall_disconnect false";
481void CConnectFreeRDP::slotClipBoardChanged()
483 qDebug(log) << Q_FUNC_INFO;
484 if(m_pParameter && m_pParameter->GetOnlyView())
return;
485 if(m_pParameter->GetClipboard())
486 m_ClipBoard.slotClipBoardChanged();
489BOOL CConnectFreeRDP::cbGlobalInit()
491 qDebug(log) << Q_FUNC_INFO;
495void CConnectFreeRDP::cbGlobalUninit()
497 qDebug(log) << Q_FUNC_INFO;
500BOOL CConnectFreeRDP::cbClientNew(freerdp *instance, rdpContext *context)
502 qDebug(log) << Q_FUNC_INFO;
505 instance->PostDisconnect = cb_post_disconnect;
508#if FREERDP_VERSION_MAJOR < 3
509 instance->Authenticate = cb_authenticate;
510 instance->GatewayAuthenticate = cb_GatewayAuthenticate;
512 instance->AuthenticateEx = cb_authenticate_ex;
513 instance->ChooseSmartcard = cb_choose_smartcard;
518 instance->PresentGatewayMessage = cb_present_gateway_message;
520 instance->LogonErrorInfo = cb_logon_error_info;
525void CConnectFreeRDP::cbClientFree(freerdp *instance, rdpContext *context)
527 qDebug(log) << Q_FUNC_INFO;
530int CConnectFreeRDP::cbClientStart(rdpContext *context)
532 qDebug(log) << Q_FUNC_INFO;
535 if (!context || !context->settings)
537 freerdp* instance = freerdp_client_get_instance(context);
541 auto settings = context->settings;
543 QString szDomainHost;
545 szDomainHost = freerdp_settings_get_string(settings, FreeRDP_ServerHostname);
546 nPort = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
548 auto &net = pThis->m_pParameter->m_Net;
549 szServer = net.GetHost() +
":" + QString::number(net.GetPort());
550 auto &proxy = pThis->m_pParameter->m_Proxy;
551 switch(proxy.GetUsedType()) {
552 case CParameterProxy::TYPE::SockesV5:
554 auto &sockesV5 = proxy.m_SockesV5;
555 szServer = sockesV5.GetHost() +
":" + QString::number(sockesV5.GetPort())
559 case CParameterProxy::TYPE::Http:
561 auto &http = proxy.m_Http;
562 szServer = http.GetHost() +
":" + QString::number(http.GetPort())
566 case CParameterProxy::TYPE::SSHTunnel:
568 auto &sshNet = proxy.m_SSH.m_Net;
569#if FREERDP_VERSION_MAJOR < 3
570 szServer = szDomainHost +
":" + QString::number(nPort)
571 +
" -> " + sshNet.GetHost() +
":" + QString::number(sshNet.GetPort())
574 szServer = sshNet.GetHost() +
":" + QString::number(sshNet.GetPort())
583 BOOL status = freerdp_connect(instance);
585 QString szInfo = tr(
"Connected to ") + szServer;
586 qInfo(log) << szInfo;
590 UINT32 nRet = freerdp_get_last_error(context);
593 szErr = tr(
"Connect to ") + szServer + tr(
" fail.");
595 szErr += QString::number(nRet) +
" - ";
596 szErr += freerdp_get_last_error_name(nRet);
601 szErr += freerdp_get_last_error_string(nRet);
605 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
607 szErr = tr(
"Logon to ") + szServer;
608 szErr += tr(
" fail. Please check that the username and password are correct.") +
"\n";
611 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
613 szErr = tr(
"Logon to ") + szServer;
614 szErr += tr(
" fail. Please check password are correct.") +
"\n";
617 case FREERDP_ERROR_AUTHENTICATION_FAILED:
619 szErr = tr(
"Logon to ") + szServer;
620 szErr += tr(
" authentication fail. please add a CA certificate to the store.") +
"\n";
623 case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
625 szErr = tr(
"Logon to ") + szServer;
626 szErr += tr(
" connect transport layer fail.") +
"\n\n";
627 szErr += tr(
"Please:") +
"\n";
628 szErr += tr(
"1. Check for any network related issues") +
"\n";
629 szErr += tr(
"2. Check you have proper security settings ('NLA' enabled is required for most connections nowadays)") +
"\n";
630 szErr +=
" " + tr(
"If you do not know the server security settings, contact your server administrator.") +
"\n";
631 szErr += tr(
"3. Check the certificate is proper (and guacd properly checks that)") +
"\n";
634 case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
636 szErr += tr(
"Please check you have proper security settings.") +
"\n";
637 szErr += tr(
"If you do not know the server security settings, contact your server administrator.");
639 case FREERDP_ERROR_CONNECT_CANCELLED:
640 szErr = tr(
"The connect was canceled.") +
"\n\n" + szErr;
647 qCritical(log) << szErr;
648 emit pThis->
sigError(nRet, szErr.toStdString().c_str());
654int CConnectFreeRDP::cbClientStop(rdpContext *context)
657 qDebug(log) << Q_FUNC_INFO;
658#if FREERDP_VERSION_MAJOR >= 3
659 nRet = freerdp_client_common_stop(context);
661 BOOL bRet = freerdp_abort_connect(context->instance);
663 { qCritical(log) <<
"freerdp_abort_connect fail";
690 qDebug(log) << Q_FUNC_INFO;
691 rdpChannels* channels =
nullptr;
692 rdpSettings* settings =
nullptr;
693 rdpContext* context = instance->context;
695 if (!instance || !instance->context || !instance->context->settings)
699 if(!pThis)
return FALSE;
700 settings = instance->context->settings;
701 channels = context->channels;
703 if(!channels || !pParameter)
707#if defined (Q_OS_WIN)
708 if (!freerdp_settings_set_uint32(
709 settings, FreeRDP_OsMajorType, OSMAJORTYPE_WINDOWS))
711 if (!freerdp_settings_set_uint32(
712 settings, FreeRDP_OsMinorType, OSMINORTYPE_WINDOWS_NT))
714#elif defined(Q_OS_ANDROID)
715 if (!freerdp_settings_set_uint32(
716 settings, FreeRDP_OsMajorType, OSMAJORTYPE_ANDROID))
718 if (!freerdp_settings_set_uint32(
719 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
721#elif defined(Q_OS_IOS)
722 if (!freerdp_settings_set_uint32(
723 settings, FreeRDP_OsMajorType, OSMAJORTYPE_IOS))
725 if (!freerdp_settings_set_uint32(
726 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
728#elif defined (Q_OS_UNIX)
729 if (!freerdp_settings_set_uint32(
730 settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX))
732 if (!freerdp_settings_set_uint32(
733 settings, FreeRDP_OsMinorType, OSMINORTYPE_NATIVE_XSERVER))
736 if (!freerdp_settings_set_uint32(
737 settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNSPECIFIED))
739 if (!freerdp_settings_set_uint32(
740 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
745 PubSub_SubscribeChannelConnected(instance->context->pubSub,
746 OnChannelConnectedEventHandler);
747 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
748 OnChannelDisconnectedEventHandler);
750#if FREERDP_VERSION_MAJOR < 3
751 if (!freerdp_client_load_addins(channels, instance->context->settings))
754 #if defined(Q_OS_LINUX) || (defined(Q_OS_WIN) && defined(WITH_WINDOWS_CERT_STORE))
755 if (!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, TRUE))
760 if(!freerdp_settings_set_bool(
761 settings, FreeRDP_NegotiateSecurityLayer,
762 pParameter->GetNegotiateSecurityLayer()))
764 CParameterFreeRDP::Security security = pParameter->GetSecurity();
766 if(!freerdp_settings_set_bool(
767 settings, FreeRDP_RdpSecurity,
768 CParameterFreeRDP::Security::RDP & security))
770 if (!freerdp_settings_set_bool(
771 settings, FreeRDP_UseRdpSecurityLayer,
772 CParameterFreeRDP::Security::RDP & security))
775 if(!freerdp_settings_set_bool(
776 settings, FreeRDP_TlsSecurity,
777 CParameterFreeRDP::Security::TLS & security))
779 if(!freerdp_settings_set_bool(
780 settings, FreeRDP_NlaSecurity,
781 CParameterFreeRDP::Security::NLA & security))
783 if(!freerdp_settings_set_bool(
784 settings, FreeRDP_ExtSecurity,
785 CParameterFreeRDP::Security::NLA_Ext & security))
787#if FREERDP_VERSION_MAJOR >= 3
788 if(!freerdp_settings_set_bool(
789 settings, FreeRDP_AadSecurity,
790 CParameterFreeRDP::Security::RDSAAD & security))
792 if(!freerdp_settings_set_bool(
793 settings, FreeRDP_RdstlsSecurity,
794 CParameterFreeRDP::Security::RDSTLS & security))
796 freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion,
797 pParameter->GetTlsVersion());
801 if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
804 auto &user = pParameter->m_Net.
m_User;
805 if(!freerdp_settings_get_string(settings, FreeRDP_Username)) {
806 if(user.GetUser().isEmpty()) {
807 if(user.GetUser().isEmpty()) {
809 qWarning(log) <<
"Auth-only, but no user name set. Will be call instance->Authenticate.";
812 freerdp_settings_set_string(
813 settings, FreeRDP_Username,
814 user.GetUser().toStdString().c_str());
816 if (!freerdp_settings_get_string(settings, FreeRDP_Password)) {
817 if (user.GetPassword().isEmpty()) {
819 qWarning(log) <<
"auth-only, but no password set. Will be call instance->Authenticate";
821 freerdp_settings_set_string(
822 settings, FreeRDP_Password,
823 user.GetPassword().toStdString().c_str());
825#if FREERDP_VERSION_MAJOR >= 3
826 if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
829 }
else if(freerdp_settings_get_bool(settings, FreeRDP_CredentialsFromStdin)){
831 }
else if(freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon)) {
842 UINT32 width = pParameter->GetDesktopWidth();
843 UINT32 height = pParameter->GetDesktopHeight();
844 if ((width < 64) || (height < 64) ||
845 (width > 4096) || (height > 4096))
847 QString szErr = tr(
"Invalid dimensions:")
848 + QString::number(width)
849 +
"*" + QString::number(height);
850 qCritical(log) << szErr;
854 qInfo(log) <<
"Init desktop size " << width <<
"*" << height;
858 <<
"width:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)
859 <<
"height:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)
860 <<
"ColorDepth:" << freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
871 if(!freerdp_set_connection_type(settings, pParameter->GetConnectType()))
873 freerdp_settings_set_uint32(
874 settings, FreeRDP_PerformanceFlags, pParameter->GetPerformanceFlags());
875 freerdp_performance_flags_split(settings);
880const char* CConnectFreeRDP::GetTitle(freerdp* instance)
882 const char* windowTitle;
885 const char* name =
nullptr;
888 rdpSettings* settings = instance->context->settings;
893 windowTitle = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
897#if FREERDP_VERSION_MAJOR >= 3
898 name = freerdp_settings_get_server_name(settings);
900 name = pThis->m_pParameter->m_Net.GetHost().toStdString().c_str();
902 port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
904 addPort = (port != 3389);
906 char buffer[MAX_PATH + 64] = { 0 };
909 sprintf_s(buffer,
sizeof(buffer),
"%s", name);
911 sprintf_s(buffer,
sizeof(buffer),
"%s:%" PRIu32, name, port);
913 freerdp_settings_set_string(settings, FreeRDP_WindowTitle, buffer);
914 return freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
924 qDebug(log) << Q_FUNC_INFO;
926 rdpContext* context = instance->context;
927 rdpSettings* settings = instance->context->settings;
928 rdpUpdate* update = instance->context->update;
931 const char* pWindowTitle = GetTitle(instance);
934 WCHAR* windowTitle = NULL;
935#if FREERDP_VERSION_MAJOR >= 3
936 windowTitle = ConvertUtf8ToWCharAlloc(pWindowTitle, NULL);
938 ConvertToUnicode(CP_UTF8, 0, pWindowTitle, -1, &windowTitle, 0);
942 QString title = QString::fromUtf16((
const char16_t*)windowTitle);
944 if(pThis->m_pParameter->GetServerName().isEmpty())
945 emit pThis->sigServerName(title);
949 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
950 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
951 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
953 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
956 if(!pThis->CreateImage(instance->context))
959 Q_ASSERT(instance->context->cache);
962 if(pThis->m_Cursor.RegisterPointer(context->graphics))
965 update->BeginPaint = cb_begin_paint;
966 update->EndPaint = cb_end_paint;
967 update->DesktopResize = cb_desktop_resize;
969 update->PlaySound = cb_play_bell_sound;
971 update->SetKeyboardIndicators = cb_keyboard_set_indicators;
972 update->SetKeyboardImeStatus = cb_keyboard_set_ime_status;
978void CConnectFreeRDP::cb_post_disconnect(freerdp* instance)
980 qDebug(log) << Q_FUNC_INFO;
981 rdpContext* context =
nullptr;
983 if (!instance || !instance->context)
986 context = instance->context;
988 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
989 OnChannelConnectedEventHandler);
990 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
991 OnChannelDisconnectedEventHandler);
995int CConnectFreeRDP::cb_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
998 const char* str_data = freerdp_get_logon_error_info_data(data);
999 const char* str_type = freerdp_get_logon_error_info_type(type);
1000 QString szErr = tr(
"FreeRDP logon info: [");
1004 qDebug(log) << szErr;
1010void CConnectFreeRDP::OnChannelConnectedEventHandler(
void *context,
1011 #
if FREERDP_VERSION_MAJOR >= 3
1014 ChannelConnectedEventArgs *e)
1016 rdpContext* pContext = (rdpContext*)context;
1018 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
1019 qDebug(log) <<
"channel" << e->name <<
"connected";
1020 pThis->m_ClipBoard.Init((CliprdrClientContext*)e->pInterface,
1021 pThis->m_pParameter->GetClipboard());
1023#if FREERDP_VERSION_MAJOR >= 3
1025 freerdp_client_OnChannelConnectedEventHandler(pContext, e);
1027 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1029 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
1030 rdpGdi* gdi = pContext->gdi;
1032 gdi_graphics_pipeline_init(gdi, (RdpgfxClientContext*) e->pInterface);
1035 qDebug(log,
"Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
1037 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1039 gdi_video_geometry_init(pContext->gdi, (GeometryClientContext*)e->pInterface);
1041 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1043 gdi_video_data_init(pContext->gdi, (VideoClientContext*)e->pInterface);
1045 qDebug(log) <<
"Unimplemented: channel" << e->name <<
"connected but we can’t use it";
1049void CConnectFreeRDP::OnChannelDisconnectedEventHandler(
void *context,
1050 #
if FREERDP_VERSION_MAJOR >= 3
1053 ChannelDisconnectedEventArgs *e)
1055 rdpContext* pContext = (rdpContext*)context;
1058 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
1059 qDebug(log) <<
"channel" << e->name <<
"disconnected";
1060 pThis->m_ClipBoard.UnInit((CliprdrClientContext*)e->pInterface,
1061 pThis->m_pParameter->GetClipboard());
1063#if FREERDP_VERSION_MAJOR >= 3
1065 freerdp_client_OnChannelDisconnectedEventHandler(pContext, e);
1067 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1069 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
1070 rdpGdi* gdi = pContext->gdi;
1071 gdi_graphics_pipeline_uninit(gdi, (RdpgfxClientContext*) e->pInterface);
1074 qDebug(log,
"Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
1077 qDebug(log) <<
"Unimplemented: channel" << e->name <<
"disconnected but we can’t use it";
1082UINT32 CConnectFreeRDP::GetImageFormat(QImage::Format format)
1085#if (QT_VERSION >= QT_VERSION_CHECK(5,2,0))
1086 case QImage::Format_RGBA8888:
1087 return PIXEL_FORMAT_RGBA32;
1088 case QImage::Format_RGBX8888:
1089 return PIXEL_FORMAT_RGBX32;
1091 case QImage::Format_RGB16:
1092 return PIXEL_FORMAT_RGB16;
1093 case QImage::Format_ARGB32:
1094 return PIXEL_FORMAT_BGRA32;
1095 case QImage::Format_RGB32:
1096 return PIXEL_FORMAT_BGRA32;
1103UINT32 CConnectFreeRDP::GetImageFormat()
1105 return GetImageFormat(m_Image.format());
1108BOOL CConnectFreeRDP::CreateImage(rdpContext *context)
1111 ClientContext* pContext = (ClientContext*)context;
1113 rdpGdi* gdi = context->gdi;
1114 Q_ASSERT(pThis && gdi);
1115 pThis->m_Image = QImage(gdi->primary_buffer,
1116 static_cast<int>(gdi->width),
1117 static_cast<int>(gdi->height),
1118 QImage::Format_ARGB32);
1122#if FREERDP_VERSION_MAJOR >= 3
1124static CREDUI_INFOW wfUiInfo = {
sizeof(CREDUI_INFOW), NULL, L
"Enter your credentials",
1125 L
"Remote Desktop Security", NULL };
1128BOOL CConnectFreeRDP::cb_authenticate_ex(freerdp* instance,
1129 char** username,
char** password,
1130 char** domain, rdp_auth_reason reason)
1132 qDebug(log) << Q_FUNC_INFO <<
"reason:" << reason;
1136 if(!username || !password || !domain)
return FALSE;
1138 rdpContext* pContext = (rdpContext*)instance->context;
1143 WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1144 WCHAR UserW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1145 WCHAR DomainW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
1146 WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
1148 WINPR_ASSERT(instance);
1149 WINPR_ASSERT(instance->context);
1150 WINPR_ASSERT(instance->context->settings);
1152 WINPR_ASSERT(username);
1153 WINPR_ASSERT(domain);
1154 WINPR_ASSERT(password);
1156 const WCHAR auth[] = L
"Target credentials requested";
1157 const WCHAR authPin[] = L
"PIN requested";
1158 const WCHAR gwAuth[] = L
"Gateway credentials requested";
1159 const WCHAR* titleW = auth;
1162 dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES |
1163 CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
1170 if ((*username) && (*password))
1173 case AUTH_SMARTCARD_PIN:
1174 dwFlags &= ~CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
1175 dwFlags |= CREDUI_FLAGS_PASSWORD_ONLY_OK | CREDUI_FLAGS_KEEP_USERNAME;
1180 *username = _strdup(
"PIN");
1193 ConvertUtf8ToWChar(*username, UserNameW, ARRAYSIZE(UserNameW));
1194 ConvertUtf8ToWChar(*username, UserW, ARRAYSIZE(UserW));
1198 ConvertUtf8ToWChar(*password, PasswordW, ARRAYSIZE(PasswordW));
1201 ConvertUtf8ToWChar(*domain, DomainW, ARRAYSIZE(DomainW));
1203 if (_wcsnlen(PasswordW, ARRAYSIZE(PasswordW)) == 0)
1205 status = CredUIPromptForCredentialsW(&wfUiInfo, titleW, NULL, 0, UserNameW,
1206 ARRAYSIZE(UserNameW), PasswordW,
1207 ARRAYSIZE(PasswordW), &fSave, dwFlags);
1208 if (status != NO_ERROR)
1211 "CredUIPromptForCredentials unexpected status: 0x%08lX",
1216 if ((dwFlags & CREDUI_FLAGS_KEEP_USERNAME) == 0)
1218 status = CredUIParseUserNameW(UserNameW, UserW, ARRAYSIZE(UserW), DomainW,
1219 ARRAYSIZE(DomainW));
1220 if (status != NO_ERROR)
1222 CHAR User[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1223 CHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1224 CHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
1226 ConvertWCharNToUtf8(UserNameW, ARRAYSIZE(UserNameW), UserName, ARRAYSIZE(UserName));
1227 ConvertWCharNToUtf8(UserW, ARRAYSIZE(UserW), User, ARRAYSIZE(User));
1228 ConvertWCharNToUtf8(DomainW, ARRAYSIZE(DomainW), Domain, ARRAYSIZE(Domain));
1230 "Failed to parse UserName: %s into User: %s Domain: %s",
1231 UserName, User, Domain);
1237 *username = ConvertWCharNToUtf8Alloc(UserW, ARRAYSIZE(UserW), NULL);
1240 qCritical(log) <<
"ConvertWCharNToUtf8Alloc failed" << status;
1244 if (_wcsnlen(DomainW, ARRAYSIZE(DomainW)) > 0)
1245 *domain = ConvertWCharNToUtf8Alloc(DomainW, ARRAYSIZE(DomainW), NULL);
1247 *domain = _strdup(
"\0");
1252 qCritical(log) <<
"strdup failed" << status;
1256 *password = ConvertWCharNToUtf8Alloc(PasswordW, ARRAYSIZE(PasswordW), NULL);
1265 return cb_authenticate(instance, username, password, domain);
1270BOOL CConnectFreeRDP::cb_choose_smartcard(freerdp* instance,
1271 SmartcardCertInfo** cert_list,
1273 DWORD* choice, BOOL gateway)
1275 rdpContext* pContext = (rdpContext*)instance->context;
1277 QString msg(
"Multiple smartcards are available for use:\n");
1278 for (DWORD i = 0; i < count; i++)
1280 const SmartcardCertInfo* cert = cert_list[i];
1281 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
1282 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
1284 msg += QString::number(i) +
" ";
1285 msg += QString(container_name) +
"\n\t";
1286 msg +=
"Reader: " + QString(reader) +
"\n\t";
1287 msg +=
"User: " + QString(cert->userHint) + +
"@" + QString(cert->domainHint) +
"\n\t";
1288 msg +=
"Subject: " + QString(cert->subject) +
"\n\t";
1289 msg +=
"Issuer: " + QString(cert->issuer) +
"\n\t";
1290 msg +=
"UPN: " + QString(cert->upn) +
"\n";
1293 free(container_name);
1296 msg +=
"\nChoose a smartcard to use for ";
1298 msg +=
"gateway authentication";
1302 msg +=
"(0 - " + QString::number(count - 1) +
")";
1310 int n = num.toInt(&ok);
1320#ifdef WITH_WINDOWS_CERT_STORE
1328static void wf_report_error(
char* wszMessage, DWORD dwErrCode)
1330 LPSTR pwszMsgBuf = NULL;
1332 if (NULL != wszMessage && 0 != *wszMessage)
1334 WLog_ERR(TAG,
"%s", wszMessage);
1337 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1342 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1352 if (NULL != pwszMsgBuf)
1354 WLog_ERR(TAG,
"Error: 0x%08x (%d) %s", dwErrCode, dwErrCode, pwszMsgBuf);
1355 LocalFree(pwszMsgBuf);
1359 WLog_ERR(TAG,
"Error: 0x%08x (%d)", dwErrCode, dwErrCode);
1363static DWORD wf_is_x509_certificate_trusted(
const char* common_name,
const char* subject,
1364 const char* issuer,
const char* fingerprint)
1366 HRESULT hr = CRYPT_E_NOT_FOUND;
1368 DWORD dwChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
1369 PCCERT_CONTEXT pCert = NULL;
1370 HCERTCHAINENGINE hChainEngine = NULL;
1371 PCCERT_CHAIN_CONTEXT pChainContext = NULL;
1373 CERT_ENHKEY_USAGE EnhkeyUsage = { 0 };
1374 CERT_USAGE_MATCH CertUsage = { 0 };
1375 CERT_CHAIN_PARA ChainPara = { 0 };
1376 CERT_CHAIN_POLICY_PARA ChainPolicy = { 0 };
1377 CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
1378 CERT_CHAIN_ENGINE_CONFIG EngineConfig = { 0 };
1380 DWORD derPubKeyLen = WINPR_ASSERTING_INT_CAST(uint32_t, strlen(fingerprint));
1381 char* derPubKey = calloc(derPubKeyLen,
sizeof(
char));
1382 if (NULL == derPubKey)
1384 WLog_ERR(TAG,
"Could not allocate derPubKey");
1391 if (!CryptStringToBinaryA(fingerprint, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &derPubKeyLen,
1394 WLog_ERR(TAG,
"CryptStringToBinary failed. Err: %d", GetLastError());
1401 EnhkeyUsage.cUsageIdentifier = 0;
1402 EnhkeyUsage.rgpszUsageIdentifier = NULL;
1404 CertUsage.dwType = USAGE_MATCH_TYPE_AND;
1405 CertUsage.Usage = EnhkeyUsage;
1407 ChainPara.cbSize =
sizeof(ChainPara);
1408 ChainPara.RequestedUsage = CertUsage;
1410 ChainPolicy.cbSize =
sizeof(ChainPolicy);
1412 PolicyStatus.cbSize =
sizeof(PolicyStatus);
1414 EngineConfig.cbSize =
sizeof(EngineConfig);
1415 EngineConfig.dwUrlRetrievalTimeout = 0;
1417 pCert = CertCreateCertificateContext(X509_ASN_ENCODING, derPubKey, derPubKeyLen);
1420 WLog_ERR(TAG,
"FAILED: Certificate could not be parsed.");
1424 dwChainFlags |= CERT_CHAIN_ENABLE_PEER_TRUST;
1433 if (!CertCreateCertificateChainEngine(&EngineConfig, &hChainEngine))
1435 hr = HRESULT_FROM_WIN32(GetLastError());
1442 if (!CertGetCertificateChain(hChainEngine,
1453 hr = HRESULT_FROM_WIN32(GetLastError());
1460 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
1465 hr = HRESULT_FROM_WIN32(GetLastError());
1469 if (PolicyStatus.dwError != S_OK)
1471 wf_report_error(
"CertVerifyCertificateChainPolicy: Chain Status", PolicyStatus.dwError);
1472 hr = PolicyStatus.dwError;
1478 if (PolicyStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK ||
1479 PolicyStatus.dwError == CRYPT_E_REVOCATION_OFFLINE)
1487 WLog_INFO(TAG,
"CertVerifyCertificateChainPolicy succeeded for %s (%s) issued by %s",
1488 common_name, subject, issuer);
1495 WLog_INFO(TAG,
"CertVerifyCertificateChainPolicy failed for %s (%s) issued by %s",
1496 common_name, subject, issuer);
1497 wf_report_error(NULL, hr);
1502 if (NULL != pChainContext)
1504 CertFreeCertificateChain(pChainContext);
1507 if (NULL != hChainEngine)
1509 CertFreeCertificateChainEngine(hChainEngine);
1514 CertFreeCertificateContext(pCert);
1523BOOL CConnectFreeRDP::cb_authenticate(freerdp* instance,
char** username,
1524 char** password,
char** domain)
1526 qDebug(log) << Q_FUNC_INFO;
1529 rdpContext* pContext = (rdpContext*)instance->context;
1531 if(!username || !password || !domain)
return FALSE;
1532 if(*username && *password )
return TRUE;
1534 int nRet = QDialog::Rejected;
1536 nRet, pThis->m_pParameter);
1537 if(QDialog::Accepted == nRet)
1539 QString szPassword = pThis->m_pParameter->m_Net.
m_User.GetPassword();
1540 QString szName = pThis->m_pParameter->m_Net.
m_User.GetUser();
1541 QString szDomain = pThis->m_pParameter->GetDomain();
1542 if(!szDomain.isEmpty() && domain)
1543 *domain = _strdup(szDomain.toStdString().c_str());
1544 if(!szName.isEmpty() && username)
1545 *username = _strdup(szName.toStdString().c_str());
1546 if(!szPassword.isEmpty() && password)
1547 *password = _strdup(szPassword.toStdString().c_str());
1554BOOL CConnectFreeRDP::cb_GatewayAuthenticate(freerdp *instance,
1555 char **username,
char **password,
char **domain)
1557 qDebug(log) << Q_FUNC_INFO;
1561 rdpContext* pContext = (rdpContext*)instance->context;
1563 if(!username || !password || !domain)
return FALSE;
1564 if(*username && *password )
return TRUE;
1566 int nRet = QDialog::Rejected;
1567 emit pThis->
sigBlockShowWidget(
"CDlgGetUserPasswordFreeRDP", nRet, pThis->m_pParameter);
1568 if(QDialog::Accepted == nRet)
1570 QString szPassword = pThis->m_pParameter->m_Net.
m_User.GetPassword();
1571 QString szName = pThis->m_pParameter->m_Net.
m_User.GetUser();
1572 QString szDomain = pThis->m_pParameter->GetDomain();
1573 if(!szDomain.isEmpty() && domain)
1574 *domain = _strdup(szDomain.toStdString().c_str());
1575 if(!szName.isEmpty() && username)
1576 *username = _strdup(szName.toStdString().c_str());
1577 if(!szPassword.isEmpty() && password)
1578 *password = _strdup(szPassword.toStdString().c_str());
1586 const BYTE* data,
size_t length,
1587 const char* hostname, UINT16 port, DWORD flags)
1589 qDebug(log) << Q_FUNC_INFO;
1590 rdpContext* pContext = (rdpContext*)instance->context;
1591 QSslCertificate cert(QByteArray((
const char*)data, length));
1592#if FREERDP_VERSION_MAJOR >= 3
1596 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM) {
1598 instance, hostname, port,
1599 cert.issuerDisplayName().toStdString().c_str(),
1600 cert.subjectDisplayName().toStdString().c_str(),
1601 cert.issuerDisplayName().toStdString().c_str(),
1607 instance, hostname, port,
1608 cert.issuerDisplayName().toStdString().c_str(),
1609 cert.subjectDisplayName().toStdString().c_str(),
1610 cert.issuerDisplayName().toStdString().c_str(),
1611 cert.serialNumber().toStdString().c_str(),
1615static QString pem_cert_fingerprint(
const char* pem, DWORD flags)
1617 QString szFingerPrint;
1618#if FREERDP_VERSION_MAJOR >= 3
1622 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1624 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
1628 char* fp = freerdp_certificate_get_fingerprint(cert);
1629 char* start = freerdp_certificate_get_validity(cert, TRUE);
1630 char* end = freerdp_certificate_get_validity(cert, FALSE);
1631 freerdp_certificate_free(cert);
1633 szFingerPrint = QObject::tr(
"Valid from: ") + QString(start) +
"\n";
1634 szFingerPrint += QObject::tr(
"Valid to: ") + QString(end) +
"\n";
1635 szFingerPrint += QObject::tr(
"Fingerprint: ") + QString(fp) +
"\n";
1642 szFingerPrint = QObject::tr(
"Fingerprint: ") + QString(pem) +
"\n";
1643 return szFingerPrint;
1662 const char *host, UINT16 port,
1663 const char *common_name,
const char *subject,
1664 const char *issuer,
const char *fingerprint, DWORD flags)
1666 qDebug(log) << Q_FUNC_INFO;
1668 rdpContext* pContext = (rdpContext*)instance->context;
1675 emit pThis->sigServerName(common_name);
1678 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1684#if FREERDP_VERSION_MAJOR >= 3
1685#if defined(Q_OS_WIN) && defined(WITH_WINDOWS_CERT_STORE)
1686 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM && !(flags & VERIFY_CERT_FLAG_MISMATCH))
1688 if (wf_is_x509_certificate_trusted(common_name, subject, issuer, fingerprint) == S_OK)
1696 QString szType = tr(
"RDP-Server");
1697 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1698 szType = tr(
"RDP-Gateway");
1699 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1700 szType = tr(
"RDP-Redirect");
1702 QString title(tr(
"Verify certificate"));
1705 message += szType + tr(
": %1:%2").arg(host, QString::number(port)) +
"\n";
1706 message += tr(
"Common name: ") + common_name +
"\n";
1707 message += tr(
"Subject: ") + subject +
"\n";
1708 message += tr(
"Issuer: ") + issuer +
"\n";
1709 message += pem_cert_fingerprint(fingerprint, flags);
1711 if(VERIFY_CERT_FLAG_CHANGED & flags) {
1712 message += tr(
"The above X.509 certificate is changed.\n"
1713 "It is possible that the server has changed its certificate, "
1714 "or Maybe it was attacked."
1715 "Please look at the OpenSSL documentation on "
1716 "how to add a private CA to the store.");
1718 message += tr(
"The above X.509 certificate could not be verified.\n"
1719 "Possibly because you do not have the CA certificate "
1720 "in your certificate store, or the certificate has expired.\n"
1721 "Please look at the OpenSSL documentation on "
1722 "how to add a private CA to the store.");
1726 message += tr(
"Yes - trusted") +
"\n";
1727 message += tr(
"Ignore - temporary trusted") +
"\n";
1728 message += tr(
"No - no trusted") +
"\n";
1730 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1731 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1732 bool bCheckBox =
false;
1734 tr(
"Don't show again"));
1735 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1741 case QMessageBox::StandardButton::Yes:
1743 case QMessageBox::StandardButton::Ignore:
1771 const char *host, UINT16 port,
1772 const char *common_name,
const char *subject,
1773 const char *issuer,
const char *fingerprint,
1774 const char *old_subject,
const char *old_issuer,
1775 const char *old_fingerprint, DWORD flags)
1777 qDebug(log) << Q_FUNC_INFO;
1778 rdpContext* pContext = (rdpContext*)instance->context;
1781 emit pThis->sigServerName(common_name);
1783 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1789 QString szType = tr(
"RDP-Server");
1790 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1791 szType = tr(
"RDP-Gateway");
1792 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1793 szType = tr(
"RDP-Redirect");
1795 QString title(tr(
"Verify changed certificate"));
1797 message += szType + tr(
": %1:%2").arg(host, QString::number(port)) +
"\n";
1798 message += tr(
"New Certificate details:") +
"\n";
1799 message +=
" " + tr(
"name: ") + common_name +
"\n";
1800 message +=
" " + tr(
"subject: ") + subject +
"\n";
1801 message +=
" " + tr(
"issuer: ") + issuer +
"\n";
1802 message +=
" " + pem_cert_fingerprint(fingerprint, flags) +
"\n";
1803 message += tr(
"Old Certificate details:") +
"\n";
1804 message +=
" " + tr(
"subject: ") + old_subject +
"\n";
1805 message +=
" " + tr(
"issuer: ") + old_issuer +
"\n";
1806 message +=
" " + pem_cert_fingerprint(old_fingerprint, flags) +
"\n";
1808 message += tr(
"The above X.509 certificate could not be verified, "
1809 "possibly because you do not have the CA certificate "
1810 "in your certificate store, or the certificate has expired. "
1811 "Please look at the OpenSSL documentation on "
1812 "how to add a private CA to the store.");
1815 message += tr(
"Yes - trusted") +
"\n";
1816 message += tr(
"Ignore - temporary trusted") +
"\n";
1817 message += tr(
"No - no trusted") +
"\n";
1819 bool bCheckBox =
false;
1820 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1821 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1823 tr(
"Don't show again"));
1824 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1831 case QMessageBox::StandardButton::Yes:
1833 case QMessageBox::StandardButton::Ignore:
1844BOOL CConnectFreeRDP::cb_present_gateway_message(
1845 freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1846 BOOL isConsentMandatory,
size_t length,
const WCHAR* message)
1848 qDebug(log) << Q_FUNC_INFO;
1850 if (!isDisplayMandatory && !isConsentMandatory)
1854 if (type == GATEWAY_MESSAGE_CONSENT && isConsentMandatory)
1856 QString msgType = (type == GATEWAY_MESSAGE_CONSENT)
1857 ? tr(
"Consent message") : tr(
"Service message");
1859#if FREERDP_VERSION_MAJOR >= 3
1860 char* pMsg = ConvertWCharToUtf8Alloc(message, NULL);
1866 msgType += QString::fromStdWString((
wchar_t*)message);
1869 msgType += tr(
"I understand and agree to the terms of this policy (Y/N)");
1871 rdpContext* pContext = (rdpContext*)instance->context;
1873 QMessageBox::StandardButton nRet = QMessageBox::No;
1874 bool bCheckBox =
false;
1876 QMessageBox::Yes|QMessageBox::No,
1879 case QMessageBox::Yes:
1887 return client_cli_present_gateway_message(
1888 instance, type, isDisplayMandatory,
1889 isConsentMandatory, length, message);
1894BOOL CConnectFreeRDP::cb_begin_paint(rdpContext *context)
1898 if (!context || !context->gdi || !context->gdi->primary
1899 || !context->gdi->primary->hdc)
1902 hdc = context->gdi->primary->hdc;
1904 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1907 hdc->hwnd->invalid->null = TRUE;
1908 hdc->hwnd->ninvalid = 0;
1912BOOL CConnectFreeRDP::UpdateBuffer(INT32 x, INT32 y, INT32 w, INT32 h)
1914 if(x > m_Image.width() || y > m_Image.height()) {
1915 qCritical(log) <<
"The width and height out of range."
1916 <<
"Image width:" << m_Image.width()
1917 <<
"Image height:" << m_Image.height()
1918 <<
"w:" << w <<
"h:" << h;
1922 QRect rect(x, y, w, h);
1923 QImage img = m_Image.copy(rect);
1929BOOL CConnectFreeRDP::cb_end_paint(rdpContext *context)
1932 ClientContext* pContext = (ClientContext*)context;
1936 REGION16 invalidRegion;
1937 RECTANGLE_16 invalidRect;
1938 const RECTANGLE_16* extents;
1942 if (!context || !context->gdi || !context->gdi->primary
1943 || !context->gdi->primary->hdc)
1946 hdc = context->gdi->primary->hdc;
1948 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1951 rdpGdi* gdi = context->gdi;
1952 if (gdi->suppressOutput)
1955 HGDI_WND hwnd = context->gdi->primary->hdc->hwnd;
1956 ninvalid = hwnd->ninvalid;
1957 cinvalid = hwnd->cinvalid;
1961 region16_init(&invalidRegion);
1963 for (i = 0; i < ninvalid; i++)
1965 if(cinvalid[i].null)
1967 qWarning(log) <<
"is null region" << cinvalid[i].x << cinvalid[i].y
1968 << cinvalid[i].w << cinvalid[i].h;
1971 invalidRect.left = cinvalid[i].x;
1972 invalidRect.top = cinvalid[i].y;
1973 invalidRect.right = cinvalid[i].x + cinvalid[i].w;
1974 invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
1975 region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
1978 if (!region16_is_empty(&invalidRegion))
1980 extents = region16_extents(&invalidRegion);
1982 pThis->UpdateBuffer(extents->left,
1984 extents->right - extents->left,
1985 extents->bottom - extents->top);
1988 region16_uninit(&invalidRegion);
1993BOOL CConnectFreeRDP::cb_desktop_resize(rdpContext* context)
1995 qDebug(log) << Q_FUNC_INFO;
1996 ClientContext* pContext = (ClientContext*)context;
1998 rdpSettings* settings;
1999 if (!context || !context->settings)
2001 settings = context->settings;
2002 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
2003 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2005 if(!gdi_resize(context->gdi, desktopWidth, desktopHeight))
2007 if(!pThis->CreateImage(context))
2010 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
2011 pThis->UpdateBuffer(0, 0, desktopWidth, desktopHeight);
2015BOOL CConnectFreeRDP::cb_play_bell_sound(rdpContext *context,
const PLAY_SOUND_UPDATE *play_sound)
2017 qDebug(log) << Q_FUNC_INFO;
2018 ClientContext* pContext = (ClientContext*)context;
2020 WINPR_UNUSED(play_sound);
2021 QApplication::beep();
2025#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2026 QSoundEffect effect;
2027 effect.setSource(QUrl::fromLocalFile(szFile));
2032 QSound::play(szFile);
2038BOOL CConnectFreeRDP::cb_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
2040 qDebug(log) << Q_FUNC_INFO;
2041 ClientContext* pContext = (ClientContext*)context;
2044 int state = CFrmViewer::LED_STATE::Unknown;
2046 if (led_flags & KBD_SYNC_NUM_LOCK)
2047 state |= CFrmViewer::LED_STATE::NumLock;
2048 if (led_flags & KBD_SYNC_CAPS_LOCK)
2049 state |= CFrmViewer::LED_STATE::CapsLock;
2050 if (led_flags & KBD_SYNC_SCROLL_LOCK)
2051 state |= CFrmViewer::LED_STATE::ScrollLock;
2053 emit pThis->sigUpdateLedState(state);
2059BOOL CConnectFreeRDP::cb_keyboard_set_ime_status(
2060 rdpContext* context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
2066 "KeyboardSetImeStatus(unitId=%04" PRIx16
", imeState=%08" PRIx32
2067 ", imeConvMode=%08" PRIx32
") ignored",
2068 imeId, imeState, imeConvMode);
2076 SetEvent(m_writeEvent);
2081bool CConnectFreeRDP::SendMouseEvent(UINT16 flags, QPoint pos,
bool isExtended)
2083 if(m_pParameter && m_pParameter->GetOnlyView())
return true;
2084 if(!m_pContext)
return false;
2086#if FREERDP_VERSION_MAJOR >= 3
2088 freerdp_client_send_extended_button_event(
2089 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
2091 freerdp_client_send_button_event(
2092 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
2094 if(!m_pContext->Context.input)
return false;
2095 return freerdp_input_send_mouse_event(
2096 m_pContext->Context.input, flags, pos.x(), pos.y());
2101void CConnectFreeRDP::wheelEvent(QWheelEvent *event)
2103 qDebug(logMouse) << Q_FUNC_INFO << event;
2104 if(!m_pContext)
return;
2105 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2109#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2110 pos =
event->position();
2114 QPoint p =
event->angleDelta();
2117 flags |= PTR_FLAGS_WHEEL | p.y();
2121 flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.y();
2126 flags |= PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.x();
2130 flags |= PTR_FLAGS_HWHEEL | p.x();
2132#if FREERDP_VERSION_MAJOR >= 3
2133 freerdp_client_send_wheel_event(&m_pContext->Context, flags);
2138 freerdp_input_send_mouse_event(
2139 m_pContext->Context.input, flags, pos.x(), pos.y());
2144void CConnectFreeRDP::mouseMoveEvent(QMouseEvent *event)
2146 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2147 if(!m_pContext)
return;
2148 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2149 UINT16 flags = PTR_FLAGS_MOVE;
2150 SendMouseEvent(flags, event->pos(),
false);
2153void CConnectFreeRDP::mousePressEvent(QMouseEvent *event)
2155 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2156 if(!m_pContext)
return;
2157 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2160 bool isExtended =
false;
2161 Qt::MouseButton button =
event->button();
2162 if (button & Qt::MouseButton::LeftButton)
2164 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
2166 else if (button & Qt::MouseButton::RightButton)
2168 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
2170 else if (button & Qt::MouseButton::MiddleButton)
2172 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3;
2174 else if (button & Qt::MouseButton::ForwardButton)
2176 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2;
2179 else if (button & Qt::MouseButton::BackButton)
2181 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1;
2186 SendMouseEvent(flags, event->pos(), isExtended);
2190void CConnectFreeRDP::mouseReleaseEvent(QMouseEvent *event)
2192 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2193 if(!m_pContext)
return;
2194 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2197 bool isExtended =
false;
2198 Qt::MouseButton button =
event->button();
2199 if (button & Qt::MouseButton::LeftButton)
2201 flags = PTR_FLAGS_BUTTON1;
2203 else if (button & Qt::MouseButton::MiddleButton)
2205 flags = PTR_FLAGS_BUTTON3;
2207 else if (button & Qt::MouseButton::RightButton)
2209 flags = PTR_FLAGS_BUTTON2;
2211 else if (button & Qt::MouseButton::ForwardButton)
2213 flags = PTR_XFLAGS_BUTTON2;
2216 else if (button & Qt::MouseButton::BackButton)
2218 flags = PTR_XFLAGS_BUTTON1;
2223 SendMouseEvent(flags, event->pos(), isExtended);
2227void CConnectFreeRDP::keyPressEvent(QKeyEvent *event)
2229 qDebug(logKey) << Q_FUNC_INFO << event;
2230 if(!m_pContext)
return;
2231 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2234 if(RDP_SCANCODE_UNKNOWN != k)
2235#if FREERDP_VERSION_MAJOR >= 3
2236 freerdp_input_send_keyboard_event_ex(
2237 m_pContext->Context.context.input,
true,
true, k);
2239 freerdp_input_send_keyboard_event_ex(
2240 m_pContext->Context.input,
true, k);
2244void CConnectFreeRDP::keyReleaseEvent(QKeyEvent *event)
2246 qDebug(logKey) << Q_FUNC_INFO << event;
2247 if(!m_pContext)
return;
2248 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2250 if(RDP_SCANCODE_UNKNOWN != k)
2251#if FREERDP_VERSION_MAJOR >= 3
2252 freerdp_input_send_keyboard_event_ex(
2253 m_pContext->Context.context.input,
false,
false, k);
2255 freerdp_input_send_keyboard_event_ex(
2256 m_pContext->Context.input,
false, k);
2260int CConnectFreeRDP::RedirectionSound()
2262 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2263 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2264 rdpSettings* settings = instance->context->settings;
2267 if(m_pParameter->GetRedirectionSound()
2268 == CParameterFreeRDP::RedirecionSoundType::Disable)
2271 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE);
2272 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE);
2274 }
else if(m_pParameter->GetRedirectionSound()
2275 == CParameterFreeRDP::RedirecionSoundType::Local)
2277 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE);
2278 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
2279 }
else if(m_pParameter->GetRedirectionSound()
2280 == CParameterFreeRDP::RedirecionSoundType::Remote)
2282 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE);
2297 ptr.p = CommandLineParseCommaSeparatedValuesEx(
"rdpsnd",
2298 m_pParameter->GetRedirectionSoundParameters().toStdString().c_str(),
2300 BOOL status = freerdp_client_add_static_channel(settings, count,
2301 #
if FREERDP_VERSION_MAJOR < 3
2309 status = freerdp_client_add_dynamic_channel(settings, count,
2310 #
if FREERDP_VERSION_MAJOR < 3
2320 qCritical(log) <<
"Load rdpsnd fail";
2327int CConnectFreeRDP::RedirectionMicrophone()
2329 if(m_pParameter->GetRedirectionSound()
2330 == CParameterFreeRDP::RedirecionSoundType::Remote)
2332 if(!m_pParameter->GetRedirectionMicrophone())
2335 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2336 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2338 rdpSettings* settings = instance->context->settings;
2341 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
2352 ptr.p = CommandLineParseCommaSeparatedValuesEx(
"audin",
2353 m_pParameter->GetRedirectionMicrophoneParameters().toStdString().c_str(),
2355 BOOL status = freerdp_client_add_dynamic_channel(settings, count,
2356 #
if FREERDP_VERSION_MAJOR < 3
2365 qCritical(log) <<
"Load audin fail";
2372int CConnectFreeRDP::RedirectionDriver()
2374 QStringList lstDrives = m_pParameter->GetRedirectionDrives();
2375 if(lstDrives.isEmpty())
2378 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2379 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2380 rdpSettings* settings = instance->context->settings;
2383 foreach (
auto drive, lstDrives) {
2385 char* pDrive = _strdup(drive.toStdString().c_str());
2386 const char* argvDrive[] = {
"drive", pDrive};
2387 int count =
sizeof(argvDrive) /
sizeof(
const char*);
2388 BOOL status = freerdp_client_add_device_channel(settings, count,
2389 #
if FREERDP_VERSION_MAJOR < 3
2393 if(pDrive) free(pDrive);
2396 qCritical(log) <<
"Load drive fail";
2404int CConnectFreeRDP::RedirectionPrinter()
2406 if(!m_pParameter->GetRedirectionPrinter())
2409 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2410 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2411 rdpSettings* settings = instance->context->settings;
2414 QStringList printerList = QPrinterInfo::availablePrinterNames();
2415 if(printerList.isEmpty())
2417 qCritical(log) <<
"The printer is empty";
2420 qDebug(log) << printerList;
2423 const char* argvPrinter[] = {
"printer",
nullptr,
nullptr};
2424 int count =
sizeof(argvPrinter) /
sizeof(
const char*);
2425 BOOL status = freerdp_client_add_device_channel(settings, count,
2426 #
if FREERDP_VERSION_MAJOR < 3
2431 qCritical(log) <<
"Load printer fail";
2438int CConnectFreeRDP::RedirectionSerial()
2442 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2443 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2444 rdpSettings* settings = instance->context->settings;
2447 QList<QSerialPortInfo> lstSerial = QSerialPortInfo::availablePorts();
2450 foreach (
auto serial, lstSerial) {
2453 qDebug(log) <<
"systemLocation:" << serial.systemLocation()
2454 <<
"portName:" << serial.portName()
2455 <<
"serialNumber:" << serial.serialNumber();
2456 char* pSerial = _strdup(serial.systemLocation().toStdString().c_str());
2457 char* pName = _strdup(serial.portName().toStdString().c_str());
2458 const char* argvSerial[] = {
"serial", pName, pSerial};
2459 int count =
sizeof(argvSerial) /
sizeof(
const char*);
2460 BOOL status = freerdp_client_add_device_channel(settings, count,
2461 #
if FREERDP_VERSION_MAJOR < 3
2465 if(pSerial) free(pSerial);
2466 if(pName) free(pName);
2470 qCritical(log) <<
"Load drive fail";
2478void CConnectFreeRDP::slotConnectProxyServer(QString szHost, quint16 nPort)
2480 qDebug(log) <<
"Connect proxy server:" << szHost +
":" + QString::number(nPort);
2481 rdpContext* pContext = (rdpContext*)m_pContext;
2482 rdpSettings* settings = pContext->settings;
2484 qCritical(log) <<
"settings is null";
2487 freerdp_settings_set_string(
2488 settings, FreeRDP_ServerHostname,
2489 szHost.toStdString().c_str());
2490 freerdp_settings_set_uint32(
2491 settings, FreeRDP_ServerPort,
2494 int nRet = freerdp_client_start(pContext);
2497 qCritical(log) <<
"freerdp_client_start fail";
2499 qDebug(log) <<
"Connect proxy server:" << szHost +
":" + QString::number(nPort) <<
"end";
2503CConnect::OnInitReturnValue CConnectFreeRDP::InitSSHTunnelPipe()
2508 &m_pParameter->m_Proxy.m_SSH, &m_pParameter->m_Net,
this);
2510 return OnInitReturnValue::Fail;
2511 bool check = connect(m_pThreadSSH, SIGNAL(sigServer(QString, quint16)),
2512 this, SLOT(slotConnectProxyServer(QString, quint16)));
2514 check = connect(m_pThreadSSH, SIGNAL(
sigError(
int,QString)),
2515 this, SIGNAL(
sigError(
int,QString)));
2520 m_pThreadSSH->start();
2521 return OnInitReturnValue::UseOnProcess;
2524int CConnectFreeRDP::CleanSSHTunnelPipe()
2528 m_pThreadSSH->Exit();
2529 m_pThreadSSH =
nullptr;
void sigUpdateRect(const QRect &r, const QImage &image)
通知视图,图像更新
virtual OnInitReturnValue OnInit() override
具体的插件实现连接初始化
virtual int OnClean() override
清理
static int cb_verify_x509_certificate(freerdp *instance, const BYTE *data, size_t length, const char *hostname, UINT16 port, DWORD flags)
Callback used if user interaction is required to accept a certificate.
static DWORD cb_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when a stored ce...
virtual int WakeUp() override
唤醒连接线程(后台线程)
static DWORD cb_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when the connect...
virtual int OnProcess() override
插件连接的具体操作处理。因为此插件是非Qt事件,所以在此函数中等待。
static BOOL cb_post_connect(freerdp *instance)
Callback given to freerdp_connect() to perform post-connection operations.
static BOOL cb_pre_connect(freerdp *instance)
Callback given to freerdp_connect() to process the pre-connect operations.
void sigError(const int nError, const QString &szError=QString())
当有错误产生时触发
void sigInformation(const QString &szInfo)
从后台线程中触发在主线程中显示信息,不阻塞后台线程
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
阻塞后台线程,并在前台线程中显示消息对话框(QMessageBox)
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
从后台线程中触发在主线程中显示消息对话框(QMessageBox),不阻塞后台线程
void sigBlockInputDialog(const QString &szTitle, const QString &szLable, const QString &szMessage, QString &szText)
阻塞后台线程,并在前台线程中显示输入对话框 (QInputDialog)
void sigConnected()
当插件连接成功后触发。仅由插件触发
void sigDisconnect()
通知用户断开连接。仅由插件触发。 当从插件中需要要断开连接时触发。例如:对端断开连接、重置连接或者连接出错。
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
阻塞后台线程,并在前台线程中显示窗口。
static UINT32 QtToScanCode(int key, Qt::KeyboardModifiers modifiers)
CConvertKeyCode::QtToScanCode
[Declare CParameterFreeRDP]
网络连接参数接口。此类仅在插件内有效。 其界面为 CParameterNetUI
CParameterUser m_User
[Instance user]
void sigChanged()
当参数改变时,触发 通常如果需要,则相应的参数会对应一个改变事件。
实现通过本地 SOCKET 与 SSH 隧道转发数据。适用于库没有实现传输层接口,只有 socket 的情况。