ReactOS  0.4.10-dev-479-g13a3cf0
stubmanager.c
Go to the documentation of this file.
1 /*
2  * A stub manager is an object that controls interface stubs. It is
3  * identified by an OID (object identifier) and acts as the network
4  * identity of the object. There can be many stub managers in a
5  * process or apartment.
6  *
7  * Copyright 2002 Marcus Meissner
8  * Copyright 2004 Mike Hearn for CodeWeavers
9  * Copyright 2004 Robert Shearman (for CodeWeavers)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #define COBJMACROS
27 
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <limits.h>
31 
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "objbase.h"
36 #include "rpc.h"
37 
38 #include "wine/debug.h"
39 #include "wine/exception.h"
40 
41 #include "compobj_private.h"
42 
44 
45 
46 /* generates an ipid in the following format (similar to native version):
47  * Data1 = apartment-local ipid counter
48  * Data2 = apartment creator thread ID
49  * Data3 = process ID
50  * Data4 = random value
51  */
52 static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
53 {
54  HRESULT hr;
55  hr = UuidCreate(ipid);
56  if (FAILED(hr))
57  {
58  ERR("couldn't create IPID for stub manager %p\n", m);
59  UuidCreateNil(ipid);
60  return hr;
61  }
62 
63  ipid->Data1 = InterlockedIncrement(&m->apt->ipidc);
64  ipid->Data2 = (USHORT)m->apt->tid;
65  ipid->Data3 = (USHORT)GetCurrentProcessId();
66  return S_OK;
67 }
68 
69 /* registers a new interface stub COM object with the stub manager and returns registration record */
71  void *dest_context_data, MSHLFLAGS flags)
72 {
73  struct ifstub *stub;
74  HRESULT hr;
75 
76  TRACE("oid=%s, stubbuffer=%p, iid=%s, dest_context=%x\n", wine_dbgstr_longlong(m->oid), sb,
77  debugstr_guid(iid), dest_context);
78 
79  stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub));
80  if (!stub) return NULL;
81 
82  hr = IUnknown_QueryInterface(m->object, iid, (void **)&stub->iface);
83  if (hr != S_OK)
84  {
85  HeapFree(GetProcessHeap(), 0, stub);
86  return NULL;
87  }
88 
89  hr = RPC_CreateServerChannel(dest_context, dest_context_data, &stub->chan);
90  if (hr != S_OK)
91  {
92  IUnknown_Release(stub->iface);
93  HeapFree(GetProcessHeap(), 0, stub);
94  return NULL;
95  }
96 
97  stub->stubbuffer = sb;
98  if (sb) IRpcStubBuffer_AddRef(sb);
99 
100  stub->flags = flags;
101  stub->iid = *iid;
102 
103  /* FIXME: find a cleaner way of identifying that we are creating an ifstub
104  * for the remunknown interface */
105  if (flags & MSHLFLAGSP_REMUNKNOWN)
106  stub->ipid = m->oxid_info.ipidRemUnknown;
107  else
108  generate_ipid(m, &stub->ipid);
109 
111  list_add_head(&m->ifstubs, &stub->entry);
112  /* every normal marshal is counted so we don't allow more than we should */
113  if (flags & MSHLFLAGS_NORMAL) m->norm_refs++;
115 
116  TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
117 
118  return stub;
119 }
120 
122 {
123  TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid));
124 
125  list_remove(&ifstub->entry);
126 
127  if (!m->disconnected)
128  RPC_UnregisterInterface(&ifstub->iid, TRUE);
129 
130  if (ifstub->stubbuffer) IRpcStubBuffer_Release(ifstub->stubbuffer);
131  IUnknown_Release(ifstub->iface);
132  IRpcChannelBuffer_Release(ifstub->chan);
133 
134  HeapFree(GetProcessHeap(), 0, ifstub);
135 }
136 
137 static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
138 {
139  struct list *cursor;
140  struct ifstub *result = NULL;
141 
143  LIST_FOR_EACH( cursor, &m->ifstubs )
144  {
145  struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry );
146 
147  if (IsEqualGUID(ipid, &ifstub->ipid))
148  {
149  result = ifstub;
150  break;
151  }
152  }
154 
155  return result;
156 }
157 
159 {
160  struct ifstub *result = NULL;
161  struct ifstub *ifstub;
162 
164  LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry )
165  {
166  if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags))
167  {
168  result = ifstub;
169  break;
170  }
171  }
173 
174  return result;
175 }
176 
177 /* creates a new stub manager and adds it into the apartment. caller must
178  * release stub manager when it is no longer required. the apartment and
179  * external refs together take one implicit ref */
181 {
182  struct stub_manager *sm;
183  HRESULT hres;
184 
185  assert( apt );
186 
187  sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager));
188  if (!sm) return NULL;
189 
190  list_init(&sm->ifstubs);
191 
193  DEBUG_SET_CRITSEC_NAME(&sm->lock, "stub_manager");
194 
195  IUnknown_AddRef(object);
196  sm->object = object;
197  sm->apt = apt;
198 
199  /* start off with 2 references because the stub is in the apartment
200  * and the caller will also hold a reference */
201  sm->refs = 2;
202  sm->weakrefs = 0;
203 
204  sm->oxid_info.dwPid = GetCurrentProcessId();
205  sm->oxid_info.dwTid = GetCurrentThreadId();
206  /*
207  * FIXME: this is a hack for marshalling IRemUnknown. In real
208  * DCOM, the IPID of the IRemUnknown interface is generated like
209  * any other and passed to the OXID resolver which then returns it
210  * when queried. We don't have an OXID resolver yet so instead we
211  * use a magic IPID reserved for IRemUnknown.
212  */
213  sm->oxid_info.ipidRemUnknown.Data1 = 0xffffffff;
214  sm->oxid_info.ipidRemUnknown.Data2 = 0xffff;
215  sm->oxid_info.ipidRemUnknown.Data3 = 0xffff;
216  assert(sizeof(sm->oxid_info.ipidRemUnknown.Data4) == sizeof(apt->oxid));
217  memcpy(sm->oxid_info.ipidRemUnknown.Data4, &apt->oxid, sizeof(OXID));
218  sm->oxid_info.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
219  sm->oxid_info.psa = NULL /* FIXME */;
220 
221  /* Yes, that's right, this starts at zero. that's zero EXTERNAL
222  * refs, i.e., nobody has unmarshalled anything yet. We can't have
223  * negative refs because the stub manager cannot be explicitly
224  * killed, it has to die by somebody unmarshalling then releasing
225  * the marshalled ifptr.
226  */
227  sm->extrefs = 0;
228  sm->disconnected = FALSE;
229 
230  hres = IUnknown_QueryInterface(object, &IID_IExternalConnection, (void**)&sm->extern_conn);
231  if(FAILED(hres))
232  sm->extern_conn = NULL;
233 
234  EnterCriticalSection(&apt->cs);
235  sm->oid = apt->oidc++;
236  list_add_head(&apt->stubmgrs, &sm->entry);
237  LeaveCriticalSection(&apt->cs);
238 
239  TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
240 
241  return sm;
242 }
243 
245 {
246  struct ifstub *ifstub;
247 
249  if (!m->disconnected)
250  {
251  LIST_FOR_EACH_ENTRY(ifstub, &m->ifstubs, struct ifstub, entry)
252  RPC_UnregisterInterface(&ifstub->iid, FALSE);
253 
254  m->disconnected = TRUE;
255  }
257 }
258 
259 /* caller must remove stub manager from apartment prior to calling this function */
260 static void stub_manager_delete(struct stub_manager *m)
261 {
262  struct list *cursor;
263 
264  TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid));
265 
266  /* release every ifstub */
267  while ((cursor = list_head(&m->ifstubs)))
268  {
269  struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry);
270  stub_manager_delete_ifstub(m, ifstub);
271  }
272 
273  if(m->extern_conn)
274  IExternalConnection_Release(m->extern_conn);
275 
276  CoTaskMemFree(m->oxid_info.psa);
277 
278  /* Some broken apps crash in object destructors. We have a test showing
279  * that on winxp+ those crashes are caught and ignored. */
280  __TRY
281  {
282  IUnknown_Release(m->object);
283  }
285  {
286  ERR("Got page fault when releasing stub!\n");
287  }
288  __ENDTRY
289 
292 
293  HeapFree(GetProcessHeap(), 0, m);
294 }
295 
296 /* increments the internal refcount */
298 {
299  ULONG refs;
300 
301  EnterCriticalSection(&This->apt->cs);
302  refs = ++This->refs;
303  LeaveCriticalSection(&This->apt->cs);
304 
305  TRACE("before %d\n", refs - 1);
306 
307  return refs;
308 }
309 
310 /* decrements the internal refcount */
312 {
313  ULONG refs;
314  APARTMENT *apt = This->apt;
315 
316  EnterCriticalSection(&apt->cs);
317  refs = --This->refs;
318 
319  TRACE("after %d\n", refs);
320 
321  /* remove from apartment so no other thread can access it... */
322  if (!refs)
323  list_remove(&This->entry);
324 
325  LeaveCriticalSection(&apt->cs);
326 
327  /* ... so now we can delete it without being inside the apartment critsec */
328  if (!refs)
329  stub_manager_delete(This);
330 
331  return refs;
332 }
333 
334 /* gets the stub manager associated with an object - caller must have
335  * a reference to the apartment while a reference to the stub manager is held.
336  * it must also call release on the stub manager when it is no longer needed */
338 {
339  struct stub_manager *result = NULL;
340  struct list *cursor;
341  IUnknown *object;
342  HRESULT hres;
343 
344  hres = IUnknown_QueryInterface(obj, &IID_IUnknown, (void**)&object);
345  if (FAILED(hres)) {
346  ERR("QueryInterface(IID_IUnknown failed): %08x\n", hres);
347  return NULL;
348  }
349 
350  EnterCriticalSection(&apt->cs);
351  LIST_FOR_EACH( cursor, &apt->stubmgrs )
352  {
353  struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
354 
355  if (m->object == object)
356  {
357  result = m;
358  stub_manager_int_addref(result);
359  break;
360  }
361  }
362  LeaveCriticalSection(&apt->cs);
363 
364  if (result) {
365  TRACE("found %p for object %p\n", result, object);
366  }else if (alloc) {
367  TRACE("not found, creating new stub manager...\n");
368  result = new_stub_manager(apt, object);
369  }else {
370  TRACE("not found for object %p\n", object);
371  }
372 
373  IUnknown_Release(object);
374  return result;
375 }
376 
377 /* gets the stub manager associated with an object id - caller must have
378  * a reference to the apartment while a reference to the stub manager is held.
379  * it must also call release on the stub manager when it is no longer needed */
381 {
382  struct stub_manager *result = NULL;
383  struct list *cursor;
384 
385  EnterCriticalSection(&apt->cs);
386  LIST_FOR_EACH( cursor, &apt->stubmgrs )
387  {
388  struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
389 
390  if (m->oid == oid)
391  {
392  result = m;
393  stub_manager_int_addref(result);
394  break;
395  }
396  }
397  LeaveCriticalSection(&apt->cs);
398 
399  if (result)
400  TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid));
401  else
402  TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid));
403 
404  return result;
405 }
406 
407 /* add some external references (ie from a client that unmarshaled an ifptr) */
409 {
410  BOOL first_extern_ref;
411  ULONG rc;
412 
414 
415  first_extern_ref = refs && !m->extrefs;
416 
417  /* make sure we don't overflow extrefs */
418  refs = min(refs, (ULONG_MAX-1 - m->extrefs));
419  rc = (m->extrefs += refs);
420 
421  if (tableweak)
422  rc += ++m->weakrefs;
423 
425 
426  TRACE("added %u refs to %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
427 
428  /*
429  * NOTE: According to tests, creating a stub causes two AddConnection calls followed by
430  * one ReleaseConnection call (with fLastReleaseCloses=FALSE).
431  */
432  if(first_extern_ref && m->extern_conn)
433  IExternalConnection_AddConnection(m->extern_conn, EXTCONN_STRONG, 0);
434 
435  return rc;
436 }
437 
438 /* remove some external references */
439 ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases)
440 {
441  BOOL last_extern_ref;
442  ULONG rc;
443 
445 
446  /* make sure we don't underflow extrefs */
447  refs = min(refs, m->extrefs);
448  rc = (m->extrefs -= refs);
449 
450  if (tableweak)
451  --m->weakrefs;
452  if (!last_unlock_releases)
453  rc += m->weakrefs;
454 
455  last_extern_ref = refs && !m->extrefs;
456 
458 
459  TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
460 
461  if (last_extern_ref && m->extern_conn)
462  IExternalConnection_ReleaseConnection(m->extern_conn, EXTCONN_STRONG, 0, last_unlock_releases);
463 
464  if (rc == 0)
465  if (!(m->extern_conn && last_unlock_releases && m->weakrefs))
467 
468  return rc;
469 }
470 
471 /* gets the stub manager associated with an ipid - caller must have
472  * a reference to the apartment while a reference to the stub manager is held.
473  * it must also call release on the stub manager when it is no longer needed */
474 static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid, struct ifstub **ifstub)
475 {
476  struct stub_manager *result = NULL;
477  struct list *cursor;
478 
479  EnterCriticalSection(&apt->cs);
480  LIST_FOR_EACH( cursor, &apt->stubmgrs )
481  {
482  struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
483 
484  if ((*ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
485  {
486  result = m;
487  stub_manager_int_addref(result);
488  break;
489  }
490  }
491  LeaveCriticalSection(&apt->cs);
492 
493  if (result)
494  TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid));
495  else
496  ERR("not found for ipid %s\n", debugstr_guid(ipid));
497 
498  return result;
499 }
500 
501 static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt,
502  struct stub_manager **stubmgr_ret, struct ifstub **ifstub)
503 {
504  /* FIXME: hack for IRemUnknown */
505  if (ipid->Data2 == 0xffff)
506  *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4, TRUE);
507  else
508  *stub_apt = apartment_findfromtid(ipid->Data2);
509  if (!*stub_apt)
510  {
511  TRACE("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2);
512  return RPC_E_INVALID_OBJECT;
513  }
514  *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid, ifstub);
515  if (!*stubmgr_ret)
516  {
517  apartment_release(*stub_apt);
518  *stub_apt = NULL;
519  return RPC_E_INVALID_OBJECT;
520  }
521  return S_OK;
522 }
523 
524 static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stub)
525 {
526  struct ifstub *ifstub;
527  return ipid_to_ifstub(ipid, stub_apt, stub, &ifstub);
528 }
529 
530 /* gets the apartment, stub and channel of an object. the caller must
531  * release the references to all objects (except iface) if the function
532  * returned success, otherwise no references are returned. */
534  struct stub_manager **manager,
536  IID *iid, IUnknown **iface)
537 {
538  struct stub_manager *stubmgr;
539  struct ifstub *ifstub;
540  APARTMENT *apt;
541  HRESULT hr;
542 
543  hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub);
544  if (hr != S_OK) return RPC_E_DISCONNECTED;
545 
546  *stub = ifstub->stubbuffer;
547  IRpcStubBuffer_AddRef(*stub);
548  *chan = ifstub->chan;
549  IRpcChannelBuffer_AddRef(*chan);
550  *stub_apt = apt;
551  *iid = ifstub->iid;
552  *iface = ifstub->iface;
553 
554  if (manager)
555  *manager = stubmgr;
556  else
557  stub_manager_int_release(stubmgr);
558  return S_OK;
559 }
560 
561 /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */
563 {
564  BOOL ret = TRUE;
565  struct ifstub *ifstub;
566 
567  if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
568  {
569  ERR("attempted unmarshal of unknown IPID %s\n", debugstr_guid(ipid));
570  return FALSE;
571  }
572 
574 
575  /* track normal marshals so we can enforce rules whilst in-process */
576  if (ifstub->flags & MSHLFLAGS_NORMAL)
577  {
578  if (m->norm_refs)
579  m->norm_refs--;
580  else
581  {
582  ERR("attempted invalid normal unmarshal, norm_refs is zero\n");
583  ret = FALSE;
584  }
585  }
586 
588 
589  return ret;
590 }
591 
592 /* handles refcounting for CoReleaseMarshalData */
593 void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak)
594 {
595  struct ifstub *ifstub;
596 
597  if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
598  return;
599 
600  if (ifstub->flags & MSHLFLAGS_TABLEWEAK)
601  refs = 0;
602  else if (ifstub->flags & MSHLFLAGS_TABLESTRONG)
603  refs = 1;
604 
605  stub_manager_ext_release(m, refs, tableweak, !tableweak);
606 }
607 
608 /* is an ifstub table marshaled? */
610 {
611  struct ifstub *ifstub = stub_manager_ipid_to_ifstub(m, ipid);
612 
613  assert( ifstub );
614 
615  return ifstub->flags & (MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK);
616 }
617 
618 
619 /*****************************************************************************
620  *
621  * IRemUnknown implementation
622  *
623  *
624  * Note: this object is not related to the lifetime of a stub_manager, but it
625  * interacts with stub managers.
626  */
627 
628 typedef struct rem_unknown
629 {
632 } RemUnknown;
633 
634 static const IRemUnknownVtbl RemUnknown_Vtbl;
635 
637 {
638  return CONTAINING_RECORD(iface, RemUnknown, IRemUnknown_iface);
639 }
640 
641 
642 /* construct an IRemUnknown object with one outstanding reference */
644 {
645  RemUnknown *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
646 
647  if (!This) return E_OUTOFMEMORY;
648 
649  This->IRemUnknown_iface.lpVtbl = &RemUnknown_Vtbl;
650  This->refs = 1;
651 
652  *ppRemUnknown = &This->IRemUnknown_iface;
653  return S_OK;
654 }
655 
657 {
658  TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
659 
660  if (IsEqualIID(riid, &IID_IUnknown) ||
661  IsEqualIID(riid, &IID_IRemUnknown))
662  {
663  *ppv = iface;
664  IRemUnknown_AddRef(iface);
665  return S_OK;
666  }
667 
668  if (!IsEqualIID(riid, &IID_IExternalConnection))
669  FIXME("No interface for iid %s\n", debugstr_guid(riid));
670 
671  *ppv = NULL;
672  return E_NOINTERFACE;
673 }
674 
676 {
677  ULONG refs;
678  RemUnknown *This = impl_from_IRemUnknown(iface);
679 
680  refs = InterlockedIncrement(&This->refs);
681 
682  TRACE("%p before: %d\n", iface, refs-1);
683  return refs;
684 }
685 
687 {
688  ULONG refs;
689  RemUnknown *This = impl_from_IRemUnknown(iface);
690 
691  refs = InterlockedDecrement(&This->refs);
692  if (!refs)
693  HeapFree(GetProcessHeap(), 0, This);
694 
695  TRACE("%p after: %d\n", iface, refs);
696  return refs;
697 }
698 
700  REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */,
701  REMQIRESULT **ppQIResults /* [size_is(,cIids)] */)
702 {
703  HRESULT hr;
704  USHORT i;
705  USHORT successful_qis = 0;
706  APARTMENT *apt;
707  struct stub_manager *stubmgr;
708  struct ifstub *ifstub;
709  DWORD dest_context;
710  void *dest_context_data;
711 
712  TRACE("(%p)->(%s, %d, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults);
713 
714  hr = ipid_to_ifstub(ripid, &apt, &stubmgr, &ifstub);
715  if (hr != S_OK) return hr;
716 
717  IRpcChannelBuffer_GetDestCtx(ifstub->chan, &dest_context, &dest_context_data);
718 
719  *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids);
720 
721  for (i = 0; i < cIids; i++)
722  {
723  HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i],
724  stubmgr->object, dest_context, dest_context_data, MSHLFLAGS_NORMAL);
725  if (hrobj == S_OK)
726  successful_qis++;
727  (*ppQIResults)[i].hResult = hrobj;
728  }
729 
730  stub_manager_int_release(stubmgr);
731  apartment_release(apt);
732 
733  if (successful_qis == cIids)
734  return S_OK; /* we got all requested interfaces */
735  else if (successful_qis == 0)
736  return E_NOINTERFACE; /* we didn't get any interfaces */
737  else
738  return S_FALSE; /* we got some interfaces */
739 }
740 
742  USHORT cInterfaceRefs,
743  REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */,
744  HRESULT *pResults /* [size_is(cInterfaceRefs)] */)
745 {
746  HRESULT hr = S_OK;
747  USHORT i;
748 
749  TRACE("(%p)->(%d, %p, %p)\n", iface, cInterfaceRefs, InterfaceRefs, pResults);
750 
751  for (i = 0; i < cInterfaceRefs; i++)
752  {
753  APARTMENT *apt;
754  struct stub_manager *stubmgr;
755 
756  pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
757  if (pResults[i] != S_OK)
758  {
759  hr = S_FALSE;
760  continue;
761  }
762 
763  stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE);
764  if (InterfaceRefs[i].cPrivateRefs)
765  FIXME("Adding %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
766 
767  stub_manager_int_release(stubmgr);
768  apartment_release(apt);
769  }
770 
771  return hr;
772 }
773 
775  USHORT cInterfaceRefs,
776  REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */)
777 {
778  HRESULT hr = S_OK;
779  USHORT i;
780 
781  TRACE("(%p)->(%d, %p)\n", iface, cInterfaceRefs, InterfaceRefs);
782 
783  for (i = 0; i < cInterfaceRefs; i++)
784  {
785  APARTMENT *apt;
786  struct stub_manager *stubmgr;
787 
788  hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
789  if (hr != S_OK)
790  {
791  hr = E_INVALIDARG;
792  /* FIXME: we should undo any changes already made in this function */
793  break;
794  }
795 
796  stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE);
797  if (InterfaceRefs[i].cPrivateRefs)
798  FIXME("Releasing %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
799 
800  stub_manager_int_release(stubmgr);
801  apartment_release(apt);
802  }
803 
804  return hr;
805 }
806 
807 static const IRemUnknownVtbl RemUnknown_Vtbl =
808 {
815 };
816 
817 /* starts the IRemUnknown listener for the current apartment */
819 {
820  IRemUnknown *pRemUnknown;
821  HRESULT hr = S_OK;
822 
823  EnterCriticalSection(&apt->cs);
824  if (!apt->remunk_exported)
825  {
826  /* create the IRemUnknown object */
827  hr = RemUnknown_Construct(&pRemUnknown);
828  if (hr == S_OK)
829  {
830  STDOBJREF stdobjref; /* dummy - not used */
831  /* register it with the stub manager */
832  hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHCTX_DIFFERENTMACHINE, NULL, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN);
833  /* release our reference to the object as the stub manager will manage the life cycle for us */
834  IRemUnknown_Release(pRemUnknown);
835  if (hr == S_OK)
836  apt->remunk_exported = TRUE;
837  }
838  }
839  LeaveCriticalSection(&apt->cs);
840  return hr;
841 }
#define MSHLFLAGSP_REMUNKNOWN
static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown)
Definition: stubmanager.c:643
HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface)
Definition: stubmanager.c:533
void stub_manager_disconnect(struct stub_manager *m)
Definition: stubmanager.c:244
struct ifstub * stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, REFIID iid, DWORD dest_context, void *dest_context_data, MSHLFLAGS flags)
Definition: stubmanager.c:70
struct rem_unknown RemUnknown
#define REFIID
Definition: guiddef.h:113
#define TRUE
Definition: types.h:120
static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface)
Definition: stubmanager.c:686
#define E_NOINTERFACE
Definition: winerror.h:2364
struct stub_manager * get_stub_manager(APARTMENT *apt, OID oid)
Definition: stubmanager.c:380
static void stub_manager_delete(struct stub_manager *m)
Definition: stubmanager.c:260
static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stub)
Definition: stubmanager.c:524
const GUID IID_IUnknown
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases)
Definition: stubmanager.c:439
struct list entry
static const IRemUnknownVtbl RemUnknown_Vtbl
Definition: stubmanager.c:634
REFIID riid
Definition: precomp.h:44
#define DEBUG_SET_CRITSEC_NAME(cs, name)
IUnknown * iface
DWORD apartment_release(struct apartment *apt)
Definition: compobj.c:1175
static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface)
Definition: stubmanager.c:675
uint8_t entry
Definition: isohybrid.c:63
MSHLFLAGS flags
APARTMENT * apt
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
REFIID LPVOID * ppv
Definition: atlbase.h:39
Definition: stubgen.c:11
#define assert(x)
Definition: debug.h:53
IExternalConnection * extern_conn
static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids, REMQIRESULT **ppQIResults)
Definition: stubmanager.c:699
IRemUnknown IRemUnknown_iface
Definition: stubmanager.c:630
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
DWORD DWORD
Definition: winlogon.h:83
superblock * sb
Definition: btrfs.c:3841
HRESULT start_apartment_remote_unknown(APARTMENT *apt)
Definition: stubmanager.c:818
__WINE_SERVER_LIST_INLINE struct list * list_head(const struct list *list)
Definition: list.h:131
CRITICAL_SECTION lock
struct list ifstubs
static struct stub_manager * new_stub_manager(APARTMENT *apt, IUnknown *object)
Definition: stubmanager.c:180
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
struct _stub stub
GLenum GLclampf GLint i
Definition: glfuncs.h:14
IRpcChannelBuffer * chan
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define FALSE
Definition: types.h:117
long LONG
Definition: pedump.c:60
#define DEBUG_CLEAR_CRITSEC_NAME(cs)
#define FIXME(fmt,...)
Definition: debug.h:110
#define S_FALSE
Definition: winerror.h:2357
#define E_INVALIDARG
Definition: ddrawi.h:101
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:697
#define LIST_FOR_EACH(cursor, list)
Definition: list.h:188
smooth NULL
Definition: ftsmooth.c:416
#define __TRY
Definition: compat.h:70
#define debugstr_guid
Definition: kernel32.h:35
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
DWORD WINAPI GetCurrentThreadId(VOID)
Definition: thread.c:444
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid)
Definition: stubmanager.c:609
IRpcStubBuffer * stubbuffer
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
#define TRACE(s)
Definition: solgame.cpp:4
unsigned int BOOL
Definition: ntddk_ex.h:94
HRESULT hres
Definition: protocol.c:465
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
Definition: stubmanager.c:52
OXID_INFO oxid_info
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
LONG HRESULT
Definition: typedefs.h:77
static RemUnknown * impl_from_IRemUnknown(IRemUnknown *iface)
Definition: stubmanager.c:636
struct list entry
static const IID IID_IRemUnknown
Definition: marshal.c:88
#define RPC_E_DISCONNECTED
Definition: winerror.h:2484
HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN
Definition: rpc.c:1164
GLbitfield flags
Definition: glext.h:7161
APARTMENT * apartment_findfromtid(DWORD tid)
Definition: compobj.c:1303
#define __ENDTRY
Definition: compat.h:72
int ret
static struct ifstub * stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
Definition: stubmanager.c:137
HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags) DECLSPEC_HIDDEN
Definition: marshal.c:124
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
Definition: stubmanager.c:562
void RPC_UnregisterInterface(REFIID riid, BOOL wait) DECLSPEC_HIDDEN
Definition: rpc.c:1589
#define InterlockedDecrement
Definition: armddk.h:52
static struct stub_manager * get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid, struct ifstub **ifstub)
Definition: stubmanager.c:474
static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret, struct ifstub **ifstub)
Definition: stubmanager.c:501
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define RPC_E_INVALID_OBJECT
Definition: winerror.h:2496
Definition: _list.h:228
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak)
Definition: stubmanager.c:408
#define WINAPI
Definition: msvc.h:20
#define ERR(fmt,...)
Definition: debug.h:109
struct stub_manager * get_stub_manager_from_object(APARTMENT *apt, IUnknown *obj, BOOL alloc)
Definition: stubmanager.c:337
WINE_DEFAULT_DEBUG_CHANNEL(ole)
APARTMENT * apartment_findfromoxid(OXID oxid, BOOL ref)
Definition: compobj.c:1279
const GLfloat * m
Definition: glext.h:10848
#define S_OK
Definition: intsafe.h:59
static ULONG stub_manager_int_addref(struct stub_manager *This)
Definition: stubmanager.c:297
IUnknown * object
#define InterlockedIncrement
Definition: armddk.h:53
RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
Definition: rpcrt4_main.c:306
static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, USHORT cInterfaceRefs, REMINTERFACEREF *InterfaceRefs)
Definition: stubmanager.c:774
const char cursor[]
Definition: icontest.c:13
static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub)
Definition: stubmanager.c:121
unsigned short USHORT
Definition: pedump.c:61
#define min(a, b)
Definition: monoChain.cc:55
#define alloc
Definition: rosglue.h:13
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4024
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid)
Definition: rpcrt4_main.c:285
struct ifstub * stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags)
Definition: stubmanager.c:158
CONST GLfloat m[16]
Definition: m_xform.h:144
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
unsigned int ULONG
Definition: retypes.h:1
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:41
struct list stubmgrs
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define LIST_ENTRY(type)
Definition: queue.h:175
CRITICAL_SECTION cs
GLuint64EXT * result
Definition: glext.h:11304
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak)
Definition: stubmanager.c:593
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:406
#define RPC_C_AUTHN_LEVEL_NONE
Definition: rpcdce.h:146
#define HeapFree(x, y, z)
Definition: compat.h:394
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:90
void * object
Definition: jmemsys.h:48
static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, USHORT cInterfaceRefs, REMINTERFACEREF *InterfaceRefs, HRESULT *pResults)
Definition: stubmanager.c:741
#define __EXCEPT_PAGE_FAULT
Definition: compat.h:71
#define ULONG_MAX
Definition: limits.h:44
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1215
ULONG stub_manager_int_release(struct stub_manager *This)
Definition: stubmanager.c:311
static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv)
Definition: stubmanager.c:656
BOOL remunk_exported