20#include <freerdp/config.h>
24#include <winpr/assert.h>
25#include <winpr/error.h>
26#include <winpr/synch.h>
27#include <winpr/wlog.h>
29#include <freerdp/log.h>
32#include "plugin_services.h"
34#define TAG FREERDP_TAG("core.services")
51typedef struct s_plugin_services CPluginServiceProvider;
52typedef struct s_window_info_proxy CWindowInfoServiceProxy;
53typedef struct s_window_changed_relay CWindowChangedRelay;
55struct s_plugin_services
64 CWindowChangedRelay* relay;
65 CWindowInfoServiceProxy* subscribers;
68struct s_window_info_proxy
71 CPluginServiceProvider* provider;
73 CWindowInfoServiceProxy* next;
77struct s_window_changed_relay
80 CPluginServiceProvider* provider;
91 EnterCriticalSection(&sp->lock);
92 if (sp->context && sp->context->windowInfoService)
94 svc = sp->context->windowInfoService;
95 WINPR_COM_ADDREF(svc);
97 LeaveCriticalSection(&sp->lock);
108 CWindowChangedRelay* relay = (CWindowChangedRelay*)This;
109 CPluginServiceProvider* sp = relay->provider;
113 EnterCriticalSection(&sp->lock);
114 for (CWindowInfoServiceProxy* p = sp->subscribers; p; p = p->next)
122 for (CWindowInfoServiceProxy* p = sp->subscribers; p; p = p->next)
124 WINPR_COM_ADDREF(p->callback);
125 callbacks[i++] = p->callback;
128 LeaveCriticalSection(&sp->lock);
129 if (count && !callbacks)
130 return E_OUTOFMEMORY;
132 for (
size_t i = 0; i < count; i++)
134 (void)callbacks[i]->lpVtbl->OnWindowChanged(callbacks[i], windowInfo);
135 WINPR_COM_RELEASE(callbacks[i]);
137 free((
void*)callbacks);
143 .OnWindowChanged = CWindowChangedRelay_OnWindowChanged,
146static void CWindowChangedRelay_free(wComBase*
object)
148 CWindowChangedRelay* relay = (CWindowChangedRelay*)
object;
154static CWindowChangedRelay* CWindowChangedRelay_new(CPluginServiceProvider* sp)
156 CWindowChangedRelay* relay = calloc(1,
sizeof(*relay));
159 winpr_com_base_init(&relay->com,
"CWindowChangedRelay", &CWindowChangedRelay_vtbl.iunknown,
160 CWindowChangedRelay_free);
162 relay->provider = sp;
179 CWindowChangedRelay* relay = CWindowChangedRelay_new(sp);
182 WINPR_COM_RELEASE(svc);
183 return E_OUTOFMEMORY;
191 WLog_WARN(
TAG,
"the client's SubscribeWindowChanged failed: 0x%08" PRIX32, (UINT32)hr);
193 WINPR_COM_RELEASE(svc);
196 sp->subscribed = svc;
205 CWindowChangedRelay* relay = sp->relay;
206 sp->subscribed =
nullptr;
210 const HRESULT hr = svc->lpVtbl->UnsubscribeWindowChanged(svc);
212 WLog_WARN(
TAG,
"the client's UnsubscribeWindowChanged failed: 0x%08" PRIX32,
214 WINPR_COM_RELEASE(svc);
225 CPluginServiceProvider* sp = p->provider;
226 EnterCriticalSection(&sp->lock);
228 p->callback =
nullptr;
229 for (CWindowInfoServiceProxy** it = &sp->subscribers; *it; it = &(*it)->next)
238 *last = (sp->subscribers ==
nullptr);
239 LeaveCriticalSection(&sp->lock);
251 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
255 const HRESULT hr = svc->lpVtbl->GetWindowInfo(svc, remoteHwnd, windowInfo);
256 WINPR_COM_RELEASE(svc);
263 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
267 const HRESULT hr = svc->lpVtbl->GetProcessId(svc, processId);
268 WINPR_COM_RELEASE(svc);
275 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
279 const HRESULT hr = svc->lpVtbl->GetRdpSessionType(svc, sessionType);
280 WINPR_COM_RELEASE(svc);
284static HRESULT
WINPR_COM_CALL CWindowInfoServiceProxy_SubscribeWindowChanged(
287 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
288 CPluginServiceProvider* sp = p->provider;
292 EnterCriticalSection(&sp->subscribeLock);
293 EnterCriticalSection(&sp->lock);
294 const BOOL already = (p->callback !=
nullptr);
295 const BOOL detached = (sp->context ==
nullptr);
296 LeaveCriticalSection(&sp->lock);
300 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
308 WINPR_COM_ADDREF(callback);
309 EnterCriticalSection(&sp->lock);
310 p->callback = callback;
311 p->next = sp->subscribers;
313 LeaveCriticalSection(&sp->lock);
315 LeaveCriticalSection(&sp->subscribeLock);
319static HRESULT unsubscribe(CWindowInfoServiceProxy* p)
321 CPluginServiceProvider* sp = p->provider;
323 EnterCriticalSection(&sp->subscribeLock);
324 EnterCriticalSection(&sp->lock);
325 const BOOL subscribed = (p->callback !=
nullptr);
326 LeaveCriticalSection(&sp->lock);
328 HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
335 WINPR_COM_RELEASE(callback);
338 LeaveCriticalSection(&sp->subscribeLock);
345 return unsubscribe((CWindowInfoServiceProxy*)This);
350 .GetWindowInfo = CWindowInfoServiceProxy_GetWindowInfo,
351 .GetProcessId = CWindowInfoServiceProxy_GetProcessId,
352 .GetRdpSessionType = CWindowInfoServiceProxy_GetRdpSessionType,
353 .SubscribeWindowChanged = CWindowInfoServiceProxy_SubscribeWindowChanged,
354 .UnsubscribeWindowChanged = CWindowInfoServiceProxy_UnsubscribeWindowChanged,
357static void CWindowInfoServiceProxy_free(wComBase*
object)
359 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)
object;
361 (void)unsubscribe(p);
367static CWindowInfoServiceProxy* CWindowInfoServiceProxy_new(CPluginServiceProvider* sp)
369 CWindowInfoServiceProxy* p = calloc(1,
sizeof(*p));
372 winpr_com_base_init(&p->com,
"CWindowInfoServiceProxy", &CWindowInfoServiceProxy_vtbl.iunknown,
373 CWindowInfoServiceProxy_free);
387 CPluginServiceProvider* sp = (CPluginServiceProvider*)This;
390 *ppunkObject =
nullptr;
392 HRESULT hr = E_NOINTERFACE;
398 WINPR_COM_RELEASE(svc);
400 CWindowInfoServiceProxy* p = CWindowInfoServiceProxy_new(sp);
414 EnterCriticalSection(&sp->lock);
415 if (sp->context && sp->context->bitmapRenderService)
418 WINPR_COM_ADDREF(svc);
422 LeaveCriticalSection(&sp->lock);
426 WINPR_COM_GUID_ARGS(&ServiceId), (UINT32)hr);
432 .GetService = CPluginServiceProvider_GetService,
435static void CPluginServiceProvider_free(wComBase*
object)
437 CPluginServiceProvider* sp = (CPluginServiceProvider*)
object;
439 WINPR_ASSERT(!sp->subscribed);
440 WINPR_ASSERT(!sp->subscribers);
441 DeleteCriticalSection(&sp->subscribeLock);
442 DeleteCriticalSection(&sp->lock);
448 WINPR_ASSERT(context);
451 WINPR_STATIC_ASSERT(offsetof(rdpContext, windowInfoService) == 46ull * 8ull);
452 WINPR_STATIC_ASSERT(offsetof(rdpContext, bitmapRenderService) == 47ull * 8ull);
453 WINPR_STATIC_ASSERT(offsetof(rdpContext, pluginServiceProvider) == 48ull * 8ull);
454 WINPR_STATIC_ASSERT(offsetof(rdpContext, dump) == 64ull * 8ull);
468#if defined(_M_X64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
474 CPluginServiceProvider* sp = calloc(1,
sizeof(*sp));
477 if (!InitializeCriticalSectionAndSpinCount(&sp->lock, 4000))
482 if (!InitializeCriticalSectionAndSpinCount(&sp->subscribeLock, 4000))
484 DeleteCriticalSection(&sp->lock);
488 winpr_com_base_init(&sp->com,
"CPluginServiceProvider", &CPluginServiceProvider_vtbl.iunknown,
489 CPluginServiceProvider_free);
490 sp->context = context;
496 CPluginServiceProvider* sp = (CPluginServiceProvider*)provider;
500 EnterCriticalSection(&sp->subscribeLock);
501 EnterCriticalSection(&sp->lock);
502 sp->context =
nullptr;
503 LeaveCriticalSection(&sp->lock);
506 LeaveCriticalSection(&sp->subscribeLock);
#define WINPR_COM_GUID_FMT
printf a GUID as {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}: WLog_DBG(TAG, "id=" WINPR_COM_GUID_FMT,...
static BOOL winpr_com_guid_equal(const GUID *a, const GUID *b)
IsEqualGUID.
WINPR_API void winpr_com_base_init(wComBase *object, const char *className, const wIUnknownVtbl *vtbl, pfnwComBaseFree Free)
sets the vtable and the reference count to 1, the caller owns that first reference.
WINPR_API ULONG winpr_com_base_add_ref(wComBase *object)
AddRef of an object starting with a wComBase.
#define WINPR_COM_IUNKNOWN_THUNKS(prefix, iid)
WINPR_COM_REFCOUNT_THUNKS plus prefix_QueryInterface answering IUnknown and iid (a const IID*,...
#define WINPR_COM_IUNKNOWN_ENTRIES(prefix)
the initializer of a wIUnknownVtbl from prefix_QueryInterface (the thunk above or the object's own),...
#define WINPR_COM_CALL
the calling convention of COM methods (STDMETHODCALLTYPE)
WINPR_API ULONG winpr_com_base_release(wComBase *object)
Release of an object starting with a wComBase: calls its Free at 0.
static WINPR_ATTR_NODISCARD HRESULT shared_subscribe(CPluginServiceProvider *sp, UINT64 remoteHwnd)
subscribes to the client's service; subscribeLock held
static void shared_unsubscribe(CPluginServiceProvider *sp)
ends the subscription to the client's service, if any; subscribeLock held
IWTSPluginServiceProvider * plugin_services_new(rdpContext *context)
the context's IWTSPluginServiceProvider (rdpContext::pluginServiceProvider), one reference for the ca...
static WINPR_ATTR_NODISCARD IWTSWindowInfoService * client_window_info(CPluginServiceProvider *sp)
the client's window info service, a reference for the caller; nullptr if it has none or the provider ...
void plugin_services_detach(IWTSPluginServiceProvider *provider)
cuts the provider from the context's client services, before the client frees them (ContextFree): the...
static WINPR_ATTR_NODISCARD IWTSWindowChangedCallback * proxy_unlink(CWindowInfoServiceProxy *p, BOOL *last)
removes p from the subscribers; its callback is returned (the reference with it). subscribeLock held