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(nullptr, 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 =
108 RegQueryValueEx(hKey, _T("Attach.ToDesktop"), nullptr, &dwType, (BYTE*)&dwValue, &dwSize);
109
110 if (status != ERROR_SUCCESS)
111 {
112 WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status);
113
114 if (status == ERROR_ACCESS_DENIED)
115 WLog_DBG(TAG, "access denied. Do you have admin privileges?");
116
117 return FALSE;
118 }
119
120 if (dwValue ^ mode) // only if we want to change modes
121 {
122 dwValue = mode;
123 dwSize = sizeof(DWORD);
124 status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*)&dwValue, dwSize);
125
126 if (status != ERROR_SUCCESS)
127 {
128 WLog_DBG(TAG, "Error writing registry key: %ld", status);
129
130 if (status == ERROR_ACCESS_DENIED)
131 WLog_DBG(TAG, "access denied. Do you have admin privileges?");
132
133 WLog_DBG(TAG, "");
134 return FALSE;
135 }
136 }
137
138 return TRUE;
139}
140
141void wf_mirror_driver_print_display_change_status(LONG status)
142{
143 TCHAR disp_change[64];
144
145 switch (status)
146 {
147 case DISP_CHANGE_SUCCESSFUL:
148 _tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
149 break;
150
151 case DISP_CHANGE_BADDUALVIEW:
152 _tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
153 break;
154
155 case DISP_CHANGE_BADFLAGS:
156 _tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
157 break;
158
159 case DISP_CHANGE_BADMODE:
160 _tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
161 break;
162
163 case DISP_CHANGE_BADPARAM:
164 _tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM"));
165 break;
166
167 case DISP_CHANGE_FAILED:
168 _tcscpy(disp_change, _T("DISP_CHANGE_FAILED"));
169 break;
170
171 case DISP_CHANGE_NOTUPDATED:
172 _tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED"));
173 break;
174
175 case DISP_CHANGE_RESTART:
176 _tcscpy(disp_change, _T("DISP_CHANGE_RESTART"));
177 break;
178
179 default:
180 _tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN"));
181 break;
182 }
183
184 if (status != DISP_CHANGE_SUCCESSFUL)
185 WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status);
186 else
187 WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status);
188}
189
197BOOL wf_mirror_driver_update(wfInfo* wfi, int mode)
198{
199 BOOL status;
200 DWORD* extHdr;
201 WORD drvExtraSaved;
202 DEVMODE* deviceMode;
203 LONG disp_change_status;
204 DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
205
206 if ((mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD))
207 {
208 WLog_DBG(TAG, "Invalid mirror mode!");
209 return FALSE;
210 }
211
212 deviceMode = (DEVMODE*)malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
213
214 if (!deviceMode)
215 return FALSE;
216
217 deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
218 extHdr = (DWORD*)((BYTE*)&deviceMode + sizeof(DEVMODE));
219 extHdr[0] = dmf_devmodewext_magic_sig;
220 extHdr[1] = 0;
221 drvExtraSaved = deviceMode->dmDriverExtra;
222 memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
223 deviceMode->dmSize = sizeof(DEVMODE);
224 deviceMode->dmDriverExtra = drvExtraSaved;
225
226 if (mode == MIRROR_LOAD)
227 {
228 wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
229 wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
230 deviceMode->dmPelsWidth = wfi->virtscreen_width;
231 deviceMode->dmPelsHeight = wfi->virtscreen_height;
232 deviceMode->dmBitsPerPel = wfi->bitsPerPixel;
233 deviceMode->u.s2.dmPosition.x = wfi->servscreen_xoffset;
234 deviceMode->u.s2.dmPosition.y = wfi->servscreen_yoffset;
235 }
236
237 deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
238 _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName));
239 disp_change_status =
240 ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, nullptr, CDS_UPDATEREGISTRY, nullptr);
241 status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
242
243 if (!status)
244 wf_mirror_driver_print_display_change_status(disp_change_status);
245
246 return status;
247}
248
249BOOL wf_mirror_driver_map_memory(wfInfo* wfi)
250{
251 int status;
252 wfi->driverDC = CreateDC(wfi->deviceName, nullptr, nullptr, nullptr);
253
254 if (wfi->driverDC == nullptr)
255 {
256 WLog_ERR(TAG, "Could not create device driver context!");
257 {
258 LPVOID lpMsgBuf;
259 DWORD dw = GetLastError();
260 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
261 FORMAT_MESSAGE_IGNORE_INSERTS,
262 nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf,
263 0, nullptr);
264 // Display the error message and exit the process
265 WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw,
266 lpMsgBuf);
267 LocalFree(lpMsgBuf);
268 }
269 return FALSE;
270 }
271
272 wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF));
273
274 if (!wfi->changeBuffer)
275 return FALSE;
276
277 status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF),
278 (LPSTR)wfi->changeBuffer);
279
280 if (status <= 0)
281 {
282 WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status);
283 return FALSE;
284 }
285
286 return TRUE;
287}
288
289/* Unmap the shared memory and release the DC */
290
291BOOL wf_mirror_driver_cleanup(wfInfo* wfi)
292{
293 int status;
294 status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF),
295 (LPSTR)wfi->changeBuffer, 0, 0);
296
297 if (status <= 0)
298 {
299 WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status);
300 }
301
302 if (wfi->driverDC != nullptr)
303 {
304 status = DeleteDC(wfi->driverDC);
305
306 if (status == 0)
307 {
308 WLog_ERR(TAG, "Failed to release DC!");
309 }
310 }
311
312 free(wfi->changeBuffer);
313 return TRUE;
314}
315
316BOOL wf_mirror_driver_activate(wfInfo* wfi)
317{
318 if (!wfi->mirrorDriverActive)
319 {
320 WLog_DBG(TAG, "Activating Mirror Driver");
321
322 if (wf_mirror_driver_find_display_device(wfi) == FALSE)
323 {
324 WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?");
325 return FALSE;
326 }
327
328 if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE)
329 {
330 WLog_DBG(TAG, "Could not attach display device!");
331 return FALSE;
332 }
333
334 if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE)
335 {
336 WLog_DBG(TAG, "could not update system with new display settings!");
337 return FALSE;
338 }
339
340 if (wf_mirror_driver_map_memory(wfi) == FALSE)
341 {
342 WLog_DBG(TAG, "Unable to map memory for mirror driver!");
343 return FALSE;
344 }
345
346 wfi->mirrorDriverActive = TRUE;
347 }
348
349 return TRUE;
350}
351
352void wf_mirror_driver_deactivate(wfInfo* wfi)
353{
354 if (wfi->mirrorDriverActive)
355 {
356 WLog_DBG(TAG, "Deactivating Mirror Driver");
357 wf_mirror_driver_cleanup(wfi);
358 wf_mirror_driver_display_device_attach(wfi, 0);
359 wf_mirror_driver_update(wfi, MIRROR_UNLOAD);
360 wfi->mirrorDriverActive = FALSE;
361 }
362}