Blame server/Windows/wf_mirage.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * FreeRDP Windows Server
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2012-2013 Corey Clayton <can.of.tuna@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
#include <winpr/tchar.h>
Packit 1fb8d4
#include <winpr/windows.h>
Packit 1fb8d4
Packit 1fb8d4
#include "wf_mirage.h"
Packit 1fb8d4
Packit 1fb8d4
#define DEVICE_KEY_PREFIX	_T("\\Registry\\Machine\\")
Packit 1fb8d4
/*
Packit 1fb8d4
This function will iterate over the loaded display devices until it finds
Packit 1fb8d4
the mirror device we want to load. If found, it will then copy the registry
Packit 1fb8d4
key corresponding to the device to the wfi and returns TRUE. Otherwise
Packit 1fb8d4
the function returns FALSE.
Packit 1fb8d4
*/
Packit 1fb8d4
BOOL wf_mirror_driver_find_display_device(wfInfo* wfi)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL result;
Packit 1fb8d4
	BOOL devFound;
Packit 1fb8d4
	DWORD deviceNumber;
Packit 1fb8d4
	DISPLAY_DEVICE deviceInfo;
Packit 1fb8d4

Packit 1fb8d4
	devFound = FALSE;
Packit 1fb8d4
	deviceNumber = 0;
Packit 1fb8d4
	deviceInfo.cb = sizeof(deviceInfo);
Packit 1fb8d4
Packit 1fb8d4
	while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			int deviceKeyLength;
Packit 1fb8d4
			int deviceKeyPrefixLength;
Packit 1fb8d4

Packit 1fb8d4
			deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX);
Packit 1fb8d4
Packit 1fb8d4
			if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
Packit 1fb8d4
				wfi->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR));
Packit 1fb8d4
				if (!wfi->deviceKey)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4

Packit 1fb8d4
				_tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1,
Packit 1fb8d4
					&deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			_tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		deviceNumber++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * This function will attempt to access the the windows registry using the device
Packit 1fb8d4
 * key stored in the current wfi. It will attempt to read the value of the
Packit 1fb8d4
 * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to
Packit 1fb8d4
 * val. If unable to read the subkey, this function will return FALSE. If the 
Packit 1fb8d4
 * subkey is not set to val it will then attempt to set it to val and return TRUE. If 
Packit 1fb8d4
 * unsuccessful or an unexpected value is encountered, the function returns 
Packit 1fb8d4
 * FALSE.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode)
Packit 1fb8d4
{
Packit 1fb8d4
	HKEY hKey;
Packit 1fb8d4
	LONG status;
Packit 1fb8d4
	DWORD dwType;
Packit 1fb8d4
	DWORD dwSize;
Packit 1fb8d4
	DWORD dwValue;
Packit 1fb8d4

Packit 1fb8d4
	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey,
Packit 1fb8d4
		0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey);
Packit 1fb8d4
Packit 1fb8d4
	if (status != ERROR_SUCCESS)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Error opening RegKey: status=0x%08lX", status);
Packit 1fb8d4
Packit 1fb8d4
		if (status == ERROR_ACCESS_DENIED)
Packit 1fb8d4
			WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit 1fb8d4
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	dwSize = sizeof(DWORD);
Packit 1fb8d4
	status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"),
Packit 1fb8d4
		NULL, &dwType, (BYTE*) &dwValue, &dwSize);
Packit 1fb8d4
Packit 1fb8d4
	if (status != ERROR_SUCCESS)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status);
Packit 1fb8d4
Packit 1fb8d4
		if (status == ERROR_ACCESS_DENIED)
Packit 1fb8d4
			WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit 1fb8d4
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (dwValue ^ mode) //only if we want to change modes
Packit 1fb8d4
	{
Packit 1fb8d4
		dwValue = mode;
Packit 1fb8d4
		dwSize = sizeof(DWORD);
Packit 1fb8d4

Packit 1fb8d4
		status = RegSetValueEx(hKey, _T("Attach.ToDesktop"),
Packit 1fb8d4
			0, REG_DWORD, (BYTE*) &dwValue, dwSize);
Packit 1fb8d4
Packit 1fb8d4
		if (status != ERROR_SUCCESS)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_DBG(TAG, "Error writing registry key: %ld", status);
Packit 1fb8d4
Packit 1fb8d4
			if (status == ERROR_ACCESS_DENIED)
Packit 1fb8d4
				WLog_DBG(TAG, "access denied. Do you have admin privleges?");
Packit 1fb8d4
Packit 1fb8d4
			WLog_DBG(TAG, "");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_mirror_driver_print_display_change_status(LONG status)
Packit 1fb8d4
{
Packit 1fb8d4
	TCHAR disp_change[64];
Packit 1fb8d4
Packit 1fb8d4
	switch (status)
Packit 1fb8d4
	{
Packit 1fb8d4
		case DISP_CHANGE_SUCCESSFUL:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_BADDUALVIEW:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_BADFLAGS:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_BADMODE:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_BADPARAM:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_FAILED:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_FAILED"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_NOTUPDATED:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		case DISP_CHANGE_RESTART:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_RESTART"));
Packit 1fb8d4
			break;
Packit 1fb8d4

Packit 1fb8d4
		default:
Packit 1fb8d4
			_tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN"));
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status != DISP_CHANGE_SUCCESSFUL)
Packit 1fb8d4
		WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status);
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * This function will attempt to apply the currently configured display settings 
Packit 1fb8d4
 * in the registry to the display driver. It will return TRUE if successful 
Packit 1fb8d4
 * otherwise it returns FALSE.
Packit 1fb8d4
 * If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL wf_mirror_driver_update(wfInfo* wfi, int mode)
Packit 1fb8d4
{
Packit 1fb8d4
	HDC dc;
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	DWORD* extHdr;
Packit 1fb8d4
	WORD drvExtraSaved;
Packit 1fb8d4
	DEVMODE* deviceMode;
Packit 1fb8d4
	LONG disp_change_status;
Packit 1fb8d4
	DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
Packit 1fb8d4
Packit 1fb8d4
	if ( (mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD) )
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Invalid mirror mode!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
Packit 1fb8d4
	if (!deviceMode)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
Packit 1fb8d4

Packit 1fb8d4
	extHdr = (DWORD*)((BYTE*) &deviceMode + sizeof(DEVMODE)); 
Packit 1fb8d4
	extHdr[0] = dmf_devmodewext_magic_sig;
Packit 1fb8d4
	extHdr[1] = 0;
Packit 1fb8d4

Packit 1fb8d4
	drvExtraSaved = deviceMode->dmDriverExtra;
Packit 1fb8d4
	memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
Packit 1fb8d4
	deviceMode->dmSize = sizeof(DEVMODE);
Packit 1fb8d4
	deviceMode->dmDriverExtra = drvExtraSaved;
Packit 1fb8d4
Packit 1fb8d4
	if (mode == MIRROR_LOAD)
Packit 1fb8d4
	{
Packit 1fb8d4
		wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
Packit 1fb8d4
		wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
Packit 1fb8d4

Packit 1fb8d4
		deviceMode->dmPelsWidth = wfi->virtscreen_width;
Packit 1fb8d4
		deviceMode->dmPelsHeight = wfi->virtscreen_height;
Packit 1fb8d4
		deviceMode->dmBitsPerPel = wfi->bitsPerPixel;
Packit 1fb8d4
		deviceMode->dmPosition.x = wfi->servscreen_xoffset;
Packit 1fb8d4
		deviceMode->dmPosition.y = wfi->servscreen_yoffset;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
Packit 1fb8d4

Packit 1fb8d4
	_tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName));
Packit 1fb8d4

Packit 1fb8d4
	disp_change_status = ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
Packit 1fb8d4

Packit 1fb8d4
	status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!status)
Packit 1fb8d4
		wf_mirror_driver_print_display_change_status(disp_change_status);
Packit 1fb8d4
		
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL wf_mirror_driver_map_memory(wfInfo* wfi)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4

Packit 1fb8d4
	wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (wfi->driverDC == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not create device driver context!");
Packit 1fb8d4
		{
Packit 1fb8d4
			LPVOID lpMsgBuf;
Packit 1fb8d4
			DWORD dw = GetLastError(); 
Packit 1fb8d4

Packit 1fb8d4
			FormatMessage(
Packit 1fb8d4
				FORMAT_MESSAGE_ALLOCATE_BUFFER | 
Packit 1fb8d4
				FORMAT_MESSAGE_FROM_SYSTEM |
Packit 1fb8d4
				FORMAT_MESSAGE_IGNORE_INSERTS,
Packit 1fb8d4
				NULL,
Packit 1fb8d4
				dw,
Packit 1fb8d4
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
Packit 1fb8d4
				(LPTSTR) &lpMsgBuf,
Packit 1fb8d4
				0, NULL );
Packit 1fb8d4

Packit 1fb8d4
			// Display the error message and exit the process
Packit 1fb8d4
			WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw, lpMsgBuf);
Packit 1fb8d4
			LocalFree(lpMsgBuf);
Packit 1fb8d4
		}
Packit 1fb8d4

Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF));
Packit 1fb8d4
	if (!wfi->changeBuffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4

Packit 1fb8d4
	status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer);
Packit 1fb8d4
Packit 1fb8d4
	if (status <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Unmap the shared memory and release the DC */
Packit 1fb8d4
Packit 1fb8d4
BOOL wf_mirror_driver_cleanup(wfInfo* wfi)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4

Packit 1fb8d4
	status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer, 0, 0);
Packit 1fb8d4
	
Packit 1fb8d4
	if (status <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (wfi->driverDC != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = DeleteDC(wfi->driverDC);
Packit 1fb8d4
Packit 1fb8d4
		if (status == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to release DC!");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(wfi->changeBuffer);
Packit 1fb8d4

Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL wf_mirror_driver_activate(wfInfo* wfi)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!wfi->mirrorDriverActive)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Activating Mirror Driver");
Packit 1fb8d4
Packit 1fb8d4
		if (wf_mirror_driver_find_display_device(wfi) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_DBG(TAG, "Could not attach display device!");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_DBG(TAG, "could not update system with new display settings!");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (wf_mirror_driver_map_memory(wfi) == FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_DBG(TAG, "Unable to map memory for mirror driver!");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		wfi->mirrorDriverActive = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_mirror_driver_deactivate(wfInfo* wfi)
Packit 1fb8d4
{
Packit 1fb8d4
	if (wfi->mirrorDriverActive)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "Deactivating Mirror Driver");
Packit 1fb8d4
		wf_mirror_driver_cleanup(wfi);
Packit 1fb8d4
		wf_mirror_driver_display_device_attach(wfi, 0);
Packit 1fb8d4
		wf_mirror_driver_update(wfi, MIRROR_UNLOAD);
Packit 1fb8d4
		wfi->mirrorDriverActive = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}