FreeRDP
wf_info.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdlib.h>
23 
24 #include <freerdp/build-config.h>
25 
26 #include <winpr/tchar.h>
27 #include <winpr/windows.h>
28 
29 #include "wf_info.h"
30 #include "wf_update.h"
31 #include "wf_mirage.h"
32 #include "wf_dxgi.h"
33 
34 #include <freerdp/log.h>
35 #define TAG SERVER_TAG("windows")
36 
37 #define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server"
38 
39 static wfInfo* wfInfoInstance = NULL;
40 static int _IDcount = 0;
41 
42 BOOL wf_info_lock(wfInfo* wfi)
43 {
44  DWORD dRes;
45  dRes = WaitForSingleObject(wfi->mutex, INFINITE);
46 
47  switch (dRes)
48  {
49  case WAIT_ABANDONED:
50  case WAIT_OBJECT_0:
51  return TRUE;
52 
53  case WAIT_TIMEOUT:
54  return FALSE;
55 
56  case WAIT_FAILED:
57  WLog_ERR(TAG, "wf_info_lock failed with 0x%08lX", GetLastError());
58  return FALSE;
59  }
60 
61  return FALSE;
62 }
63 
64 BOOL wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds)
65 {
66  DWORD dRes;
67  dRes = WaitForSingleObject(wfi->mutex, dwMilliseconds);
68 
69  switch (dRes)
70  {
71  case WAIT_ABANDONED:
72  case WAIT_OBJECT_0:
73  return TRUE;
74 
75  case WAIT_TIMEOUT:
76  return FALSE;
77 
78  case WAIT_FAILED:
79  WLog_ERR(TAG, "wf_info_try_lock failed with 0x%08lX", GetLastError());
80  return FALSE;
81  }
82 
83  return FALSE;
84 }
85 
86 BOOL wf_info_unlock(wfInfo* wfi)
87 {
88  if (!ReleaseMutex(wfi->mutex))
89  {
90  WLog_ERR(TAG, "wf_info_unlock failed with 0x%08lX", GetLastError());
91  return FALSE;
92  }
93 
94  return TRUE;
95 }
96 
97 wfInfo* wf_info_init()
98 {
99  wfInfo* wfi;
100  wfi = (wfInfo*)calloc(1, sizeof(wfInfo));
101 
102  if (wfi != NULL)
103  {
104  HKEY hKey;
105  LONG status;
106  DWORD dwType;
107  DWORD dwSize;
108  DWORD dwValue;
109  wfi->mutex = CreateMutex(NULL, FALSE, NULL);
110 
111  if (wfi->mutex == NULL)
112  {
113  WLog_ERR(TAG, "CreateMutex error: %lu", GetLastError());
114  free(wfi);
115  return NULL;
116  }
117 
118  wfi->updateSemaphore = CreateSemaphore(NULL, 0, 32, NULL);
119 
120  if (!wfi->updateSemaphore)
121  {
122  WLog_ERR(TAG, "CreateSemaphore error: %lu", GetLastError());
123  (void)CloseHandle(wfi->mutex);
124  free(wfi);
125  return NULL;
126  }
127 
128  wfi->updateThread = CreateThread(NULL, 0, wf_update_thread, wfi, CREATE_SUSPENDED, NULL);
129 
130  if (!wfi->updateThread)
131  {
132  WLog_ERR(TAG, "Failed to create update thread");
133  (void)CloseHandle(wfi->mutex);
134  (void)CloseHandle(wfi->updateSemaphore);
135  free(wfi);
136  return NULL;
137  }
138 
139  wfi->peers =
140  (freerdp_peer**)calloc(FREERDP_SERVER_WIN_INFO_MAXPEERS, sizeof(freerdp_peer*));
141 
142  if (!wfi->peers)
143  {
144  WLog_ERR(TAG, "Failed to allocate memory for peer");
145  (void)CloseHandle(wfi->mutex);
146  (void)CloseHandle(wfi->updateSemaphore);
147  (void)CloseHandle(wfi->updateThread);
148  free(wfi);
149  return NULL;
150  }
151 
152  // Set FPS
153  wfi->framesPerSecond = FREERDP_SERVER_WIN_INFO_DEFAULT_FPS;
154  status =
155  RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
156 
157  if (status == ERROR_SUCCESS)
158  {
159  if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*)&dwValue,
160  &dwSize) == ERROR_SUCCESS)
161  wfi->framesPerSecond = dwValue;
162  }
163 
164  RegCloseKey(hKey);
165  // Set input toggle
166  wfi->input_disabled = FALSE;
167  status =
168  RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
169 
170  if (status == ERROR_SUCCESS)
171  {
172  if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*)&dwValue,
173  &dwSize) == ERROR_SUCCESS)
174  {
175  if (dwValue != 0)
176  wfi->input_disabled = TRUE;
177  }
178  }
179 
180  RegCloseKey(hKey);
181  }
182 
183  return wfi;
184 }
185 
186 wfInfo* wf_info_get_instance()
187 {
188  if (wfInfoInstance == NULL)
189  wfInfoInstance = wf_info_init();
190 
191  return wfInfoInstance;
192 }
193 
194 BOOL wf_info_peer_register(wfInfo* wfi, wfPeerContext* context)
195 {
196  int peerId = 0;
197 
198  if (!wfi || !context)
199  return FALSE;
200 
201  if (!wf_info_lock(wfi))
202  return FALSE;
203 
204  if (wfi->peerCount == FREERDP_SERVER_WIN_INFO_MAXPEERS)
205  goto fail_peer_count;
206 
207  context->info = wfi;
208 
209  if (!(context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
210  goto fail_update_event;
211 
212  // get the offset of the top left corner of selected screen
213  EnumDisplayMonitors(NULL, NULL, wf_info_monEnumCB, 0);
214  _IDcount = 0;
215 #ifdef WITH_DXGI_1_2
216 
217  if (wfi->peerCount == 0)
218  if (wf_dxgi_init(wfi) != 0)
219  goto fail_driver_init;
220 
221 #else
222 
223  if (!wf_mirror_driver_activate(wfi))
224  goto fail_driver_init;
225 
226 #endif
227 
228  // look through the array of peers until an empty slot
229  for (int i = 0; i < FREERDP_SERVER_WIN_INFO_MAXPEERS; ++i)
230  {
231  // empty index will be our peer id
232  if (wfi->peers[i] == NULL)
233  {
234  peerId = i;
235  break;
236  }
237  }
238 
239  wfi->peers[peerId] = ((rdpContext*)context)->peer;
240  wfi->peers[peerId]->pId = peerId;
241  wfi->peerCount++;
242  WLog_INFO(TAG, "Registering Peer: id=%d #=%d", peerId, wfi->peerCount);
243  wf_info_unlock(wfi);
244  wfreerdp_server_peer_callback_event(peerId, FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_CONNECT);
245  return TRUE;
246 fail_driver_init:
247  (void)CloseHandle(context->updateEvent);
248  context->updateEvent = NULL;
249 fail_update_event:
250 fail_peer_count:
251  context->socketClose = TRUE;
252  wf_info_unlock(wfi);
253  return FALSE;
254 }
255 
256 void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context)
257 {
258  if (wf_info_lock(wfi))
259  {
260  int peerId;
261  peerId = ((rdpContext*)context)->peer->pId;
262  wfi->peers[peerId] = NULL;
263  wfi->peerCount--;
264  (void)CloseHandle(context->updateEvent);
265  WLog_INFO(TAG, "Unregistering Peer: id=%d, #=%d", peerId, wfi->peerCount);
266 #ifdef WITH_DXGI_1_2
267 
268  if (wfi->peerCount == 0)
269  wf_dxgi_cleanup(wfi);
270 
271 #endif
272  wf_info_unlock(wfi);
273  wfreerdp_server_peer_callback_event(peerId,
274  FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_DISCONNECT);
275  }
276 }
277 
278 BOOL wf_info_have_updates(wfInfo* wfi)
279 {
280 #ifdef WITH_DXGI_1_2
281 
282  if (wfi->framesWaiting == 0)
283  return FALSE;
284 
285 #else
286 
287  if (wfi->nextUpdate == wfi->lastUpdate)
288  return FALSE;
289 
290 #endif
291  return TRUE;
292 }
293 
294 void wf_info_update_changes(wfInfo* wfi)
295 {
296 #ifdef WITH_DXGI_1_2
297  wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000);
298 #else
299  GETCHANGESBUF* buf;
300  buf = (GETCHANGESBUF*)wfi->changeBuffer;
301  wfi->nextUpdate = buf->buffer->counter;
302 #endif
303 }
304 
305 void wf_info_find_invalid_region(wfInfo* wfi)
306 {
307 #ifdef WITH_DXGI_1_2
308  wf_dxgi_getInvalidRegion(&wfi->invalid);
309 #else
310  GETCHANGESBUF* buf;
311  buf = (GETCHANGESBUF*)wfi->changeBuffer;
312 
313  for (ULONG i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF)
314  {
315  LPRECT lpR = &buf->buffer->pointrect[i].rect;
316 
317  // need to make sure we only get updates from the selected screen
318  if ((lpR->left >= wfi->servscreen_xoffset) &&
319  (lpR->right <= (wfi->servscreen_xoffset + wfi->servscreen_width)) &&
320  (lpR->top >= wfi->servscreen_yoffset) &&
321  (lpR->bottom <= (wfi->servscreen_yoffset + wfi->servscreen_height)))
322  {
323  UnionRect(&wfi->invalid, &wfi->invalid, lpR);
324  }
325  else
326  {
327  continue;
328  }
329  }
330 
331 #endif
332 
333  if (wfi->invalid.left < 0)
334  wfi->invalid.left = 0;
335 
336  if (wfi->invalid.top < 0)
337  wfi->invalid.top = 0;
338 
339  if (wfi->invalid.right >= wfi->servscreen_width)
340  wfi->invalid.right = wfi->servscreen_width - 1;
341 
342  if (wfi->invalid.bottom >= wfi->servscreen_height)
343  wfi->invalid.bottom = wfi->servscreen_height - 1;
344 
345  // WLog_DBG(TAG, "invalid region: (%"PRId32", %"PRId32"), (%"PRId32", %"PRId32")",
346  // wfi->invalid.left, wfi->invalid.top, wfi->invalid.right, wfi->invalid.bottom);
347 }
348 
349 void wf_info_clear_invalid_region(wfInfo* wfi)
350 {
351  wfi->lastUpdate = wfi->nextUpdate;
352  SetRectEmpty(&wfi->invalid);
353 }
354 
355 void wf_info_invalidate_full_screen(wfInfo* wfi)
356 {
357  SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height);
358 }
359 
360 BOOL wf_info_have_invalid_region(wfInfo* wfi)
361 {
362  return IsRectEmpty(&wfi->invalid);
363 }
364 
365 void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch)
366 {
367  *width = (wfi->invalid.right - wfi->invalid.left);
368  *height = (wfi->invalid.bottom - wfi->invalid.top);
369 #ifdef WITH_DXGI_1_2
370  wf_dxgi_getPixelData(wfi, pBits, pitch, &wfi->invalid);
371 #else
372  {
373  long offset;
374  GETCHANGESBUF* changes;
375  changes = (GETCHANGESBUF*)wfi->changeBuffer;
376  *width += 1;
377  *height += 1;
378  offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4);
379  *pBits = ((BYTE*)(changes->Userbuffer)) + offset;
380  *pitch = wfi->virtscreen_width * 4;
381  }
382 #endif
383 }
384 
385 BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,
386  LPARAM dwData)
387 {
388  wfInfo* wfi;
389  wfi = wf_info_get_instance();
390 
391  if (!wfi)
392  return FALSE;
393 
394  if (_IDcount == wfi->screenID)
395  {
396  wfi->servscreen_xoffset = lprcMonitor->left;
397  wfi->servscreen_yoffset = lprcMonitor->top;
398  }
399 
400  _IDcount++;
401  return TRUE;
402 }