FreeRDP
Loading...
Searching...
No Matches
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/*
31This function will iterate over the loaded display devices until it finds
32the mirror device we want to load. If found, it will then copy the registry
33key corresponding to the device to the wfi and returns TRUE. Otherwise
34the function returns FALSE.
35*/
36BOOL 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
86BOOL 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 privileges?");
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 privileges?");
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 privileges?");
131
132 WLog_DBG(TAG, "");
133 return FALSE;
134 }
135 }
136
137 return TRUE;
138}
139
140void 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
196BOOL 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->u.s2.dmPosition.x = wfi->servscreen_xoffset;
233 deviceMode->u.s2.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
248BOOL 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
290BOOL 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
315BOOL 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
351void 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}