20#include <freerdp/config.h>
24#include <freerdp/build-config.h>
26#include <winpr/tchar.h>
27#include <winpr/windows.h>
34#include <freerdp/log.h>
35#define TAG SERVER_TAG("windows")
37#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server"
39static wfInfo* wfInfoInstance =
nullptr;
40static int _IDcount = 0;
42BOOL wf_info_lock(wfInfo* wfi)
45 dRes = WaitForSingleObject(wfi->mutex, INFINITE);
57 WLog_ERR(TAG,
"wf_info_lock failed with 0x%08lX", GetLastError());
64BOOL wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds)
67 dRes = WaitForSingleObject(wfi->mutex, dwMilliseconds);
79 WLog_ERR(TAG,
"wf_info_try_lock failed with 0x%08lX", GetLastError());
86BOOL wf_info_unlock(wfInfo* wfi)
88 if (!ReleaseMutex(wfi->mutex))
90 WLog_ERR(TAG,
"wf_info_unlock failed with 0x%08lX", GetLastError());
100 wfi = (wfInfo*)calloc(1,
sizeof(wfInfo));
109 wfi->mutex = CreateMutex(
nullptr, FALSE,
nullptr);
111 if (wfi->mutex ==
nullptr)
113 WLog_ERR(TAG,
"CreateMutex error: %lu", GetLastError());
118 wfi->updateSemaphore = CreateSemaphore(
nullptr, 0, 32,
nullptr);
120 if (!wfi->updateSemaphore)
122 WLog_ERR(TAG,
"CreateSemaphore error: %lu", GetLastError());
123 (void)CloseHandle(wfi->mutex);
129 CreateThread(
nullptr, 0, wf_update_thread, wfi, CREATE_SUSPENDED,
nullptr);
131 if (!wfi->updateThread)
133 WLog_ERR(TAG,
"Failed to create update thread");
134 (void)CloseHandle(wfi->mutex);
135 (void)CloseHandle(wfi->updateSemaphore);
141 (freerdp_peer**)calloc(FREERDP_SERVER_WIN_INFO_MAXPEERS,
sizeof(freerdp_peer*));
145 WLog_ERR(TAG,
"Failed to allocate memory for peer");
146 (void)CloseHandle(wfi->mutex);
147 (void)CloseHandle(wfi->updateSemaphore);
148 (void)CloseHandle(wfi->updateThread);
154 wfi->framesPerSecond = FREERDP_SERVER_WIN_INFO_DEFAULT_FPS;
156 RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
158 if (status == ERROR_SUCCESS)
160 if (RegQueryValueEx(hKey, _T(
"FramesPerSecond"),
nullptr, &dwType, (BYTE*)&dwValue,
161 &dwSize) == ERROR_SUCCESS)
162 wfi->framesPerSecond = dwValue;
167 wfi->input_disabled = FALSE;
169 RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
171 if (status == ERROR_SUCCESS)
173 if (RegQueryValueEx(hKey, _T(
"DisableInput"),
nullptr, &dwType, (BYTE*)&dwValue,
174 &dwSize) == ERROR_SUCCESS)
177 wfi->input_disabled = TRUE;
187wfInfo* wf_info_get_instance()
189 if (wfInfoInstance ==
nullptr)
190 wfInfoInstance = wf_info_init();
192 return wfInfoInstance;
195BOOL wf_info_peer_register(wfInfo* wfi, wfPeerContext* context)
199 if (!wfi || !context)
202 if (!wf_info_lock(wfi))
205 if (wfi->peerCount == FREERDP_SERVER_WIN_INFO_MAXPEERS)
206 goto fail_peer_count;
210 if (!(context->updateEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
211 goto fail_update_event;
214 EnumDisplayMonitors(
nullptr,
nullptr, wf_info_monEnumCB, 0);
218 if (wfi->peerCount == 0)
219 if (wf_dxgi_init(wfi) != 0)
220 goto fail_driver_init;
224 if (!wf_mirror_driver_activate(wfi))
225 goto fail_driver_init;
230 for (
int i = 0; i < FREERDP_SERVER_WIN_INFO_MAXPEERS; ++i)
233 if (wfi->peers[i] ==
nullptr)
240 wfi->peers[peerId] = ((rdpContext*)context)->peer;
241 wfi->peers[peerId]->pId = peerId;
243 WLog_INFO(TAG,
"Registering Peer: id=%d #=%d", peerId, wfi->peerCount);
245 wfreerdp_server_peer_callback_event(peerId, FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_CONNECT);
248 (void)CloseHandle(context->updateEvent);
249 context->updateEvent =
nullptr;
252 context->socketClose = TRUE;
257void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context)
259 if (wf_info_lock(wfi))
262 peerId = ((rdpContext*)context)->peer->pId;
263 wfi->peers[peerId] =
nullptr;
265 (void)CloseHandle(context->updateEvent);
266 WLog_INFO(TAG,
"Unregistering Peer: id=%d, #=%d", peerId, wfi->peerCount);
269 if (wfi->peerCount == 0)
270 wf_dxgi_cleanup(wfi);
274 wfreerdp_server_peer_callback_event(peerId,
275 FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_DISCONNECT);
279BOOL wf_info_have_updates(wfInfo* wfi)
283 if (wfi->framesWaiting == 0)
288 if (wfi->nextUpdate == wfi->lastUpdate)
295void wf_info_update_changes(wfInfo* wfi)
298 wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000);
302 wfi->nextUpdate = buf->buffer->counter;
306void wf_info_find_invalid_region(wfInfo* wfi)
309 wf_dxgi_getInvalidRegion(&wfi->invalid);
314 for (ULONG i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF)
316 LPRECT lpR = &buf->buffer->pointrect[i].rect;
319 if ((lpR->left >= wfi->servscreen_xoffset) &&
320 (lpR->right <= (wfi->servscreen_xoffset + wfi->servscreen_width)) &&
321 (lpR->top >= wfi->servscreen_yoffset) &&
322 (lpR->bottom <= (wfi->servscreen_yoffset + wfi->servscreen_height)))
324 UnionRect(&wfi->invalid, &wfi->invalid, lpR);
334 if (wfi->invalid.left < 0)
335 wfi->invalid.left = 0;
337 if (wfi->invalid.top < 0)
338 wfi->invalid.top = 0;
340 if (wfi->invalid.right >= wfi->servscreen_width)
341 wfi->invalid.right = wfi->servscreen_width - 1;
343 if (wfi->invalid.bottom >= wfi->servscreen_height)
344 wfi->invalid.bottom = wfi->servscreen_height - 1;
350void wf_info_clear_invalid_region(wfInfo* wfi)
352 wfi->lastUpdate = wfi->nextUpdate;
353 SetRectEmpty(&wfi->invalid);
356void wf_info_invalidate_full_screen(wfInfo* wfi)
358 SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height);
361BOOL wf_info_have_invalid_region(wfInfo* wfi)
363 return IsRectEmpty(&wfi->invalid);
366void wf_info_getScreenData(wfInfo* wfi,
long* width,
long* height, BYTE** pBits,
int* pitch)
368 *width = (wfi->invalid.right - wfi->invalid.left);
369 *height = (wfi->invalid.bottom - wfi->invalid.top);
371 wf_dxgi_getPixelData(wfi, pBits, pitch, &wfi->invalid);
379 offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4);
380 *pBits = ((BYTE*)(changes->Userbuffer)) + offset;
381 *pitch = wfi->virtscreen_width * 4;
386BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,
390 wfi = wf_info_get_instance();
395 if (_IDcount == wfi->screenID)
397 wfi->servscreen_xoffset = lprcMonitor->left;
398 wfi->servscreen_yoffset = lprcMonitor->top;