diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /server/Windows/wf_mirage.c | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'server/Windows/wf_mirage.c')
-rw-r--r-- | server/Windows/wf_mirage.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/server/Windows/wf_mirage.c b/server/Windows/wf_mirage.c new file mode 100644 index 0000000..524ff6e --- /dev/null +++ b/server/Windows/wf_mirage.c @@ -0,0 +1,361 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Windows Server + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * Copyright 2012-2013 Corey Clayton <can.of.tuna@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/tchar.h> +#include <winpr/windows.h> + +#include "wf_mirage.h" + +#include <freerdp/log.h> +#define TAG SERVER_TAG("Windows.mirror") + +#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\") +/* +This function will iterate over the loaded display devices until it finds +the mirror device we want to load. If found, it will then copy the registry +key corresponding to the device to the wfi and returns TRUE. Otherwise +the function returns FALSE. +*/ +BOOL wf_mirror_driver_find_display_device(wfInfo* wfi) +{ + BOOL result; + BOOL devFound; + DWORD deviceNumber; + DISPLAY_DEVICE deviceInfo; + devFound = FALSE; + deviceNumber = 0; + deviceInfo.cb = sizeof(deviceInfo); + + while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0)) + { + if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0) + { + int deviceKeyLength; + int deviceKeyPrefixLength; + deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX); + + if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0) + { + deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength; + wfi->deviceKey = (LPTSTR)malloc((deviceKeyLength + 1) * sizeof(TCHAR)); + + if (!wfi->deviceKey) + return FALSE; + + _tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1, + &deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength); + } + + _tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName)); + return TRUE; + } + + deviceNumber++; + } + + return FALSE; +} + +/** + * This function will attempt to access the the windows registry using the device + * key stored in the current wfi. It will attempt to read the value of the + * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to + * val. If unable to read the subkey, this function will return FALSE. If the + * subkey is not set to val it will then attempt to set it to val and return TRUE. If + * unsuccessful or an unexpected value is encountered, the function returns + * FALSE. + */ + +BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode) +{ + HKEY hKey; + LONG status; + DWORD dwType; + DWORD dwSize; + DWORD dwValue; + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, + &hKey); + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error opening RegKey: status=0x%08lX", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + return FALSE; + } + + dwSize = sizeof(DWORD); + status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), NULL, &dwType, (BYTE*)&dwValue, &dwSize); + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + return FALSE; + } + + if (dwValue ^ mode) // only if we want to change modes + { + dwValue = mode; + dwSize = sizeof(DWORD); + status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*)&dwValue, dwSize); + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error writing registry key: %ld", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + WLog_DBG(TAG, ""); + return FALSE; + } + } + + return TRUE; +} + +void wf_mirror_driver_print_display_change_status(LONG status) +{ + TCHAR disp_change[64]; + + switch (status) + { + case DISP_CHANGE_SUCCESSFUL: + _tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL")); + break; + + case DISP_CHANGE_BADDUALVIEW: + _tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW")); + break; + + case DISP_CHANGE_BADFLAGS: + _tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS")); + break; + + case DISP_CHANGE_BADMODE: + _tcscpy(disp_change, _T("DISP_CHANGE_BADMODE")); + break; + + case DISP_CHANGE_BADPARAM: + _tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM")); + break; + + case DISP_CHANGE_FAILED: + _tcscpy(disp_change, _T("DISP_CHANGE_FAILED")); + break; + + case DISP_CHANGE_NOTUPDATED: + _tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED")); + break; + + case DISP_CHANGE_RESTART: + _tcscpy(disp_change, _T("DISP_CHANGE_RESTART")); + break; + + default: + _tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN")); + break; + } + + if (status != DISP_CHANGE_SUCCESSFUL) + WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status); + else + WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status); +} + +/** + * This function will attempt to apply the currently configured display settings + * in the registry to the display driver. It will return TRUE if successful + * otherwise it returns FALSE. + * If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself. + */ + +BOOL wf_mirror_driver_update(wfInfo* wfi, int mode) +{ + BOOL status; + DWORD* extHdr; + WORD drvExtraSaved; + DEVMODE* deviceMode; + LONG disp_change_status; + DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE; + + if ((mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD)) + { + WLog_DBG(TAG, "Invalid mirror mode!"); + return FALSE; + } + + deviceMode = (DEVMODE*)malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); + + if (!deviceMode) + return FALSE; + + deviceMode->dmDriverExtra = 2 * sizeof(DWORD); + extHdr = (DWORD*)((BYTE*)&deviceMode + sizeof(DEVMODE)); + extHdr[0] = dmf_devmodewext_magic_sig; + extHdr[1] = 0; + drvExtraSaved = deviceMode->dmDriverExtra; + memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); + deviceMode->dmSize = sizeof(DEVMODE); + deviceMode->dmDriverExtra = drvExtraSaved; + + if (mode == MIRROR_LOAD) + { + wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + deviceMode->dmPelsWidth = wfi->virtscreen_width; + deviceMode->dmPelsHeight = wfi->virtscreen_height; + deviceMode->dmBitsPerPel = wfi->bitsPerPixel; + deviceMode->dmPosition.x = wfi->servscreen_xoffset; + deviceMode->dmPosition.y = wfi->servscreen_yoffset; + } + + deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; + _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName)); + disp_change_status = + ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL); + status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE; + + if (!status) + wf_mirror_driver_print_display_change_status(disp_change_status); + + return status; +} + +BOOL wf_mirror_driver_map_memory(wfInfo* wfi) +{ + int status; + wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL); + + if (wfi->driverDC == NULL) + { + WLog_ERR(TAG, "Could not create device driver context!"); + { + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, + NULL); + // Display the error message and exit the process + WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw, + lpMsgBuf); + LocalFree(lpMsgBuf); + } + return FALSE; + } + + wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF)); + + if (!wfi->changeBuffer) + return FALSE; + + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), + (LPSTR)wfi->changeBuffer); + + if (status <= 0) + { + WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status); + return FALSE; + } + + return TRUE; +} + +/* Unmap the shared memory and release the DC */ + +BOOL wf_mirror_driver_cleanup(wfInfo* wfi) +{ + int status; + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), + (LPSTR)wfi->changeBuffer, 0, 0); + + if (status <= 0) + { + WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status); + } + + if (wfi->driverDC != NULL) + { + status = DeleteDC(wfi->driverDC); + + if (status == 0) + { + WLog_ERR(TAG, "Failed to release DC!"); + } + } + + free(wfi->changeBuffer); + return TRUE; +} + +BOOL wf_mirror_driver_activate(wfInfo* wfi) +{ + if (!wfi->mirrorDriverActive) + { + WLog_DBG(TAG, "Activating Mirror Driver"); + + if (wf_mirror_driver_find_display_device(wfi) == FALSE) + { + WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?"); + return FALSE; + } + + if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE) + { + WLog_DBG(TAG, "Could not attach display device!"); + return FALSE; + } + + if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE) + { + WLog_DBG(TAG, "could not update system with new display settings!"); + return FALSE; + } + + if (wf_mirror_driver_map_memory(wfi) == FALSE) + { + WLog_DBG(TAG, "Unable to map memory for mirror driver!"); + return FALSE; + } + + wfi->mirrorDriverActive = TRUE; + } + + return TRUE; +} + +void wf_mirror_driver_deactivate(wfInfo* wfi) +{ + if (wfi->mirrorDriverActive) + { + WLog_DBG(TAG, "Deactivating Mirror Driver"); + wf_mirror_driver_cleanup(wfi); + wf_mirror_driver_display_device_attach(wfi, 0); + wf_mirror_driver_update(wfi, MIRROR_UNLOAD); + wfi->mirrorDriverActive = FALSE; + } +} |