FreeRDP
wf_mirage.c
1 
21 #include <winpr/tchar.h>
22 #include <winpr/windows.h>
23 
24 #include "wf_mirage.h"
25 
26 #include <freerdp/log.h>
27 #define TAG SERVER_TAG("Windows.mirror")
28 
29 #define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\")
30 /*
31 This function will iterate over the loaded display devices until it finds
32 the mirror device we want to load. If found, it will then copy the registry
33 key corresponding to the device to the wfi and returns TRUE. Otherwise
34 the function returns FALSE.
35 */
36 BOOL wf_mirror_driver_find_display_device(wfInfo* wfi)
37 {
38  BOOL result;
39  BOOL devFound;
40  DWORD deviceNumber;
41  DISPLAY_DEVICE deviceInfo;
42  devFound = FALSE;
43  deviceNumber = 0;
44  deviceInfo.cb = sizeof(deviceInfo);
45 
46  while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0))
47  {
48  if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
49  {
50  int deviceKeyLength;
51  int deviceKeyPrefixLength;
52  deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX);
53 
54  if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
55  {
56  deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
57  wfi->deviceKey = (LPTSTR)malloc((deviceKeyLength + 1) * sizeof(TCHAR));
58 
59  if (!wfi->deviceKey)
60  return FALSE;
61 
62  _tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1,
63  &deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
64  }
65 
66  _tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
67  return TRUE;
68  }
69 
70  deviceNumber++;
71  }
72 
73  return FALSE;
74 }
75 
86 BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode)
87 {
88  HKEY hKey;
89  LONG status;
90  DWORD dwType;
91  DWORD dwSize;
92  DWORD dwValue;
93  status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY,
94  &hKey);
95 
96  if (status != ERROR_SUCCESS)
97  {
98  WLog_DBG(TAG, "Error opening RegKey: status=0x%08lX", status);
99 
100  if (status == ERROR_ACCESS_DENIED)
101  WLog_DBG(TAG, "access denied. Do you have admin privleges?");
102 
103  return FALSE;
104  }
105 
106  dwSize = sizeof(DWORD);
107  status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), NULL, &dwType, (BYTE*)&dwValue, &dwSize);
108 
109  if (status != ERROR_SUCCESS)
110  {
111  WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status);
112 
113  if (status == ERROR_ACCESS_DENIED)
114  WLog_DBG(TAG, "access denied. Do you have admin privleges?");
115 
116  return FALSE;
117  }
118 
119  if (dwValue ^ mode) // only if we want to change modes
120  {
121  dwValue = mode;
122  dwSize = sizeof(DWORD);
123  status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*)&dwValue, dwSize);
124 
125  if (status != ERROR_SUCCESS)
126  {
127  WLog_DBG(TAG, "Error writing registry key: %ld", status);
128 
129  if (status == ERROR_ACCESS_DENIED)
130  WLog_DBG(TAG, "access denied. Do you have admin privleges?");
131 
132  WLog_DBG(TAG, "");
133  return FALSE;
134  }
135  }
136 
137  return TRUE;
138 }
139 
140 void wf_mirror_driver_print_display_change_status(LONG status)
141 {
142  TCHAR disp_change[64];
143 
144  switch (status)
145  {
146  case DISP_CHANGE_SUCCESSFUL:
147  _tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
148  break;
149 
150  case DISP_CHANGE_BADDUALVIEW:
151  _tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
152  break;
153 
154  case DISP_CHANGE_BADFLAGS:
155  _tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
156  break;
157 
158  case DISP_CHANGE_BADMODE:
159  _tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
160  break;
161 
162  case DISP_CHANGE_BADPARAM:
163  _tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM"));
164  break;
165 
166  case DISP_CHANGE_FAILED:
167  _tcscpy(disp_change, _T("DISP_CHANGE_FAILED"));
168  break;
169 
170  case DISP_CHANGE_NOTUPDATED:
171  _tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED"));
172  break;
173 
174  case DISP_CHANGE_RESTART:
175  _tcscpy(disp_change, _T("DISP_CHANGE_RESTART"));
176  break;
177 
178  default:
179  _tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN"));
180  break;
181  }
182 
183  if (status != DISP_CHANGE_SUCCESSFUL)
184  WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status);
185  else
186  WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status);
187 }
188 
196 BOOL wf_mirror_driver_update(wfInfo* wfi, int mode)
197 {
198  BOOL status;
199  DWORD* extHdr;
200  WORD drvExtraSaved;
201  DEVMODE* deviceMode;
202  LONG disp_change_status;
203  DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
204 
205  if ((mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD))
206  {
207  WLog_DBG(TAG, "Invalid mirror mode!");
208  return FALSE;
209  }
210 
211  deviceMode = (DEVMODE*)malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
212 
213  if (!deviceMode)
214  return FALSE;
215 
216  deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
217  extHdr = (DWORD*)((BYTE*)&deviceMode + sizeof(DEVMODE));
218  extHdr[0] = dmf_devmodewext_magic_sig;
219  extHdr[1] = 0;
220  drvExtraSaved = deviceMode->dmDriverExtra;
221  memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
222  deviceMode->dmSize = sizeof(DEVMODE);
223  deviceMode->dmDriverExtra = drvExtraSaved;
224 
225  if (mode == MIRROR_LOAD)
226  {
227  wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
228  wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
229  deviceMode->dmPelsWidth = wfi->virtscreen_width;
230  deviceMode->dmPelsHeight = wfi->virtscreen_height;
231  deviceMode->dmBitsPerPel = wfi->bitsPerPixel;
232  deviceMode->dmPosition.x = wfi->servscreen_xoffset;
233  deviceMode->dmPosition.y = wfi->servscreen_yoffset;
234  }
235 
236  deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
237  _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName));
238  disp_change_status =
239  ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
240  status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
241 
242  if (!status)
243  wf_mirror_driver_print_display_change_status(disp_change_status);
244 
245  return status;
246 }
247 
248 BOOL wf_mirror_driver_map_memory(wfInfo* wfi)
249 {
250  int status;
251  wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL);
252 
253  if (wfi->driverDC == NULL)
254  {
255  WLog_ERR(TAG, "Could not create device driver context!");
256  {
257  LPVOID lpMsgBuf;
258  DWORD dw = GetLastError();
259  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
260  FORMAT_MESSAGE_IGNORE_INSERTS,
261  NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0,
262  NULL);
263  // Display the error message and exit the process
264  WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw,
265  lpMsgBuf);
266  LocalFree(lpMsgBuf);
267  }
268  return FALSE;
269  }
270 
271  wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF));
272 
273  if (!wfi->changeBuffer)
274  return FALSE;
275 
276  status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF),
277  (LPSTR)wfi->changeBuffer);
278 
279  if (status <= 0)
280  {
281  WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status);
282  return FALSE;
283  }
284 
285  return TRUE;
286 }
287 
288 /* Unmap the shared memory and release the DC */
289 
290 BOOL wf_mirror_driver_cleanup(wfInfo* wfi)
291 {
292  int status;
293  status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF),
294  (LPSTR)wfi->changeBuffer, 0, 0);
295 
296  if (status <= 0)
297  {
298  WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status);
299  }
300 
301  if (wfi->driverDC != NULL)
302  {
303  status = DeleteDC(wfi->driverDC);
304 
305  if (status == 0)
306  {
307  WLog_ERR(TAG, "Failed to release DC!");
308  }
309  }
310 
311  free(wfi->changeBuffer);
312  return TRUE;
313 }
314 
315 BOOL wf_mirror_driver_activate(wfInfo* wfi)
316 {
317  if (!wfi->mirrorDriverActive)
318  {
319  WLog_DBG(TAG, "Activating Mirror Driver");
320 
321  if (wf_mirror_driver_find_display_device(wfi) == FALSE)
322  {
323  WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?");
324  return FALSE;
325  }
326 
327  if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE)
328  {
329  WLog_DBG(TAG, "Could not attach display device!");
330  return FALSE;
331  }
332 
333  if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE)
334  {
335  WLog_DBG(TAG, "could not update system with new display settings!");
336  return FALSE;
337  }
338 
339  if (wf_mirror_driver_map_memory(wfi) == FALSE)
340  {
341  WLog_DBG(TAG, "Unable to map memory for mirror driver!");
342  return FALSE;
343  }
344 
345  wfi->mirrorDriverActive = TRUE;
346  }
347 
348  return TRUE;
349 }
350 
351 void wf_mirror_driver_deactivate(wfInfo* wfi)
352 {
353  if (wfi->mirrorDriverActive)
354  {
355  WLog_DBG(TAG, "Deactivating Mirror Driver");
356  wf_mirror_driver_cleanup(wfi);
357  wf_mirror_driver_display_device_attach(wfi, 0);
358  wf_mirror_driver_update(wfi, MIRROR_UNLOAD);
359  wfi->mirrorDriverActive = FALSE;
360  }
361 }