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