2012-08-14 19:57:25 +04:00
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2012-08-14 19:57:25 +04:00
|
|
|
* FreeRDP Windows Server
|
|
|
|
*
|
|
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@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"
|
|
|
|
|
|
|
|
#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 context and returns true. Otherwise
|
|
|
|
the function returns false.
|
|
|
|
*/
|
2012-09-07 08:01:16 +04:00
|
|
|
BOOL wf_mirror_driver_find_display_device(wfInfo* context)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
BOOL result;
|
|
|
|
BOOL devFound;
|
2012-08-14 19:57:25 +04:00
|
|
|
DWORD deviceNumber;
|
|
|
|
DISPLAY_DEVICE deviceInfo;
|
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
devFound = FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
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 (_tcsncmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
|
|
|
|
{
|
|
|
|
deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
|
|
|
|
context->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR));
|
|
|
|
|
|
|
|
_tcsncpy_s(context->deviceKey, deviceKeyLength + 1,
|
|
|
|
&deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
_tcsncpy_s(context->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
|
2012-09-02 22:39:27 +04:00
|
|
|
return TRUE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
deviceNumber++;
|
|
|
|
}
|
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
return FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-24 01:10:22 +04:00
|
|
|
/**
|
|
|
|
* This function will attempt to access the the windows registry using the device
|
|
|
|
* key stored in the current context. 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.
|
2012-08-14 20:31:52 +04:00
|
|
|
*/
|
2012-08-31 03:57:21 +04:00
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
BOOL wf_mirror_driver_display_device_attach(wfInfo* context, DWORD mode)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-08-31 03:57:21 +04:00
|
|
|
HKEY hKey;
|
2012-08-14 19:57:25 +04:00
|
|
|
LONG status;
|
2012-08-31 03:57:21 +04:00
|
|
|
DWORD dwType;
|
|
|
|
DWORD dwSize;
|
|
|
|
DWORD dwValue;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, context->deviceKey,
|
|
|
|
0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
if (status != ERROR_SUCCESS)
|
|
|
|
return FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
dwSize = sizeof(DWORD);
|
|
|
|
status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"),
|
|
|
|
NULL, &dwType, (BYTE*) &dwValue, &dwSize);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
|
|
|
if (status != ERROR_SUCCESS)
|
2012-08-31 03:57:21 +04:00
|
|
|
return FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
if (dwValue == 1)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-09-03 02:04:41 +04:00
|
|
|
dwValue = mode;
|
2012-08-31 03:57:21 +04:00
|
|
|
dwSize = sizeof(DWORD);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
status = RegSetValueEx(HKEY_LOCAL_MACHINE, _T("Attach.ToDesktop"),
|
|
|
|
0, REG_DWORD, (BYTE*) &dwValue, dwSize);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
|
|
|
if (status != ERROR_SUCCESS)
|
2012-08-31 03:57:21 +04:00
|
|
|
return FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-31 03:57:21 +04:00
|
|
|
return TRUE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
void wf_mirror_driver_print_display_change_status(LONG status)
|
2012-09-02 22:39:27 +04:00
|
|
|
{
|
|
|
|
TCHAR disp_change[64];
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
switch (status)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
case DISP_CHANGE_SUCCESSFUL:
|
|
|
|
_tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_BADDUALVIEW:
|
|
|
|
_tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
|
|
|
|
break;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
case DISP_CHANGE_BADFLAGS:
|
|
|
|
_tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
|
|
|
|
break;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
case DISP_CHANGE_BADMODE:
|
|
|
|
_tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
|
|
|
|
break;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
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;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
if (status != DISP_CHANGE_SUCCESSFUL)
|
|
|
|
_tprintf(_T("ChangeDisplaySettingsEx() failed with %s (%d)\n"), disp_change, status);
|
|
|
|
else
|
|
|
|
_tprintf(_T("ChangeDisplaySettingsEx() succeeded with %s (%d)\n"), disp_change, status);
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-24 01:10:22 +04:00
|
|
|
/**
|
|
|
|
* 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 unload is nonzero then the the driver will be asked to remove itself.
|
|
|
|
*/
|
2012-08-15 04:30:36 +04:00
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
BOOL wf_mirror_driver_update(wfInfo* context, int unload)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-09-18 22:07:38 +04:00
|
|
|
HDC dc;
|
2012-08-24 00:35:54 +04:00
|
|
|
BOOL status;
|
2012-08-14 19:57:25 +04:00
|
|
|
DWORD* extHdr;
|
|
|
|
WORD drvExtraSaved;
|
|
|
|
DEVMODE* deviceMode;
|
2012-08-24 00:35:54 +04:00
|
|
|
LONG disp_change_status;
|
2012-08-14 19:57:25 +04:00
|
|
|
DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
|
2012-08-14 22:49:53 +04:00
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
if (!unload)
|
2012-09-18 22:07:38 +04:00
|
|
|
{
|
2012-08-15 04:30:36 +04:00
|
|
|
/*
|
2012-08-24 00:35:54 +04:00
|
|
|
* Will have to come back to this for supporting non primary displays and multimonitor setups
|
|
|
|
*/
|
2012-08-15 04:30:36 +04:00
|
|
|
dc = GetDC(NULL);
|
2012-09-07 08:01:16 +04:00
|
|
|
context->width = GetDeviceCaps(dc, HORZRES);
|
|
|
|
context->height = GetDeviceCaps(dc, VERTRES);
|
|
|
|
context->bitsPerPixel = GetDeviceCaps(dc, BITSPIXEL);
|
2012-08-15 04:30:36 +04:00
|
|
|
ReleaseDC(NULL, dc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-17 01:38:33 +04:00
|
|
|
context->width = 0;
|
2012-09-07 08:01:16 +04:00
|
|
|
context->height = 0;
|
|
|
|
context->bitsPerPixel = 0;
|
2012-08-15 04:30:36 +04:00
|
|
|
}
|
2012-08-14 22:49:53 +04:00
|
|
|
|
2012-08-14 19:57:25 +04:00
|
|
|
deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
|
|
|
|
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;
|
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
deviceMode->dmPelsWidth = context->width;
|
|
|
|
deviceMode->dmPelsHeight = context->height;
|
|
|
|
deviceMode->dmBitsPerPel = context->bitsPerPixel;
|
2012-08-14 19:57:25 +04:00
|
|
|
deviceMode->dmPosition.x = 0;
|
|
|
|
deviceMode->dmPosition.y = 0;
|
|
|
|
|
|
|
|
deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
|
|
|
|
|
|
|
|
_tcsncpy_s(deviceMode->dmDeviceName, 32, context->deviceName, _tcslen(context->deviceName));
|
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
disp_change_status = ChangeDisplaySettingsEx(context->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
if (!status)
|
2012-09-07 08:01:16 +04:00
|
|
|
wf_mirror_driver_print_display_change_status(disp_change_status);
|
2012-08-14 22:49:53 +04:00
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
return status;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
BOOL wf_mirror_driver_map_memory(wfInfo* context)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
|
|
|
int status;
|
2012-08-15 04:30:36 +04:00
|
|
|
GETCHANGESBUF* b;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
|
|
|
context->driverDC = CreateDC(context->deviceName, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (context->driverDC == NULL)
|
|
|
|
{
|
2012-08-15 00:49:24 +04:00
|
|
|
_tprintf(_T("Could not create device driver context!\n"));
|
2012-08-24 00:35:54 +04:00
|
|
|
return FALSE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
context->changeBuffer = malloc(sizeof(GETCHANGESBUF));
|
2012-08-24 01:10:22 +04:00
|
|
|
ZeroMemory(context->changeBuffer, sizeof(GETCHANGESBUF));
|
2012-08-14 19:57:25 +04:00
|
|
|
|
|
|
|
status = ExtEscape(context->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) context->changeBuffer);
|
|
|
|
|
|
|
|
if (status <= 0)
|
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
_tprintf(_T("Failed to map shared memory from the driver! code %d\n"), status);
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-24 01:10:22 +04:00
|
|
|
b = (GETCHANGESBUF*) context->changeBuffer;
|
2012-08-15 04:30:36 +04:00
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
return TRUE;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
2012-08-15 00:49:24 +04:00
|
|
|
|
2012-08-24 01:10:22 +04:00
|
|
|
/* Unmap the shared memory and release the DC */
|
|
|
|
|
2012-09-07 08:01:16 +04:00
|
|
|
BOOL wf_mirror_driver_cleanup(wfInfo* context)
|
2012-08-15 00:49:24 +04:00
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
int status;
|
2012-08-15 00:49:24 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
status = ExtEscape(context->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) context->changeBuffer, 0, 0);
|
2012-08-24 01:10:22 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
if (status <= 0)
|
2012-08-15 00:49:24 +04:00
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
_tprintf(_T("Failed to unmap shared memory from the driver! code %d\n"), status);
|
2012-08-15 00:49:24 +04:00
|
|
|
}
|
|
|
|
|
2012-08-24 00:35:54 +04:00
|
|
|
if (context->driverDC != NULL)
|
2012-08-15 00:49:24 +04:00
|
|
|
{
|
2012-09-02 22:39:27 +04:00
|
|
|
status = DeleteDC(context->driverDC);
|
2012-08-24 01:10:22 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
if (status == 0)
|
2012-08-15 00:49:24 +04:00
|
|
|
{
|
|
|
|
_tprintf(_T("Failed to release DC!\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(context->changeBuffer);
|
2012-08-15 04:30:36 +04:00
|
|
|
|
2012-09-02 22:39:27 +04:00
|
|
|
return TRUE;
|
2012-08-24 00:35:54 +04:00
|
|
|
}
|
2012-09-17 05:05:51 +04:00
|
|
|
|
|
|
|
void wf_mirror_driver_activate(wfInfo* wfi)
|
|
|
|
{
|
|
|
|
if (!wfi->mirrorDriverActive)
|
|
|
|
{
|
|
|
|
printf("Activating Mirror Driver\n");
|
|
|
|
|
|
|
|
wf_mirror_driver_find_display_device(wfi);
|
|
|
|
wf_mirror_driver_display_device_attach(wfi, 1);
|
|
|
|
wf_mirror_driver_update(wfi, FALSE);
|
|
|
|
wf_mirror_driver_map_memory(wfi);
|
|
|
|
wfi->mirrorDriverActive = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void wf_mirror_driver_deactivate(wfInfo* wfi)
|
|
|
|
{
|
|
|
|
if (wfi->mirrorDriverActive)
|
|
|
|
{
|
|
|
|
printf("Deactivating Mirror Driver\n");
|
|
|
|
|
|
|
|
wf_mirror_driver_cleanup(wfi);
|
|
|
|
wf_mirror_driver_display_device_attach(wfi, 0);
|
|
|
|
wf_mirror_driver_update(wfi, 1);
|
|
|
|
wfi->mirrorDriverActive = FALSE;
|
|
|
|
}
|
2012-09-18 22:07:38 +04:00
|
|
|
}
|