Blame client/Windows/wf_client.c

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