2012-08-14 19:57:25 +04:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Client
|
|
|
|
* 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-08-15 04:30:36 +04:00
|
|
|
BOOL wf_check_disp_devices(wfInfo* context)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
|
|
|
BOOL result, devFound;
|
|
|
|
DWORD deviceNumber;
|
|
|
|
DISPLAY_DEVICE deviceInfo;
|
|
|
|
|
|
|
|
devFound = false;
|
|
|
|
deviceNumber = 0;
|
|
|
|
deviceInfo.cb = sizeof(deviceInfo);
|
|
|
|
|
|
|
|
printf("Detecting display devices:\n");
|
|
|
|
|
|
|
|
while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0))
|
|
|
|
{
|
|
|
|
_tprintf(_T("\t%s\n"), deviceInfo.DeviceString);
|
|
|
|
|
|
|
|
if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
|
|
|
|
{
|
|
|
|
int deviceKeyLength;
|
|
|
|
int deviceKeyPrefixLength;
|
|
|
|
|
|
|
|
_tprintf(_T("\n\nFound our target of interest!\n"));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
_tprintf(_T("DeviceKey: %s\n"), context->deviceKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
_tcsncpy_s(context->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
deviceNumber++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-08-14 20:31:52 +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-15 04:30:36 +04:00
|
|
|
BOOL wf_disp_device_set_attatch(wfInfo* context, DWORD val)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
|
|
|
LONG status;
|
|
|
|
DWORD rtype, rdata, rdata_size;
|
|
|
|
|
|
|
|
_tprintf(_T("\nOpening registry key %s\n"), context->deviceKey);
|
|
|
|
|
|
|
|
rtype = 0;
|
|
|
|
rdata = 0;
|
|
|
|
rdata_size = sizeof(rdata);
|
|
|
|
|
|
|
|
status = RegGetValue(HKEY_LOCAL_MACHINE, context->deviceKey,
|
|
|
|
_T("Attach.ToDesktop"), RRF_RT_REG_DWORD, &rtype, &rdata, &rdata_size);
|
|
|
|
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
printf("Failed to read registry value.\n");
|
|
|
|
printf("operation returned %d\n", status);
|
2012-08-14 20:31:52 +04:00
|
|
|
return false;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-15 04:30:36 +04:00
|
|
|
_tprintf(_T("type = %04X, data = %04X\n"), rtype, rdata);
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-15 04:30:36 +04:00
|
|
|
if (rdata == (val ^ 1))
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-08-14 20:31:52 +04:00
|
|
|
rdata = val;
|
2012-08-14 19:57:25 +04:00
|
|
|
|
|
|
|
status = RegSetKeyValue(HKEY_LOCAL_MACHINE, context->deviceKey,
|
|
|
|
_T("Attach.ToDesktop"), REG_DWORD, &rdata, rdata_size);
|
|
|
|
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
|
|
{
|
2012-08-14 20:31:52 +04:00
|
|
|
_tprintf(_T("Failed to write registry value.\n"));
|
2012-08-14 19:57:25 +04:00
|
|
|
_tprintf(_T("operation returned %d\n"), status);
|
2012-08-14 20:31:52 +04:00
|
|
|
return false;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-15 04:30:36 +04:00
|
|
|
_tprintf(_T("Wrote subkey \"Attach.ToDesktop\" -> %04X\n\n"), rdata);
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
2012-08-14 20:31:52 +04:00
|
|
|
else if (rdata == val)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-08-15 04:30:36 +04:00
|
|
|
_tprintf(_T("\"Attach.ToDesktop\" is already set to %04X!\n"), rdata);
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-14 20:31:52 +04:00
|
|
|
_tprintf(_T("An wild value appeared!...\nrdata=%d\n"), rdata);
|
|
|
|
return false;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 20:31:52 +04:00
|
|
|
return true;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 22:49:53 +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.
|
2012-08-15 04:30:36 +04:00
|
|
|
|
|
|
|
If unload is nonzero then the the driver will be asked to remove it self.
|
2012-08-14 22:49:53 +04:00
|
|
|
*/
|
2012-08-15 04:30:36 +04:00
|
|
|
BOOL wf_update_mirror_drv(wfInfo* context, int unload)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
2012-08-16 02:01:06 +04:00
|
|
|
int currentScreenPixHeight, currentScreenPixWidth, currentScreenBPP;
|
2012-08-14 22:49:53 +04:00
|
|
|
HDC dc;
|
2012-08-14 19:57:25 +04:00
|
|
|
LONG status;
|
|
|
|
DWORD* extHdr;
|
|
|
|
WORD drvExtraSaved;
|
|
|
|
DEVMODE* deviceMode;
|
|
|
|
DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
|
2012-08-14 23:12:44 +04:00
|
|
|
TCHAR rMsg[64];
|
2012-08-14 22:49:53 +04:00
|
|
|
BOOL rturn;
|
|
|
|
|
2012-08-15 04:30:36 +04:00
|
|
|
if(!unload)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Will have to come back to this for supporting non primary displays and
|
|
|
|
multimonitor setups
|
|
|
|
*/
|
|
|
|
dc = GetDC(NULL);
|
2012-08-16 02:01:06 +04:00
|
|
|
currentScreenPixHeight = GetDeviceCaps(dc, VERTRES);
|
|
|
|
currentScreenPixWidth = GetDeviceCaps(dc, HORZRES);
|
2012-08-15 04:30:36 +04:00
|
|
|
currentScreenBPP = GetDeviceCaps(dc, BITSPIXEL);
|
|
|
|
ReleaseDC(NULL, dc);
|
|
|
|
|
2012-08-16 02:01:06 +04:00
|
|
|
context->height = currentScreenPixHeight;
|
|
|
|
context->width = currentScreenPixWidth;
|
|
|
|
context->bitsPerPix = currentScreenBPP;
|
|
|
|
|
|
|
|
_tprintf(_T("Detected current screen settings: %dx%dx%d\n"), currentScreenPixHeight, currentScreenPixWidth, currentScreenBPP);
|
2012-08-15 04:30:36 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-16 02:01:06 +04:00
|
|
|
currentScreenPixHeight = 0;
|
|
|
|
currentScreenPixWidth = 0;
|
2012-08-15 04:30:36 +04:00
|
|
|
currentScreenBPP = 0;
|
|
|
|
}
|
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-08-16 02:01:06 +04:00
|
|
|
deviceMode->dmPelsWidth = currentScreenPixWidth;
|
|
|
|
deviceMode->dmPelsHeight = currentScreenPixHeight;
|
2012-08-14 22:49:53 +04:00
|
|
|
deviceMode->dmBitsPerPel = currentScreenBPP;
|
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));
|
|
|
|
|
|
|
|
status = ChangeDisplaySettingsEx(context->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
|
|
|
|
|
2012-08-14 22:49:53 +04:00
|
|
|
rturn = false;
|
2012-08-14 19:57:25 +04:00
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case DISP_CHANGE_SUCCESSFUL:
|
2012-08-14 22:49:53 +04:00
|
|
|
_tprintf(_T("ChangeDisplaySettingsEx() was successfull\n"));
|
|
|
|
rturn = true;
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_BADDUALVIEW:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_BADDUALVIEW"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_BADFLAGS:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_BADFLAGS"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_BADMODE:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_BADMODE"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_BADPARAM:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_BADPARAM"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_FAILED:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_FAILED"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_NOTUPDATED:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_NOTUPDATED"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DISP_CHANGE_RESTART:
|
2012-08-14 23:12:44 +04:00
|
|
|
_tcscpy(rMsg, _T("DISP_CHANGE_RESTART"));
|
2012-08-14 19:57:25 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-08-14 22:49:53 +04:00
|
|
|
if(!rturn)
|
|
|
|
_tprintf(_T("ChangeDisplaySettingsEx() failed with %s, code %d\n"), rMsg, status);
|
|
|
|
|
|
|
|
return rturn;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
2012-08-15 00:49:24 +04:00
|
|
|
|
2012-08-15 04:30:36 +04:00
|
|
|
BOOL wf_map_mirror_mem(wfInfo* context)
|
2012-08-14 19:57:25 +04:00
|
|
|
{
|
|
|
|
int status;
|
2012-08-15 04:30:36 +04:00
|
|
|
GETCHANGESBUF* b;
|
2012-08-15 00:49:24 +04:00
|
|
|
_tprintf(_T("\n\nCreating a device context...\n"));
|
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"));
|
|
|
|
return false;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
context->changeBuffer = malloc(sizeof(GETCHANGESBUF));
|
2012-08-15 04:30:36 +04:00
|
|
|
memset(context->changeBuffer, 0, sizeof(GETCHANGESBUF));
|
2012-08-14 19:57:25 +04:00
|
|
|
|
2012-08-15 00:49:24 +04:00
|
|
|
_tprintf(_T("\n\nConnecting to driver...\n"));
|
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-08-15 00:49:24 +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-15 04:30:36 +04:00
|
|
|
b = (GETCHANGESBUF*)context->changeBuffer;
|
|
|
|
_tprintf(_T("ExtEscape() returned code %d\n"), status);
|
|
|
|
|
2012-08-15 00:49:24 +04:00
|
|
|
return true;
|
2012-08-14 19:57:25 +04:00
|
|
|
}
|
2012-08-15 00:49:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
Unmap the shared memory and release the DC
|
|
|
|
*/
|
2012-08-15 04:30:36 +04:00
|
|
|
BOOL wf_mirror_cleanup(wfInfo* context)
|
2012-08-15 00:49:24 +04:00
|
|
|
{
|
|
|
|
int iResult;
|
|
|
|
|
|
|
|
_tprintf(_T("\n\nCleaning up...\nDisconnecting driver...\n"));
|
|
|
|
iResult = ExtEscape(context->driverDC, dmf_esc_usm_pipe_unmap, sizeof(context->changeBuffer), (LPSTR) context->changeBuffer, 0, 0);
|
|
|
|
|
|
|
|
if(iResult <= 0)
|
|
|
|
{
|
|
|
|
_tprintf(_T("Failed to unmap shared memory from the driver! Code %d\n"), iResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
_tprintf(_T("Releasing DC\n"));
|
|
|
|
if(context->driverDC != NULL)
|
|
|
|
{
|
|
|
|
iResult = DeleteDC(context->driverDC);
|
|
|
|
if(iResult == 0)
|
|
|
|
{
|
|
|
|
_tprintf(_T("Failed to release DC!\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(context->changeBuffer);
|
2012-08-15 04:30:36 +04:00
|
|
|
|
|
|
|
return true;
|
2012-08-15 00:49:24 +04:00
|
|
|
}
|