Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/combase/marshal.c
4389 views
1
/*
2
* Copyright 2002 Juergen Schmied
3
* Copyright 2002 Marcus Meissner
4
* Copyright 2004 Mike Hearn, for CodeWeavers
5
* Copyright 2004 Rob Shearman, for CodeWeavers
6
*
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
*/
21
22
#include <assert.h>
23
24
#define COBJMACROS
25
#include "objbase.h"
26
27
#include "dcom.h"
28
#include "combase_private.h"
29
30
#include "wine/debug.h"
31
32
WINE_DEFAULT_DEBUG_CHANNEL(ole);
33
34
HRESULT WINAPI RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
35
const OXID_INFO *oxid_info, const IID *iid,
36
DWORD dest_context, void *dest_context_data,
37
IRpcChannelBuffer **chan, struct apartment *apt);
38
39
static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
40
MSHCTX dest_context, void *dest_context_data,
41
REFIID riid, const OXID_INFO *oxid_info,
42
void **object);
43
44
/* number of refs given out for normal marshaling */
45
#define NORMALEXTREFS 5
46
47
/* private flag indicating that the object was marshaled as table-weak */
48
#define SORFP_TABLEWEAK SORF_OXRES1
49
/* private flag indicating that the caller does not want to notify the stub
50
* when the proxy disconnects or is destroyed */
51
#define SORFP_NOLIFETIMEMGMT SORF_OXRES2
52
53
/* imported interface proxy */
54
struct ifproxy
55
{
56
struct list entry; /* entry in proxy_manager list (CS parent->cs) */
57
struct proxy_manager *parent; /* owning proxy_manager (RO) */
58
void *iface; /* interface pointer (RO) */
59
STDOBJREF stdobjref; /* marshal data that represents this object (RO) */
60
IID iid; /* interface ID (RO) */
61
IRpcProxyBuffer *proxy; /* interface proxy (RO) */
62
ULONG refs; /* imported (public) references (LOCK) */
63
IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */
64
};
65
66
/* imported object / proxy manager */
67
struct proxy_manager
68
{
69
IMultiQI IMultiQI_iface;
70
IMarshal IMarshal_iface;
71
IClientSecurity IClientSecurity_iface;
72
struct apartment *parent; /* owning apartment (RO) */
73
struct list entry; /* entry in apartment (CS parent->cs) */
74
OXID oxid; /* object exported ID (RO) */
75
OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */
76
OID oid; /* object ID (RO) */
77
struct list interfaces; /* imported interfaces (CS cs) */
78
LONG refs; /* proxy reference count (LOCK); 0 if about to be removed from list */
79
CRITICAL_SECTION cs; /* thread safety for this object and children */
80
ULONG sorflags; /* STDOBJREF flags (RO) */
81
IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */
82
HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */
83
MSHCTX dest_context; /* context used for activating optimisations (LOCK) */
84
void *dest_context_data; /* reserved context value (LOCK) */
85
};
86
87
static inline struct proxy_manager *impl_from_IMultiQI(IMultiQI *iface)
88
{
89
return CONTAINING_RECORD(iface, struct proxy_manager, IMultiQI_iface);
90
}
91
92
static inline struct proxy_manager *impl_from_IMarshal(IMarshal *iface)
93
{
94
return CONTAINING_RECORD(iface, struct proxy_manager, IMarshal_iface);
95
}
96
97
static inline struct proxy_manager *impl_from_IClientSecurity(IClientSecurity *iface)
98
{
99
return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface);
100
}
101
102
struct ftmarshaler
103
{
104
IUnknown IUnknown_inner;
105
IMarshal IMarshal_iface;
106
IUnknown *outer_unk;
107
LONG refcount;
108
};
109
110
static struct ftmarshaler *impl_ft_from_IUnknown(IUnknown *iface)
111
{
112
return CONTAINING_RECORD(iface, struct ftmarshaler, IUnknown_inner);
113
}
114
115
static struct ftmarshaler *impl_ft_from_IMarshal(IMarshal *iface)
116
{
117
return CONTAINING_RECORD(iface, struct ftmarshaler, IMarshal_iface);
118
}
119
120
/***********************************************************************
121
* CoMarshalHresult (combase.@)
122
*/
123
HRESULT WINAPI CoMarshalHresult(IStream *stream, HRESULT hresult)
124
{
125
return IStream_Write(stream, &hresult, sizeof(hresult), NULL);
126
}
127
128
/***********************************************************************
129
* CoUnmarshalHresult (combase.@)
130
*/
131
HRESULT WINAPI CoUnmarshalHresult(IStream *stream, HRESULT *phresult)
132
{
133
return IStream_Read(stream, phresult, sizeof(*phresult), NULL);
134
}
135
136
/***********************************************************************
137
* CoGetInterfaceAndReleaseStream (combase.@)
138
*/
139
HRESULT WINAPI CoGetInterfaceAndReleaseStream(IStream *stream, REFIID riid, void **obj)
140
{
141
HRESULT hr;
142
143
TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), obj);
144
145
if (!stream) return E_INVALIDARG;
146
hr = CoUnmarshalInterface(stream, riid, obj);
147
IStream_Release(stream);
148
return hr;
149
}
150
151
/***********************************************************************
152
* CoMarshalInterThreadInterfaceInStream (combase.@)
153
*/
154
HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(REFIID riid, IUnknown *unk, IStream **stream)
155
{
156
ULARGE_INTEGER xpos;
157
LARGE_INTEGER seekto;
158
HRESULT hr;
159
160
TRACE("%s, %p, %p\n", debugstr_guid(riid), unk, stream);
161
162
hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
163
if (FAILED(hr)) return hr;
164
hr = CoMarshalInterface(*stream, riid, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
165
166
if (SUCCEEDED(hr))
167
{
168
memset(&seekto, 0, sizeof(seekto));
169
IStream_Seek(*stream, seekto, STREAM_SEEK_SET, &xpos);
170
}
171
else
172
{
173
IStream_Release(*stream);
174
*stream = NULL;
175
}
176
177
return hr;
178
}
179
180
static HRESULT WINAPI ftmarshaler_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
181
{
182
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
183
184
TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
185
186
*obj = NULL;
187
188
if (IsEqualIID(&IID_IUnknown, riid))
189
*obj = &marshaler->IUnknown_inner;
190
else if (IsEqualIID(&IID_IMarshal, riid))
191
*obj = &marshaler->IMarshal_iface;
192
else
193
{
194
FIXME("No interface for %s\n", debugstr_guid(riid));
195
return E_NOINTERFACE;
196
}
197
198
IUnknown_AddRef((IUnknown *)*obj);
199
200
return S_OK;
201
}
202
203
static ULONG WINAPI ftmarshaler_inner_AddRef(IUnknown *iface)
204
{
205
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
206
ULONG refcount = InterlockedIncrement(&marshaler->refcount);
207
208
TRACE("%p, refcount %lu\n", iface, refcount);
209
210
return refcount;
211
}
212
213
static ULONG WINAPI ftmarshaler_inner_Release(IUnknown *iface)
214
{
215
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
216
ULONG refcount = InterlockedDecrement(&marshaler->refcount);
217
218
TRACE("%p, refcount %lu\n", iface, refcount);
219
220
if (!refcount)
221
free(marshaler);
222
223
return refcount;
224
}
225
226
static const IUnknownVtbl ftmarshaler_inner_vtbl =
227
{
228
ftmarshaler_inner_QueryInterface,
229
ftmarshaler_inner_AddRef,
230
ftmarshaler_inner_Release
231
};
232
233
static HRESULT WINAPI ftmarshaler_QueryInterface(IMarshal *iface, REFIID riid, void **obj)
234
{
235
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
236
237
TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
238
239
return IUnknown_QueryInterface(marshaler->outer_unk, riid, obj);
240
}
241
242
static ULONG WINAPI ftmarshaler_AddRef(IMarshal *iface)
243
{
244
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
245
246
TRACE("%p\n", iface);
247
248
return IUnknown_AddRef(marshaler->outer_unk);
249
}
250
251
static ULONG WINAPI ftmarshaler_Release(IMarshal *iface)
252
{
253
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
254
255
TRACE("%p\n", iface);
256
257
return IUnknown_Release(marshaler->outer_unk);
258
}
259
260
static HRESULT WINAPI ftmarshaler_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
261
DWORD dest_context, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
262
{
263
TRACE("%s, %p, %#lx, %p, %#lx, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, clsid);
264
265
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
266
*clsid = CLSID_InProcFreeMarshaler;
267
else
268
*clsid = CLSID_StdMarshal;
269
270
return S_OK;
271
}
272
273
union ftmarshaler_data
274
{
275
UINT64 value;
276
IUnknown *object;
277
};
278
279
static HRESULT WINAPI ftmarshaler_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
280
DWORD dest_context, void *pvDestContext, DWORD mshlflags, DWORD *size)
281
{
282
IMarshal *marshal = NULL;
283
HRESULT hr;
284
285
TRACE("%s, %p, %#lx, %p, %#lx, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, size);
286
287
/* If the marshalling happens inside the same process the interface pointer is
288
copied between the apartments */
289
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
290
{
291
*size = sizeof(mshlflags) + sizeof(union ftmarshaler_data) + sizeof(GUID);
292
return S_OK;
293
}
294
295
/* Use the standard marshaller to handle all other cases */
296
CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
297
hr = IMarshal_GetMarshalSizeMax(marshal, riid, pv, dest_context, pvDestContext, mshlflags, size);
298
IMarshal_Release(marshal);
299
return hr;
300
}
301
302
static HRESULT WINAPI ftmarshaler_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid,
303
void *pv, DWORD dest_context, void *pvDestContext, DWORD mshlflags)
304
{
305
IMarshal *marshal = NULL;
306
HRESULT hr;
307
308
TRACE("%p, %s, %p, %#lx, %p, %#lx\n", stream, debugstr_guid(riid), pv,
309
dest_context, pvDestContext, mshlflags);
310
311
/* If the marshalling happens inside the same process the interface pointer is
312
copied between the apartments */
313
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
314
{
315
union ftmarshaler_data data;
316
GUID unknown_guid = { 0 };
317
318
data.value = 0;
319
hr = IUnknown_QueryInterface((IUnknown *)pv, riid, (void **)&data.object);
320
if (FAILED(hr))
321
return hr;
322
323
/* don't hold a reference to table-weak marshaled interfaces */
324
if (mshlflags & MSHLFLAGS_TABLEWEAK)
325
IUnknown_Release(data.object);
326
327
hr = IStream_Write(stream, &mshlflags, sizeof(mshlflags), NULL);
328
if (hr != S_OK) return STG_E_MEDIUMFULL;
329
330
hr = IStream_Write(stream, &data, sizeof(data), NULL);
331
if (hr != S_OK) return STG_E_MEDIUMFULL;
332
333
hr = IStream_Write(stream, &unknown_guid, sizeof(unknown_guid), NULL);
334
if (hr != S_OK) return STG_E_MEDIUMFULL;
335
336
return S_OK;
337
}
338
339
/* Use the standard marshaler to handle all other cases */
340
CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
341
hr = IMarshal_MarshalInterface(marshal, stream, riid, pv, dest_context, pvDestContext, mshlflags);
342
IMarshal_Release(marshal);
343
return hr;
344
}
345
346
static HRESULT WINAPI ftmarshaler_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv)
347
{
348
union ftmarshaler_data data;
349
DWORD mshlflags;
350
GUID unknown_guid;
351
HRESULT hr;
352
353
TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
354
355
hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
356
if (hr != S_OK) return STG_E_READFAULT;
357
358
hr = IStream_Read(stream, &data, sizeof(data), NULL);
359
if (hr != S_OK) return STG_E_READFAULT;
360
361
hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
362
if (hr != S_OK) return STG_E_READFAULT;
363
364
hr = IUnknown_QueryInterface(data.object, riid, ppv);
365
if (!(mshlflags & (MSHLFLAGS_TABLEWEAK | MSHLFLAGS_TABLESTRONG)))
366
IUnknown_Release(data.object);
367
368
return hr;
369
}
370
371
static HRESULT WINAPI ftmarshaler_ReleaseMarshalData(IMarshal *iface, IStream *stream)
372
{
373
union ftmarshaler_data data;
374
DWORD mshlflags;
375
GUID unknown_guid;
376
HRESULT hr;
377
378
TRACE("%p\n", stream);
379
380
hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
381
if (hr != S_OK) return STG_E_READFAULT;
382
383
hr = IStream_Read(stream, &data, sizeof(data), NULL);
384
if (hr != S_OK) return STG_E_READFAULT;
385
386
hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
387
if (hr != S_OK) return STG_E_READFAULT;
388
389
IUnknown_Release(data.object);
390
return S_OK;
391
}
392
393
static HRESULT WINAPI ftmarshaler_DisconnectObject(IMarshal *iface, DWORD reserved)
394
{
395
TRACE("\n");
396
397
/* nothing to do */
398
return S_OK;
399
}
400
401
static const IMarshalVtbl ftmarshaler_vtbl =
402
{
403
ftmarshaler_QueryInterface,
404
ftmarshaler_AddRef,
405
ftmarshaler_Release,
406
ftmarshaler_GetUnmarshalClass,
407
ftmarshaler_GetMarshalSizeMax,
408
ftmarshaler_MarshalInterface,
409
ftmarshaler_UnmarshalInterface,
410
ftmarshaler_ReleaseMarshalData,
411
ftmarshaler_DisconnectObject
412
};
413
414
/***********************************************************************
415
* CoCreateFreeThreadedMarshaler (combase.@)
416
*/
417
HRESULT WINAPI CoCreateFreeThreadedMarshaler(IUnknown *outer, IUnknown **marshaler)
418
{
419
struct ftmarshaler *object;
420
421
TRACE("%p, %p\n", outer, marshaler);
422
423
object = malloc(sizeof(*object));
424
if (!object)
425
return E_OUTOFMEMORY;
426
427
object->IUnknown_inner.lpVtbl = &ftmarshaler_inner_vtbl;
428
object->IMarshal_iface.lpVtbl = &ftmarshaler_vtbl;
429
object->refcount = 1;
430
object->outer_unk = outer ? outer : &object->IUnknown_inner;
431
432
*marshaler = &object->IUnknown_inner;
433
434
return S_OK;
435
}
436
437
/***********************************************************************
438
* CoGetMarshalSizeMax (combase.@)
439
*/
440
HRESULT WINAPI CoGetMarshalSizeMax(ULONG *size, REFIID riid, IUnknown *unk,
441
DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
442
{
443
BOOL std_marshal = FALSE;
444
IMarshal *marshal;
445
HRESULT hr;
446
447
if (!unk)
448
return E_POINTER;
449
450
hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
451
if (hr != S_OK)
452
{
453
std_marshal = TRUE;
454
hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
455
}
456
if (hr != S_OK)
457
return hr;
458
459
hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags, size);
460
if (!std_marshal)
461
/* add on the size of the whole OBJREF structure like native does */
462
*size += sizeof(OBJREF);
463
464
IMarshal_Release(marshal);
465
return hr;
466
}
467
468
static void dump_mshflags(MSHLFLAGS flags)
469
{
470
if (flags & MSHLFLAGS_TABLESTRONG)
471
TRACE(" MSHLFLAGS_TABLESTRONG");
472
if (flags & MSHLFLAGS_TABLEWEAK)
473
TRACE(" MSHLFLAGS_TABLEWEAK");
474
if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
475
TRACE(" MSHLFLAGS_NORMAL");
476
if (flags & MSHLFLAGS_NOPING)
477
TRACE(" MSHLFLAGS_NOPING");
478
}
479
480
/***********************************************************************
481
* CoMarshalInterface (combase.@)
482
*/
483
HRESULT WINAPI CoMarshalInterface(IStream *stream, REFIID riid, IUnknown *unk,
484
DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
485
{
486
CLSID marshaler_clsid;
487
IMarshal *marshal;
488
HRESULT hr;
489
490
TRACE("%p, %s, %p, %lx, %p, ", stream, debugstr_guid(riid), unk, dest_context, pvDestContext);
491
dump_mshflags(mshlFlags);
492
TRACE("\n");
493
494
if (!unk || !stream)
495
return E_INVALIDARG;
496
497
hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
498
if (hr != S_OK)
499
hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
500
if (hr != S_OK)
501
{
502
ERR("Failed to get marshaller, %#lx\n", hr);
503
return hr;
504
}
505
506
hr = IMarshal_GetUnmarshalClass(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
507
&marshaler_clsid);
508
if (hr != S_OK)
509
{
510
ERR("IMarshal::GetUnmarshalClass failed, %#lx\n", hr);
511
goto cleanup;
512
}
513
514
/* FIXME: implement handler marshaling too */
515
if (IsEqualCLSID(&marshaler_clsid, &CLSID_StdMarshal))
516
{
517
TRACE("Using standard marshaling\n");
518
}
519
else
520
{
521
OBJREF objref;
522
523
TRACE("Using custom marshaling\n");
524
objref.signature = OBJREF_SIGNATURE;
525
objref.iid = *riid;
526
objref.flags = OBJREF_CUSTOM;
527
objref.u_objref.u_custom.clsid = marshaler_clsid;
528
objref.u_objref.u_custom.cbExtension = 0;
529
objref.u_objref.u_custom.size = 0;
530
hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
531
&objref.u_objref.u_custom.size);
532
if (hr != S_OK)
533
{
534
ERR("Failed to get max size of marshal data, error %#lx\n", hr);
535
goto cleanup;
536
}
537
/* write constant sized common header and OR_CUSTOM data into stream */
538
hr = IStream_Write(stream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
539
if (hr != S_OK)
540
{
541
ERR("Failed to write OR_CUSTOM header to stream with %#lx\n", hr);
542
goto cleanup;
543
}
544
}
545
546
TRACE("Calling IMarshal::MarshalInterface\n");
547
548
hr = IMarshal_MarshalInterface(marshal, stream, riid, unk, dest_context, pvDestContext, mshlFlags);
549
if (hr != S_OK)
550
{
551
ERR("Failed to marshal the interface %s, hr %#lx\n", debugstr_guid(riid), hr);
552
goto cleanup;
553
}
554
555
cleanup:
556
IMarshal_Release(marshal);
557
558
TRACE("completed with hr %#lx\n", hr);
559
560
return hr;
561
}
562
563
/* Creates an IMarshal* object according to the data marshaled to the stream.
564
* The function leaves the stream pointer at the start of the data written
565
* to the stream by the IMarshal* object.
566
*/
567
static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
568
{
569
OBJREF objref;
570
HRESULT hr;
571
ULONG res;
572
573
/* read common OBJREF header */
574
hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
575
if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
576
{
577
ERR("Failed to read common OBJREF header, %#lx\n", hr);
578
return STG_E_READFAULT;
579
}
580
581
/* sanity check on header */
582
if (objref.signature != OBJREF_SIGNATURE)
583
{
584
ERR("Bad OBJREF signature %#lx\n", objref.signature);
585
return RPC_E_INVALID_OBJREF;
586
}
587
588
if (iid) *iid = objref.iid;
589
590
/* FIXME: handler marshaling */
591
if (objref.flags & OBJREF_STANDARD)
592
{
593
TRACE("Using standard unmarshaling\n");
594
*marshal = NULL;
595
return S_FALSE;
596
}
597
else if (objref.flags & OBJREF_CUSTOM)
598
{
599
ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) -
600
FIELD_OFFSET(OBJREF, u_objref.u_custom);
601
TRACE("Using custom unmarshaling\n");
602
/* read constant sized OR_CUSTOM data from stream */
603
hr = IStream_Read(stream, &objref.u_objref.u_custom,
604
custom_header_size, &res);
605
if (hr != S_OK || (res != custom_header_size))
606
{
607
ERR("Failed to read OR_CUSTOM header, %#lx\n", hr);
608
return STG_E_READFAULT;
609
}
610
/* now create the marshaler specified in the stream */
611
hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
612
CLSCTX_INPROC_SERVER, &IID_IMarshal,
613
(LPVOID*)marshal);
614
}
615
else
616
{
617
FIXME("Invalid or unimplemented marshaling type specified: %lx\n", objref.flags);
618
return RPC_E_INVALID_OBJREF;
619
}
620
621
if (hr != S_OK)
622
ERR("Failed to create marshal, %#lx\n", hr);
623
624
return hr;
625
}
626
627
static HRESULT std_release_marshal_data(IStream *stream)
628
{
629
struct stub_manager *stubmgr;
630
struct OR_STANDARD obj;
631
struct apartment *apt;
632
ULONG res;
633
HRESULT hr;
634
635
hr = IStream_Read(stream, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res);
636
if (hr != S_OK) return STG_E_READFAULT;
637
638
if (obj.saResAddr.wNumEntries)
639
{
640
ERR("unsupported size of DUALSTRINGARRAY\n");
641
return E_NOTIMPL;
642
}
643
644
TRACE("oxid = %s, oid = %s, ipid = %s\n", wine_dbgstr_longlong(obj.std.oxid),
645
wine_dbgstr_longlong(obj.std.oid), wine_dbgstr_guid(&obj.std.ipid));
646
647
if (!(apt = apartment_findfromoxid(obj.std.oxid)))
648
{
649
WARN("Could not map OXID %s to apartment object\n",
650
wine_dbgstr_longlong(obj.std.oxid));
651
return RPC_E_INVALID_OBJREF;
652
}
653
654
if (!(stubmgr = get_stub_manager(apt, obj.std.oid)))
655
{
656
apartment_release(apt);
657
ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n",
658
wine_dbgstr_longlong(obj.std.oxid), wine_dbgstr_longlong(obj.std.oid));
659
return RPC_E_INVALID_OBJREF;
660
}
661
662
stub_manager_release_marshal_data(stubmgr, obj.std.cPublicRefs, &obj.std.ipid, obj.std.flags & SORFP_TABLEWEAK);
663
664
stub_manager_int_release(stubmgr);
665
apartment_release(apt);
666
667
return S_OK;
668
}
669
670
/***********************************************************************
671
* CoReleaseMarshalData (combase.@)
672
*/
673
HRESULT WINAPI CoReleaseMarshalData(IStream *stream)
674
{
675
IMarshal *marshal;
676
HRESULT hr;
677
678
TRACE("%p\n", stream);
679
680
hr = get_unmarshaler_from_stream(stream, &marshal, NULL);
681
if (hr == S_FALSE)
682
{
683
hr = std_release_marshal_data(stream);
684
if (hr != S_OK)
685
ERR("StdMarshal ReleaseMarshalData failed with error %#lx\n", hr);
686
return hr;
687
}
688
if (hr != S_OK)
689
return hr;
690
691
/* call the helper object to do the releasing of marshal data */
692
hr = IMarshal_ReleaseMarshalData(marshal, stream);
693
if (hr != S_OK)
694
ERR("IMarshal::ReleaseMarshalData failed with error %#lx\n", hr);
695
696
IMarshal_Release(marshal);
697
return hr;
698
}
699
700
static HRESULT std_unmarshal_interface(MSHCTX dest_context, void *dest_context_data,
701
IStream *stream, REFIID riid, void **ppv, BOOL dest_context_known)
702
{
703
struct stub_manager *stubmgr = NULL;
704
struct OR_STANDARD obj;
705
ULONG res;
706
HRESULT hres;
707
struct apartment *apt, *stub_apt;
708
709
TRACE("(...,%s,....)\n", debugstr_guid(riid));
710
711
/* we need an apartment to unmarshal into */
712
if (!(apt = apartment_get_current_or_mta()))
713
{
714
ERR("Apartment not initialized\n");
715
return CO_E_NOTINITIALIZED;
716
}
717
718
/* read STDOBJREF from wire */
719
hres = IStream_Read(stream, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res);
720
if (hres != S_OK)
721
{
722
apartment_release(apt);
723
return STG_E_READFAULT;
724
}
725
726
if (obj.saResAddr.wNumEntries)
727
{
728
ERR("unsupported size of DUALSTRINGARRAY\n");
729
return E_NOTIMPL;
730
}
731
732
/* check if we're marshalling back to ourselves */
733
if ((apartment_getoxid(apt) == obj.std.oxid) && (stubmgr = get_stub_manager(apt, obj.std.oid)))
734
{
735
TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
736
"returning original object %p\n", debugstr_guid(riid), stubmgr->object);
737
738
hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
739
740
/* unref the ifstub. FIXME: only do this on success? */
741
if (!stub_manager_is_table_marshaled(stubmgr, &obj.std.ipid))
742
stub_manager_ext_release(stubmgr, obj.std.cPublicRefs, obj.std.flags & SORFP_TABLEWEAK, FALSE);
743
744
stub_manager_int_release(stubmgr);
745
apartment_release(apt);
746
return hres;
747
}
748
749
/* notify stub manager about unmarshal if process-local object.
750
* note: if the oxid is not found then we and native will quite happily
751
* ignore table marshaling and normal marshaling rules regarding number of
752
* unmarshals, etc, but if you abuse these rules then your proxy could end
753
* up returning RPC_E_DISCONNECTED. */
754
if ((stub_apt = apartment_findfromoxid(obj.std.oxid)))
755
{
756
if ((stubmgr = get_stub_manager(stub_apt, obj.std.oid)))
757
{
758
if (!stub_manager_notify_unmarshal(stubmgr, &obj.std.ipid))
759
hres = CO_E_OBJNOTCONNECTED;
760
if (SUCCEEDED(hres) && !dest_context_known)
761
hres = ipid_get_dest_context(&obj.std.ipid, &dest_context, &dest_context_data);
762
}
763
else
764
{
765
WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
766
wine_dbgstr_longlong(obj.std.oxid),
767
wine_dbgstr_longlong(obj.std.oid));
768
hres = CO_E_OBJNOTCONNECTED;
769
}
770
}
771
else
772
TRACE("Treating unmarshal from OXID %s as inter-process\n",
773
wine_dbgstr_longlong(obj.std.oxid));
774
775
if (hres == S_OK)
776
hres = unmarshal_object(&obj.std, apt, dest_context,
777
dest_context_data, riid,
778
stubmgr ? &stubmgr->oxid_info : NULL, ppv);
779
780
if (stubmgr) stub_manager_int_release(stubmgr);
781
if (stub_apt) apartment_release(stub_apt);
782
783
if (hres != S_OK) WARN("Failed with error %#lx\n", hres);
784
else TRACE("Successfully created proxy %p\n", *ppv);
785
786
apartment_release(apt);
787
return hres;
788
}
789
790
/***********************************************************************
791
* CoUnmarshalInterface (combase.@)
792
*/
793
HRESULT WINAPI CoUnmarshalInterface(IStream *stream, REFIID riid, void **ppv)
794
{
795
IMarshal *marshal;
796
IUnknown *object;
797
HRESULT hr;
798
IID iid;
799
800
TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
801
802
if (!stream || !ppv)
803
return E_INVALIDARG;
804
805
hr = get_unmarshaler_from_stream(stream, &marshal, &iid);
806
if (hr == S_FALSE)
807
{
808
hr = std_unmarshal_interface(0, NULL, stream, &iid, (void **)&object, FALSE);
809
if (hr != S_OK)
810
ERR("StdMarshal UnmarshalInterface failed, hr %#lx\n", hr);
811
}
812
else if (hr == S_OK)
813
{
814
/* call the helper object to do the actual unmarshaling */
815
hr = IMarshal_UnmarshalInterface(marshal, stream, &iid, (void **)&object);
816
IMarshal_Release(marshal);
817
if (hr != S_OK)
818
ERR("IMarshal::UnmarshalInterface failed, hr %#lx\n", hr);
819
}
820
821
if (hr == S_OK)
822
{
823
/* IID_NULL means use the interface ID of the marshaled object */
824
if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
825
{
826
TRACE("requested interface != marshalled interface, additional QI needed\n");
827
hr = IUnknown_QueryInterface(object, riid, ppv);
828
if (hr != S_OK)
829
ERR("Couldn't query for interface %s, hr %#lx\n", debugstr_guid(riid), hr);
830
IUnknown_Release(object);
831
}
832
else
833
{
834
*ppv = object;
835
}
836
}
837
838
TRACE("completed with hr %#lx\n", hr);
839
840
return hr;
841
}
842
843
/* Marshalling just passes a unique identifier to the remote client,
844
* that makes it possible to find the passed interface again.
845
*
846
* So basically we need a set of values that make it unique.
847
*
848
* Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
849
*
850
* A triple is used: OXID (apt id), OID (stub manager id),
851
* IPID (interface ptr/stub id).
852
*
853
* OXIDs identify an apartment and are network scoped
854
* OIDs identify a stub manager and are apartment scoped
855
* IPIDs identify an interface stub and are apartment scoped
856
*/
857
858
static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
859
{
860
HRESULT hr;
861
CLSID clsid;
862
863
hr = CoGetPSClsid(riid, &clsid);
864
if (hr != S_OK)
865
return hr;
866
return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | CLSCTX_PS_DLL, NULL, &IID_IPSFactoryBuffer, (void **)facbuf);
867
}
868
869
/* marshals an object into a STDOBJREF structure */
870
HRESULT marshal_object(struct apartment *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object,
871
DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags)
872
{
873
struct stub_manager *manager;
874
struct ifstub *ifstub;
875
BOOL tablemarshal;
876
HRESULT hr;
877
878
stdobjref->oxid = apartment_getoxid(apt);
879
880
hr = apartment_createwindowifneeded(apt);
881
if (hr != S_OK)
882
return hr;
883
884
if (!(manager = get_stub_manager_from_object(apt, object, TRUE)))
885
return E_OUTOFMEMORY;
886
887
stdobjref->flags = SORF_NULL;
888
if (mshlflags & MSHLFLAGS_TABLEWEAK)
889
stdobjref->flags |= SORFP_TABLEWEAK;
890
if (mshlflags & MSHLFLAGS_NOPING)
891
stdobjref->flags |= SORF_NOPING;
892
stdobjref->oid = manager->oid;
893
894
tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
895
896
/* make sure ifstub that we are creating is unique */
897
ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
898
if (!ifstub) {
899
IRpcStubBuffer *stub = NULL;
900
901
/* IUnknown doesn't require a stub buffer, because it never goes out on
902
* the wire */
903
if (!IsEqualIID(riid, &IID_IUnknown))
904
{
905
IPSFactoryBuffer *psfb;
906
907
hr = get_facbuf_for_iid(riid, &psfb);
908
if (hr == S_OK) {
909
hr = IPSFactoryBuffer_CreateStub(psfb, riid, manager->object, &stub);
910
IPSFactoryBuffer_Release(psfb);
911
if (hr != S_OK)
912
ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error %#lx\n",
913
debugstr_guid(riid), hr);
914
}else {
915
WARN("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
916
hr = E_NOINTERFACE;
917
}
918
919
}
920
921
if (hr == S_OK) {
922
ifstub = stub_manager_new_ifstub(manager, stub, riid, dest_context, dest_context_data, mshlflags);
923
if (!ifstub)
924
hr = E_OUTOFMEMORY;
925
}
926
if (stub) IRpcStubBuffer_Release(stub);
927
928
if (hr != S_OK) {
929
stub_manager_int_release(manager);
930
/* destroy the stub manager if it has no ifstubs by releasing
931
* zero external references */
932
stub_manager_ext_release(manager, 0, FALSE, TRUE);
933
return hr;
934
}
935
}
936
937
if (!tablemarshal)
938
{
939
stdobjref->cPublicRefs = NORMALEXTREFS;
940
stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
941
}
942
else
943
{
944
stdobjref->cPublicRefs = 0;
945
if (mshlflags & MSHLFLAGS_TABLESTRONG)
946
stub_manager_ext_addref(manager, 1, FALSE);
947
else
948
stub_manager_ext_addref(manager, 0, TRUE);
949
}
950
951
/* FIXME: check return value */
952
rpc_register_interface(riid);
953
954
stdobjref->ipid = ifstub->ipid;
955
956
stub_manager_int_release(manager);
957
return S_OK;
958
}
959
960
/* Client-side identity of the server object */
961
962
static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
963
static void proxy_manager_destroy(struct proxy_manager * This);
964
static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
965
static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
966
967
static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
968
{
969
HRESULT hr;
970
MULTI_QI mqi;
971
972
TRACE("%s\n", debugstr_guid(riid));
973
974
mqi.pIID = riid;
975
hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
976
*ppv = mqi.pItf;
977
978
return hr;
979
}
980
981
static ULONG WINAPI ClientIdentity_AddRef(IMultiQI *iface)
982
{
983
struct proxy_manager *This = impl_from_IMultiQI(iface);
984
TRACE("%p - before %ld\n", iface, This->refs);
985
return InterlockedIncrement(&This->refs);
986
}
987
988
static ULONG WINAPI ClientIdentity_Release(IMultiQI *iface)
989
{
990
struct proxy_manager *This = impl_from_IMultiQI(iface);
991
ULONG refs = InterlockedDecrement(&This->refs);
992
TRACE("%p - after %ld\n", iface, refs);
993
if (!refs)
994
proxy_manager_destroy(This);
995
return refs;
996
}
997
998
static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
999
{
1000
struct proxy_manager *This = impl_from_IMultiQI(iface);
1001
REMQIRESULT *qiresults = NULL;
1002
ULONG nonlocal_mqis = 0;
1003
ULONG i;
1004
ULONG successful_mqis = 0;
1005
IID *iids = malloc(cMQIs * sizeof(*iids));
1006
/* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
1007
ULONG *mapping = malloc(cMQIs * sizeof(*mapping));
1008
1009
TRACE("cMQIs: %ld\n", cMQIs);
1010
1011
/* try to get a local interface - this includes already active proxy
1012
* interfaces and also interfaces exposed by the proxy manager */
1013
for (i = 0; i < cMQIs; i++)
1014
{
1015
TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
1016
pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
1017
if (pMQIs[i].hr == S_OK)
1018
successful_mqis++;
1019
else
1020
{
1021
iids[nonlocal_mqis] = *pMQIs[i].pIID;
1022
mapping[nonlocal_mqis] = i;
1023
nonlocal_mqis++;
1024
}
1025
}
1026
1027
TRACE("%ld interfaces not found locally\n", nonlocal_mqis);
1028
1029
/* if we have more than one interface not found locally then we must try
1030
* to query the remote object for it */
1031
if (nonlocal_mqis != 0)
1032
{
1033
IRemUnknown *remunk;
1034
HRESULT hr;
1035
IPID *ipid;
1036
1037
/* get the ipid of the first entry */
1038
/* FIXME: should we implement ClientIdentity on the ifproxies instead
1039
* of the proxy_manager so we use the correct ipid here? */
1040
ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
1041
1042
/* get IRemUnknown proxy so we can communicate with the remote object */
1043
hr = proxy_manager_get_remunknown(This, &remunk);
1044
1045
if (SUCCEEDED(hr))
1046
{
1047
hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
1048
nonlocal_mqis, iids, &qiresults);
1049
IRemUnknown_Release(remunk);
1050
if (FAILED(hr))
1051
WARN("IRemUnknown_RemQueryInterface failed with error %#lx\n", hr);
1052
}
1053
1054
/* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
1055
* the interfaces were returned */
1056
if (SUCCEEDED(hr))
1057
{
1058
struct apartment *apt = apartment_get_current_or_mta();
1059
1060
/* try to unmarshal each object returned to us */
1061
for (i = 0; i < nonlocal_mqis; i++)
1062
{
1063
ULONG index = mapping[i];
1064
HRESULT hrobj = qiresults[i].hResult;
1065
if (hrobj == S_OK)
1066
hrobj = unmarshal_object(&qiresults[i].std, apt,
1067
This->dest_context,
1068
This->dest_context_data,
1069
pMQIs[index].pIID, &This->oxid_info,
1070
(void **)&pMQIs[index].pItf);
1071
1072
if (hrobj == S_OK)
1073
successful_mqis++;
1074
else
1075
ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
1076
pMQIs[index].hr = hrobj;
1077
}
1078
1079
apartment_release(apt);
1080
}
1081
1082
/* free the memory allocated by the proxy */
1083
CoTaskMemFree(qiresults);
1084
}
1085
1086
TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs);
1087
1088
free(iids);
1089
free(mapping);
1090
1091
if (successful_mqis == cMQIs)
1092
return S_OK; /* we got all requested interfaces */
1093
else if (successful_mqis == 0)
1094
return E_NOINTERFACE; /* we didn't get any interfaces */
1095
else
1096
return S_FALSE; /* we got some interfaces */
1097
}
1098
1099
static const IMultiQIVtbl ClientIdentity_Vtbl =
1100
{
1101
ClientIdentity_QueryInterface,
1102
ClientIdentity_AddRef,
1103
ClientIdentity_Release,
1104
ClientIdentity_QueryMultipleInterfaces
1105
};
1106
1107
static HRESULT StdMarshalImpl_Construct(REFIID, DWORD, void*, void**);
1108
1109
static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
1110
{
1111
struct proxy_manager *This = impl_from_IMarshal( iface );
1112
return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
1113
}
1114
1115
static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
1116
{
1117
struct proxy_manager *This = impl_from_IMarshal( iface );
1118
return IMultiQI_AddRef(&This->IMultiQI_iface);
1119
}
1120
1121
static ULONG WINAPI Proxy_Release(IMarshal *iface)
1122
{
1123
struct proxy_manager *This = impl_from_IMarshal( iface );
1124
return IMultiQI_Release(&This->IMultiQI_iface);
1125
}
1126
1127
static HRESULT WINAPI Proxy_GetUnmarshalClass(
1128
IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1129
void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1130
{
1131
*pCid = CLSID_StdMarshal;
1132
return S_OK;
1133
}
1134
1135
static HRESULT WINAPI Proxy_GetMarshalSizeMax(
1136
IMarshal *iface, REFIID riid, void* pv, DWORD dwDestContext,
1137
void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1138
{
1139
*pSize = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
1140
return S_OK;
1141
}
1142
1143
static void fill_std_objref(OBJREF *objref, const GUID *iid, STDOBJREF *std)
1144
{
1145
objref->signature = OBJREF_SIGNATURE;
1146
objref->flags = OBJREF_STANDARD;
1147
objref->iid = *iid;
1148
if(std)
1149
objref->u_objref.u_standard.std = *std;
1150
memset(&objref->u_objref.u_standard.saResAddr, 0,
1151
sizeof(objref->u_objref.u_standard.saResAddr));
1152
}
1153
1154
static HRESULT WINAPI Proxy_MarshalInterface(
1155
LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
1156
void* pvDestContext, DWORD mshlflags)
1157
{
1158
struct proxy_manager *This = impl_from_IMarshal( iface );
1159
HRESULT hr;
1160
struct ifproxy *ifproxy;
1161
1162
TRACE("(...,%s,...)\n", debugstr_guid(riid));
1163
1164
hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
1165
if (SUCCEEDED(hr))
1166
{
1167
STDOBJREF stdobjref = ifproxy->stdobjref;
1168
1169
stdobjref.cPublicRefs = 0;
1170
1171
if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
1172
(mshlflags != MSHLFLAGS_TABLESTRONG))
1173
{
1174
ULONG cPublicRefs = ifproxy->refs;
1175
ULONG cPublicRefsOld;
1176
/* optimization - share out proxy's public references if possible
1177
* instead of making new proxy do a roundtrip through the server */
1178
do
1179
{
1180
ULONG cPublicRefsNew;
1181
cPublicRefsOld = cPublicRefs;
1182
stdobjref.cPublicRefs = cPublicRefs / 2;
1183
cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
1184
cPublicRefs = InterlockedCompareExchange(
1185
(LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
1186
} while (cPublicRefs != cPublicRefsOld);
1187
}
1188
1189
/* normal and table-strong marshaling need at least one reference */
1190
if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
1191
{
1192
IRemUnknown *remunk;
1193
hr = proxy_manager_get_remunknown(This, &remunk);
1194
if (hr == S_OK)
1195
{
1196
HRESULT hrref = S_OK;
1197
REMINTERFACEREF rif;
1198
rif.ipid = ifproxy->stdobjref.ipid;
1199
rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
1200
rif.cPrivateRefs = 0;
1201
hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
1202
IRemUnknown_Release(remunk);
1203
if (hr == S_OK && hrref == S_OK)
1204
{
1205
/* table-strong marshaling doesn't give the refs to the
1206
* client that unmarshals the STDOBJREF */
1207
if (mshlflags != MSHLFLAGS_TABLESTRONG)
1208
stdobjref.cPublicRefs = rif.cPublicRefs;
1209
}
1210
else
1211
ERR("IRemUnknown_RemAddRef returned with %#lx, hrref = %#lx\n", hr, hrref);
1212
}
1213
}
1214
1215
if (SUCCEEDED(hr))
1216
{
1217
OBJREF objref;
1218
1219
TRACE("writing stdobjref: flags = %#lx cPublicRefs = %ld oxid = %s oid = %s ipid = %s\n",
1220
stdobjref.flags, stdobjref.cPublicRefs,
1221
wine_dbgstr_longlong(stdobjref.oxid),
1222
wine_dbgstr_longlong(stdobjref.oid),
1223
debugstr_guid(&stdobjref.ipid));
1224
fill_std_objref(&objref, riid, &stdobjref);
1225
hr = IStream_Write(pStm, &objref, FIELD_OFFSET(OBJREF,
1226
u_objref.u_standard.saResAddr.aStringArray), NULL);
1227
}
1228
}
1229
else
1230
{
1231
/* we don't have the interface already unmarshaled so we have to
1232
* request the object from the server */
1233
IRemUnknown *remunk;
1234
IPID *ipid;
1235
REMQIRESULT *qiresults = NULL;
1236
IID iid = *riid;
1237
1238
/* get the ipid of the first entry */
1239
/* FIXME: should we implement ClientIdentity on the ifproxies instead
1240
* of the proxy_manager so we use the correct ipid here? */
1241
ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
1242
1243
/* get IRemUnknown proxy so we can communicate with the remote object */
1244
hr = proxy_manager_get_remunknown(This, &remunk);
1245
1246
if (hr == S_OK)
1247
{
1248
hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
1249
1, &iid, &qiresults);
1250
if (SUCCEEDED(hr))
1251
{
1252
OBJREF objref;
1253
1254
fill_std_objref(&objref, riid, &qiresults->std);
1255
hr = IStream_Write(pStm, &objref, FIELD_OFFSET(OBJREF,
1256
u_objref.u_standard.saResAddr.aStringArray), NULL);
1257
if (FAILED(hr))
1258
{
1259
REMINTERFACEREF rif;
1260
rif.ipid = qiresults->std.ipid;
1261
rif.cPublicRefs = qiresults->std.cPublicRefs;
1262
rif.cPrivateRefs = 0;
1263
IRemUnknown_RemRelease(remunk, 1, &rif);
1264
}
1265
CoTaskMemFree(qiresults);
1266
}
1267
else
1268
ERR("IRemUnknown_RemQueryInterface failed with error %#lx\n", hr);
1269
IRemUnknown_Release(remunk);
1270
}
1271
}
1272
1273
return hr;
1274
}
1275
1276
static HRESULT WINAPI Proxy_UnmarshalInterface(
1277
IMarshal *iface, IStream *pStm, REFIID riid, void **ppv)
1278
{
1279
struct proxy_manager *This = impl_from_IMarshal( iface );
1280
IMarshal *marshal;
1281
HRESULT hr;
1282
1283
TRACE("(%p, %p, %s, %p)\n", This, pStm, wine_dbgstr_guid(riid), ppv);
1284
1285
hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1286
This->dest_context_data, (void**)&marshal);
1287
if(FAILED(hr))
1288
return hr;
1289
1290
hr = IMarshal_UnmarshalInterface(marshal, pStm, riid, ppv);
1291
IMarshal_Release(marshal);
1292
return hr;
1293
}
1294
1295
static HRESULT WINAPI Proxy_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1296
{
1297
struct proxy_manager *This = impl_from_IMarshal( iface );
1298
IMarshal *marshal;
1299
HRESULT hr;
1300
1301
TRACE("(%p, %p)\n", This, pStm);
1302
1303
hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1304
This->dest_context_data, (void**)&marshal);
1305
if(FAILED(hr))
1306
return hr;
1307
1308
hr = IMarshal_ReleaseMarshalData(marshal, pStm);
1309
IMarshal_Release(marshal);
1310
return hr;
1311
}
1312
1313
static HRESULT WINAPI Proxy_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1314
{
1315
struct proxy_manager *This = impl_from_IMarshal( iface );
1316
IMarshal *marshal;
1317
HRESULT hr;
1318
1319
TRACE("%p, %#lx\n", This, dwReserved);
1320
1321
hr = StdMarshalImpl_Construct(&IID_IMarshal, This->dest_context,
1322
This->dest_context_data, (void**)&marshal);
1323
if(FAILED(hr))
1324
return hr;
1325
1326
hr = IMarshal_DisconnectObject(marshal, dwReserved);
1327
IMarshal_Release(marshal);
1328
return hr;
1329
}
1330
1331
static const IMarshalVtbl ProxyMarshal_Vtbl =
1332
{
1333
Proxy_QueryInterface,
1334
Proxy_AddRef,
1335
Proxy_Release,
1336
Proxy_GetUnmarshalClass,
1337
Proxy_GetMarshalSizeMax,
1338
Proxy_MarshalInterface,
1339
Proxy_UnmarshalInterface,
1340
Proxy_ReleaseMarshalData,
1341
Proxy_DisconnectObject
1342
};
1343
1344
static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
1345
{
1346
struct proxy_manager *This = impl_from_IClientSecurity( iface );
1347
return IMultiQI_QueryInterface(&This->IMultiQI_iface, riid, ppvObject);
1348
}
1349
1350
static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
1351
{
1352
struct proxy_manager *This = impl_from_IClientSecurity( iface );
1353
return IMultiQI_AddRef(&This->IMultiQI_iface);
1354
}
1355
1356
static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
1357
{
1358
struct proxy_manager *This = impl_from_IClientSecurity( iface );
1359
return IMultiQI_Release(&This->IMultiQI_iface);
1360
}
1361
1362
static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
1363
IUnknown *pProxy,
1364
DWORD *pAuthnSvc,
1365
DWORD *pAuthzSvc,
1366
OLECHAR **ppServerPrincName,
1367
DWORD *pAuthnLevel,
1368
DWORD *pImpLevel,
1369
void **pAuthInfo,
1370
DWORD *pCapabilities)
1371
{
1372
FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
1373
pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
1374
pCapabilities);
1375
1376
if (pAuthnSvc)
1377
*pAuthnSvc = 0;
1378
if (pAuthzSvc)
1379
*pAuthzSvc = 0;
1380
if (ppServerPrincName)
1381
*ppServerPrincName = NULL;
1382
if (pAuthnLevel)
1383
*pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
1384
if (pImpLevel)
1385
*pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
1386
if (pAuthInfo)
1387
*pAuthInfo = NULL;
1388
if (pCapabilities)
1389
*pCapabilities = EOAC_NONE;
1390
1391
return E_NOTIMPL;
1392
}
1393
1394
static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
1395
IUnknown *pProxy, DWORD AuthnSvc,
1396
DWORD AuthzSvc,
1397
OLECHAR *pServerPrincName,
1398
DWORD AuthnLevel, DWORD ImpLevel,
1399
void *pAuthInfo,
1400
DWORD Capabilities)
1401
{
1402
FIXME("%p, %ld, %ld, %s, %ld, %ld, %p, %#lx: stub\n", pProxy, AuthnSvc, AuthzSvc,
1403
pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName),
1404
AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
1405
return E_NOTIMPL;
1406
}
1407
1408
static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
1409
IUnknown *pProxy, IUnknown **ppCopy)
1410
{
1411
FIXME("(%p, %p): stub\n", pProxy, ppCopy);
1412
*ppCopy = NULL;
1413
return E_NOTIMPL;
1414
}
1415
1416
static const IClientSecurityVtbl ProxyCliSec_Vtbl =
1417
{
1418
ProxyCliSec_QueryInterface,
1419
ProxyCliSec_AddRef,
1420
ProxyCliSec_Release,
1421
ProxyCliSec_QueryBlanket,
1422
ProxyCliSec_SetBlanket,
1423
ProxyCliSec_CopyProxy
1424
};
1425
1426
static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
1427
{
1428
HRESULT hr = S_OK;
1429
1430
if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
1431
{
1432
ERR("Wait failed for ifproxy %p\n", This);
1433
return E_UNEXPECTED;
1434
}
1435
1436
if (This->refs == 0)
1437
{
1438
IRemUnknown *remunk = NULL;
1439
1440
TRACE("getting public ref for ifproxy %p\n", This);
1441
1442
hr = proxy_manager_get_remunknown(This->parent, &remunk);
1443
if (hr == S_OK)
1444
{
1445
HRESULT hrref = S_OK;
1446
REMINTERFACEREF rif;
1447
rif.ipid = This->stdobjref.ipid;
1448
rif.cPublicRefs = NORMALEXTREFS;
1449
rif.cPrivateRefs = 0;
1450
hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
1451
IRemUnknown_Release(remunk);
1452
if (hr == S_OK && hrref == S_OK)
1453
InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
1454
else
1455
ERR("IRemUnknown_RemAddRef returned with %#lx, hrref = %#lx\n", hr, hrref);
1456
}
1457
}
1458
ReleaseMutex(This->parent->remoting_mutex);
1459
1460
return hr;
1461
}
1462
1463
static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
1464
{
1465
HRESULT hr = S_OK;
1466
LONG public_refs;
1467
1468
if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
1469
{
1470
ERR("Wait failed for ifproxy %p\n", This);
1471
return E_UNEXPECTED;
1472
}
1473
1474
public_refs = This->refs;
1475
if (public_refs > 0)
1476
{
1477
IRemUnknown *remunk = NULL;
1478
1479
TRACE("releasing %ld refs\n", public_refs);
1480
1481
hr = proxy_manager_get_remunknown(This->parent, &remunk);
1482
if (hr == S_OK)
1483
{
1484
REMINTERFACEREF rif;
1485
rif.ipid = This->stdobjref.ipid;
1486
rif.cPublicRefs = public_refs;
1487
rif.cPrivateRefs = 0;
1488
hr = IRemUnknown_RemRelease(remunk, 1, &rif);
1489
IRemUnknown_Release(remunk);
1490
if (hr == S_OK)
1491
InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
1492
else if (hr == RPC_E_DISCONNECTED)
1493
WARN("couldn't release references because object was "
1494
"disconnected: oxid = %s, oid = %s\n",
1495
wine_dbgstr_longlong(This->parent->oxid),
1496
wine_dbgstr_longlong(This->parent->oid));
1497
else
1498
ERR("IRemUnknown_RemRelease failed with error %#lx\n", hr);
1499
}
1500
}
1501
ReleaseMutex(This->parent->remoting_mutex);
1502
1503
return hr;
1504
}
1505
1506
/* should be called inside This->parent->cs critical section */
1507
static void ifproxy_disconnect(struct ifproxy * This)
1508
{
1509
ifproxy_release_public_refs(This);
1510
if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
1511
1512
IRpcChannelBuffer_Release(This->chan);
1513
This->chan = NULL;
1514
}
1515
1516
/* should be called in This->parent->cs critical section if it is an entry in parent's list */
1517
static void ifproxy_destroy(struct ifproxy * This)
1518
{
1519
TRACE("%p\n", This);
1520
1521
/* release public references to this object so that the stub can know
1522
* when to destroy itself */
1523
ifproxy_release_public_refs(This);
1524
1525
list_remove(&This->entry);
1526
1527
if (This->chan)
1528
{
1529
IRpcChannelBuffer_Release(This->chan);
1530
This->chan = NULL;
1531
}
1532
1533
if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
1534
1535
free(This);
1536
}
1537
1538
static HRESULT proxy_manager_construct(
1539
struct apartment * apt, ULONG sorflags, OXID oxid, OID oid,
1540
const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
1541
{
1542
struct proxy_manager * This = malloc(sizeof(*This));
1543
if (!This) return E_OUTOFMEMORY;
1544
1545
This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
1546
if (!This->remoting_mutex)
1547
{
1548
free(This);
1549
return HRESULT_FROM_WIN32(GetLastError());
1550
}
1551
1552
if (oxid_info)
1553
{
1554
This->oxid_info.dwPid = oxid_info->dwPid;
1555
This->oxid_info.dwTid = oxid_info->dwTid;
1556
This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
1557
This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
1558
This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
1559
}
1560
else
1561
{
1562
HRESULT hr = rpc_resolve_oxid(oxid, &This->oxid_info);
1563
if (FAILED(hr))
1564
{
1565
CloseHandle(This->remoting_mutex);
1566
free(This);
1567
return hr;
1568
}
1569
}
1570
1571
This->IMultiQI_iface.lpVtbl = &ClientIdentity_Vtbl;
1572
This->IMarshal_iface.lpVtbl = &ProxyMarshal_Vtbl;
1573
This->IClientSecurity_iface.lpVtbl = &ProxyCliSec_Vtbl;
1574
1575
list_init(&This->entry);
1576
list_init(&This->interfaces);
1577
1578
InitializeCriticalSectionEx(&This->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
1579
This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": proxy_manager");
1580
1581
/* the apartment the object was unmarshaled into */
1582
This->parent = apt;
1583
1584
/* the source apartment and id of the object */
1585
This->oxid = oxid;
1586
This->oid = oid;
1587
1588
This->refs = 1;
1589
1590
/* the DCOM draft specification states that the SORF_NOPING flag is
1591
* proxy manager specific, not ifproxy specific, so this implies that we
1592
* should store the STDOBJREF flags here in the proxy manager. */
1593
This->sorflags = sorflags;
1594
1595
/* we create the IRemUnknown proxy on demand */
1596
This->remunk = NULL;
1597
1598
/* initialise these values to the weakest values and they will be
1599
* overwritten in proxy_manager_set_context */
1600
This->dest_context = MSHCTX_INPROC;
1601
This->dest_context_data = NULL;
1602
1603
EnterCriticalSection(&apt->cs);
1604
/* FIXME: we are dependent on the ordering in here to make sure a proxy's
1605
* IRemUnknown proxy doesn't get destroyed before the regular proxy does
1606
* because we need the IRemUnknown proxy during the destruction of the
1607
* regular proxy. Ideally, we should maintain a separate list for the
1608
* IRemUnknown proxies that need late destruction */
1609
list_add_tail(&apt->proxies, &This->entry);
1610
LeaveCriticalSection(&apt->cs);
1611
1612
TRACE("%p created for OXID %s, OID %s\n", This,
1613
wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
1614
1615
*proxy_manager = This;
1616
return S_OK;
1617
}
1618
1619
static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
1620
{
1621
MSHCTX old_dest_context;
1622
MSHCTX new_dest_context;
1623
1624
do
1625
{
1626
old_dest_context = This->dest_context;
1627
new_dest_context = old_dest_context;
1628
/* "stronger" values overwrite "weaker" values. stronger values are
1629
* ones that disable more optimisations */
1630
switch (old_dest_context)
1631
{
1632
case MSHCTX_INPROC:
1633
new_dest_context = dest_context;
1634
break;
1635
case MSHCTX_CROSSCTX:
1636
switch (dest_context)
1637
{
1638
case MSHCTX_INPROC:
1639
break;
1640
default:
1641
new_dest_context = dest_context;
1642
}
1643
break;
1644
case MSHCTX_LOCAL:
1645
switch (dest_context)
1646
{
1647
case MSHCTX_INPROC:
1648
case MSHCTX_CROSSCTX:
1649
break;
1650
default:
1651
new_dest_context = dest_context;
1652
}
1653
break;
1654
case MSHCTX_NOSHAREDMEM:
1655
switch (dest_context)
1656
{
1657
case MSHCTX_DIFFERENTMACHINE:
1658
new_dest_context = dest_context;
1659
break;
1660
default:
1661
break;
1662
}
1663
break;
1664
default:
1665
break;
1666
}
1667
1668
if (old_dest_context == new_dest_context) break;
1669
1670
new_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
1671
} while (new_dest_context != old_dest_context);
1672
1673
if (dest_context_data)
1674
InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
1675
}
1676
1677
static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
1678
{
1679
HRESULT hr;
1680
struct ifproxy * ifproxy;
1681
1682
TRACE("%s\n", debugstr_guid(riid));
1683
1684
if (IsEqualIID(riid, &IID_IUnknown) ||
1685
IsEqualIID(riid, &IID_IMultiQI))
1686
{
1687
*ppv = &This->IMultiQI_iface;
1688
IMultiQI_AddRef(&This->IMultiQI_iface);
1689
return S_OK;
1690
}
1691
if (IsEqualIID(riid, &IID_IMarshal))
1692
{
1693
*ppv = &This->IMarshal_iface;
1694
IMarshal_AddRef(&This->IMarshal_iface);
1695
return S_OK;
1696
}
1697
if (IsEqualIID(riid, &IID_IClientSecurity))
1698
{
1699
*ppv = &This->IClientSecurity_iface;
1700
IClientSecurity_AddRef(&This->IClientSecurity_iface);
1701
return S_OK;
1702
}
1703
1704
hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
1705
if (hr == S_OK)
1706
{
1707
*ppv = ifproxy->iface;
1708
IUnknown_AddRef((IUnknown *)*ppv);
1709
return S_OK;
1710
}
1711
1712
*ppv = NULL;
1713
return E_NOINTERFACE;
1714
}
1715
1716
static HRESULT proxy_manager_create_ifproxy(
1717
struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
1718
IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
1719
{
1720
HRESULT hr;
1721
IPSFactoryBuffer * psfb;
1722
struct ifproxy * ifproxy = malloc(sizeof(*ifproxy));
1723
if (!ifproxy) return E_OUTOFMEMORY;
1724
1725
list_init(&ifproxy->entry);
1726
1727
ifproxy->parent = This;
1728
ifproxy->stdobjref = *stdobjref;
1729
ifproxy->iid = *riid;
1730
ifproxy->refs = 0;
1731
ifproxy->proxy = NULL;
1732
1733
assert(channel);
1734
ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
1735
1736
/* the IUnknown interface is special because it does not have a
1737
* proxy associated with the ifproxy as we handle IUnknown ourselves */
1738
if (IsEqualIID(riid, &IID_IUnknown))
1739
{
1740
ifproxy->iface = &This->IMultiQI_iface;
1741
IMultiQI_AddRef(&This->IMultiQI_iface);
1742
hr = S_OK;
1743
}
1744
else
1745
{
1746
hr = get_facbuf_for_iid(riid, &psfb);
1747
if (hr == S_OK)
1748
{
1749
/* important note: the outer unknown is set to the proxy manager.
1750
* This ensures the COM identity rules are not violated, by having a
1751
* one-to-one mapping of objects on the proxy side to objects on the
1752
* stub side, no matter which interface you view the object through */
1753
hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)&This->IMultiQI_iface, riid,
1754
&ifproxy->proxy, &ifproxy->iface);
1755
IPSFactoryBuffer_Release(psfb);
1756
if (hr != S_OK)
1757
ERR("Could not create proxy for interface %s, error %#lx\n", debugstr_guid(riid), hr);
1758
}
1759
else
1760
ERR("Could not get IPSFactoryBuffer for interface %s, error %#lx\n", debugstr_guid(riid), hr);
1761
1762
if (hr == S_OK)
1763
hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
1764
}
1765
1766
if (hr == S_OK)
1767
{
1768
EnterCriticalSection(&This->cs);
1769
list_add_tail(&This->interfaces, &ifproxy->entry);
1770
LeaveCriticalSection(&This->cs);
1771
1772
*iif_out = ifproxy;
1773
TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
1774
ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs);
1775
}
1776
else
1777
ifproxy_destroy(ifproxy);
1778
1779
return hr;
1780
}
1781
1782
static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found)
1783
{
1784
HRESULT hr = E_NOINTERFACE; /* assume not found */
1785
struct ifproxy *ifproxy;
1786
1787
EnterCriticalSection(&This->cs);
1788
LIST_FOR_EACH_ENTRY(ifproxy, &This->interfaces, struct ifproxy, entry)
1789
{
1790
if (IsEqualIID(riid, &ifproxy->iid))
1791
{
1792
*ifproxy_found = ifproxy;
1793
hr = S_OK;
1794
break;
1795
}
1796
}
1797
LeaveCriticalSection(&This->cs);
1798
1799
return hr;
1800
}
1801
1802
static void proxy_manager_disconnect(struct proxy_manager * This)
1803
{
1804
struct ifproxy *ifproxy;
1805
1806
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1807
wine_dbgstr_longlong(This->oid));
1808
1809
EnterCriticalSection(&This->cs);
1810
1811
/* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
1812
* disconnected - it won't do anything anyway, except cause
1813
* problems for other objects that depend on this proxy always
1814
* working */
1815
if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
1816
{
1817
LIST_FOR_EACH_ENTRY(ifproxy, &This->interfaces, struct ifproxy, entry)
1818
{
1819
ifproxy_disconnect(ifproxy);
1820
}
1821
}
1822
1823
/* apartment is being destroyed so don't keep a pointer around to it */
1824
This->parent = NULL;
1825
1826
LeaveCriticalSection(&This->cs);
1827
}
1828
1829
static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
1830
{
1831
HRESULT hr = S_OK;
1832
struct apartment *apt;
1833
BOOL called_in_original_apt;
1834
1835
/* we don't want to try and unmarshal or use IRemUnknown if we don't want
1836
* lifetime management */
1837
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
1838
return S_FALSE;
1839
1840
if (!(apt = apartment_get_current_or_mta()))
1841
return CO_E_NOTINITIALIZED;
1842
1843
called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
1844
1845
EnterCriticalSection(&This->cs);
1846
/* only return the cached object if called from the original apartment.
1847
* in future, we might want to make the IRemUnknown proxy callable from any
1848
* apartment to avoid these checks */
1849
if (This->remunk && called_in_original_apt)
1850
{
1851
/* already created - return existing object */
1852
*remunk = This->remunk;
1853
IRemUnknown_AddRef(*remunk);
1854
}
1855
else if (!This->parent)
1856
{
1857
/* disconnected - we can't create IRemUnknown */
1858
*remunk = NULL;
1859
hr = S_FALSE;
1860
}
1861
else
1862
{
1863
STDOBJREF stdobjref;
1864
/* Don't want IRemUnknown lifetime management as this is IRemUnknown!
1865
* We also don't care about whether or not the stub is still alive */
1866
stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING;
1867
stdobjref.cPublicRefs = 1;
1868
/* oxid of destination object */
1869
stdobjref.oxid = This->oxid;
1870
/* FIXME: what should be used for the oid? The DCOM draft doesn't say */
1871
stdobjref.oid = (OID)-1;
1872
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
1873
1874
/* do the unmarshal */
1875
hr = unmarshal_object(&stdobjref, apt, This->dest_context,
1876
This->dest_context_data, &IID_IRemUnknown,
1877
&This->oxid_info, (void**)remunk);
1878
if (hr == S_OK && called_in_original_apt)
1879
{
1880
This->remunk = *remunk;
1881
IRemUnknown_AddRef(This->remunk);
1882
}
1883
}
1884
LeaveCriticalSection(&This->cs);
1885
apartment_release(apt);
1886
1887
TRACE("got IRemUnknown* pointer %p, hr = %#lx\n", *remunk, hr);
1888
1889
return hr;
1890
}
1891
1892
/*
1893
* Safely increment the reference count of a proxy manager obtained from an
1894
* apartment proxy list.
1895
*
1896
* This function shall be called inside the apartment's critical section.
1897
*/
1898
static LONG proxy_manager_addref_if_alive(struct proxy_manager * This)
1899
{
1900
LONG refs = ReadNoFence(&This->refs);
1901
LONG old_refs, new_refs;
1902
1903
do
1904
{
1905
if (refs == 0)
1906
{
1907
/* This proxy manager is about to be destroyed */
1908
return 0;
1909
}
1910
1911
old_refs = refs;
1912
new_refs = refs + 1;
1913
} while ((refs = InterlockedCompareExchange(&This->refs, new_refs, old_refs)) != old_refs);
1914
1915
return new_refs;
1916
}
1917
1918
/* destroys a proxy manager, freeing the memory it used.
1919
* Note: this function should not be called from a list iteration in the
1920
* apartment, due to the fact that it removes itself from the apartment and
1921
* it could add a proxy to IRemUnknown into the apartment. */
1922
static void proxy_manager_destroy(struct proxy_manager * This)
1923
{
1924
struct list * cursor;
1925
1926
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
1927
wine_dbgstr_longlong(This->oid));
1928
1929
if (This->parent)
1930
{
1931
EnterCriticalSection(&This->parent->cs);
1932
1933
/* remove ourself from the list of proxy objects in the apartment */
1934
LIST_FOR_EACH(cursor, &This->parent->proxies)
1935
{
1936
if (cursor == &This->entry)
1937
{
1938
list_remove(&This->entry);
1939
break;
1940
}
1941
}
1942
1943
LeaveCriticalSection(&This->parent->cs);
1944
}
1945
1946
/* destroy all of the interface proxies */
1947
while ((cursor = list_head(&This->interfaces)))
1948
{
1949
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
1950
ifproxy_destroy(ifproxy);
1951
}
1952
1953
if (This->remunk) IRemUnknown_Release(This->remunk);
1954
CoTaskMemFree(This->oxid_info.psa);
1955
1956
This->cs.DebugInfo->Spare[0] = 0;
1957
DeleteCriticalSection(&This->cs);
1958
1959
CloseHandle(This->remoting_mutex);
1960
1961
free(This);
1962
}
1963
1964
/* finds the proxy manager corresponding to a given OXID and OID that has
1965
* been unmarshaled in the specified apartment. The caller must release the
1966
* reference to the proxy_manager when the object is no longer used. */
1967
static BOOL find_proxy_manager(struct apartment * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
1968
{
1969
struct proxy_manager *proxy;
1970
BOOL found = FALSE;
1971
1972
EnterCriticalSection(&apt->cs);
1973
LIST_FOR_EACH_ENTRY(proxy, &apt->proxies, struct proxy_manager, entry)
1974
{
1975
if ((oxid == proxy->oxid) && (oid == proxy->oid))
1976
{
1977
/* be careful of a race with ClientIdentity_Release, which would
1978
* cause us to return a proxy which is in the process of being
1979
* destroyed */
1980
if (proxy_manager_addref_if_alive(proxy) != 0)
1981
{
1982
*proxy_found = proxy;
1983
found = TRUE;
1984
break;
1985
}
1986
}
1987
}
1988
LeaveCriticalSection(&apt->cs);
1989
return found;
1990
}
1991
1992
HRESULT apartment_disconnectproxies(struct apartment *apt)
1993
{
1994
struct proxy_manager *proxy;
1995
1996
LIST_FOR_EACH_ENTRY(proxy, &apt->proxies, struct proxy_manager, entry)
1997
{
1998
proxy_manager_disconnect(proxy);
1999
}
2000
2001
return S_OK;
2002
}
2003
2004
/********************** StdMarshal implementation ****************************/
2005
2006
struct stdmarshal
2007
{
2008
IMarshal IMarshal_iface;
2009
LONG refcount;
2010
DWORD dest_context;
2011
void *dest_context_data;
2012
};
2013
2014
static inline struct stdmarshal *impl_from_StdMarshal(IMarshal *iface)
2015
{
2016
return CONTAINING_RECORD(iface, struct stdmarshal, IMarshal_iface);
2017
}
2018
2019
static HRESULT WINAPI StdMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
2020
{
2021
*ppv = NULL;
2022
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
2023
{
2024
*ppv = iface;
2025
IMarshal_AddRef(iface);
2026
return S_OK;
2027
}
2028
FIXME("No interface for %s.\n", debugstr_guid(riid));
2029
return E_NOINTERFACE;
2030
}
2031
2032
static ULONG WINAPI StdMarshalImpl_AddRef(IMarshal *iface)
2033
{
2034
struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2035
return InterlockedIncrement(&marshal->refcount);
2036
}
2037
2038
static ULONG WINAPI StdMarshalImpl_Release(IMarshal *iface)
2039
{
2040
struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2041
ULONG refcount = InterlockedDecrement(&marshal->refcount);
2042
2043
if (!refcount)
2044
free(marshal);
2045
2046
return refcount;
2047
}
2048
2049
static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
2050
DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
2051
{
2052
*pCid = CLSID_StdMarshal;
2053
return S_OK;
2054
}
2055
2056
static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
2057
DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
2058
{
2059
*pSize = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
2060
return S_OK;
2061
}
2062
2063
static HRESULT WINAPI StdMarshalImpl_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void *pv,
2064
DWORD dest_context, void *dest_context_data, DWORD mshlflags)
2065
{
2066
ULONG res;
2067
HRESULT hr;
2068
OBJREF objref;
2069
struct apartment *apt;
2070
2071
TRACE("(...,%s,...)\n", debugstr_guid(riid));
2072
2073
if (!(apt = apartment_get_current_or_mta()))
2074
{
2075
ERR("Apartment not initialized\n");
2076
return CO_E_NOTINITIALIZED;
2077
}
2078
2079
/* make sure this apartment can be reached from other threads / processes */
2080
rpc_start_remoting(apt);
2081
2082
fill_std_objref(&objref, riid, NULL);
2083
hr = marshal_object(apt, &objref.u_objref.u_standard.std, riid, pv, dest_context,
2084
dest_context_data, mshlflags);
2085
apartment_release(apt);
2086
if (hr != S_OK)
2087
{
2088
ERR("Failed to create ifstub, hr %#lx\n", hr);
2089
return hr;
2090
}
2091
2092
return IStream_Write(stream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray), &res);
2093
}
2094
2095
/* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
2096
* no questions asked about the rules surrounding same-apartment unmarshals
2097
* and table marshaling */
2098
static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context,
2099
void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object)
2100
{
2101
struct proxy_manager *proxy_manager = NULL;
2102
HRESULT hr = S_OK;
2103
2104
assert(apt);
2105
2106
TRACE("stdobjref: flags = %#lx cPublicRefs = %ld oxid = %s oid = %s ipid = %s\n",
2107
stdobjref->flags, stdobjref->cPublicRefs,
2108
wine_dbgstr_longlong(stdobjref->oxid),
2109
wine_dbgstr_longlong(stdobjref->oid),
2110
debugstr_guid(&stdobjref->ipid));
2111
2112
/* create a new proxy manager if one doesn't already exist for the
2113
* object */
2114
if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager))
2115
{
2116
hr = proxy_manager_construct(apt, stdobjref->flags,
2117
stdobjref->oxid, stdobjref->oid, oxid_info,
2118
&proxy_manager);
2119
}
2120
else
2121
TRACE("proxy manager already created, using\n");
2122
2123
if (hr == S_OK)
2124
{
2125
struct ifproxy * ifproxy;
2126
2127
proxy_manager_set_context(proxy_manager, dest_context, dest_context_data);
2128
2129
hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
2130
if (hr == E_NOINTERFACE)
2131
{
2132
IRpcChannelBuffer *chanbuf;
2133
hr = rpc_create_clientchannel(&stdobjref->oxid, &stdobjref->ipid,
2134
&proxy_manager->oxid_info, riid, proxy_manager->dest_context,
2135
proxy_manager->dest_context_data, &chanbuf, apt);
2136
if (hr == S_OK)
2137
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, riid, chanbuf, &ifproxy);
2138
}
2139
else
2140
IUnknown_AddRef((IUnknown *)ifproxy->iface);
2141
2142
if (hr == S_OK)
2143
{
2144
InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
2145
/* get at least one external reference to the object to keep it alive */
2146
hr = ifproxy_get_public_ref(ifproxy);
2147
if (FAILED(hr))
2148
ifproxy_destroy(ifproxy);
2149
}
2150
2151
if (hr == S_OK)
2152
*object = ifproxy->iface;
2153
}
2154
2155
/* release our reference to the proxy manager - the client/apartment
2156
* will hold on to the remaining reference for us */
2157
if (proxy_manager) IMultiQI_Release(&proxy_manager->IMultiQI_iface);
2158
2159
return hr;
2160
}
2161
2162
static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv)
2163
{
2164
struct stdmarshal *marshal = impl_from_StdMarshal(iface);
2165
OBJREF objref;
2166
HRESULT hr;
2167
ULONG res;
2168
2169
hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
2170
if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
2171
{
2172
ERR("Failed to read common OBJREF header, %#lx\n", hr);
2173
return STG_E_READFAULT;
2174
}
2175
2176
if (objref.signature != OBJREF_SIGNATURE)
2177
{
2178
ERR("Bad OBJREF signature %#lx\n", objref.signature);
2179
return RPC_E_INVALID_OBJREF;
2180
}
2181
2182
if (!(objref.flags & OBJREF_STANDARD))
2183
{
2184
FIXME("unsupported objref.flags = %lx\n", objref.flags);
2185
return E_NOTIMPL;
2186
}
2187
2188
return std_unmarshal_interface(marshal->dest_context, marshal->dest_context_data, stream, riid, ppv, TRUE);
2189
}
2190
2191
static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *stream)
2192
{
2193
OBJREF objref;
2194
HRESULT hr;
2195
ULONG res;
2196
2197
TRACE("%p, %p\n", iface, stream);
2198
2199
hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
2200
if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
2201
{
2202
ERR("Failed to read common OBJREF header, %#lx\n", hr);
2203
return STG_E_READFAULT;
2204
}
2205
2206
if (objref.signature != OBJREF_SIGNATURE)
2207
{
2208
ERR("Bad OBJREF signature %#lx\n", objref.signature);
2209
return RPC_E_INVALID_OBJREF;
2210
}
2211
2212
if (!(objref.flags & OBJREF_STANDARD))
2213
{
2214
FIXME("unsupported objref.flags = %lx\n", objref.flags);
2215
return E_NOTIMPL;
2216
}
2217
2218
return std_release_marshal_data(stream);
2219
}
2220
2221
static HRESULT WINAPI StdMarshalImpl_DisconnectObject(IMarshal *iface, DWORD reserved)
2222
{
2223
FIXME("(), stub!\n");
2224
return S_OK;
2225
}
2226
2227
static const IMarshalVtbl StdMarshalVtbl =
2228
{
2229
StdMarshalImpl_QueryInterface,
2230
StdMarshalImpl_AddRef,
2231
StdMarshalImpl_Release,
2232
StdMarshalImpl_GetUnmarshalClass,
2233
StdMarshalImpl_GetMarshalSizeMax,
2234
StdMarshalImpl_MarshalInterface,
2235
StdMarshalImpl_UnmarshalInterface,
2236
StdMarshalImpl_ReleaseMarshalData,
2237
StdMarshalImpl_DisconnectObject
2238
};
2239
2240
static HRESULT StdMarshalImpl_Construct(REFIID riid, DWORD dest_context, void *dest_context_data, void **ppvObject)
2241
{
2242
struct stdmarshal *object;
2243
HRESULT hr;
2244
2245
object = malloc(sizeof(*object));
2246
if (!object)
2247
return E_OUTOFMEMORY;
2248
2249
object->IMarshal_iface.lpVtbl = &StdMarshalVtbl;
2250
object->refcount = 1;
2251
object->dest_context = dest_context;
2252
object->dest_context_data = dest_context_data;
2253
2254
hr = IMarshal_QueryInterface(&object->IMarshal_iface, riid, ppvObject);
2255
IMarshal_Release(&object->IMarshal_iface);
2256
2257
return hr;
2258
}
2259
2260
HRESULT WINAPI InternalCoStdMarshalObject(REFIID riid, DWORD dest_context, void *dest_context_data, void **ppvObject)
2261
{
2262
return StdMarshalImpl_Construct(riid, dest_context, dest_context_data, ppvObject);
2263
}
2264
2265
/***********************************************************************
2266
* CoGetStandardMarshal (combase.@)
2267
*/
2268
HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
2269
void *dest_context, DWORD flags, IMarshal **marshal)
2270
{
2271
if (pUnk == NULL)
2272
{
2273
FIXME("%s, NULL, %lx, %p, %lx, %p, unimplemented yet.\n", debugstr_guid(riid), dwDestContext,
2274
dest_context, flags, marshal);
2275
return E_NOTIMPL;
2276
}
2277
TRACE("%s, %p, %lx, %p, %lx, %p\n", debugstr_guid(riid), pUnk, dwDestContext, dest_context, flags, marshal);
2278
2279
return StdMarshalImpl_Construct(&IID_IMarshal, dwDestContext, dest_context, (void **)marshal);
2280
}
2281
2282