Blame server/Windows/wf_mirage.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * FreeRDP Windows Server
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2012-2013 Corey Clayton <can.of.tuna@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
#include <winpr/tchar.h>
Packit Service fa4841
#include <winpr/windows.h>
Packit Service fa4841
Packit Service fa4841
#include "wf_mirage.h"
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#define TAG SERVER_TAG("Windows.mirror")
Packit Service fa4841
Packit Service fa4841
#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\")
Packit Service fa4841
/*
Packit Service fa4841
This function will iterate over the loaded display devices until it finds
Packit Service fa4841
the mirror device we want to load. If found, it will then copy the registry
Packit Service fa4841
key corresponding to the device to the wfi and returns TRUE. Otherwise
Packit Service fa4841
the function returns FALSE.
Packit Service fa4841
*/
Packit Service fa4841
BOOL wf_mirror_driver_find_display_device(wfInfo* wfi)
Packit Service fa4841
{
Packit Service fa4841
	BOOL result;
Packit Service fa4841
	BOOL devFound;
Packit Service fa4841
	DWORD deviceNumber;
Packit Service fa4841
	DISPLAY_DEVICE deviceInfo;
Packit Service fa4841
	devFound = FALSE;
Packit Service fa4841
	deviceNumber = 0;
Packit Service fa4841
	deviceInfo.cb = sizeof(deviceInfo);
Packit Service fa4841
Packit Service fa4841
	while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0))
Packit Service fa4841
	{
Packit Service fa4841
		if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
Packit Service fa4841
		{
Packit Service fa4841
			int deviceKeyLength;
Packit Service fa4841
			int deviceKeyPrefixLength;
Packit Service fa4841
			deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX);
Packit Service fa4841
Packit Service fa4841
			if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
Packit Service fa4841
			{
Packit Service fa4841
				deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
Packit Service fa4841
				wfi->deviceKey = (LPTSTR)malloc((deviceKeyLength + 1) * sizeof(TCHAR));
Packit Service fa4841
Packit Service fa4841
				if (!wfi->deviceKey)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				_tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1,
Packit Service fa4841
				           &deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			_tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
Packit Service fa4841
			return TRUE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		deviceNumber++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * This function will attempt to access the the windows registry using the device
Packit Service fa4841
 * key stored in the current wfi. It will attempt to read the value of the
Packit Service fa4841
 * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to
Packit Service fa4841
 * val. If unable to read the subkey, this function will return FALSE. If the
Packit Service fa4841
 * subkey is not set to val it will then attempt to set it to val and return TRUE. If
Packit Service fa4841
 * unsuccessful or an unexpected value is encountered, the function returns
Packit Service fa4841
 * FALSE.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode)
Packit Service fa4841
{
Packit Service fa4841
	HKEY hKey;
Packit Service fa4841
	LONG status;
Packit Service fa4841
	DWORD dwType;
Packit Service fa4841
	DWORD dwSize;
Packit Service fa4841
	DWORD dwValue;
Packit Service fa4841
	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY,
Packit Service fa4841
	                      &hKey);
Packit Service fa4841
Packit Service fa4841
	if (status != ERROR_SUCCESS)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Error opening RegKey: status=0x%08lX", status);
Packit Service fa4841
Packit Service fa4841
		if (status == ERROR_ACCESS_DENIED)
Packit Service fa4841
			WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit Service fa4841
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	dwSize = sizeof(DWORD);
Packit Service fa4841
	status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), NULL, &dwType, (BYTE*)&dwValue, &dwSize);
Packit Service fa4841
Packit Service fa4841
	if (status != ERROR_SUCCESS)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status);
Packit Service fa4841
Packit Service fa4841
		if (status == ERROR_ACCESS_DENIED)
Packit Service fa4841
			WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit Service fa4841
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (dwValue ^ mode) // only if we want to change modes
Packit Service fa4841
	{
Packit Service fa4841
		dwValue = mode;
Packit Service fa4841
		dwSize = sizeof(DWORD);
Packit Service fa4841
		status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*)&dwValue, dwSize);
Packit Service fa4841
Packit Service fa4841
		if (status != ERROR_SUCCESS)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_DBG(TAG, "Error writing registry key: %ld", status);
Packit Service fa4841
Packit Service fa4841
			if (status == ERROR_ACCESS_DENIED)
Packit Service fa4841
				WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit Service fa4841
Packit Service fa4841
			WLog_DBG(TAG, "");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void wf_mirror_driver_print_display_change_status(LONG status)
Packit Service fa4841
{
Packit Service fa4841
	TCHAR disp_change[64];
Packit Service fa4841
Packit Service fa4841
	switch (status)
Packit Service fa4841
	{
Packit Service fa4841
		case DISP_CHANGE_SUCCESSFUL:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_BADDUALVIEW:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_BADFLAGS:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_BADMODE:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_BADPARAM:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_FAILED:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_FAILED"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_NOTUPDATED:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case DISP_CHANGE_RESTART:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_RESTART"));
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			_tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN"));
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (status != DISP_CHANGE_SUCCESSFUL)
Packit Service fa4841
		WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status);
Packit Service fa4841
	else
Packit Service fa4841
		WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * This function will attempt to apply the currently configured display settings
Packit Service fa4841
 * in the registry to the display driver. It will return TRUE if successful
Packit Service fa4841
 * otherwise it returns FALSE.
Packit Service fa4841
 * If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL wf_mirror_driver_update(wfInfo* wfi, int mode)
Packit Service fa4841
{
Packit Service fa4841
	HDC dc;
Packit Service fa4841
	BOOL status;
Packit Service fa4841
	DWORD* extHdr;
Packit Service fa4841
	WORD drvExtraSaved;
Packit Service fa4841
	DEVMODE* deviceMode;
Packit Service fa4841
	LONG disp_change_status;
Packit Service fa4841
	DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
Packit Service fa4841
Packit Service fa4841
	if ((mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Invalid mirror mode!");
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	deviceMode = (DEVMODE*)malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
Packit Service fa4841
Packit Service fa4841
	if (!deviceMode)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
Packit Service fa4841
	extHdr = (DWORD*)((BYTE*)&deviceMode + sizeof(DEVMODE));
Packit Service fa4841
	extHdr[0] = dmf_devmodewext_magic_sig;
Packit Service fa4841
	extHdr[1] = 0;
Packit Service fa4841
	drvExtraSaved = deviceMode->dmDriverExtra;
Packit Service fa4841
	memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
Packit Service fa4841
	deviceMode->dmSize = sizeof(DEVMODE);
Packit Service fa4841
	deviceMode->dmDriverExtra = drvExtraSaved;
Packit Service fa4841
Packit Service fa4841
	if (mode == MIRROR_LOAD)
Packit Service fa4841
	{
Packit Service fa4841
		wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
Packit Service fa4841
		wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
Packit Service fa4841
		deviceMode->dmPelsWidth = wfi->virtscreen_width;
Packit Service fa4841
		deviceMode->dmPelsHeight = wfi->virtscreen_height;
Packit Service fa4841
		deviceMode->dmBitsPerPel = wfi->bitsPerPixel;
Packit Service fa4841
		deviceMode->dmPosition.x = wfi->servscreen_xoffset;
Packit Service fa4841
		deviceMode->dmPosition.y = wfi->servscreen_yoffset;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
Packit Service fa4841
	_tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName));
Packit Service fa4841
	disp_change_status =
Packit Service fa4841
	    ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
Packit Service fa4841
	status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!status)
Packit Service fa4841
		wf_mirror_driver_print_display_change_status(disp_change_status);
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL wf_mirror_driver_map_memory(wfInfo* wfi)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL);
Packit Service fa4841
Packit Service fa4841
	if (wfi->driverDC == NULL)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Could not create device driver context!");
Packit Service fa4841
		{
Packit Service fa4841
			LPVOID lpMsgBuf;
Packit Service fa4841
			DWORD dw = GetLastError();
Packit Service fa4841
			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
Packit Service fa4841
			                  FORMAT_MESSAGE_IGNORE_INSERTS,
Packit Service fa4841
			              NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0,
Packit Service fa4841
			              NULL);
Packit Service fa4841
			// Display the error message and exit the process
Packit Service fa4841
			WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw,
Packit Service fa4841
			         lpMsgBuf);
Packit Service fa4841
			LocalFree(lpMsgBuf);
Packit Service fa4841
		}
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF));
Packit Service fa4841
Packit Service fa4841
	if (!wfi->changeBuffer)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF),
Packit Service fa4841
	                   (LPSTR)wfi->changeBuffer);
Packit Service fa4841
Packit Service fa4841
	if (status <= 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status);
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
/* Unmap the shared memory and release the DC */
Packit Service fa4841
Packit Service fa4841
BOOL wf_mirror_driver_cleanup(wfInfo* wfi)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF),
Packit Service fa4841
	                   (LPSTR)wfi->changeBuffer, 0, 0);
Packit Service fa4841
Packit Service fa4841
	if (status <= 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (wfi->driverDC != NULL)
Packit Service fa4841
	{
Packit Service fa4841
		status = DeleteDC(wfi->driverDC);
Packit Service fa4841
Packit Service fa4841
		if (status == 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Failed to release DC!");
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(wfi->changeBuffer);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL wf_mirror_driver_activate(wfInfo* wfi)
Packit Service fa4841
{
Packit Service fa4841
	if (!wfi->mirrorDriverActive)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Activating Mirror Driver");
Packit Service fa4841
Packit Service fa4841
		if (wf_mirror_driver_find_display_device(wfi) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_DBG(TAG, "Could not attach display device!");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_DBG(TAG, "could not update system with new display settings!");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (wf_mirror_driver_map_memory(wfi) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_DBG(TAG, "Unable to map memory for mirror driver!");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		wfi->mirrorDriverActive = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void wf_mirror_driver_deactivate(wfInfo* wfi)
Packit Service fa4841
{
Packit Service fa4841
	if (wfi->mirrorDriverActive)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Deactivating Mirror Driver");
Packit Service fa4841
		wf_mirror_driver_cleanup(wfi);
Packit Service fa4841
		wf_mirror_driver_display_device_attach(wfi, 0);
Packit Service fa4841
		wf_mirror_driver_update(wfi, MIRROR_UNLOAD);
Packit Service fa4841
		wfi->mirrorDriverActive = FALSE;
Packit Service fa4841
	}
Packit Service fa4841
}