2 * FreeRDP: A Remote Desktop Protocol Implementation
5 * Copyright 2009-2011 Jay Sorg
6 * Copyright 2010-2011 Vic Lee
7 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
26 #include <winpr/windows.h>
28 #include <winpr/crt.h>
29 #include <winpr/credui.h>
37 #include <sys/types.h>
39 #include <freerdp/log.h>
40 #include <freerdp/event.h>
41 #include <freerdp/freerdp.h>
42 #include <freerdp/constants.h>
44 #include <freerdp/codec/region.h>
45 #include <freerdp/client/cmdline.h>
46 #include <freerdp/client/channels.h>
47 #include <freerdp/channels/channels.h>
51 #include "wf_channels.h"
52 #include "wf_graphics.h"
53 #include "wf_cliprdr.h"
55 #include "wf_client.h"
59 #define TAG CLIENT_TAG("windows")
61 int wf_create_console(void)
66 freopen("CONOUT$", "w", stdout);
67 freopen("CONOUT$", "w", stderr);
68 WLog_INFO(TAG, "Debug console created.");
72 BOOL wf_sw_begin_paint(wfContext* wfc)
74 rdpGdi* gdi = ((rdpContext*) wfc)->gdi;
75 gdi->primary->hdc->hwnd->invalid->null = 1;
76 gdi->primary->hdc->hwnd->ninvalid = 0;
80 BOOL wf_sw_end_paint(wfContext* wfc)
87 REGION16 invalidRegion;
88 RECTANGLE_16 invalidRect;
89 const RECTANGLE_16* extents;
90 rdpContext* context = (rdpContext*) wfc;
94 ninvalid = gdi->primary->hdc->hwnd->ninvalid;
95 cinvalid = gdi->primary->hdc->hwnd->cinvalid;
100 region16_init(&invalidRegion);
102 for (i = 0; i < ninvalid; i++)
104 invalidRect.left = cinvalid[i].x;
105 invalidRect.top = cinvalid[i].y;
106 invalidRect.right = cinvalid[i].x + cinvalid[i].w;
107 invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
109 region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
112 if (!region16_is_empty(&invalidRegion))
114 extents = region16_extents(&invalidRegion);
116 updateRect.left = extents->left;
117 updateRect.top = extents->top;
118 updateRect.right = extents->right;
119 updateRect.bottom = extents->bottom;
121 InvalidateRect(wfc->hwnd, &updateRect, FALSE);
124 wf_rail_invalidate_region(wfc, &invalidRegion);
127 region16_uninit(&invalidRegion);
131 BOOL wf_sw_desktop_resize(wfContext* wfc)
135 rdpSettings* settings;
136 freerdp* instance = wfc->instance;
138 context = (rdpContext*) wfc;
139 settings = wfc->instance->settings;
142 wfc->width = settings->DesktopWidth;
143 wfc->height = settings->DesktopHeight;
145 gdi->primary->bitmap->data = NULL;
150 wf_image_free(wfc->primary);
151 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
154 if (!gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, wfc->primary->pdata))
157 gdi = instance->context->gdi;
158 wfc->hdc = gdi->primary->hdc;
163 BOOL wf_hw_begin_paint(wfContext* wfc)
165 wfc->hdc->hwnd->invalid->null = 1;
166 wfc->hdc->hwnd->ninvalid = 0;
170 BOOL wf_hw_end_paint(wfContext* wfc)
175 BOOL wf_hw_desktop_resize(wfContext* wfc)
179 rdpSettings* settings;
181 settings = wfc->instance->settings;
183 wfc->width = settings->DesktopWidth;
184 wfc->height = settings->DesktopHeight;
188 same = (wfc->primary == wfc->drawing) ? TRUE : FALSE;
190 wf_image_free(wfc->primary);
192 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
195 wfc->drawing = wfc->primary;
198 if (wfc->fullscreen != TRUE)
201 SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1, wfc->width + wfc->diff.x, wfc->height + wfc->diff.y, SWP_NOMOVE);
205 wf_update_offset(wfc);
206 GetWindowRect(wfc->hwnd, &rect);
207 InvalidateRect(wfc->hwnd, &rect, TRUE);
212 BOOL wf_pre_connect(freerdp* instance)
218 rdpSettings* settings;
220 context = instance->context;
221 wfc = (wfContext*) instance->context;
222 wfc->instance = instance;
223 wfc->codecs = instance->context->codecs;
225 settings = instance->settings;
227 if (settings->ConnectionFile)
229 if (wfc->connectionRdpFile)
231 freerdp_client_rdp_file_free(wfc->connectionRdpFile);
234 wfc->connectionRdpFile = freerdp_client_rdp_file_new();
235 WLog_INFO(TAG, "Using connection file: %s", settings->ConnectionFile);
236 freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile);
237 freerdp_client_populate_settings_from_rdp_file(wfc->connectionRdpFile, settings);
240 settings->OsMajorType = OSMAJORTYPE_WINDOWS;
241 settings->OsMinorType = OSMINORTYPE_WINDOWS_NT;
242 settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
243 settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
244 settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
245 settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
246 settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
247 settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
248 settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
249 settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
250 settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
251 settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
252 settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
253 settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
254 settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE;
255 settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
256 settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
257 settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = FALSE;
258 settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE;
259 settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE;
260 settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
261 settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
262 settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
263 settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
265 settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE;
267 wfc->fullscreen = settings->Fullscreen;
272 wfc->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV));
273 ZeroMemory(wfc->clrconv, sizeof(CLRCONV));
275 wfc->clrconv->palette = NULL;
276 wfc->clrconv->alpha = FALSE;
278 if (!(instance->context->cache = cache_new(settings)))
281 desktopWidth = settings->DesktopWidth;
282 desktopHeight = settings->DesktopHeight;
284 if (wfc->percentscreen > 0)
286 desktopWidth = (GetSystemMetrics(SM_CXSCREEN) * wfc->percentscreen) / 100;
287 settings->DesktopWidth = desktopWidth;
289 desktopHeight = (GetSystemMetrics(SM_CYSCREEN) * wfc->percentscreen) / 100;
290 settings->DesktopHeight = desktopHeight;
295 if (settings->UseMultimon)
297 desktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
298 desktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
302 desktopWidth = GetSystemMetrics(SM_CXSCREEN);
303 desktopHeight = GetSystemMetrics(SM_CYSCREEN);
307 /* FIXME: desktopWidth has a limitation that it should be divisible by 4,
308 * otherwise the screen will crash when connecting to an XP desktop.*/
309 desktopWidth = (desktopWidth + 3) & (~3);
311 if (desktopWidth != settings->DesktopWidth)
313 freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, desktopWidth);
316 if (desktopHeight != settings->DesktopHeight)
318 freerdp_set_param_uint32(settings, FreeRDP_DesktopHeight, desktopHeight);
321 if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) ||
322 (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
324 WLog_ERR(TAG, "invalid dimensions %d %d", settings->DesktopWidth, settings->DesktopHeight);
328 freerdp_set_param_uint32(settings, FreeRDP_KeyboardLayout, (int) GetKeyboardLayout(0) & 0x0000FFFF);
330 PubSub_SubscribeChannelConnected(instance->context->pubSub,
331 (pChannelConnectedEventHandler) wf_OnChannelConnectedEventHandler);
333 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
334 (pChannelDisconnectedEventHandler) wf_OnChannelDisconnectedEventHandler);
336 freerdp_channels_pre_connect(instance->context->channels, instance);
341 void wf_add_system_menu(wfContext* wfc)
343 HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE);
345 MENUITEMINFO item_info;
346 ZeroMemory(&item_info, sizeof(MENUITEMINFO));
348 item_info.fMask = MIIM_CHECKMARKS | MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_DATA;
349 item_info.cbSize = sizeof(MENUITEMINFO);
350 item_info.wID = SYSCOMMAND_ID_SMARTSIZING;
351 item_info.fType = MFT_STRING;
352 item_info.dwTypeData = _wcsdup(_T("Smart sizing"));
353 item_info.cch = (UINT) _wcslen(_T("Smart sizing"));
354 item_info.dwItemData = (ULONG_PTR) wfc;
356 InsertMenuItem(hMenu, 6, TRUE, &item_info);
358 if (wfc->instance->settings->SmartSizing)
360 CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, MF_CHECKED);
364 BOOL wf_post_connect(freerdp* instance)
371 WCHAR lpWindowName[64];
372 rdpSettings* settings;
373 EmbedWindowEventArgs e;
375 settings = instance->settings;
376 context = instance->context;
377 wfc = (wfContext*) instance->context;
378 cache = instance->context->cache;
381 wfc->width = settings->DesktopWidth;
382 wfc->height = settings->DesktopHeight;
384 if (settings->SoftwareGdi)
386 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
388 if (!gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, wfc->primary->pdata))
391 gdi = instance->context->gdi;
392 wfc->hdc = gdi->primary->hdc;
396 wf_gdi_register_update_callbacks(instance->update);
397 wfc->srcBpp = instance->settings->ColorDepth;
398 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
400 if (!(wfc->hdc = gdi_GetDC()))
403 wfc->hdc->bitsPerPixel = wfc->dstBpp;
404 wfc->hdc->bytesPerPixel = wfc->dstBpp / 8;
406 wfc->hdc->alpha = wfc->clrconv->alpha;
407 wfc->hdc->invert = wfc->clrconv->invert;
409 wfc->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
410 wfc->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
411 wfc->hdc->hwnd->invalid->null = 1;
413 wfc->hdc->hwnd->count = 32;
414 wfc->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * wfc->hdc->hwnd->count);
415 wfc->hdc->hwnd->ninvalid = 0;
417 if (settings->RemoteFxCodec)
419 wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL);
423 if (settings->WindowTitle != NULL)
424 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"%S", settings->WindowTitle);
425 else if (settings->ServerPort == 3389)
426 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"FreeRDP: %S", settings->ServerHostname);
428 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"FreeRDP: %S:%d", settings->ServerHostname, settings->ServerPort);
430 if (settings->EmbeddedWindow)
431 settings->Decorations = FALSE;
435 else if (!settings->Decorations)
436 dwStyle = WS_CHILD | WS_BORDER;
438 dwStyle = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX;
442 wfc->hwnd = CreateWindowEx((DWORD) NULL, wfc->wndClassName, lpWindowName, dwStyle,
443 0, 0, 0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL);
445 SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR) wfc);
448 wf_resize_window(wfc);
450 wf_add_system_menu(wfc);
452 BitBlt(wfc->primary->hdc, 0, 0, wfc->width, wfc->height, NULL, 0, 0, BLACKNESS);
453 wfc->drawing = wfc->primary;
455 EventArgsInit(&e, "wfreerdp");
457 e.handle = (void*) wfc->hwnd;
458 PubSub_OnEmbedWindow(context->pubSub, context, &e);
460 ShowWindow(wfc->hwnd, SW_SHOWNORMAL);
461 UpdateWindow(wfc->hwnd);
463 if (settings->SoftwareGdi)
465 instance->update->BeginPaint = (pBeginPaint) wf_sw_begin_paint;
466 instance->update->EndPaint = (pEndPaint) wf_sw_end_paint;
467 instance->update->DesktopResize = (pDesktopResize) wf_sw_desktop_resize;
471 instance->update->BeginPaint = (pBeginPaint) wf_hw_begin_paint;
472 instance->update->EndPaint = (pEndPaint) wf_hw_end_paint;
473 instance->update->DesktopResize = (pDesktopResize) wf_hw_desktop_resize;
476 pointer_cache_register_callbacks(instance->update);
477 wf_register_pointer(context->graphics);
479 if (!settings->SoftwareGdi)
481 brush_cache_register_callbacks(instance->update);
482 bitmap_cache_register_callbacks(instance->update);
483 offscreen_cache_register_callbacks(instance->update);
484 wf_register_graphics(context->graphics);
485 instance->update->BitmapUpdate = wf_gdi_bitmap_update;
488 if (freerdp_channels_post_connect(context->channels, instance) < 0)
492 floatbar_window_create(wfc);
497 static CREDUI_INFOA wfUiInfo =
499 sizeof(CREDUI_INFOA),
501 "Enter your credentials",
502 "Remote Desktop Security",
506 static BOOL wf_authenticate_raw(freerdp* instance, const char* title,
507 char** username, char** password, char** domain)
512 char UserName[CREDUI_MAX_USERNAME_LENGTH + 1];
513 char Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
514 char User[CREDUI_MAX_USERNAME_LENGTH + 1];
515 char Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
518 ZeroMemory(UserName, sizeof(UserName));
519 ZeroMemory(Password, sizeof(Password));
520 dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES;
522 status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0,
523 UserName, CREDUI_MAX_USERNAME_LENGTH + 1,
524 Password, CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
526 if (status != NO_ERROR)
528 WLog_ERR(TAG, "CredUIPromptForCredentials unexpected status: 0x%08X", status);
532 ZeroMemory(User, sizeof(User));
533 ZeroMemory(Domain, sizeof(Domain));
535 status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, sizeof(Domain));
536 //WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password);
537 *username = _strdup(User);
540 WLog_ERR(TAG, "strdup failed", status);
544 if (strlen(Domain) > 0)
545 *domain = _strdup(Domain);
547 *domain = _strdup("\0");
552 WLog_ERR(TAG, "strdup failed", status);
556 *password = _strdup(Password);
567 static BOOL wf_authenticate(freerdp* instance,
568 char** username, char** password, char** domain)
570 return wf_authenticate_raw(instance, instance->settings->ServerHostname,
571 username, password, domain);
574 static BOOL wf_gw_authenticate(freerdp* instance,
575 char** username, char** password, char** domain)
578 sprintf_s(tmp, sizeof(tmp), "Gateway %s", instance->settings->GatewayHostname);
579 return wf_authenticate_raw(instance, tmp, username, password, domain);
582 BOOL wf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
592 WLog_INFO(TAG, "Certificate details:");
593 WLog_INFO(TAG, "\tSubject: %s", subject);
594 WLog_INFO(TAG, "\tIssuer: %s", issuer);
595 WLog_INFO(TAG, "\tThumbprint: %s", fingerprint);
596 WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have "
597 "the CA certificate in your certificate store, or the certificate has expired. "
598 "Please look at the documentation on how to create local certificate store for a private CA.");
599 /* TODO: ask for user validation */
601 input_handle = GetStdHandle(STD_INPUT_HANDLE);
603 GetConsoleMode(input_handle, &mode);
604 mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT;
605 SetConsoleMode(input_handle, mode);
611 static BOOL wf_auto_reconnect(freerdp* instance)
613 wfContext* wfc = (wfContext *)instance->context;
615 UINT32 num_retries = 0;
616 UINT32 max_retries = instance->settings->AutoReconnectMaxRetries;
618 /* Only auto reconnect on network disconnects. */
619 if (freerdp_error_info(instance) != 0)
622 /* A network disconnect was detected */
623 WLog_ERR(TAG, "Network disconnect!");
625 if (!instance->settings->AutoReconnectionEnabled)
627 /* No auto-reconnect - just quit */
631 /* Perform an auto-reconnect. */
634 /* Quit retrying if max retries has been exceeded */
635 if (num_retries++ >= max_retries)
638 /* Attempt the next reconnect */
639 WLog_INFO(TAG, "Attempting reconnect (%u of %u)", num_retries, max_retries);
641 if (freerdp_reconnect(instance))
649 WLog_ERR(TAG, "Maximum reconnect retries exceeded");
653 void* wf_input_thread(void* arg)
657 wMessageQueue* queue;
658 freerdp* instance = (freerdp*) arg;
660 assert( NULL != instance);
663 queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
665 while (MessageQueue_Wait(queue))
667 while (MessageQueue_Peek(queue, &message, TRUE))
669 status = freerdp_message_queue_process_message(instance,
670 FREERDP_INPUT_MESSAGE_QUEUE, &message);
685 DWORD WINAPI wf_client_thread(LPVOID lpParam)
697 rdpChannels* channels;
698 rdpSettings* settings;
700 BOOL async_transport;
703 instance = (freerdp*) lpParam;
704 context = instance->context;
705 wfc = (wfContext*) instance->context;
707 if (!freerdp_connect(instance))
710 channels = instance->context->channels;
711 settings = instance->context->settings;
713 async_input = settings->AsyncInput;
714 async_transport = settings->AsyncTransport;
718 if (!(input_thread = CreateThread(NULL, 0,
719 (LPTHREAD_START_ROUTINE) wf_input_thread,
722 WLog_ERR(TAG, "Failed to create async input thread.");
731 if (freerdp_focus_required(instance))
733 wf_event_focus_in(wfc);
734 wf_event_focus_in(wfc);
737 if (!async_transport)
739 DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], 64 - nCount);
743 WLog_ERR(TAG, "freerdp_get_event_handles failed");
750 if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED)
752 WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%04X", GetLastError());
756 if (!async_transport)
758 if (!freerdp_check_event_handles(context))
760 if (wf_auto_reconnect(instance))
763 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
768 if (freerdp_shall_disconnect(instance))
773 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
775 msg_ret = GetMessage(&msg, NULL, 0, 0);
777 if (instance->settings->EmbeddedWindow)
779 if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1))
781 PostMessage(wfc->hwnd, WM_SETFOCUS, 0, 0);
783 else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1))
785 PostMessage(wfc->hwnd, WM_KILLFOCUS, 0, 0);
789 if (msg.message == WM_SIZE)
791 width = LOWORD(msg.lParam);
792 height = HIWORD(msg.lParam);
794 SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
797 if ((msg_ret == 0) || (msg_ret == -1))
803 TranslateMessage(&msg);
804 DispatchMessage(&msg);
812 freerdp_channels_disconnect(channels, instance);
816 wMessageQueue* input_queue;
817 input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
818 if (MessageQueue_PostQuit(input_queue, 0))
819 WaitForSingleObject(input_thread, INFINITE);
820 CloseHandle(input_thread);
824 freerdp_disconnect(instance);
825 WLog_DBG(TAG, "Main thread exited.");
831 DWORD WINAPI wf_keyboard_thread(LPVOID lpParam)
838 wfc = (wfContext*) lpParam;
841 hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, wfc->hInstance, 0);
845 while ((status = GetMessage(&msg, NULL, 0, 0)) != 0)
849 WLog_ERR(TAG, "keyboard thread error getting message");
854 TranslateMessage(&msg);
855 DispatchMessage(&msg);
859 UnhookWindowsHookEx(hook_handle);
863 WLog_ERR(TAG, "failed to install keyboard hook");
866 WLog_DBG(TAG, "Keyboard thread exited.");
871 rdpSettings* freerdp_client_get_settings(wfContext* wfc)
873 return wfc->instance->settings;
876 int freerdp_client_focus_in(wfContext* wfc)
878 PostThreadMessage(wfc->mainThreadId, WM_SETFOCUS, 0, 1);
882 int freerdp_client_focus_out(wfContext* wfc)
884 PostThreadMessage(wfc->mainThreadId, WM_KILLFOCUS, 0, 1);
888 int freerdp_client_set_window_size(wfContext* wfc, int width, int height)
890 WLog_DBG(TAG, "freerdp_client_set_window_size %d, %d", width, height);
892 if ((width != wfc->client_width) || (height != wfc->client_height))
894 PostThreadMessage(wfc->mainThreadId, WM_SIZE, SIZE_RESTORED, ((UINT) height << 16) | (UINT) width);
900 // TODO: Some of that code is a duplicate of wf_pre_connect. Refactor?
901 int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename)
903 rdpSettings* settings;
905 settings = wfc->instance->settings;
909 settings->ConnectionFile = _strdup(filename);
910 if (!settings->ConnectionFile)
915 // free old settings file
916 freerdp_client_rdp_file_free(wfc->connectionRdpFile);
917 wfc->connectionRdpFile = freerdp_client_rdp_file_new();
918 WLog_INFO(TAG, "Using connection file: %s", settings->ConnectionFile);
920 if (!freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile))
925 if (!freerdp_client_populate_settings_from_rdp_file(wfc->connectionRdpFile, settings))
934 void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height)
936 if (wfc->disablewindowtracking)
939 // prevent infinite message loop
940 wfc->disablewindowtracking = TRUE;
942 if (wfc->instance->settings->SmartSizing)
944 wfc->xCurrentScroll = 0;
945 wfc->yCurrentScroll = 0;
947 if (wfc->xScrollVisible || wfc->yScrollVisible)
949 if (ShowScrollBar(wfc->hwnd, SB_BOTH, FALSE))
951 wfc->xScrollVisible = FALSE;
952 wfc->yScrollVisible = FALSE;
959 BOOL horiz = wfc->xScrollVisible;
960 BOOL vert = wfc->yScrollVisible;;
962 if (!horiz && client_width < wfc->instance->settings->DesktopWidth)
966 else if (horiz && client_width >= wfc->instance->settings->DesktopWidth/* - GetSystemMetrics(SM_CXVSCROLL)*/)
971 if (!vert && client_height < wfc->instance->settings->DesktopHeight)
975 else if (vert && client_height >= wfc->instance->settings->DesktopHeight/* - GetSystemMetrics(SM_CYHSCROLL)*/)
980 if (horiz == vert && (horiz != wfc->xScrollVisible && vert != wfc->yScrollVisible))
982 if (ShowScrollBar(wfc->hwnd, SB_BOTH, horiz))
984 wfc->xScrollVisible = horiz;
985 wfc->yScrollVisible = vert;
989 if (horiz != wfc->xScrollVisible)
991 if (ShowScrollBar(wfc->hwnd, SB_HORZ, horiz))
993 wfc->xScrollVisible = horiz;
997 if (vert != wfc->yScrollVisible)
999 if (ShowScrollBar(wfc->hwnd, SB_VERT, vert))
1001 wfc->yScrollVisible = vert;
1007 // The horizontal scrolling range is defined by
1008 // (bitmap_width) - (client_width). The current horizontal
1009 // scroll value remains within the horizontal scrolling range.
1010 wfc->xMaxScroll = MAX(wfc->instance->settings->DesktopWidth - client_width, 0);
1011 wfc->xCurrentScroll = MIN(wfc->xCurrentScroll, wfc->xMaxScroll);
1012 si.cbSize = sizeof(si);
1013 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
1014 si.nMin = wfc->xMinScroll;
1015 si.nMax = wfc->instance->settings->DesktopWidth;
1016 si.nPage = client_width;
1017 si.nPos = wfc->xCurrentScroll;
1018 SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE);
1023 // The vertical scrolling range is defined by
1024 // (bitmap_height) - (client_height). The current vertical
1025 // scroll value remains within the vertical scrolling range.
1026 wfc->yMaxScroll = MAX(wfc->instance->settings->DesktopHeight - client_height, 0);
1027 wfc->yCurrentScroll = MIN(wfc->yCurrentScroll, wfc->yMaxScroll);
1028 si.cbSize = sizeof(si);
1029 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
1030 si.nMin = wfc->yMinScroll;
1031 si.nMax = wfc->instance->settings->DesktopHeight;
1032 si.nPage = client_height;
1033 si.nPos = wfc->yCurrentScroll;
1034 SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE);
1038 wfc->disablewindowtracking = FALSE;
1039 wf_update_canvas_diff(wfc);
1042 BOOL wfreerdp_client_global_init(void)
1046 if (!getenv("HOME"))
1048 char home[MAX_PATH * 2] = "HOME=";
1049 strcat(home, getenv("HOMEDRIVE"));
1050 strcat(home, getenv("HOMEPATH"));
1054 WSAStartup(0x101, &wsaData);
1056 #if defined(WITH_DEBUG) || defined(_DEBUG)
1057 wf_create_console();
1060 freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
1064 void wfreerdp_client_global_uninit(void)
1069 BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context)
1071 wfContext* wfc = (wfContext*) context;
1073 if (!(wfreerdp_client_global_init()))
1076 if (!(context->channels = freerdp_channels_new()))
1079 instance->PreConnect = wf_pre_connect;
1080 instance->PostConnect = wf_post_connect;
1081 instance->Authenticate = wf_authenticate;
1082 instance->GatewayAuthenticate = wf_gw_authenticate;
1083 instance->VerifyCertificate = wf_verify_certificate;
1085 wfc->instance = instance;
1086 wfc->settings = instance->settings;
1091 void wfreerdp_client_free(freerdp* instance, rdpContext* context)
1096 if (context->channels)
1098 freerdp_channels_close(context->channels, instance);
1099 freerdp_channels_free(context->channels);
1100 context->channels = NULL;
1105 cache_free(context->cache);
1106 context->cache = NULL;
1110 int wfreerdp_client_start(rdpContext* context)
1113 HINSTANCE hInstance;
1114 wfContext* wfc = (wfContext*) context;
1115 freerdp* instance = context->instance;
1117 hInstance = GetModuleHandle(NULL);
1118 hWndParent = (HWND) instance->settings->ParentWindowId;
1119 instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE;
1121 wfc->hWndParent = hWndParent;
1122 wfc->hInstance = hInstance;
1123 wfc->cursor = LoadCursor(NULL, IDC_ARROW);
1124 wfc->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
1125 wfc->wndClassName = _tcsdup(_T("FreeRDP"));
1127 wfc->wndClass.cbSize = sizeof(WNDCLASSEX);
1128 wfc->wndClass.style = CS_HREDRAW | CS_VREDRAW;
1129 wfc->wndClass.lpfnWndProc = wf_event_proc;
1130 wfc->wndClass.cbClsExtra = 0;
1131 wfc->wndClass.cbWndExtra = 0;
1132 wfc->wndClass.hCursor = wfc->cursor;
1133 wfc->wndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
1134 wfc->wndClass.lpszMenuName = NULL;
1135 wfc->wndClass.lpszClassName = wfc->wndClassName;
1136 wfc->wndClass.hInstance = hInstance;
1137 wfc->wndClass.hIcon = wfc->icon;
1138 wfc->wndClass.hIconSm = wfc->icon;
1139 RegisterClassEx(&(wfc->wndClass));
1141 wfc->keyboardThread = CreateThread(NULL, 0, wf_keyboard_thread, (void*) wfc, 0, &wfc->keyboardThreadId);
1143 if (!wfc->keyboardThread)
1146 freerdp_client_load_addins(context->channels, instance->settings);
1148 wfc->thread = CreateThread(NULL, 0, wf_client_thread, (void*) instance, 0, &wfc->mainThreadId);
1156 int wfreerdp_client_stop(rdpContext* context)
1158 wfContext* wfc = (wfContext*) context;
1162 PostThreadMessage(wfc->mainThreadId, WM_QUIT, 0, 0);
1164 WaitForSingleObject(wfc->thread, INFINITE);
1165 CloseHandle(wfc->thread);
1167 wfc->mainThreadId = 0;
1170 if (wfc->keyboardThread)
1172 PostThreadMessage(wfc->keyboardThreadId, WM_QUIT, 0, 0);
1174 WaitForSingleObject(wfc->keyboardThread, INFINITE);
1175 CloseHandle(wfc->keyboardThread);
1177 wfc->keyboardThread = NULL;
1178 wfc->keyboardThreadId = 0;
1184 int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1186 pEntryPoints->Version = 1;
1187 pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1189 pEntryPoints->GlobalInit = wfreerdp_client_global_init;
1190 pEntryPoints->GlobalUninit = wfreerdp_client_global_uninit;
1192 pEntryPoints->ContextSize = sizeof(wfContext);
1193 pEntryPoints->ClientNew = wfreerdp_client_new;
1194 pEntryPoints->ClientFree = wfreerdp_client_free;
1196 pEntryPoints->ClientStart = wfreerdp_client_start;
1197 pEntryPoints->ClientStop = wfreerdp_client_stop;