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