Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/combase/stubmanager.c
4393 views
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 "initguid.h"
42
#include "dcom.h"
43
#include "combase_private.h"
44
45
WINE_DEFAULT_DEBUG_CHANNEL(ole);
46
47
/* generates an ipid in the following format (similar to native version):
48
* Data1 = apartment-local ipid counter
49
* Data2 = apartment creator thread ID, or 0 for an MTA.
50
* Data3 = process ID
51
* Data4 = random value
52
*/
53
static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
54
{
55
HRESULT hr;
56
hr = UuidCreate(ipid);
57
if (FAILED(hr))
58
{
59
ERR("couldn't create IPID for stub manager %p\n", m);
60
UuidCreateNil(ipid);
61
return hr;
62
}
63
64
ipid->Data1 = InterlockedIncrement(&m->apt->ipidc);
65
ipid->Data2 = !m->apt->multi_threaded ? (USHORT)m->apt->tid : 0;
66
ipid->Data3 = (USHORT)GetCurrentProcessId();
67
return S_OK;
68
}
69
70
/* registers a new interface stub COM object with the stub manager and returns registration record */
71
struct ifstub * stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, REFIID iid, DWORD dest_context,
72
void *dest_context_data, MSHLFLAGS flags)
73
{
74
struct ifstub *stub;
75
HRESULT hr;
76
77
TRACE("oid=%s, stubbuffer=%p, iid=%s, dest_context=%lx\n", wine_dbgstr_longlong(m->oid), sb,
78
debugstr_guid(iid), dest_context);
79
80
stub = calloc(1, sizeof(struct ifstub));
81
if (!stub) return NULL;
82
83
hr = IUnknown_QueryInterface(m->object, iid, (void **)&stub->iface);
84
if (hr != S_OK)
85
{
86
free(stub);
87
return NULL;
88
}
89
90
hr = rpc_create_serverchannel(dest_context, dest_context_data, &stub->chan);
91
if (hr != S_OK)
92
{
93
IUnknown_Release(stub->iface);
94
free(stub);
95
return NULL;
96
}
97
98
stub->stubbuffer = sb;
99
if (sb) IRpcStubBuffer_AddRef(sb);
100
101
stub->flags = flags;
102
stub->iid = *iid;
103
104
/* FIXME: find a cleaner way of identifying that we are creating an ifstub
105
* for the remunknown interface */
106
if (flags & MSHLFLAGSP_REMUNKNOWN)
107
stub->ipid = m->oxid_info.ipidRemUnknown;
108
else
109
generate_ipid(m, &stub->ipid);
110
111
EnterCriticalSection(&m->lock);
112
list_add_head(&m->ifstubs, &stub->entry);
113
/* every normal marshal is counted so we don't allow more than we should */
114
if (flags & MSHLFLAGS_NORMAL) m->norm_refs++;
115
LeaveCriticalSection(&m->lock);
116
117
TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
118
119
return stub;
120
}
121
122
static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub)
123
{
124
TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid));
125
126
list_remove(&ifstub->entry);
127
128
if (!m->disconnected)
129
rpc_unregister_interface(&ifstub->iid, TRUE);
130
131
if (ifstub->stubbuffer) IRpcStubBuffer_Release(ifstub->stubbuffer);
132
IUnknown_Release(ifstub->iface);
133
IRpcChannelBuffer_Release(ifstub->chan);
134
135
free(ifstub);
136
}
137
138
static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
139
{
140
struct ifstub *result = NULL, *ifstub;
141
142
EnterCriticalSection(&m->lock);
143
LIST_FOR_EACH_ENTRY(ifstub, &m->ifstubs, struct ifstub, entry)
144
{
145
if (IsEqualGUID(ipid, &ifstub->ipid))
146
{
147
result = ifstub;
148
break;
149
}
150
}
151
LeaveCriticalSection(&m->lock);
152
153
return result;
154
}
155
156
struct ifstub * stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags)
157
{
158
struct ifstub *result = NULL;
159
struct ifstub *ifstub;
160
161
EnterCriticalSection(&m->lock);
162
LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry )
163
{
164
if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags))
165
{
166
result = ifstub;
167
break;
168
}
169
}
170
LeaveCriticalSection(&m->lock);
171
172
return result;
173
}
174
175
/* creates a new stub manager and adds it into the apartment. caller must
176
* release stub manager when it is no longer required. the apartment and
177
* external refs together take one implicit ref */
178
static struct stub_manager *new_stub_manager(struct apartment *apt, IUnknown *object)
179
{
180
struct stub_manager *sm;
181
HRESULT hres;
182
183
assert(apt);
184
185
sm = calloc(1, sizeof(struct stub_manager));
186
if (!sm) return NULL;
187
188
list_init(&sm->ifstubs);
189
190
InitializeCriticalSectionEx(&sm->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
191
sm->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": stub_manager");
192
193
IUnknown_AddRef(object);
194
sm->object = object;
195
sm->apt = apt;
196
197
/* start off with 2 references because the stub is in the apartment
198
* and the caller will also hold a reference */
199
sm->refs = 2;
200
sm->weakrefs = 0;
201
202
sm->oxid_info.dwPid = GetCurrentProcessId();
203
sm->oxid_info.dwTid = GetCurrentThreadId();
204
/*
205
* FIXME: this is a hack for marshalling IRemUnknown. In real
206
* DCOM, the IPID of the IRemUnknown interface is generated like
207
* any other and passed to the OXID resolver which then returns it
208
* when queried. We don't have an OXID resolver yet so instead we
209
* use a magic IPID reserved for IRemUnknown.
210
*/
211
sm->oxid_info.ipidRemUnknown.Data1 = 0xffffffff;
212
sm->oxid_info.ipidRemUnknown.Data2 = 0xffff;
213
sm->oxid_info.ipidRemUnknown.Data3 = 0xffff;
214
assert(sizeof(sm->oxid_info.ipidRemUnknown.Data4) == sizeof(apt->oxid));
215
memcpy(sm->oxid_info.ipidRemUnknown.Data4, &apt->oxid, sizeof(OXID));
216
sm->oxid_info.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
217
sm->oxid_info.psa = NULL /* FIXME */;
218
219
/* Yes, that's right, this starts at zero. that's zero EXTERNAL
220
* refs, i.e., nobody has unmarshalled anything yet. We can't have
221
* negative refs because the stub manager cannot be explicitly
222
* killed, it has to die by somebody unmarshalling then releasing
223
* the marshalled ifptr.
224
*/
225
sm->extrefs = 0;
226
sm->disconnected = FALSE;
227
228
hres = IUnknown_QueryInterface(object, &IID_IExternalConnection, (void**)&sm->extern_conn);
229
if(FAILED(hres))
230
sm->extern_conn = NULL;
231
232
EnterCriticalSection(&apt->cs);
233
sm->oid = apt->oidc++;
234
list_add_head(&apt->stubmgrs, &sm->entry);
235
LeaveCriticalSection(&apt->cs);
236
237
TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
238
239
return sm;
240
}
241
242
void stub_manager_disconnect(struct stub_manager *m)
243
{
244
struct ifstub *ifstub;
245
246
EnterCriticalSection(&m->lock);
247
if (!m->disconnected)
248
{
249
LIST_FOR_EACH_ENTRY(ifstub, &m->ifstubs, struct ifstub, entry)
250
rpc_unregister_interface(&ifstub->iid, FALSE);
251
252
m->disconnected = TRUE;
253
}
254
LeaveCriticalSection(&m->lock);
255
}
256
257
/* caller must remove stub manager from apartment prior to calling this function */
258
static void stub_manager_delete(struct stub_manager *m)
259
{
260
struct list *cursor;
261
262
TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid));
263
264
/* release every ifstub */
265
while ((cursor = list_head(&m->ifstubs)))
266
{
267
struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry);
268
stub_manager_delete_ifstub(m, ifstub);
269
}
270
271
if(m->extern_conn)
272
IExternalConnection_Release(m->extern_conn);
273
274
CoTaskMemFree(m->oxid_info.psa);
275
276
/* Some broken apps crash in object destructors. We have a test showing
277
* that on winxp+ those crashes are caught and ignored. */
278
__TRY
279
{
280
IUnknown_Release(m->object);
281
}
282
__EXCEPT_PAGE_FAULT
283
{
284
ERR("Got page fault when releasing stub!\n");
285
}
286
__ENDTRY
287
288
m->lock.DebugInfo->Spare[0] = 0;
289
DeleteCriticalSection(&m->lock);
290
291
free(m);
292
}
293
294
/* increments the internal refcount */
295
static ULONG stub_manager_int_addref(struct stub_manager *m)
296
{
297
ULONG refs;
298
299
EnterCriticalSection(&m->apt->cs);
300
refs = ++m->refs;
301
LeaveCriticalSection(&m->apt->cs);
302
303
TRACE("before %ld\n", refs - 1);
304
305
return refs;
306
}
307
308
/* decrements the internal refcount */
309
ULONG stub_manager_int_release(struct stub_manager *m)
310
{
311
ULONG refs;
312
struct apartment *apt = m->apt;
313
314
EnterCriticalSection(&apt->cs);
315
refs = --m->refs;
316
317
TRACE("after %ld\n", refs);
318
319
/* remove from apartment so no other thread can access it... */
320
if (!refs)
321
list_remove(&m->entry);
322
323
LeaveCriticalSection(&apt->cs);
324
325
/* ... so now we can delete it without being inside the apartment critsec */
326
if (!refs)
327
stub_manager_delete(m);
328
329
return refs;
330
}
331
332
/* gets the stub manager associated with an object - caller must have
333
* a reference to the apartment while a reference to the stub manager is held.
334
* it must also call release on the stub manager when it is no longer needed */
335
struct stub_manager * get_stub_manager_from_object(struct apartment *apt, IUnknown *obj, BOOL alloc)
336
{
337
struct stub_manager *result = NULL, *m;
338
IUnknown *object;
339
HRESULT hres;
340
341
hres = IUnknown_QueryInterface(obj, &IID_IUnknown, (void**)&object);
342
if (FAILED(hres))
343
{
344
ERR("QueryInterface(IID_IUnknown failed): %#lx\n", hres);
345
return NULL;
346
}
347
348
EnterCriticalSection(&apt->cs);
349
LIST_FOR_EACH_ENTRY(m, &apt->stubmgrs, struct stub_manager, entry)
350
{
351
if (m->object == object)
352
{
353
result = m;
354
stub_manager_int_addref(result);
355
break;
356
}
357
}
358
LeaveCriticalSection(&apt->cs);
359
360
if (result)
361
{
362
TRACE("found %p for object %p\n", result, object);
363
}
364
else if (alloc)
365
{
366
TRACE("not found, creating new stub manager...\n");
367
result = new_stub_manager(apt, object);
368
}
369
else
370
{
371
TRACE("not found for object %p\n", object);
372
}
373
374
IUnknown_Release(object);
375
return result;
376
}
377
378
/* gets the stub manager associated with an object id - caller must have
379
* a reference to the apartment while a reference to the stub manager is held.
380
* it must also call release on the stub manager when it is no longer needed */
381
struct stub_manager * get_stub_manager(struct apartment *apt, OID oid)
382
{
383
struct stub_manager *result = NULL, *m;
384
385
EnterCriticalSection(&apt->cs);
386
LIST_FOR_EACH_ENTRY(m, &apt->stubmgrs, struct stub_manager, entry)
387
{
388
if (m->oid == oid)
389
{
390
result = m;
391
stub_manager_int_addref(result);
392
break;
393
}
394
}
395
LeaveCriticalSection(&apt->cs);
396
397
if (result)
398
TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid));
399
else
400
TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid));
401
402
return result;
403
}
404
405
/* add some external references (ie from a client that unmarshaled an ifptr) */
406
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak)
407
{
408
BOOL first_extern_ref;
409
ULONG rc;
410
411
EnterCriticalSection(&m->lock);
412
413
first_extern_ref = refs && !m->extrefs;
414
415
/* make sure we don't overflow extrefs */
416
refs = min(refs, (ULONG_MAX-1 - m->extrefs));
417
rc = (m->extrefs += refs);
418
419
if (tableweak)
420
rc += ++m->weakrefs;
421
422
LeaveCriticalSection(&m->lock);
423
424
TRACE("added %lu refs to %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
425
426
/*
427
* NOTE: According to tests, creating a stub causes two AddConnection calls followed by
428
* one ReleaseConnection call (with fLastReleaseCloses=FALSE).
429
*/
430
if(first_extern_ref && m->extern_conn)
431
IExternalConnection_AddConnection(m->extern_conn, EXTCONN_STRONG, 0);
432
433
return rc;
434
}
435
436
/* remove some external references */
437
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases)
438
{
439
BOOL last_extern_ref;
440
ULONG rc;
441
442
EnterCriticalSection(&m->lock);
443
444
/* make sure we don't underflow extrefs */
445
refs = min(refs, m->extrefs);
446
rc = (m->extrefs -= refs);
447
448
if (tableweak)
449
--m->weakrefs;
450
if (!last_unlock_releases)
451
rc += m->weakrefs;
452
453
last_extern_ref = refs && !m->extrefs;
454
455
LeaveCriticalSection(&m->lock);
456
457
TRACE("removed %lu refs from %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
458
459
if (last_extern_ref && m->extern_conn)
460
IExternalConnection_ReleaseConnection(m->extern_conn, EXTCONN_STRONG, 0, last_unlock_releases);
461
462
if (rc == 0)
463
if (!(m->extern_conn && last_unlock_releases && m->weakrefs))
464
stub_manager_int_release(m);
465
466
return rc;
467
}
468
469
/* gets the stub manager associated with an ipid - caller must have
470
* a reference to the apartment while a reference to the stub manager is held.
471
* it must also call release on the stub manager when it is no longer needed */
472
static struct stub_manager *get_stub_manager_from_ipid(struct apartment *apt, const IPID *ipid, struct ifstub **ifstub)
473
{
474
struct stub_manager *result = NULL, *m;
475
476
EnterCriticalSection(&apt->cs);
477
LIST_FOR_EACH_ENTRY(m, &apt->stubmgrs, struct stub_manager, entry)
478
{
479
if ((*ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
480
{
481
result = m;
482
stub_manager_int_addref(result);
483
break;
484
}
485
}
486
LeaveCriticalSection(&apt->cs);
487
488
if (result)
489
TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid));
490
else
491
ERR("not found for ipid %s\n", debugstr_guid(ipid));
492
493
return result;
494
}
495
496
static HRESULT ipid_to_ifstub(const IPID *ipid, struct apartment **stub_apt,
497
struct stub_manager **stubmgr_ret, struct ifstub **ifstub)
498
{
499
/* FIXME: hack for IRemUnknown */
500
if (ipid->Data2 == 0xffff)
501
*stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4);
502
else if (!ipid->Data2 && (ipid->Data3 == (USHORT)GetCurrentProcessId()))
503
*stub_apt = apartment_get_mta();
504
else
505
*stub_apt = apartment_findfromtid(ipid->Data2);
506
if (!*stub_apt)
507
{
508
TRACE("Couldn't find apartment corresponding to TID 0x%04x, PID 0x%04x\n", ipid->Data2, ipid->Data3);
509
return RPC_E_INVALID_OBJECT;
510
}
511
*stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid, ifstub);
512
if (!*stubmgr_ret)
513
{
514
apartment_release(*stub_apt);
515
*stub_apt = NULL;
516
return RPC_E_INVALID_OBJECT;
517
}
518
return S_OK;
519
}
520
521
static HRESULT ipid_to_stub_manager(const IPID *ipid, struct apartment **stub_apt, struct stub_manager **stub)
522
{
523
struct ifstub *ifstub;
524
return ipid_to_ifstub(ipid, stub_apt, stub, &ifstub);
525
}
526
527
/* gets the apartment, stub and channel of an object. the caller must
528
* release the references to all objects (except iface) if the function
529
* returned success, otherwise no references are returned. */
530
HRESULT ipid_get_dispatch_params(const IPID *ipid, struct apartment **stub_apt,
531
struct stub_manager **manager, IRpcStubBuffer **stub, IRpcChannelBuffer **chan,
532
IID *iid, IUnknown **iface)
533
{
534
struct stub_manager *stubmgr;
535
struct ifstub *ifstub;
536
struct apartment *apt;
537
HRESULT hr;
538
539
hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub);
540
if (hr != S_OK) return RPC_E_DISCONNECTED;
541
542
*stub = ifstub->stubbuffer;
543
IRpcStubBuffer_AddRef(*stub);
544
*chan = ifstub->chan;
545
IRpcChannelBuffer_AddRef(*chan);
546
*stub_apt = apt;
547
*iid = ifstub->iid;
548
*iface = ifstub->iface;
549
550
if (manager)
551
*manager = stubmgr;
552
else
553
stub_manager_int_release(stubmgr);
554
return S_OK;
555
}
556
557
HRESULT ipid_get_dest_context(const IPID *ipid, MSHCTX *dest_context, void **dest_context_data)
558
{
559
struct stub_manager *stubmgr;
560
struct ifstub *ifstub;
561
struct apartment *apt;
562
void *data;
563
HRESULT hr;
564
DWORD ctx;
565
566
hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub);
567
if (hr != S_OK) return RPC_E_DISCONNECTED;
568
569
hr = IRpcChannelBuffer_GetDestCtx(ifstub->chan, &ctx, &data);
570
if (SUCCEEDED(hr))
571
{
572
*dest_context = ctx;
573
*dest_context_data = data;
574
}
575
576
stub_manager_int_release(stubmgr);
577
apartment_release(apt);
578
579
return hr;
580
}
581
582
/* returns TRUE if it is possible to unmarshal, FALSE otherwise. */
583
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
584
{
585
BOOL ret = TRUE;
586
struct ifstub *ifstub;
587
588
if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
589
{
590
ERR("attempted unmarshal of unknown IPID %s\n", debugstr_guid(ipid));
591
return FALSE;
592
}
593
594
EnterCriticalSection(&m->lock);
595
596
/* track normal marshals so we can enforce rules whilst in-process */
597
if (ifstub->flags & MSHLFLAGS_NORMAL)
598
{
599
if (m->norm_refs)
600
m->norm_refs--;
601
else
602
{
603
ERR("attempted invalid normal unmarshal, norm_refs is zero\n");
604
ret = FALSE;
605
}
606
}
607
608
LeaveCriticalSection(&m->lock);
609
610
return ret;
611
}
612
613
/* handles refcounting for CoReleaseMarshalData */
614
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak)
615
{
616
struct ifstub *ifstub;
617
618
if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
619
return;
620
621
if (ifstub->flags & MSHLFLAGS_TABLEWEAK)
622
refs = 0;
623
else if (ifstub->flags & MSHLFLAGS_TABLESTRONG)
624
refs = 1;
625
626
stub_manager_ext_release(m, refs, tableweak, !tableweak);
627
}
628
629
/* is an ifstub table marshaled? */
630
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid)
631
{
632
struct ifstub *ifstub = stub_manager_ipid_to_ifstub(m, ipid);
633
634
assert(ifstub);
635
636
return ifstub->flags & (MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK);
637
}
638
639
/*****************************************************************************
640
*
641
* IRemUnknown implementation
642
*
643
*
644
* Note: this object is not related to the lifetime of a stub_manager, but it
645
* interacts with stub managers.
646
*/
647
648
typedef struct rem_unknown
649
{
650
IRemUnknown IRemUnknown_iface;
651
LONG refs;
652
} RemUnknown;
653
654
static const IRemUnknownVtbl RemUnknown_Vtbl;
655
656
static inline RemUnknown *impl_from_IRemUnknown(IRemUnknown *iface)
657
{
658
return CONTAINING_RECORD(iface, RemUnknown, IRemUnknown_iface);
659
}
660
661
/* construct an IRemUnknown object with one outstanding reference */
662
static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown)
663
{
664
RemUnknown *object = malloc(sizeof(*object));
665
666
if (!object)
667
return E_OUTOFMEMORY;
668
669
object->IRemUnknown_iface.lpVtbl = &RemUnknown_Vtbl;
670
object->refs = 1;
671
672
*ppRemUnknown = &object->IRemUnknown_iface;
673
return S_OK;
674
}
675
676
static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv)
677
{
678
TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), ppv);
679
680
if (IsEqualIID(riid, &IID_IUnknown) ||
681
IsEqualIID(riid, &IID_IRemUnknown))
682
{
683
*ppv = iface;
684
IRemUnknown_AddRef(iface);
685
return S_OK;
686
}
687
688
if (!IsEqualIID(riid, &IID_IExternalConnection))
689
FIXME("No interface for iid %s\n", debugstr_guid(riid));
690
691
*ppv = NULL;
692
return E_NOINTERFACE;
693
}
694
695
static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface)
696
{
697
ULONG refs;
698
RemUnknown *remunk = impl_from_IRemUnknown(iface);
699
700
refs = InterlockedIncrement(&remunk->refs);
701
702
TRACE("%p before: %ld\n", iface, refs-1);
703
return refs;
704
}
705
706
static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface)
707
{
708
ULONG refs;
709
RemUnknown *remunk = impl_from_IRemUnknown(iface);
710
711
refs = InterlockedDecrement(&remunk->refs);
712
if (!refs)
713
free(remunk);
714
715
TRACE("%p after: %ld\n", iface, refs);
716
return refs;
717
}
718
719
static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface,
720
REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */,
721
REMQIRESULT **ppQIResults /* [size_is(,cIids)] */)
722
{
723
HRESULT hr;
724
USHORT i;
725
USHORT successful_qis = 0;
726
struct apartment *apt;
727
struct stub_manager *stubmgr;
728
struct ifstub *ifstub;
729
DWORD dest_context;
730
void *dest_context_data;
731
732
TRACE("%p, %s, %ld, %d, %p, %p.\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults);
733
734
hr = ipid_to_ifstub(ripid, &apt, &stubmgr, &ifstub);
735
if (hr != S_OK) return hr;
736
737
IRpcChannelBuffer_GetDestCtx(ifstub->chan, &dest_context, &dest_context_data);
738
739
*ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids);
740
741
for (i = 0; i < cIids; i++)
742
{
743
HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i],
744
stubmgr->object, dest_context, dest_context_data, MSHLFLAGS_NORMAL);
745
if (hrobj == S_OK)
746
successful_qis++;
747
(*ppQIResults)[i].hResult = hrobj;
748
}
749
750
stub_manager_int_release(stubmgr);
751
apartment_release(apt);
752
753
if (successful_qis == cIids)
754
return S_OK; /* we got all requested interfaces */
755
else if (successful_qis == 0)
756
return E_NOINTERFACE; /* we didn't get any interfaces */
757
else
758
return S_FALSE; /* we got some interfaces */
759
}
760
761
static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface,
762
USHORT cInterfaceRefs,
763
REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */,
764
HRESULT *pResults /* [size_is(cInterfaceRefs)] */)
765
{
766
HRESULT hr = S_OK;
767
USHORT i;
768
769
TRACE("%p, %d, %p, %p\n", iface, cInterfaceRefs, InterfaceRefs, pResults);
770
771
for (i = 0; i < cInterfaceRefs; i++)
772
{
773
struct apartment *apt;
774
struct stub_manager *stubmgr;
775
776
pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
777
if (pResults[i] != S_OK)
778
{
779
hr = S_FALSE;
780
continue;
781
}
782
783
stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE);
784
if (InterfaceRefs[i].cPrivateRefs)
785
FIXME("Adding %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
786
787
stub_manager_int_release(stubmgr);
788
apartment_release(apt);
789
}
790
791
return hr;
792
}
793
794
static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface,
795
USHORT cInterfaceRefs,
796
REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */)
797
{
798
HRESULT hr = S_OK;
799
USHORT i;
800
801
TRACE("%p, %d, %p\n", iface, cInterfaceRefs, InterfaceRefs);
802
803
for (i = 0; i < cInterfaceRefs; i++)
804
{
805
struct apartment *apt;
806
struct stub_manager *stubmgr;
807
808
hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
809
if (hr != S_OK)
810
{
811
hr = E_INVALIDARG;
812
/* FIXME: we should undo any changes already made in this function */
813
break;
814
}
815
816
stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE);
817
if (InterfaceRefs[i].cPrivateRefs)
818
FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
819
820
stub_manager_int_release(stubmgr);
821
apartment_release(apt);
822
}
823
824
return hr;
825
}
826
827
static const IRemUnknownVtbl RemUnknown_Vtbl =
828
{
829
RemUnknown_QueryInterface,
830
RemUnknown_AddRef,
831
RemUnknown_Release,
832
RemUnknown_RemQueryInterface,
833
RemUnknown_RemAddRef,
834
RemUnknown_RemRelease
835
};
836
837
/* starts the IRemUnknown listener for the current apartment */
838
HRESULT start_apartment_remote_unknown(struct apartment *apt)
839
{
840
IRemUnknown *pRemUnknown;
841
HRESULT hr = S_OK;
842
843
EnterCriticalSection(&apt->cs);
844
if (!apt->remunk_exported)
845
{
846
/* create the IRemUnknown object */
847
hr = RemUnknown_Construct(&pRemUnknown);
848
if (hr == S_OK)
849
{
850
STDOBJREF stdobjref; /* dummy - not used */
851
/* register it with the stub manager */
852
hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown,
853
MSHCTX_DIFFERENTMACHINE, NULL, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN);
854
/* release our reference to the object as the stub manager will manage the life cycle for us */
855
IRemUnknown_Release(pRemUnknown);
856
if (hr == S_OK)
857
apt->remunk_exported = TRUE;
858
}
859
}
860
LeaveCriticalSection(&apt->cs);
861
return hr;
862
}
863
864