FreeRDP
Loading...
Searching...
No Matches
plugin_services.c File Reference
#include <freerdp/config.h>
#include <stddef.h>
#include <winpr/assert.h>
#include <winpr/error.h>
#include <winpr/synch.h>
#include <winpr/wlog.h>
#include <freerdp/log.h>
#include <freerdp/wts_services.h>
#include "plugin_services.h"

Go to the source code of this file.

Macros

#define TAG   FREERDP_TAG("core.services")
 

Functions

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 is detached
 
static HRESULT WINPR_COM_CALL CWindowChangedRelay_OnWindowChanged (IWTSWindowChangedCallback *This, const WTS_WINDOW_INFO *windowInfo)
 
static void CWindowChangedRelay_free (wComBase *object)
 
static WINPR_ATTR_NODISCARD CWindowChangedRelay * CWindowChangedRelay_new (CPluginServiceProvider *sp)
 
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
 
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
 
static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetWindowInfo (IWTSWindowInfoService *This, UINT64 remoteHwnd, WTS_WINDOW_INFO *windowInfo)
 
static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetProcessId (IWTSWindowInfoService *This, DWORD *processId)
 
static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetRdpSessionType (IWTSWindowInfoService *This, UINT32 *sessionType)
 
static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_SubscribeWindowChanged (IWTSWindowInfoService *This, UINT64 remoteHwnd, IWTSWindowChangedCallback *callback)
 
static HRESULT unsubscribe (CWindowInfoServiceProxy *p)
 
static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_UnsubscribeWindowChanged (IWTSWindowInfoService *This)
 
static void CWindowInfoServiceProxy_free (wComBase *object)
 
static WINPR_ATTR_NODISCARD CWindowInfoServiceProxy * CWindowInfoServiceProxy_new (CPluginServiceProvider *sp)
 
static HRESULT WINPR_COM_CALL CPluginServiceProvider_GetService (IWTSPluginServiceProvider *This, GUID ServiceId, wIUnknown **ppunkObject)
 
static void CPluginServiceProvider_free (wComBase *object)
 
IWTSPluginServiceProvider * plugin_services_new (rdpContext *context)
 the context's IWTSPluginServiceProvider (rdpContext::pluginServiceProvider), one reference for the caller
 
void plugin_services_detach (IWTSPluginServiceProvider *provider)
 cuts the provider from the context's client services, before the client frees them (ContextFree): the shared window change subscription is dropped, and the services handed out then answer E_UNEXPECTED. Channels and plugins may still hold them.
 

Variables

static const IWTSWindowChangedCallbackVtbl CWindowChangedRelay_vtbl
 
static const IWTSWindowInfoServiceVtbl CWindowInfoServiceProxy_vtbl
 
static const IWTSPluginServiceProviderVtbl CPluginServiceProvider_vtbl
 

Detailed Description

rdpContext::pluginServiceProvider: GetService() as Microsoft's clients answer it, on top of the services the client put in the context.

Microsoft's GetService(RDCLIENT_WINDOW_INFO_SERVICE) creates a new IWTSWindowInfoService on each call, with one change subscriber per object (UnsubscribeWindowChanged() says nobody's). The client implements a single object with these rules; each caller gets a proxy here, and the proxies' subscriptions share one subscription to the client's object, made while at least one proxy is subscribed.

Locking: lock protects the context pointer and the subscriber list, and is never held while calling out. subscribeLock serializes the calls to the client's Subscribe/Unsubscribe (which Microsoft's client runs synchronously on its core thread); change notifications don't take it, so a client may notify from any thread while subscribing.

Definition in file plugin_services.c.

Macro Definition Documentation

◆ TAG

#define TAG   FREERDP_TAG("core.services")

FreeRDP: A Remote Desktop Protocol Implementation Services for virtual channel plugins

Copyright 2026 David Fort conta.nosp@m.ct@h.nosp@m.arden.nosp@m.ing-.nosp@m.consu.nosp@m.ltin.nosp@m.g.com

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Definition at line 34 of file plugin_services.c.

Function Documentation

◆ client_window_info()

static WINPR_ATTR_NODISCARD IWTSWindowInfoService * client_window_info ( CPluginServiceProvider *  sp)
static

the client's window info service, a reference for the caller; nullptr if it has none or the provider is detached

Definition at line 88 of file plugin_services.c.

89{
90 IWTSWindowInfoService* svc = nullptr;
91 EnterCriticalSection(&sp->lock);
92 if (sp->context && sp->context->windowInfoService)
93 {
94 svc = sp->context->windowInfoService;
95 WINPR_COM_ADDREF(svc);
96 }
97 LeaveCriticalSection(&sp->lock);
98 return svc;
99}

Referenced by shared_subscribe().

Here is the caller graph for this function:

◆ CPluginServiceProvider_free()

static void CPluginServiceProvider_free ( wComBase *  object)
static

Definition at line 435 of file plugin_services.c.

436{
437 CPluginServiceProvider* sp = (CPluginServiceProvider*)object;
438 /* subscribed proxies and the relay hold references: nothing is left here */
439 WINPR_ASSERT(!sp->subscribed);
440 WINPR_ASSERT(!sp->subscribers);
441 DeleteCriticalSection(&sp->subscribeLock);
442 DeleteCriticalSection(&sp->lock);
443 free(sp);
444}

◆ CPluginServiceProvider_GetService()

static HRESULT WINPR_COM_CALL CPluginServiceProvider_GetService ( IWTSPluginServiceProvider *  This,
GUID  ServiceId,
wIUnknown **  ppunkObject 
)
static

Definition at line 383 of file plugin_services.c.

386{
387 CPluginServiceProvider* sp = (CPluginServiceProvider*)This;
388 if (!ppunkObject)
389 return E_POINTER;
390 *ppunkObject = nullptr;
391
392 HRESULT hr = E_NOINTERFACE;
393 if (winpr_com_guid_equal(&ServiceId, &RDCLIENT_WINDOW_INFO_SERVICE))
394 {
396 if (svc)
397 {
398 WINPR_COM_RELEASE(svc);
399 /* a new object for each caller, as Microsoft's client does */
400 CWindowInfoServiceProxy* p = CWindowInfoServiceProxy_new(sp);
401 if (p)
402 {
403 *ppunkObject = (wIUnknown*)p;
404 hr = S_OK;
405 }
406 else
407 hr = E_OUTOFMEMORY;
408 }
409 }
410 else if (winpr_com_guid_equal(&ServiceId, &RDCLIENT_BITMAP_RENDER_SERVICE))
411 {
412 /* stateless: every renderer comes from GetMappedRenderer, the client's object is
413 * shared */
414 EnterCriticalSection(&sp->lock);
415 if (sp->context && sp->context->bitmapRenderService)
416 {
417 IWTSBitmapRenderService* svc = sp->context->bitmapRenderService;
418 WINPR_COM_ADDREF(svc);
419 *ppunkObject = (wIUnknown*)svc;
420 hr = S_OK;
421 }
422 LeaveCriticalSection(&sp->lock);
423 }
424
425 WLog_DBG(TAG, "GetService(" WINPR_COM_GUID_FMT ") -> 0x%08" PRIX32,
426 WINPR_COM_GUID_ARGS(&ServiceId), (UINT32)hr);
427 return hr;
428}
#define WINPR_COM_GUID_FMT
printf a GUID as {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}: WLog_DBG(TAG, "id=" WINPR_COM_GUID_FMT,...
Definition com.h:137
static BOOL winpr_com_guid_equal(const GUID *a, const GUID *b)
IsEqualGUID.
Definition com.h:130
IUnknown, C form.
Definition com.h:111
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 ...
#define TAG

◆ CWindowChangedRelay_free()

static void CWindowChangedRelay_free ( wComBase *  object)
static

Definition at line 146 of file plugin_services.c.

147{
148 CWindowChangedRelay* relay = (CWindowChangedRelay*)object;
149 winpr_com_base_release(&relay->provider->com);
150 free(relay);
151}
WINPR_API ULONG winpr_com_base_release(wComBase *object)
Release of an object starting with a wComBase: calls its Free at 0.
Definition com.c:51

◆ CWindowChangedRelay_new()

static WINPR_ATTR_NODISCARD CWindowChangedRelay * CWindowChangedRelay_new ( CPluginServiceProvider *  sp)
static

Definition at line 154 of file plugin_services.c.

155{
156 CWindowChangedRelay* relay = calloc(1, sizeof(*relay));
157 if (!relay)
158 return nullptr;
159 winpr_com_base_init(&relay->com, "CWindowChangedRelay", &CWindowChangedRelay_vtbl.iunknown,
160 CWindowChangedRelay_free);
161 winpr_com_base_add_ref(&sp->com);
162 relay->provider = sp;
163 return relay;
164}
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.
Definition com.c:30
WINPR_API ULONG winpr_com_base_add_ref(wComBase *object)
AddRef of an object starting with a wComBase.
Definition com.c:43

◆ CWindowChangedRelay_OnWindowChanged()

static HRESULT WINPR_COM_CALL CWindowChangedRelay_OnWindowChanged ( IWTSWindowChangedCallback *  This,
const WTS_WINDOW_INFO *  windowInfo 
)
static

Definition at line 105 of file plugin_services.c.

107{
108 CWindowChangedRelay* relay = (CWindowChangedRelay*)This;
109 CPluginServiceProvider* sp = relay->provider;
110
111 /* the callbacks are called without the lock: they may call the service back */
112 size_t count = 0;
113 EnterCriticalSection(&sp->lock);
114 for (CWindowInfoServiceProxy* p = sp->subscribers; p; p = p->next)
115 count++;
116 IWTSWindowChangedCallback** callbacks =
117 count ? (IWTSWindowChangedCallback**)calloc(count, sizeof(IWTSWindowChangedCallback*))
118 : nullptr;
119 if (callbacks)
120 {
121 size_t i = 0;
122 for (CWindowInfoServiceProxy* p = sp->subscribers; p; p = p->next)
123 {
124 WINPR_COM_ADDREF(p->callback);
125 callbacks[i++] = p->callback;
126 }
127 }
128 LeaveCriticalSection(&sp->lock);
129 if (count && !callbacks)
130 return E_OUTOFMEMORY;
131
132 for (size_t i = 0; i < count; i++)
133 {
134 (void)callbacks[i]->lpVtbl->OnWindowChanged(callbacks[i], windowInfo);
135 WINPR_COM_RELEASE(callbacks[i]);
136 }
137 free((void*)callbacks);
138 return S_OK;
139}

◆ CWindowInfoServiceProxy_free()

static void CWindowInfoServiceProxy_free ( wComBase *  object)
static

Definition at line 357 of file plugin_services.c.

358{
359 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)object;
360 /* released while subscribed: the subscription goes with it */
361 (void)unsubscribe(p);
362 winpr_com_base_release(&p->provider->com);
363 free(p);
364}

◆ CWindowInfoServiceProxy_GetProcessId()

static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetProcessId ( IWTSWindowInfoService *  This,
DWORD *  processId 
)
static

Definition at line 260 of file plugin_services.c.

262{
263 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
264 IWTSWindowInfoService* svc = client_window_info(p->provider);
265 if (!svc)
266 return E_UNEXPECTED;
267 const HRESULT hr = svc->lpVtbl->GetProcessId(svc, processId);
268 WINPR_COM_RELEASE(svc);
269 return hr;
270}

◆ CWindowInfoServiceProxy_GetRdpSessionType()

static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetRdpSessionType ( IWTSWindowInfoService *  This,
UINT32 *  sessionType 
)
static

Definition at line 272 of file plugin_services.c.

274{
275 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
276 IWTSWindowInfoService* svc = client_window_info(p->provider);
277 if (!svc)
278 return E_UNEXPECTED;
279 const HRESULT hr = svc->lpVtbl->GetRdpSessionType(svc, sessionType);
280 WINPR_COM_RELEASE(svc);
281 return hr;
282}

◆ CWindowInfoServiceProxy_GetWindowInfo()

static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_GetWindowInfo ( IWTSWindowInfoService *  This,
UINT64  remoteHwnd,
WTS_WINDOW_INFO *  windowInfo 
)
static

Definition at line 247 of file plugin_services.c.

250{
251 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
252 IWTSWindowInfoService* svc = client_window_info(p->provider);
253 if (!svc)
254 return E_UNEXPECTED;
255 const HRESULT hr = svc->lpVtbl->GetWindowInfo(svc, remoteHwnd, windowInfo);
256 WINPR_COM_RELEASE(svc);
257 return hr;
258}

◆ CWindowInfoServiceProxy_new()

static WINPR_ATTR_NODISCARD CWindowInfoServiceProxy * CWindowInfoServiceProxy_new ( CPluginServiceProvider *  sp)
static

Definition at line 367 of file plugin_services.c.

368{
369 CWindowInfoServiceProxy* p = calloc(1, sizeof(*p));
370 if (!p)
371 return nullptr;
372 winpr_com_base_init(&p->com, "CWindowInfoServiceProxy", &CWindowInfoServiceProxy_vtbl.iunknown,
373 CWindowInfoServiceProxy_free);
374 winpr_com_base_add_ref(&sp->com);
375 p->provider = sp;
376 return p;
377}

◆ CWindowInfoServiceProxy_SubscribeWindowChanged()

static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_SubscribeWindowChanged ( IWTSWindowInfoService *  This,
UINT64  remoteHwnd,
IWTSWindowChangedCallback *  callback 
)
static

Definition at line 284 of file plugin_services.c.

286{
287 CWindowInfoServiceProxy* p = (CWindowInfoServiceProxy*)This;
288 CPluginServiceProvider* sp = p->provider;
289 if (!callback)
290 return E_POINTER;
291
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);
297
298 HRESULT hr = S_OK;
299 if (already)
300 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
301 else if (detached)
302 hr = E_UNEXPECTED;
303 else
304 hr = shared_subscribe(sp, remoteHwnd);
305
306 if (SUCCEEDED(hr))
307 {
308 WINPR_COM_ADDREF(callback);
309 EnterCriticalSection(&sp->lock);
310 p->callback = callback;
311 p->next = sp->subscribers;
312 sp->subscribers = p;
313 LeaveCriticalSection(&sp->lock);
314 }
315 LeaveCriticalSection(&sp->subscribeLock);
316 return hr;
317}
static WINPR_ATTR_NODISCARD HRESULT shared_subscribe(CPluginServiceProvider *sp, UINT64 remoteHwnd)
subscribes to the client's service; subscribeLock held

◆ CWindowInfoServiceProxy_UnsubscribeWindowChanged()

static HRESULT WINPR_COM_CALL CWindowInfoServiceProxy_UnsubscribeWindowChanged ( IWTSWindowInfoService *  This)
static

Definition at line 343 of file plugin_services.c.

344{
345 return unsubscribe((CWindowInfoServiceProxy*)This);
346}

◆ plugin_services_detach()

void plugin_services_detach ( IWTSPluginServiceProvider *  provider)

cuts the provider from the context's client services, before the client frees them (ContextFree): the shared window change subscription is dropped, and the services handed out then answer E_UNEXPECTED. Channels and plugins may still hold them.

Definition at line 494 of file plugin_services.c.

495{
496 CPluginServiceProvider* sp = (CPluginServiceProvider*)provider;
497 if (!sp)
498 return;
499
500 EnterCriticalSection(&sp->subscribeLock);
501 EnterCriticalSection(&sp->lock);
502 sp->context = nullptr;
503 LeaveCriticalSection(&sp->lock);
504 /* proxies stay subscribed (their Unsubscribe still answers S_OK), without notifications */
506 LeaveCriticalSection(&sp->subscribeLock);
507}
static void shared_unsubscribe(CPluginServiceProvider *sp)
ends the subscription to the client's service, if any; subscribeLock held

References shared_unsubscribe().

Here is the call graph for this function:

◆ plugin_services_new()

IWTSPluginServiceProvider * plugin_services_new ( rdpContext *  context)

the context's IWTSPluginServiceProvider (rdpContext::pluginServiceProvider), one reference for the caller

FreeRDP: A Remote Desktop Protocol Implementation Services for virtual channel plugins

Copyright 2026 David Fort conta.nosp@m.ct@h.nosp@m.arden.nosp@m.ing-.nosp@m.consu.nosp@m.ltin.nosp@m.g.com

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Definition at line 446 of file plugin_services.c.

447{
448 WINPR_ASSERT(context);
449
450 /* the rdp_context slots are ABI: 64 bit each, whatever the pointer size */
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);
455
456 /* the vtables have the flat layout of MIDL's: IUnknown's three entries, then the others */
457 WINPR_STATIC_ASSERT(offsetof(IWTSPluginServiceProviderVtbl, GetService) == 3 * sizeof(void*));
458 WINPR_STATIC_ASSERT(offsetof(IWTSBitmapRendererVtbl, Render) == 3 * sizeof(void*));
459 WINPR_STATIC_ASSERT(offsetof(IWTSBitmapRendererCallbackVtbl, OnTargetSizeChanged) ==
460 3 * sizeof(void*));
461 WINPR_STATIC_ASSERT(offsetof(IWTSBitmapRenderServiceVtbl, GetMappedRenderer) ==
462 3 * sizeof(void*));
463 WINPR_STATIC_ASSERT(offsetof(IWTSWindowChangedCallbackVtbl, OnWindowChanged) ==
464 3 * sizeof(void*));
465 WINPR_STATIC_ASSERT(offsetof(IWTSWindowInfoServiceVtbl, UnsubscribeWindowChanged) ==
466 7 * sizeof(void*));
467
468#if defined(_M_X64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
469 WINPR_STATIC_ASSERT(sizeof(WTS_WINDOW_INFO) == 40);
470 WINPR_STATIC_ASSERT(offsetof(WTS_WINDOW_INFO, viewWidth) == 0x10);
471 WINPR_STATIC_ASSERT(offsetof(WTS_WINDOW_INFO, scale) == 0x20);
472#endif
473
474 CPluginServiceProvider* sp = calloc(1, sizeof(*sp));
475 if (!sp)
476 return nullptr;
477 if (!InitializeCriticalSectionAndSpinCount(&sp->lock, 4000))
478 {
479 free(sp);
480 return nullptr;
481 }
482 if (!InitializeCriticalSectionAndSpinCount(&sp->subscribeLock, 4000))
483 {
484 DeleteCriticalSection(&sp->lock);
485 free(sp);
486 return nullptr;
487 }
488 winpr_com_base_init(&sp->com, "CPluginServiceProvider", &CPluginServiceProvider_vtbl.iunknown,
489 CPluginServiceProvider_free);
490 sp->context = context;
491 return (IWTSPluginServiceProvider*)sp;
492}
40 bytes on x64

References winpr_com_base_init().

Here is the call graph for this function:

◆ proxy_unlink()

static WINPR_ATTR_NODISCARD IWTSWindowChangedCallback * proxy_unlink ( CWindowInfoServiceProxy *  p,
BOOL *  last 
)
static

removes p from the subscribers; its callback is returned (the reference with it). subscribeLock held

Definition at line 223 of file plugin_services.c.

224{
225 CPluginServiceProvider* sp = p->provider;
226 EnterCriticalSection(&sp->lock);
227 IWTSWindowChangedCallback* callback = p->callback;
228 p->callback = nullptr;
229 for (CWindowInfoServiceProxy** it = &sp->subscribers; *it; it = &(*it)->next)
230 {
231 if (*it == p)
232 {
233 *it = p->next;
234 break;
235 }
236 }
237 p->next = nullptr;
238 *last = (sp->subscribers == nullptr);
239 LeaveCriticalSection(&sp->lock);
240 return callback;
241}

◆ shared_subscribe()

static WINPR_ATTR_NODISCARD HRESULT shared_subscribe ( CPluginServiceProvider *  sp,
UINT64  remoteHwnd 
)
static

subscribes to the client's service; subscribeLock held

Definition at line 170 of file plugin_services.c.

171{
172 if (sp->subscribed)
173 return S_OK;
174
176 if (!svc)
177 return E_UNEXPECTED;
178
179 CWindowChangedRelay* relay = CWindowChangedRelay_new(sp);
180 if (!relay)
181 {
182 WINPR_COM_RELEASE(svc);
183 return E_OUTOFMEMORY;
184 }
185
186 /* Microsoft's client ignores remoteHwnd: the first subscriber's is as good as any */
187 const HRESULT hr =
188 svc->lpVtbl->SubscribeWindowChanged(svc, remoteHwnd, (IWTSWindowChangedCallback*)relay);
189 if (FAILED(hr))
190 {
191 WLog_WARN(TAG, "the client's SubscribeWindowChanged failed: 0x%08" PRIX32, (UINT32)hr);
192 winpr_com_base_release(&relay->com);
193 WINPR_COM_RELEASE(svc);
194 return hr;
195 }
196 sp->subscribed = svc;
197 sp->relay = relay;
198 return S_OK;
199}

References client_window_info(), TAG, and winpr_com_base_release().

Here is the call graph for this function:

◆ shared_unsubscribe()

static void shared_unsubscribe ( CPluginServiceProvider *  sp)
static

ends the subscription to the client's service, if any; subscribeLock held

Definition at line 202 of file plugin_services.c.

203{
204 IWTSWindowInfoService* svc = sp->subscribed;
205 CWindowChangedRelay* relay = sp->relay;
206 sp->subscribed = nullptr;
207 sp->relay = nullptr;
208 if (svc)
209 {
210 const HRESULT hr = svc->lpVtbl->UnsubscribeWindowChanged(svc);
211 if (FAILED(hr))
212 WLog_WARN(TAG, "the client's UnsubscribeWindowChanged failed: 0x%08" PRIX32,
213 (UINT32)hr);
214 WINPR_COM_RELEASE(svc);
215 }
216 if (relay)
217 winpr_com_base_release(&relay->com);
218}

References TAG, and winpr_com_base_release().

Referenced by plugin_services_detach().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ unsubscribe()

static HRESULT unsubscribe ( CWindowInfoServiceProxy *  p)
static

Definition at line 319 of file plugin_services.c.

320{
321 CPluginServiceProvider* sp = p->provider;
322
323 EnterCriticalSection(&sp->subscribeLock);
324 EnterCriticalSection(&sp->lock);
325 const BOOL subscribed = (p->callback != nullptr);
326 LeaveCriticalSection(&sp->lock);
327
328 HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
329 if (subscribed)
330 {
331 BOOL last = FALSE;
332 IWTSWindowChangedCallback* callback = proxy_unlink(p, &last);
333 if (last)
335 WINPR_COM_RELEASE(callback);
336 hr = S_OK;
337 }
338 LeaveCriticalSection(&sp->subscribeLock);
339 return hr;
340}
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

Variable Documentation

◆ CPluginServiceProvider_vtbl

const IWTSPluginServiceProviderVtbl CPluginServiceProvider_vtbl
static
Initial value:
= {
.iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CPluginServiceProvider),
.GetService = CPluginServiceProvider_GetService,
}
#define WINPR_COM_IUNKNOWN_ENTRIES(prefix)
the initializer of a wIUnknownVtbl from prefix_QueryInterface (the thunk above or the object's own),...
Definition com.h:241

Definition at line 430 of file plugin_services.c.

430 {
431 .iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CPluginServiceProvider),
432 .GetService = CPluginServiceProvider_GetService,
433};

◆ CWindowChangedRelay_vtbl

const IWTSWindowChangedCallbackVtbl CWindowChangedRelay_vtbl
static
Initial value:
= {
.iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CWindowChangedRelay),
.OnWindowChanged = CWindowChangedRelay_OnWindowChanged,
}

Definition at line 141 of file plugin_services.c.

141 {
142 .iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CWindowChangedRelay),
143 .OnWindowChanged = CWindowChangedRelay_OnWindowChanged,
144};

◆ CWindowInfoServiceProxy_vtbl

const IWTSWindowInfoServiceVtbl CWindowInfoServiceProxy_vtbl
static
Initial value:
= {
.iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CWindowInfoServiceProxy),
.GetWindowInfo = CWindowInfoServiceProxy_GetWindowInfo,
.GetProcessId = CWindowInfoServiceProxy_GetProcessId,
.GetRdpSessionType = CWindowInfoServiceProxy_GetRdpSessionType,
.SubscribeWindowChanged = CWindowInfoServiceProxy_SubscribeWindowChanged,
.UnsubscribeWindowChanged = CWindowInfoServiceProxy_UnsubscribeWindowChanged,
}

Definition at line 348 of file plugin_services.c.

348 {
349 .iunknown = WINPR_COM_IUNKNOWN_ENTRIES(CWindowInfoServiceProxy),
350 .GetWindowInfo = CWindowInfoServiceProxy_GetWindowInfo,
351 .GetProcessId = CWindowInfoServiceProxy_GetProcessId,
352 .GetRdpSessionType = CWindowInfoServiceProxy_GetRdpSessionType,
353 .SubscribeWindowChanged = CWindowInfoServiceProxy_SubscribeWindowChanged,
354 .UnsubscribeWindowChanged = CWindowInfoServiceProxy_UnsubscribeWindowChanged,
355};