Blame client/Windows/wf_client.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Windows Client
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2009-2011 Jay Sorg
Packit Service fa4841
 * Copyright 2010-2011 Vic Lee
Packit Service fa4841
 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *	 http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/windows.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/credui.h>
Packit Service fa4841
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
#include <stdio.h>
Packit Service fa4841
#include <stdlib.h>
Packit Service fa4841
#include <string.h>
Packit Service fa4841
#include <tchar.h>
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
#include <sys/types.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <freerdp/event.h>
Packit Service fa4841
#include <freerdp/freerdp.h>
Packit Service fa4841
#include <freerdp/constants.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/codec/region.h>
Packit Service fa4841
#include <freerdp/client/cmdline.h>
Packit Service fa4841
#include <freerdp/client/channels.h>
Packit Service fa4841
#include <freerdp/channels/channels.h>
Packit Service fa4841
Packit Service fa4841
#include "wf_gdi.h"
Packit Service fa4841
#include "wf_rail.h"
Packit Service fa4841
#include "wf_channels.h"
Packit Service fa4841
#include "wf_graphics.h"
Packit Service fa4841
#include "wf_cliprdr.h"
Packit Service fa4841
Packit Service fa4841
#include "wf_client.h"
Packit Service fa4841
Packit Service fa4841
#include "resource.h"
Packit Service fa4841
Packit Service fa4841
#define TAG CLIENT_TAG("windows")
Packit Service fa4841
Packit Service fa4841
static BOOL wf_create_console(void)
Packit Service fa4841
{
Packit Service fa4841
#if defined(WITH_WIN_CONSOLE)
Packit Service fa4841
	if (!AttachConsole(ATTACH_PARENT_PROCESS))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	freopen("CONOUT$", "w", stdout);
Packit Service fa4841
	freopen("CONOUT$", "w", stderr);
Packit Service fa4841
	clearerr(stdout);
Packit Service fa4841
	clearerr(stderr);
Packit Service fa4841
	fflush(stdout);
Packit Service fa4841
	fflush(stderr);
Packit Service fa4841
Packit Service fa4841
	freopen("CONIN$", "r", stdin);
Packit Service fa4841
	clearerr(stdin);
Packit Service fa4841
Packit Service fa4841
	WLog_INFO(TAG, "Debug console created.");
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
#else
Packit Service fa4841
	return FALSE;
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_end_paint(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	rdpGdi* gdi;
Packit Service fa4841
	int ninvalid;
Packit Service fa4841
	RECT updateRect;
Packit Service fa4841
	HGDI_RGN cinvalid;
Packit Service fa4841
	REGION16 invalidRegion;
Packit Service fa4841
	RECTANGLE_16 invalidRect;
Packit Service fa4841
	const RECTANGLE_16* extents;
Packit Service fa4841
	wfContext* wfc = (wfContext*)context;
Packit Service fa4841
	gdi = context->gdi;
Packit Service fa4841
	ninvalid = gdi->primary->hdc->hwnd->ninvalid;
Packit Service fa4841
	cinvalid = gdi->primary->hdc->hwnd->cinvalid;
Packit Service fa4841
Packit Service fa4841
	if (ninvalid < 1)
Packit Service fa4841
		return TRUE;
Packit Service fa4841
Packit Service fa4841
	region16_init(&invalidRegion);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < ninvalid; i++)
Packit Service fa4841
	{
Packit Service fa4841
		invalidRect.left = cinvalid[i].x;
Packit Service fa4841
		invalidRect.top = cinvalid[i].y;
Packit Service fa4841
		invalidRect.right = cinvalid[i].x + cinvalid[i].w;
Packit Service fa4841
		invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
Packit Service fa4841
		region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!region16_is_empty(&invalidRegion))
Packit Service fa4841
	{
Packit Service fa4841
		extents = region16_extents(&invalidRegion);
Packit Service fa4841
		updateRect.left = extents->left;
Packit Service fa4841
		updateRect.top = extents->top;
Packit Service fa4841
		updateRect.right = extents->right;
Packit Service fa4841
		updateRect.bottom = extents->bottom;
Packit Service fa4841
		InvalidateRect(wfc->hwnd, &updateRect, FALSE);
Packit Service fa4841
Packit Service fa4841
		if (wfc->rail)
Packit Service fa4841
			wf_rail_invalidate_region(wfc, &invalidRegion);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	region16_uninit(&invalidRegion);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_begin_paint(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	HGDI_DC hdc;
Packit Service fa4841
Packit Service fa4841
	if (!context || !context->gdi || !context->gdi->primary || !context->gdi->primary->hdc)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	hdc = context->gdi->primary->hdc;
Packit Service fa4841
Packit Service fa4841
	if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	hdc->hwnd->invalid->null = TRUE;
Packit Service fa4841
	hdc->hwnd->ninvalid = 0;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_desktop_resize(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	BOOL same;
Packit Service fa4841
	RECT rect;
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
	wfContext* wfc = (wfContext*)context;
Packit Service fa4841
Packit Service fa4841
	if (!context || !context->settings)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	settings = context->settings;
Packit Service fa4841
Packit Service fa4841
	if (wfc->primary)
Packit Service fa4841
	{
Packit Service fa4841
		same = (wfc->primary == wfc->drawing) ? TRUE : FALSE;
Packit Service fa4841
		wf_image_free(wfc->primary);
Packit Service fa4841
		wfc->primary = wf_image_new(wfc, settings->DesktopWidth, settings->DesktopHeight,
Packit Service fa4841
		                            context->gdi->dstFormat, NULL);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!gdi_resize_ex(context->gdi, settings->DesktopWidth, settings->DesktopHeight, 0,
Packit Service fa4841
	                   context->gdi->dstFormat, wfc->primary->pdata, NULL))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (same)
Packit Service fa4841
		wfc->drawing = wfc->primary;
Packit Service fa4841
Packit Service fa4841
	if (wfc->fullscreen != TRUE)
Packit Service fa4841
	{
Packit Service fa4841
		if (wfc->hwnd)
Packit Service fa4841
			SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1, settings->DesktopWidth + wfc->diff.x,
Packit Service fa4841
			             settings->DesktopHeight + wfc->diff.y, SWP_NOMOVE);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		wf_update_offset(wfc);
Packit Service fa4841
		GetWindowRect(wfc->hwnd, &rect);
Packit Service fa4841
		InvalidateRect(wfc->hwnd, &rect, TRUE);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_pre_connect(freerdp* instance)
Packit Service fa4841
{
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
	int desktopWidth;
Packit Service fa4841
	int desktopHeight;
Packit Service fa4841
	rdpContext* context;
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
Packit Service fa4841
	if (!instance || !instance->context || !instance->settings)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	context = instance->context;
Packit Service fa4841
	wfc = (wfContext*)instance->context;
Packit Service fa4841
	settings = instance->settings;
Packit Service fa4841
	settings->OsMajorType = OSMAJORTYPE_WINDOWS;
Packit Service fa4841
	settings->OsMinorType = OSMINORTYPE_WINDOWS_NT;
Packit Service fa4841
	wfc->fullscreen = settings->Fullscreen;
Packit Service fa4841
	wfc->fullscreen_toggle = settings->ToggleFullscreen;
Packit Service fa4841
	desktopWidth = settings->DesktopWidth;
Packit Service fa4841
	desktopHeight = settings->DesktopHeight;
Packit Service fa4841
Packit Service fa4841
	if (wfc->percentscreen > 0)
Packit Service fa4841
	{
Packit Service fa4841
		desktopWidth = (GetSystemMetrics(SM_CXSCREEN) * wfc->percentscreen) / 100;
Packit Service fa4841
		settings->DesktopWidth = desktopWidth;
Packit Service fa4841
		desktopHeight = (GetSystemMetrics(SM_CYSCREEN) * wfc->percentscreen) / 100;
Packit Service fa4841
		settings->DesktopHeight = desktopHeight;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (wfc->fullscreen)
Packit Service fa4841
	{
Packit Service fa4841
		if (settings->UseMultimon)
Packit Service fa4841
		{
Packit Service fa4841
			desktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
Packit Service fa4841
			desktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			desktopWidth = GetSystemMetrics(SM_CXSCREEN);
Packit Service fa4841
			desktopHeight = GetSystemMetrics(SM_CYSCREEN);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* FIXME: desktopWidth has a limitation that it should be divisible by 4,
Packit Service fa4841
	 *        otherwise the screen will crash when connecting to an XP desktop.*/
Packit Service fa4841
	desktopWidth = (desktopWidth + 3) & (~3);
Packit Service fa4841
Packit Service fa4841
	if (desktopWidth != settings->DesktopWidth)
Packit Service fa4841
	{
Packit Service fa4841
		freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, desktopWidth);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (desktopHeight != settings->DesktopHeight)
Packit Service fa4841
	{
Packit Service fa4841
		freerdp_set_param_uint32(settings, FreeRDP_DesktopHeight, desktopHeight);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) ||
Packit Service fa4841
	    (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "invalid dimensions %lu %lu", settings->DesktopWidth,
Packit Service fa4841
		         settings->DesktopHeight);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_client_load_addins(context->channels, instance->settings))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	freerdp_set_param_uint32(settings, FreeRDP_KeyboardLayout,
Packit Service fa4841
	                         (int)GetKeyboardLayout(0) & 0x0000FFFF);
Packit Service fa4841
	PubSub_SubscribeChannelConnected(instance->context->pubSub, wf_OnChannelConnectedEventHandler);
Packit Service fa4841
	PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
Packit Service fa4841
	                                    wf_OnChannelDisconnectedEventHandler);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void wf_add_system_menu(wfContext* wfc)
Packit Service fa4841
{
Packit Service fa4841
	HMENU hMenu;
Packit Service fa4841
	MENUITEMINFO item_info;
Packit Service fa4841
Packit Service fa4841
	if (wfc->fullscreen && !wfc->fullscreen_toggle)
Packit Service fa4841
	{
Packit Service fa4841
		return;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	hMenu = GetSystemMenu(wfc->hwnd, FALSE);
Packit Service fa4841
	ZeroMemory(&item_info, sizeof(MENUITEMINFO));
Packit Service fa4841
	item_info.fMask = MIIM_CHECKMARKS | MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_DATA;
Packit Service fa4841
	item_info.cbSize = sizeof(MENUITEMINFO);
Packit Service fa4841
	item_info.wID = SYSCOMMAND_ID_SMARTSIZING;
Packit Service fa4841
	item_info.fType = MFT_STRING;
Packit Service fa4841
	item_info.dwTypeData = _wcsdup(_T("Smart sizing"));
Packit Service fa4841
	item_info.cch = (UINT)_wcslen(_T("Smart sizing"));
Packit Service fa4841
	item_info.dwItemData = (ULONG_PTR)wfc;
Packit Service fa4841
	InsertMenuItem(hMenu, 6, TRUE, &item_info);
Packit Service fa4841
Packit Service fa4841
	if (wfc->context.settings->SmartSizing)
Packit Service fa4841
	{
Packit Service fa4841
		CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, MF_CHECKED);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static WCHAR* wf_window_get_title(rdpSettings* settings)
Packit Service fa4841
{
Packit Service fa4841
	BOOL port;
Packit Service fa4841
	WCHAR* windowTitle = NULL;
Packit Service fa4841
	size_t size;
Packit Service fa4841
	char* name;
Packit Service fa4841
	WCHAR prefix[] = L"FreeRDP:";
Packit Service fa4841
Packit Service fa4841
	if (!settings)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	name = settings->ServerHostname;
Packit Service fa4841
Packit Service fa4841
	if (settings->WindowTitle)
Packit Service fa4841
	{
Packit Service fa4841
		ConvertToUnicode(CP_UTF8, 0, settings->WindowTitle, -1, &windowTitle, 0);
Packit Service fa4841
		return windowTitle;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	port = (settings->ServerPort != 3389);
Packit Service fa4841
	size = strlen(name) + 16 + wcslen(prefix);
Packit Service fa4841
	windowTitle = calloc(size, sizeof(WCHAR));
Packit Service fa4841
Packit Service fa4841
	if (!windowTitle)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (!port)
Packit Service fa4841
		_snwprintf_s(windowTitle, size, _TRUNCATE, L"%s %S", prefix, name);
Packit Service fa4841
	else
Packit Service fa4841
		_snwprintf_s(windowTitle, size, _TRUNCATE, L"%s %S:%u", prefix, name, settings->ServerPort);
Packit Service fa4841
Packit Service fa4841
	return windowTitle;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_post_connect(freerdp* instance)
Packit Service fa4841
{
Packit Service fa4841
	rdpGdi* gdi;
Packit Service fa4841
	DWORD dwStyle;
Packit Service fa4841
	rdpCache* cache;
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
	rdpContext* context;
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
	EmbedWindowEventArgs e;
Packit Service fa4841
	const UINT32 format = PIXEL_FORMAT_BGRX32;
Packit Service fa4841
	settings = instance->settings;
Packit Service fa4841
	context = instance->context;
Packit Service fa4841
	wfc = (wfContext*)instance->context;
Packit Service fa4841
	cache = instance->context->cache;
Packit Service fa4841
	wfc->primary = wf_image_new(wfc, settings->DesktopWidth, settings->DesktopHeight, format, NULL);
Packit Service fa4841
Packit Service fa4841
	if (!gdi_init_ex(instance, format, 0, wfc->primary->pdata, NULL))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	gdi = instance->context->gdi;
Packit Service fa4841
Packit Service fa4841
	if (!settings->SoftwareGdi)
Packit Service fa4841
	{
Packit Service fa4841
		wf_gdi_register_update_callbacks(instance->update);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	wfc->window_title = wf_window_get_title(settings);
Packit Service fa4841
Packit Service fa4841
	if (!wfc->window_title)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->EmbeddedWindow)
Packit Service fa4841
		settings->Decorations = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (wfc->fullscreen)
Packit Service fa4841
		dwStyle = WS_POPUP;
Packit Service fa4841
	else if (!settings->Decorations)
Packit Service fa4841
		dwStyle = WS_CHILD | WS_BORDER;
Packit Service fa4841
	else
Packit Service fa4841
		dwStyle =
Packit Service fa4841
		    WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX;
Packit Service fa4841
Packit Service fa4841
	if (!wfc->hwnd)
Packit Service fa4841
	{
Packit Service fa4841
		wfc->hwnd = CreateWindowEx((DWORD)NULL, wfc->wndClassName, wfc->window_title, dwStyle, 0, 0,
Packit Service fa4841
		                           0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL);
Packit Service fa4841
		SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR)wfc);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	wf_resize_window(wfc);
Packit Service fa4841
	wf_add_system_menu(wfc);
Packit Service fa4841
	BitBlt(wfc->primary->hdc, 0, 0, settings->DesktopWidth, settings->DesktopHeight, NULL, 0, 0,
Packit Service fa4841
	       BLACKNESS);
Packit Service fa4841
	wfc->drawing = wfc->primary;
Packit Service fa4841
	EventArgsInit(&e, "wfreerdp");
Packit Service fa4841
	e.embed = FALSE;
Packit Service fa4841
	e.handle = (void*)wfc->hwnd;
Packit Service fa4841
	PubSub_OnEmbedWindow(context->pubSub, context, &e);
Packit Service fa4841
	ShowWindow(wfc->hwnd, SW_SHOWNORMAL);
Packit Service fa4841
	UpdateWindow(wfc->hwnd);
Packit Service fa4841
	instance->update->BeginPaint = wf_begin_paint;
Packit Service fa4841
	instance->update->DesktopResize = wf_desktop_resize;
Packit Service fa4841
	instance->update->EndPaint = wf_end_paint;
Packit Service fa4841
	wf_register_pointer(context->graphics);
Packit Service fa4841
Packit Service fa4841
	if (!settings->SoftwareGdi)
Packit Service fa4841
	{
Packit Service fa4841
		wf_register_graphics(context->graphics);
Packit Service fa4841
		wf_gdi_register_update_callbacks(instance->update);
Packit Service fa4841
		brush_cache_register_callbacks(instance->update);
Packit Service fa4841
		glyph_cache_register_callbacks(instance->update);
Packit Service fa4841
		bitmap_cache_register_callbacks(instance->update);
Packit Service fa4841
		offscreen_cache_register_callbacks(instance->update);
Packit Service fa4841
		palette_cache_register_callbacks(instance->update);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	wfc->floatbar = wf_floatbar_new(wfc, wfc->hInstance, settings->Floatbar);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void wf_post_disconnect(freerdp* instance)
Packit Service fa4841
{
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
Packit Service fa4841
	if (!instance || !instance->context || !instance->settings)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	wfc = (wfContext*)instance->context;
Packit Service fa4841
	free(wfc->window_title);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static CREDUI_INFOA wfUiInfo = { sizeof(CREDUI_INFOA), NULL, "Enter your credentials",
Packit Service fa4841
	                             "Remote Desktop Security", NULL };
Packit Service fa4841
Packit Service fa4841
static BOOL wf_authenticate_raw(freerdp* instance, const char* title, char** username,
Packit Service fa4841
                                char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
	BOOL fSave;
Packit Service fa4841
	DWORD status;
Packit Service fa4841
	DWORD dwFlags;
Packit Service fa4841
	char UserName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
Packit Service fa4841
	char Password[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
Packit Service fa4841
	char User[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
Packit Service fa4841
	char Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
Packit Service fa4841
Packit Service fa4841
	if (!instance || !instance->context)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	wfc = (wfContext*)instance->context;
Packit Service fa4841
Packit Service fa4841
	fSave = FALSE;
Packit Service fa4841
	dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES;
Packit Service fa4841
Packit Service fa4841
	if (username && *username)
Packit Service fa4841
		strncpy(UserName, *username, CREDUI_MAX_USERNAME_LENGTH);
Packit Service fa4841
	if (wfc->isConsole)
Packit Service fa4841
		status = CredUICmdLinePromptForCredentialsA(
Packit Service fa4841
		    title, NULL, 0, UserName, CREDUI_MAX_USERNAME_LENGTH + 1, Password,
Packit Service fa4841
		    CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
Packit Service fa4841
	else
Packit Service fa4841
		status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0, UserName,
Packit Service fa4841
		                                     CREDUI_MAX_USERNAME_LENGTH + 1, Password,
Packit Service fa4841
		                                     CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
Packit Service fa4841
Packit Service fa4841
	if (status != NO_ERROR)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "CredUIPromptForCredentials unexpected status: 0x%08lX", status);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, sizeof(Domain));
Packit Service fa4841
	// WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password);
Packit Service fa4841
	*username = _strdup(User);
Packit Service fa4841
Packit Service fa4841
	if (!(*username))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "strdup failed", status);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (strlen(Domain) > 0)
Packit Service fa4841
		*domain = _strdup(Domain);
Packit Service fa4841
	else
Packit Service fa4841
		*domain = _strdup("\0");
Packit Service fa4841
Packit Service fa4841
	if (!(*domain))
Packit Service fa4841
	{
Packit Service fa4841
		free(*username);
Packit Service fa4841
		WLog_ERR(TAG, "strdup failed", status);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	*password = _strdup(Password);
Packit Service fa4841
Packit Service fa4841
	if (!(*password))
Packit Service fa4841
	{
Packit Service fa4841
		free(*username);
Packit Service fa4841
		free(*domain);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_authenticate(freerdp* instance, char** username, char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	return wf_authenticate_raw(instance, instance->settings->ServerHostname, username, password,
Packit Service fa4841
	                           domain);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wf_gw_authenticate(freerdp* instance, char** username, char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	char tmp[MAX_PATH];
Packit Service fa4841
	sprintf_s(tmp, sizeof(tmp), "Gateway %s", instance->settings->GatewayHostname);
Packit Service fa4841
	return wf_authenticate_raw(instance, tmp, username, password, domain);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static WCHAR* wf_format_text(const WCHAR* fmt, ...)
Packit Service fa4841
{
Packit Service fa4841
	int rc;
Packit Service fa4841
	size_t size = 1024;
Packit Service fa4841
	WCHAR* buffer = calloc(size, sizeof(WCHAR));
Packit Service fa4841
	if (!buffer)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		WCHAR* tmp;
Packit Service fa4841
		va_list ap;
Packit Service fa4841
		va_start(ap, fmt);
Packit Service fa4841
		rc = vswprintf_s(buffer, size, fmt, ap);
Packit Service fa4841
		va_end(ap);
Packit Service fa4841
		if (rc <= 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		if ((size_t)rc < size)
Packit Service fa4841
			return buffer;
Packit Service fa4841
Packit Service fa4841
		size = (size_t)rc + 1;
Packit Service fa4841
		tmp = realloc(buffer, size * sizeof(WCHAR));
Packit Service fa4841
		if (!tmp)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		buffer = tmp;
Packit Service fa4841
	} while (TRUE);
Packit Service fa4841
Packit Service fa4841
fail:
Packit Service fa4841
	free(buffer);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD wf_verify_certificate_ex(freerdp* instance, const char* host, UINT16 port,
Packit Service fa4841
                                      const char* common_name, const char* subject,
Packit Service fa4841
                                      const char* issuer, const char* fingerprint, DWORD flags)
Packit Service fa4841
{
Packit Service fa4841
	WCHAR* buffer;
Packit Service fa4841
	WCHAR* caption;
Packit Service fa4841
	int what = IDCANCEL;
Packit Service fa4841
Packit Service fa4841
	buffer = wf_format_text(
Packit Service fa4841
	    L"Certificate details:\n"
Packit Service fa4841
	    L"\tCommonName: %S\n"
Packit Service fa4841
	    L"\tSubject: %S\n"
Packit Service fa4841
	    L"\tIssuer: %S\n"
Packit Service fa4841
	    L"\tThumbprint: %S\n"
Packit Service fa4841
	    L"\tHostMismatch: %S\n"
Packit Service fa4841
	    L"\n"
Packit Service fa4841
	    L"The above X.509 certificate could not be verified, possibly because you do not have "
Packit Service fa4841
	    L"the CA certificate in your certificate store, or the certificate has expired. "
Packit Service fa4841
	    L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n"
Packit Service fa4841
	    L"\n"
Packit Service fa4841
	    L"YES\tAccept permanently\n"
Packit Service fa4841
	    L"NO\tAccept for this session only\n"
Packit Service fa4841
	    L"CANCEL\tAbort connection\n",
Packit Service fa4841
	    common_name, subject, issuer, fingerprint,
Packit Service fa4841
	    flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No");
Packit Service fa4841
	caption = wf_format_text(L"Verify certificate for %S:%hu", host, port);
Packit Service fa4841
Packit Service fa4841
	if (!buffer || !caption)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL);
Packit Service fa4841
fail:
Packit Service fa4841
	free(buffer);
Packit Service fa4841
	free(caption);
Packit Service fa4841
Packit Service fa4841
	/* return 1 to accept and store a certificate, 2 to accept
Packit Service fa4841
	 * a certificate only for this session, 0 otherwise */
Packit Service fa4841
	switch (what)
Packit Service fa4841
	{
Packit Service fa4841
		case IDYES:
Packit Service fa4841
			return 1;
Packit Service fa4841
		case IDNO:
Packit Service fa4841
			return 2;
Packit Service fa4841
		default:
Packit Service fa4841
			return 0;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD wf_verify_changed_certificate_ex(freerdp* instance, const char* host, UINT16 port,
Packit Service fa4841
                                              const char* common_name, const char* subject,
Packit Service fa4841
                                              const char* issuer, const char* new_fingerprint,
Packit Service fa4841
                                              const char* old_subject, const char* old_issuer,
Packit Service fa4841
                                              const char* old_fingerprint, DWORD flags)
Packit Service fa4841
{
Packit Service fa4841
	WCHAR* buffer;
Packit Service fa4841
	WCHAR* caption;
Packit Service fa4841
	int what = IDCANCEL;
Packit Service fa4841
Packit Service fa4841
	buffer = wf_format_text(
Packit Service fa4841
	    L"New Certificate details:\n"
Packit Service fa4841
	    L"\tCommonName: %S\n"
Packit Service fa4841
	    L"\tSubject: %S\n"
Packit Service fa4841
	    L"\tIssuer: %S\n"
Packit Service fa4841
	    L"\tThumbprint: %S\n"
Packit Service fa4841
	    L"\tHostMismatch: %S\n"
Packit Service fa4841
	    L"\n"
Packit Service fa4841
	    L"Old Certificate details:\n"
Packit Service fa4841
	    L"\tSubject: %S\n"
Packit Service fa4841
	    L"\tIssuer: %S\n"
Packit Service fa4841
	    L"\tThumbprint: %S"
Packit Service fa4841
	    L"The above X.509 certificate could not be verified, possibly because you do not have "
Packit Service fa4841
	    L"the CA certificate in your certificate store, or the certificate has expired. "
Packit Service fa4841
	    L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n"
Packit Service fa4841
	    L"\n"
Packit Service fa4841
	    L"YES\tAccept permanently\n"
Packit Service fa4841
	    L"NO\tAccept for this session only\n"
Packit Service fa4841
	    L"CANCEL\tAbort connection\n",
Packit Service fa4841
	    common_name, subject, issuer, new_fingerprint,
Packit Service fa4841
	    flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No", old_subject, old_issuer, old_fingerprint);
Packit Service fa4841
	caption = wf_format_text(L"Verify certificate change for %S:%hu", host, port);
Packit Service fa4841
Packit Service fa4841
	if (!buffer || !caption)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL);
Packit Service fa4841
fail:
Packit Service fa4841
	free(buffer);
Packit Service fa4841
	free(caption);
Packit Service fa4841
Packit Service fa4841
	/* return 1 to accept and store a certificate, 2 to accept
Packit Service fa4841
	 * a certificate only for this session, 0 otherwise */
Packit Service fa4841
	switch (what)
Packit Service fa4841
	{
Packit Service fa4841
		case IDYES:
Packit Service fa4841
			return 1;
Packit Service fa4841
		case IDNO:
Packit Service fa4841
			return 2;
Packit Service fa4841
		default:
Packit Service fa4841
			return 0;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI wf_input_thread(LPVOID arg)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	wMessage message;
Packit Service fa4841
	wMessageQueue* queue;
Packit Service fa4841
	freerdp* instance = (freerdp*)arg;
Packit Service fa4841
	assert(NULL != instance);
Packit Service fa4841
	status = 1;
Packit Service fa4841
	queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
Packit Service fa4841
Packit Service fa4841
	while (MessageQueue_Wait(queue))
Packit Service fa4841
	{
Packit Service fa4841
		while (MessageQueue_Peek(queue, &message, TRUE))
Packit Service fa4841
		{
Packit Service fa4841
			status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE,
Packit Service fa4841
			                                               &message);
Packit Service fa4841
Packit Service fa4841
			if (!status)
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (!status)
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	ExitThread(0);
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI wf_client_thread(LPVOID lpParam)
Packit Service fa4841
{
Packit Service fa4841
	MSG msg;
Packit Service fa4841
	int width;
Packit Service fa4841
	int height;
Packit Service fa4841
	BOOL msg_ret;
Packit Service fa4841
	int quit_msg;
Packit Service fa4841
	DWORD nCount;
Packit Service fa4841
	DWORD error;
Packit Service fa4841
	HANDLE handles[64];
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
	freerdp* instance;
Packit Service fa4841
	rdpContext* context;
Packit Service fa4841
	rdpChannels* channels;
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
	BOOL async_input;
Packit Service fa4841
	HANDLE input_thread;
Packit Service fa4841
	instance = (freerdp*)lpParam;
Packit Service fa4841
	context = instance->context;
Packit Service fa4841
	wfc = (wfContext*)instance->context;
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_connect(instance))
Packit Service fa4841
		goto end;
Packit Service fa4841
Packit Service fa4841
	channels = instance->context->channels;
Packit Service fa4841
	settings = instance->context->settings;
Packit Service fa4841
	async_input = settings->AsyncInput;
Packit Service fa4841
Packit Service fa4841
	if (async_input)
Packit Service fa4841
	{
Packit Service fa4841
		if (!(input_thread = CreateThread(NULL, 0, wf_input_thread, instance, 0, NULL)))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Failed to create async input thread.");
Packit Service fa4841
			goto disconnect;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	while (1)
Packit Service fa4841
	{
Packit Service fa4841
		nCount = 0;
Packit Service fa4841
Packit Service fa4841
		if (freerdp_focus_required(instance))
Packit Service fa4841
		{
Packit Service fa4841
			wf_event_focus_in(wfc);
Packit Service fa4841
			wf_event_focus_in(wfc);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		{
Packit Service fa4841
			DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], 64 - nCount);
Packit Service fa4841
Packit Service fa4841
			if (tmp == 0)
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "freerdp_get_event_handles failed");
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			nCount += tmp;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%08lX", GetLastError());
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		{
Packit Service fa4841
			if (!freerdp_check_event_handles(context))
Packit Service fa4841
			{
Packit Service fa4841
				if (client_auto_reconnect(instance))
Packit Service fa4841
					continue;
Packit Service fa4841
Packit Service fa4841
				WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (freerdp_shall_disconnect(instance))
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		quit_msg = FALSE;
Packit Service fa4841
Packit Service fa4841
		while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
Packit Service fa4841
		{
Packit Service fa4841
			msg_ret = GetMessage(&msg, NULL, 0, 0);
Packit Service fa4841
Packit Service fa4841
			if (instance->settings->EmbeddedWindow)
Packit Service fa4841
			{
Packit Service fa4841
				if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1))
Packit Service fa4841
				{
Packit Service fa4841
					PostMessage(wfc->hwnd, WM_SETFOCUS, 0, 0);
Packit Service fa4841
				}
Packit Service fa4841
				else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1))
Packit Service fa4841
				{
Packit Service fa4841
					PostMessage(wfc->hwnd, WM_KILLFOCUS, 0, 0);
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if (msg.message == WM_SIZE)
Packit Service fa4841
			{
Packit Service fa4841
				width = LOWORD(msg.lParam);
Packit Service fa4841
				height = HIWORD(msg.lParam);
Packit Service fa4841
				SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if ((msg_ret == 0) || (msg_ret == -1))
Packit Service fa4841
			{
Packit Service fa4841
				quit_msg = TRUE;
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			TranslateMessage(&msg;;
Packit Service fa4841
			DispatchMessage(&msg;;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (quit_msg)
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* cleanup */
Packit Service fa4841
	if (async_input)
Packit Service fa4841
	{
Packit Service fa4841
		wMessageQueue* input_queue;
Packit Service fa4841
		input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
Packit Service fa4841
Packit Service fa4841
		if (MessageQueue_PostQuit(input_queue, 0))
Packit Service fa4841
			WaitForSingleObject(input_thread, INFINITE);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
disconnect:
Packit Service fa4841
	freerdp_disconnect(instance);
Packit Service fa4841
Packit Service fa4841
	if (async_input)
Packit Service fa4841
		CloseHandle(input_thread);
Packit Service fa4841
Packit Service fa4841
end:
Packit Service fa4841
	error = freerdp_get_last_error(instance->context);
Packit Service fa4841
	WLog_DBG(TAG, "Main thread exited with %" PRIu32, error);
Packit Service fa4841
	ExitThread(error);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI wf_keyboard_thread(LPVOID lpParam)
Packit Service fa4841
{
Packit Service fa4841
	MSG msg;
Packit Service fa4841
	BOOL status;
Packit Service fa4841
	wfContext* wfc;
Packit Service fa4841
	HHOOK hook_handle;
Packit Service fa4841
	wfc = (wfContext*)lpParam;
Packit Service fa4841
	assert(NULL != wfc);
Packit Service fa4841
	hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, wfc->hInstance, 0);
Packit Service fa4841
Packit Service fa4841
	if (hook_handle)
Packit Service fa4841
	{
Packit Service fa4841
		while ((status = GetMessage(&msg, NULL, 0, 0)) != 0)
Packit Service fa4841
		{
Packit Service fa4841
			if (status == -1)
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "keyboard thread error getting message");
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				TranslateMessage(&msg;;
Packit Service fa4841
				DispatchMessage(&msg;;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		UnhookWindowsHookEx(hook_handle);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to install keyboard hook");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	WLog_DBG(TAG, "Keyboard thread exited.");
Packit Service fa4841
	ExitThread(0);
Packit Service fa4841
	return (DWORD)NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static rdpSettings* freerdp_client_get_settings(wfContext* wfc)
Packit Service fa4841
{
Packit Service fa4841
	return wfc->context.settings;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int freerdp_client_focus_in(wfContext* wfc)
Packit Service fa4841
{
Packit Service fa4841
	PostThreadMessage(wfc->mainThreadId, WM_SETFOCUS, 0, 1);
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int freerdp_client_focus_out(wfContext* wfc)
Packit Service fa4841
{
Packit Service fa4841
	PostThreadMessage(wfc->mainThreadId, WM_KILLFOCUS, 0, 1);
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int freerdp_client_set_window_size(wfContext* wfc, int width, int height)
Packit Service fa4841
{
Packit Service fa4841
	WLog_DBG(TAG, "freerdp_client_set_window_size %d, %d", width, height);
Packit Service fa4841
Packit Service fa4841
	if ((width != wfc->client_width) || (height != wfc->client_height))
Packit Service fa4841
	{
Packit Service fa4841
		PostThreadMessage(wfc->mainThreadId, WM_SIZE, SIZE_RESTORED,
Packit Service fa4841
		                  ((UINT)height << 16) | (UINT)width);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height)
Packit Service fa4841
{
Packit Service fa4841
	if (wfc->disablewindowtracking)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	// prevent infinite message loop
Packit Service fa4841
	wfc->disablewindowtracking = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (wfc->context.settings->SmartSizing)
Packit Service fa4841
	{
Packit Service fa4841
		wfc->xCurrentScroll = 0;
Packit Service fa4841
		wfc->yCurrentScroll = 0;
Packit Service fa4841
Packit Service fa4841
		if (wfc->xScrollVisible || wfc->yScrollVisible)
Packit Service fa4841
		{
Packit Service fa4841
			if (ShowScrollBar(wfc->hwnd, SB_BOTH, FALSE))
Packit Service fa4841
			{
Packit Service fa4841
				wfc->xScrollVisible = FALSE;
Packit Service fa4841
				wfc->yScrollVisible = FALSE;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		SCROLLINFO si;
Packit Service fa4841
		BOOL horiz = wfc->xScrollVisible;
Packit Service fa4841
		BOOL vert = wfc->yScrollVisible;
Packit Service fa4841
Packit Service fa4841
		if (!horiz && client_width < wfc->context.settings->DesktopWidth)
Packit Service fa4841
		{
Packit Service fa4841
			horiz = TRUE;
Packit Service fa4841
		}
Packit Service fa4841
		else if (horiz &&
Packit Service fa4841
		         client_width >=
Packit Service fa4841
		             wfc->context.settings->DesktopWidth /* - GetSystemMetrics(SM_CXVSCROLL)*/)
Packit Service fa4841
		{
Packit Service fa4841
			horiz = FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (!vert && client_height < wfc->context.settings->DesktopHeight)
Packit Service fa4841
		{
Packit Service fa4841
			vert = TRUE;
Packit Service fa4841
		}
Packit Service fa4841
		else if (vert &&
Packit Service fa4841
		         client_height >=
Packit Service fa4841
		             wfc->context.settings->DesktopHeight /* - GetSystemMetrics(SM_CYHSCROLL)*/)
Packit Service fa4841
		{
Packit Service fa4841
			vert = FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (horiz == vert && (horiz != wfc->xScrollVisible && vert != wfc->yScrollVisible))
Packit Service fa4841
		{
Packit Service fa4841
			if (ShowScrollBar(wfc->hwnd, SB_BOTH, horiz))
Packit Service fa4841
			{
Packit Service fa4841
				wfc->xScrollVisible = horiz;
Packit Service fa4841
				wfc->yScrollVisible = vert;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (horiz != wfc->xScrollVisible)
Packit Service fa4841
		{
Packit Service fa4841
			if (ShowScrollBar(wfc->hwnd, SB_HORZ, horiz))
Packit Service fa4841
			{
Packit Service fa4841
				wfc->xScrollVisible = horiz;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (vert != wfc->yScrollVisible)
Packit Service fa4841
		{
Packit Service fa4841
			if (ShowScrollBar(wfc->hwnd, SB_VERT, vert))
Packit Service fa4841
			{
Packit Service fa4841
				wfc->yScrollVisible = vert;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (horiz)
Packit Service fa4841
		{
Packit Service fa4841
			// The horizontal scrolling range is defined by
Packit Service fa4841
			// (bitmap_width) - (client_width). The current horizontal
Packit Service fa4841
			// scroll value remains within the horizontal scrolling range.
Packit Service fa4841
			wfc->xMaxScroll = MAX(wfc->context.settings->DesktopWidth - client_width, 0);
Packit Service fa4841
			wfc->xCurrentScroll = MIN(wfc->xCurrentScroll, wfc->xMaxScroll);
Packit Service fa4841
			si.cbSize = sizeof(si);
Packit Service fa4841
			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
Packit Service fa4841
			si.nMin = wfc->xMinScroll;
Packit Service fa4841
			si.nMax = wfc->context.settings->DesktopWidth;
Packit Service fa4841
			si.nPage = client_width;
Packit Service fa4841
			si.nPos = wfc->xCurrentScroll;
Packit Service fa4841
			SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (vert)
Packit Service fa4841
		{
Packit Service fa4841
			// The vertical scrolling range is defined by
Packit Service fa4841
			// (bitmap_height) - (client_height). The current vertical
Packit Service fa4841
			// scroll value remains within the vertical scrolling range.
Packit Service fa4841
			wfc->yMaxScroll = MAX(wfc->context.settings->DesktopHeight - client_height, 0);
Packit Service fa4841
			wfc->yCurrentScroll = MIN(wfc->yCurrentScroll, wfc->yMaxScroll);
Packit Service fa4841
			si.cbSize = sizeof(si);
Packit Service fa4841
			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
Packit Service fa4841
			si.nMin = wfc->yMinScroll;
Packit Service fa4841
			si.nMax = wfc->context.settings->DesktopHeight;
Packit Service fa4841
			si.nPage = client_height;
Packit Service fa4841
			si.nPos = wfc->yCurrentScroll;
Packit Service fa4841
			SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	wfc->disablewindowtracking = FALSE;
Packit Service fa4841
	wf_update_canvas_diff(wfc);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wfreerdp_client_global_init(void)
Packit Service fa4841
{
Packit Service fa4841
	WSADATA wsaData;
Packit Service fa4841
Packit Service fa4841
	WSAStartup(0x101, &wsaData);
Packit Service fa4841
Packit Service fa4841
	freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void wfreerdp_client_global_uninit(void)
Packit Service fa4841
{
Packit Service fa4841
	WSACleanup();
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	wfContext* wfc = (wfContext*)context;
Packit Service fa4841
	if (!wfc)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	// AttachConsole and stdin do not work well.
Packit Service fa4841
	// Use GUI input dialogs instead of command line ones.
Packit Service fa4841
	wfc->isConsole = wf_create_console();
Packit Service fa4841
Packit Service fa4841
	if (!(wfreerdp_client_global_init()))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	instance->PreConnect = wf_pre_connect;
Packit Service fa4841
	instance->PostConnect = wf_post_connect;
Packit Service fa4841
	instance->PostDisconnect = wf_post_disconnect;
Packit Service fa4841
	instance->Authenticate = wf_authenticate;
Packit Service fa4841
	instance->GatewayAuthenticate = wf_gw_authenticate;
Packit Service fa4841
	if (wfc->isConsole)
Packit Service fa4841
	{
Packit Service fa4841
		instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
Packit Service fa4841
		instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		instance->VerifyCertificateEx = wf_verify_certificate_ex;
Packit Service fa4841
		instance->VerifyChangedCertificateEx = wf_verify_changed_certificate_ex;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void wfreerdp_client_free(freerdp* instance, rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	if (!context)
Packit Service fa4841
		return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int wfreerdp_client_start(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	HWND hWndParent;
Packit Service fa4841
	HINSTANCE hInstance;
Packit Service fa4841
	wfContext* wfc = (wfContext*)context;
Packit Service fa4841
	freerdp* instance = context->instance;
Packit Service fa4841
	hInstance = GetModuleHandle(NULL);
Packit Service fa4841
	hWndParent = (HWND)instance->settings->ParentWindowId;
Packit Service fa4841
	instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE;
Packit Service fa4841
	wfc->hWndParent = hWndParent;
Packit Service fa4841
	wfc->hInstance = hInstance;
Packit Service fa4841
	wfc->cursor = LoadCursor(NULL, IDC_ARROW);
Packit Service fa4841
	wfc->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
Packit Service fa4841
	wfc->wndClassName = _tcsdup(_T("FreeRDP"));
Packit Service fa4841
	wfc->wndClass.cbSize = sizeof(WNDCLASSEX);
Packit Service fa4841
	wfc->wndClass.style = CS_HREDRAW | CS_VREDRAW;
Packit Service fa4841
	wfc->wndClass.lpfnWndProc = wf_event_proc;
Packit Service fa4841
	wfc->wndClass.cbClsExtra = 0;
Packit Service fa4841
	wfc->wndClass.cbWndExtra = 0;
Packit Service fa4841
	wfc->wndClass.hCursor = wfc->cursor;
Packit Service fa4841
	wfc->wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
Packit Service fa4841
	wfc->wndClass.lpszMenuName = NULL;
Packit Service fa4841
	wfc->wndClass.lpszClassName = wfc->wndClassName;
Packit Service fa4841
	wfc->wndClass.hInstance = hInstance;
Packit Service fa4841
	wfc->wndClass.hIcon = wfc->icon;
Packit Service fa4841
	wfc->wndClass.hIconSm = wfc->icon;
Packit Service fa4841
	RegisterClassEx(&(wfc->wndClass));
Packit Service fa4841
	wfc->keyboardThread =
Packit Service fa4841
	    CreateThread(NULL, 0, wf_keyboard_thread, (void*)wfc, 0, &wfc->keyboardThreadId);
Packit Service fa4841
Packit Service fa4841
	if (!wfc->keyboardThread)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	wfc->thread = CreateThread(NULL, 0, wf_client_thread, (void*)instance, 0, &wfc->mainThreadId);
Packit Service fa4841
Packit Service fa4841
	if (!wfc->thread)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int wfreerdp_client_stop(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	wfContext* wfc = (wfContext*)context;
Packit Service fa4841
Packit Service fa4841
	if (wfc->thread)
Packit Service fa4841
	{
Packit Service fa4841
		PostThreadMessage(wfc->mainThreadId, WM_QUIT, 0, 0);
Packit Service fa4841
		WaitForSingleObject(wfc->thread, INFINITE);
Packit Service fa4841
		CloseHandle(wfc->thread);
Packit Service fa4841
		wfc->thread = NULL;
Packit Service fa4841
		wfc->mainThreadId = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (wfc->keyboardThread)
Packit Service fa4841
	{
Packit Service fa4841
		PostThreadMessage(wfc->keyboardThreadId, WM_QUIT, 0, 0);
Packit Service fa4841
		WaitForSingleObject(wfc->keyboardThread, INFINITE);
Packit Service fa4841
		CloseHandle(wfc->keyboardThread);
Packit Service fa4841
		wfc->keyboardThread = NULL;
Packit Service fa4841
		wfc->keyboardThreadId = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
Packit Service fa4841
{
Packit Service fa4841
	pEntryPoints->Version = 1;
Packit Service fa4841
	pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
Packit Service fa4841
	pEntryPoints->GlobalInit = wfreerdp_client_global_init;
Packit Service fa4841
	pEntryPoints->GlobalUninit = wfreerdp_client_global_uninit;
Packit Service fa4841
	pEntryPoints->ContextSize = sizeof(wfContext);
Packit Service fa4841
	pEntryPoints->ClientNew = wfreerdp_client_new;
Packit Service fa4841
	pEntryPoints->ClientFree = wfreerdp_client_free;
Packit Service fa4841
	pEntryPoints->ClientStart = wfreerdp_client_start;
Packit Service fa4841
	pEntryPoints->ClientStop = wfreerdp_client_stop;
Packit Service fa4841
	return 0;
Packit Service fa4841
}