~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ole32/marshal.c

Version: ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
 56                                 MSHCTX dest_context, void *dest_context_data,
 57                                 REFIID riid, const OXID_INFO *oxid_info,
 58                                 void **object);
 59 
 60 /* Marshalling just passes a unique identifier to the remote client,
 61  * that makes it possible to find the passed interface again.
 62  *
 63  * So basically we need a set of values that make it unique.
 64  *
 65  * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
 66  *
 67  * A triple is used: OXID (apt id), OID (stub manager id),
 68  * IPID (interface ptr/stub id).
 69  *
 70  * OXIDs identify an apartment and are network scoped
 71  * OIDs identify a stub manager and are apartment scoped
 72  * IPIDs identify an interface stub and are apartment scoped
 73  */
 74 
 75 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
 76 {
 77     HRESULT       hr;
 78     CLSID         clsid;
 79 
 80     if ((hr = CoGetPSClsid(riid, &clsid)))
 81         return hr;
 82     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | WINE_CLSCTX_DONT_HOST,
 83         NULL, &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
 84 }
 85 
 86 /* marshals an object into a STDOBJREF structure */
 87 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, MSHLFLAGS mshlflags)
 88 {
 89     struct stub_manager *manager;
 90     struct ifstub       *ifstub;
 91     BOOL                 tablemarshal;
 92     IRpcStubBuffer      *stub = NULL;
 93     HRESULT              hr;
 94     IUnknown            *iobject = NULL; /* object of type riid */
 95 
 96     hr = apartment_getoxid(apt, &stdobjref->oxid);
 97     if (hr != S_OK)
 98         return hr;
 99 
100     hr = apartment_createwindowifneeded(apt);
101     if (hr != S_OK)
102         return hr;
103 
104     hr = IUnknown_QueryInterface(object, riid, (void **)&iobject);
105     if (hr != S_OK)
106     {
107         ERR("object doesn't expose interface %s, failing with error 0x%08x\n",
108             debugstr_guid(riid), hr);
109         return E_NOINTERFACE;
110     }
111   
112     /* IUnknown doesn't require a stub buffer, because it never goes out on
113      * the wire */
114     if (!IsEqualIID(riid, &IID_IUnknown))
115     {
116         IPSFactoryBuffer *psfb;
117 
118         hr = get_facbuf_for_iid(riid, &psfb);
119         if (hr != S_OK)
120         {
121             ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid));
122             IUnknown_Release(iobject);
123             return hr;
124         }
125     
126         hr = IPSFactoryBuffer_CreateStub(psfb, riid, iobject, &stub);
127         IPSFactoryBuffer_Release(psfb);
128         if (hr != S_OK)
129         {
130             ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n",
131                 debugstr_guid(riid), hr);
132             IUnknown_Release(iobject);
133             return hr;
134         }
135     }
136 
137     stdobjref->flags = SORF_NULL;
138     if (mshlflags & MSHLFLAGS_TABLEWEAK)
139         stdobjref->flags |= SORFP_TABLEWEAK;
140     if (mshlflags & MSHLFLAGS_NOPING)
141         stdobjref->flags |= SORF_NOPING;
142 
143     if ((manager = get_stub_manager_from_object(apt, object)))
144         TRACE("registering new ifstub on pre-existing manager\n");
145     else
146     {
147         TRACE("constructing new stub manager\n");
148 
149         manager = new_stub_manager(apt, object);
150         if (!manager)
151         {
152             if (stub) IRpcStubBuffer_Release(stub);
153             IUnknown_Release(iobject);
154             return E_OUTOFMEMORY;
155         }
156     }
157     stdobjref->oid = manager->oid;
158 
159     tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK));
160 
161     /* make sure ifstub that we are creating is unique */
162     ifstub = stub_manager_find_ifstub(manager, riid, mshlflags);
163     if (!ifstub)
164         ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid, mshlflags);
165 
166     if (stub) IRpcStubBuffer_Release(stub);
167     IUnknown_Release(iobject);
168 
169     if (!ifstub)
170     {
171         stub_manager_int_release(manager);
172         /* destroy the stub manager if it has no ifstubs by releasing
173          * zero external references */
174         stub_manager_ext_release(manager, 0, FALSE, TRUE);
175         return E_OUTOFMEMORY;
176     }
177 
178     if (!tablemarshal)
179     {
180         stdobjref->cPublicRefs = NORMALEXTREFS;
181         stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
182     }
183     else
184     {
185         stdobjref->cPublicRefs = 0;
186         if (mshlflags & MSHLFLAGS_TABLESTRONG)
187             stub_manager_ext_addref(manager, 1, FALSE);
188         else
189             stub_manager_ext_addref(manager, 0, TRUE);
190     }
191 
192     /* FIXME: check return value */
193     RPC_RegisterInterface(riid);
194 
195     stdobjref->ipid = ifstub->ipid;
196 
197     stub_manager_int_release(manager);
198     return S_OK;
199 }
200 
201 
202 
203 /* Client-side identity of the server object */
204 
205 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk);
206 static void proxy_manager_destroy(struct proxy_manager * This);
207 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found);
208 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv);
209 
210 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv)
211 {
212     HRESULT hr;
213     MULTI_QI mqi;
214 
215     TRACE("%s\n", debugstr_guid(riid));
216 
217     mqi.pIID = riid;
218     hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
219     *ppv = (void *)mqi.pItf;
220 
221     return hr;
222 }
223 
224 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface)
225 {
226     struct proxy_manager * This = (struct proxy_manager *)iface;
227     TRACE("%p - before %d\n", iface, This->refs);
228     return InterlockedIncrement(&This->refs);
229 }
230 
231 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface)
232 {
233     struct proxy_manager * This = (struct proxy_manager *)iface;
234     ULONG refs = InterlockedDecrement(&This->refs);
235     TRACE("%p - after %d\n", iface, refs);
236     if (!refs)
237         proxy_manager_destroy(This);
238     return refs;
239 }
240 
241 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs)
242 {
243     struct proxy_manager * This = (struct proxy_manager *)iface;
244     REMQIRESULT *qiresults = NULL;
245     ULONG nonlocal_mqis = 0;
246     ULONG i;
247     ULONG successful_mqis = 0;
248     IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids));
249     /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */
250     ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping));
251 
252     TRACE("cMQIs: %d\n", cMQIs);
253 
254     /* try to get a local interface - this includes already active proxy
255      * interfaces and also interfaces exposed by the proxy manager */
256     for (i = 0; i < cMQIs; i++)
257     {
258         TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID));
259         pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf);
260         if (pMQIs[i].hr == S_OK)
261             successful_mqis++;
262         else
263         {
264             iids[nonlocal_mqis] = *pMQIs[i].pIID;
265             mapping[nonlocal_mqis] = i;
266             nonlocal_mqis++;
267         }
268     }
269 
270     TRACE("%d interfaces not found locally\n", nonlocal_mqis);
271 
272     /* if we have more than one interface not found locally then we must try
273      * to query the remote object for it */
274     if (nonlocal_mqis != 0)
275     {
276         IRemUnknown *remunk;
277         HRESULT hr;
278         IPID *ipid;
279 
280         /* get the ipid of the first entry */
281         /* FIXME: should we implement ClientIdentity on the ifproxies instead
282          * of the proxy_manager so we use the correct ipid here? */
283         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
284 
285         /* get IRemUnknown proxy so we can communicate with the remote object */
286         hr = proxy_manager_get_remunknown(This, &remunk);
287 
288         if (SUCCEEDED(hr))
289         {
290             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
291                                                nonlocal_mqis, iids, &qiresults);
292             IRemUnknown_Release(remunk);
293             if (FAILED(hr))
294                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
295         }
296 
297         /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of
298          * the interfaces were returned */
299         if (SUCCEEDED(hr))
300         {
301             /* try to unmarshal each object returned to us */
302             for (i = 0; i < nonlocal_mqis; i++)
303             {
304                 ULONG index = mapping[i];
305                 HRESULT hrobj = qiresults[i].hResult;
306                 if (hrobj == S_OK)
307                     hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
308                                              This->dest_context,
309                                              This->dest_context_data,
310                                              pMQIs[index].pIID, &This->oxid_info,
311                                              (void **)&pMQIs[index].pItf);
312 
313                 if (hrobj == S_OK)
314                     successful_mqis++;
315                 else
316                     ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID));
317                 pMQIs[index].hr = hrobj;
318             }
319         }
320 
321         /* free the memory allocated by the proxy */
322         CoTaskMemFree(qiresults);
323     }
324 
325     TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs);
326 
327     HeapFree(GetProcessHeap(), 0, iids);
328     HeapFree(GetProcessHeap(), 0, mapping);
329 
330     if (successful_mqis == cMQIs)
331         return S_OK; /* we got all requested interfaces */
332     else if (successful_mqis == 0)
333         return E_NOINTERFACE; /* we didn't get any interfaces */
334     else
335         return S_FALSE; /* we got some interfaces */
336 }
337 
338 static const IMultiQIVtbl ClientIdentity_Vtbl =
339 {
340     ClientIdentity_QueryInterface,
341     ClientIdentity_AddRef,
342     ClientIdentity_Release,
343     ClientIdentity_QueryMultipleInterfaces
344 };
345 
346 /* FIXME: remove these */
347 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
348 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
349 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv);
350 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm);
351 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved);
352 
353 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
354 {
355     ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
356     return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
357 }
358 
359 static ULONG WINAPI Proxy_AddRef(IMarshal *iface)
360 {
361     ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
362     return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
363 }
364 
365 static ULONG WINAPI Proxy_Release(IMarshal *iface)
366 {
367     ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
368     return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
369 }
370 
371 static HRESULT WINAPI Proxy_MarshalInterface(
372     LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext,
373     void* pvDestContext, DWORD mshlflags)
374 {
375     ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
376     HRESULT hr;
377     struct ifproxy *ifproxy;
378 
379     TRACE("(...,%s,...)\n", debugstr_guid(riid));
380 
381     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
382     if (SUCCEEDED(hr))
383     {
384         STDOBJREF stdobjref = ifproxy->stdobjref;
385 
386         stdobjref.cPublicRefs = 0;
387 
388         if ((mshlflags != MSHLFLAGS_TABLEWEAK) &&
389             (mshlflags != MSHLFLAGS_TABLESTRONG))
390         {
391             ULONG cPublicRefs = ifproxy->refs;
392             ULONG cPublicRefsOld;
393             /* optimization - share out proxy's public references if possible
394              * instead of making new proxy do a roundtrip through the server */
395             do
396             {
397                 ULONG cPublicRefsNew;
398                 cPublicRefsOld = cPublicRefs;
399                 stdobjref.cPublicRefs = cPublicRefs / 2;
400                 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
401                 cPublicRefs = InterlockedCompareExchange(
402                     (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
403             } while (cPublicRefs != cPublicRefsOld);
404         }
405 
406         /* normal and table-strong marshaling need at least one reference */
407         if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK))
408         {
409             IRemUnknown *remunk;
410             hr = proxy_manager_get_remunknown(This, &remunk);
411             if (hr == S_OK)
412             {
413                 HRESULT hrref = S_OK;
414                 REMINTERFACEREF rif;
415                 rif.ipid = ifproxy->stdobjref.ipid;
416                 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS;
417                 rif.cPrivateRefs = 0;
418                 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
419                 IRemUnknown_Release(remunk);
420                 if (hr == S_OK && hrref == S_OK)
421                 {
422                     /* table-strong marshaling doesn't give the refs to the
423                      * client that unmarshals the STDOBJREF */
424                     if (mshlflags != MSHLFLAGS_TABLESTRONG)
425                         stdobjref.cPublicRefs = rif.cPublicRefs;
426                 }
427                 else
428                     ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
429             }
430         }
431 
432         if (SUCCEEDED(hr))
433         {
434             TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
435                 stdobjref.flags, stdobjref.cPublicRefs,
436                 wine_dbgstr_longlong(stdobjref.oxid),
437                 wine_dbgstr_longlong(stdobjref.oid),
438                 debugstr_guid(&stdobjref.ipid));
439             hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
440         }
441     }
442     else
443     {
444         /* we don't have the interface already unmarshaled so we have to
445          * request the object from the server */
446         IRemUnknown *remunk;
447         IPID *ipid;
448         REMQIRESULT *qiresults = NULL;
449         IID iid = *riid;
450 
451         /* get the ipid of the first entry */
452         /* FIXME: should we implement ClientIdentity on the ifproxies instead
453          * of the proxy_manager so we use the correct ipid here? */
454         ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
455 
456         /* get IRemUnknown proxy so we can communicate with the remote object */
457         hr = proxy_manager_get_remunknown(This, &remunk);
458 
459         if (hr == S_OK)
460         {
461             hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
462                                                1, &iid, &qiresults);
463             if (SUCCEEDED(hr))
464             {
465                 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
466                 if (FAILED(hr))
467                 {
468                     REMINTERFACEREF rif;
469                     rif.ipid = qiresults->std.ipid;
470                     rif.cPublicRefs = qiresults->std.cPublicRefs;
471                     rif.cPrivateRefs = 0;
472                     IRemUnknown_RemRelease(remunk, 1, &rif);
473                 }
474                 CoTaskMemFree(qiresults);
475             }
476             else
477                 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr);
478             IRemUnknown_Release(remunk);
479         }
480     }
481 
482     return hr;
483 }
484 
485 static const IMarshalVtbl ProxyMarshal_Vtbl =
486 {
487     Proxy_QueryInterface,
488     Proxy_AddRef,
489     Proxy_Release,
490     StdMarshalImpl_GetUnmarshalClass,
491     StdMarshalImpl_GetMarshalSizeMax,
492     Proxy_MarshalInterface,
493     StdMarshalImpl_UnmarshalInterface,
494     StdMarshalImpl_ReleaseMarshalData,
495     StdMarshalImpl_DisconnectObject
496 };
497 
498 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject)
499 {
500     ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
501     return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject);
502 }
503 
504 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface)
505 {
506     ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
507     return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
508 }
509 
510 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface)
511 {
512     ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface);
513     return IMultiQI_Release((IMultiQI *)&This->lpVtbl);
514 }
515 
516 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface,
517                                                IUnknown *pProxy,
518                                                DWORD *pAuthnSvc,
519                                                DWORD *pAuthzSvc,
520                                                OLECHAR **ppServerPrincName,
521                                                DWORD *pAuthnLevel,
522                                                DWORD *pImpLevel,
523                                                void **pAuthInfo,
524                                                DWORD *pCapabilities)
525 {
526     FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc,
527           pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo,
528           pCapabilities);
529 
530     if (pAuthnSvc)
531         *pAuthnSvc = 0;
532     if (pAuthzSvc)
533         *pAuthzSvc = 0;
534     if (ppServerPrincName)
535         *ppServerPrincName = NULL;
536     if (pAuthnLevel)
537         *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
538     if (pImpLevel)
539         *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT;
540     if (pAuthInfo)
541         *pAuthInfo = NULL;
542     if (pCapabilities)
543         *pCapabilities = EOAC_NONE;
544 
545     return E_NOTIMPL;
546 }
547 
548 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface,
549                                              IUnknown *pProxy, DWORD AuthnSvc,
550                                              DWORD AuthzSvc,
551                                              OLECHAR *pServerPrincName,
552                                              DWORD AuthnLevel, DWORD ImpLevel,
553                                              void *pAuthInfo,
554                                              DWORD Capabilities)
555 {
556     FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc,
557           AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel,
558           pAuthInfo, Capabilities);
559     return E_NOTIMPL;
560 }
561 
562 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface,
563                                             IUnknown *pProxy, IUnknown **ppCopy)
564 {
565     FIXME("(%p, %p): stub\n", pProxy, ppCopy);
566     *ppCopy = NULL;
567     return E_NOTIMPL;
568 }
569 
570 static const IClientSecurityVtbl ProxyCliSec_Vtbl =
571 {
572     ProxyCliSec_QueryInterface,
573     ProxyCliSec_AddRef,
574     ProxyCliSec_Release,
575     ProxyCliSec_QueryBlanket,
576     ProxyCliSec_SetBlanket,
577     ProxyCliSec_CopyProxy
578 };
579 
580 static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
581 {
582     HRESULT hr = S_OK;
583 
584     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
585     {
586         ERR("Wait failed for ifproxy %p\n", This);
587         return E_UNEXPECTED;
588     }
589 
590     if (This->refs == 0)
591     {
592         IRemUnknown *remunk = NULL;
593 
594         TRACE("getting public ref for ifproxy %p\n", This);
595 
596         hr = proxy_manager_get_remunknown(This->parent, &remunk);
597         if (hr == S_OK)
598         {
599             HRESULT hrref = S_OK;
600             REMINTERFACEREF rif;
601             rif.ipid = This->stdobjref.ipid;
602             rif.cPublicRefs = NORMALEXTREFS;
603             rif.cPrivateRefs = 0;
604             hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
605             IRemUnknown_Release(remunk);
606             if (hr == S_OK && hrref == S_OK)
607                 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
608             else
609                 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
610         }
611     }
612     ReleaseMutex(This->parent->remoting_mutex);
613 
614     return hr;
615 }
616 
617 static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
618 {
619     HRESULT hr = S_OK;
620     LONG public_refs;
621 
622     if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
623     {
624         ERR("Wait failed for ifproxy %p\n", This);
625         return E_UNEXPECTED;
626     }
627 
628     public_refs = This->refs;
629     if (public_refs > 0)
630     {
631         IRemUnknown *remunk = NULL;
632 
633         TRACE("releasing %d refs\n", public_refs);
634 
635         hr = proxy_manager_get_remunknown(This->parent, &remunk);
636         if (hr == S_OK)
637         {
638             REMINTERFACEREF rif;
639             rif.ipid = This->stdobjref.ipid;
640             rif.cPublicRefs = public_refs;
641             rif.cPrivateRefs = 0;
642             hr = IRemUnknown_RemRelease(remunk, 1, &rif);
643             IRemUnknown_Release(remunk);
644             if (hr == S_OK)
645                 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
646             else if (hr == RPC_E_DISCONNECTED)
647                 WARN("couldn't release references because object was "
648                      "disconnected: oxid = %s, oid = %s\n",
649                      wine_dbgstr_longlong(This->parent->oxid),
650                      wine_dbgstr_longlong(This->parent->oid));
651             else
652                 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr);
653         }
654     }
655     ReleaseMutex(This->parent->remoting_mutex);
656 
657     return hr;
658 }
659 
660 /* should be called inside This->parent->cs critical section */
661 static void ifproxy_disconnect(struct ifproxy * This)
662 {
663     ifproxy_release_public_refs(This);
664     if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy);
665 
666     IRpcChannelBuffer_Release(This->chan);
667     This->chan = NULL;
668 }
669 
670 /* should be called in This->parent->cs critical section if it is an entry in parent's list */
671 static void ifproxy_destroy(struct ifproxy * This)
672 {
673     TRACE("%p\n", This);
674 
675     /* release public references to this object so that the stub can know
676      * when to destroy itself */
677     ifproxy_release_public_refs(This);
678 
679     list_remove(&This->entry);
680 
681     if (This->chan)
682     {
683         IRpcChannelBuffer_Release(This->chan);
684         This->chan = NULL;
685     }
686 
687     if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
688 
689     HeapFree(GetProcessHeap(), 0, This);
690 }
691 
692 static HRESULT proxy_manager_construct(
693     APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid,
694     const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager)
695 {
696     struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
697     if (!This) return E_OUTOFMEMORY;
698 
699     This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL);
700     if (!This->remoting_mutex)
701     {
702         HeapFree(GetProcessHeap(), 0, This);
703         return HRESULT_FROM_WIN32(GetLastError());
704     }
705 
706     if (oxid_info)
707     {
708         This->oxid_info.dwPid = oxid_info->dwPid;
709         This->oxid_info.dwTid = oxid_info->dwTid;
710         This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown;
711         This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint;
712         This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */;
713     }
714     else
715     {
716         HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info);
717         if (FAILED(hr))
718         {
719             CloseHandle(This->remoting_mutex);
720             HeapFree(GetProcessHeap(), 0, This);
721             return hr;
722         }
723     }
724 
725     This->lpVtbl = &ClientIdentity_Vtbl;
726     This->lpVtblMarshal = &ProxyMarshal_Vtbl;
727     This->lpVtblCliSec = &ProxyCliSec_Vtbl;
728 
729     list_init(&This->entry);
730     list_init(&This->interfaces);
731 
732     InitializeCriticalSection(&This->cs);
733     DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager");
734 
735     /* the apartment the object was unmarshaled into */
736     This->parent = apt;
737 
738     /* the source apartment and id of the object */
739     This->oxid = oxid;
740     This->oid = oid;
741 
742     This->refs = 1;
743 
744     /* the DCOM draft specification states that the SORF_NOPING flag is
745      * proxy manager specific, not ifproxy specific, so this implies that we
746      * should store the STDOBJREF flags here in the proxy manager. */
747     This->sorflags = sorflags;
748 
749     /* we create the IRemUnknown proxy on demand */
750     This->remunk = NULL;
751 
752     /* initialise these values to the weakest values and they will be
753      * overwritten in proxy_manager_set_context */
754     This->dest_context = MSHCTX_INPROC;
755     This->dest_context_data = NULL;
756 
757     EnterCriticalSection(&apt->cs);
758     /* FIXME: we are dependent on the ordering in here to make sure a proxy's
759      * IRemUnknown proxy doesn't get destroyed before the regual proxy does
760      * because we need the IRemUnknown proxy during the destruction of the
761      * regular proxy. Ideally, we should maintain a separate list for the
762      * IRemUnknown proxies that need late destruction */
763     list_add_tail(&apt->proxies, &This->entry);
764     LeaveCriticalSection(&apt->cs);
765 
766     TRACE("%p created for OXID %s, OID %s\n", This,
767         wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid));
768 
769     *proxy_manager = This;
770     return S_OK;
771 }
772 
773 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data)
774 {
775     MSHCTX old_dest_context = This->dest_context;
776     MSHCTX new_dest_context;
777 
778     do
779     {
780         new_dest_context = old_dest_context;
781         /* "stronger" values overwrite "weaker" values. stronger values are
782          * ones that disable more optimisations */
783         switch (old_dest_context)
784         {
785         case MSHCTX_INPROC:
786             new_dest_context = dest_context;
787             break;
788         case MSHCTX_CROSSCTX:
789             switch (dest_context)
790             {
791             case MSHCTX_INPROC:
792                 break;
793             default:
794                 new_dest_context = dest_context;
795             }
796             break;
797         case MSHCTX_LOCAL:
798             switch (dest_context)
799             {
800             case MSHCTX_INPROC:
801             case MSHCTX_CROSSCTX:
802                 break;
803             default:
804                 new_dest_context = dest_context;
805             }
806             break;
807         case MSHCTX_NOSHAREDMEM:
808             switch (dest_context)
809             {
810             case MSHCTX_DIFFERENTMACHINE:
811                 new_dest_context = dest_context;
812                 break;
813             default:
814                 break;
815             }
816             break;
817         default:
818             break;
819         }
820 
821         if (old_dest_context == new_dest_context) break;
822 
823         old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context);
824     } while (new_dest_context != old_dest_context);
825 
826     if (dest_context_data)
827         InterlockedExchangePointer(&This->dest_context_data, dest_context_data);
828 }
829 
830 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv)
831 {
832     HRESULT hr;
833     struct ifproxy * ifproxy;
834 
835     TRACE("%s\n", debugstr_guid(riid));
836 
837     if (IsEqualIID(riid, &IID_IUnknown) ||
838         IsEqualIID(riid, &IID_IMultiQI))
839     {
840         *ppv = (void *)&This->lpVtbl;
841         IUnknown_AddRef((IUnknown *)*ppv);
842         return S_OK;
843     }
844     if (IsEqualIID(riid, &IID_IMarshal))
845     {
846         *ppv = (void *)&This->lpVtblMarshal;
847         IUnknown_AddRef((IUnknown *)*ppv);
848         return S_OK;
849     }
850     if (IsEqualIID(riid, &IID_IClientSecurity))
851     {
852         *ppv = (void *)&This->lpVtblCliSec;
853         IUnknown_AddRef((IUnknown *)*ppv);
854         return S_OK;
855     }
856 
857     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
858     if (hr == S_OK)
859     {
860         *ppv = ifproxy->iface;
861         IUnknown_AddRef((IUnknown *)*ppv);
862         return S_OK;
863     }
864 
865     *ppv = NULL;
866     return E_NOINTERFACE;
867 }
868 
869 static HRESULT proxy_manager_create_ifproxy(
870     struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid,
871     IRpcChannelBuffer * channel, struct ifproxy ** iif_out)
872 {
873     HRESULT hr;
874     IPSFactoryBuffer * psfb;
875     struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy));
876     if (!ifproxy) return E_OUTOFMEMORY;
877 
878     list_init(&ifproxy->entry);
879 
880     ifproxy->parent = This;
881     ifproxy->stdobjref = *stdobjref;
882     ifproxy->iid = *riid;
883     ifproxy->refs = 0;
884     ifproxy->proxy = NULL;
885 
886     assert(channel);
887     ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
888 
889     /* the IUnknown interface is special because it does not have a
890      * proxy associated with the ifproxy as we handle IUnknown ourselves */
891     if (IsEqualIID(riid, &IID_IUnknown))
892     {
893         ifproxy->iface = (void *)&This->lpVtbl;
894         IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
895         hr = S_OK;
896     }
897     else
898     {
899         hr = get_facbuf_for_iid(riid, &psfb);
900         if (hr == S_OK)
901         {
902             /* important note: the outer unknown is set to the proxy manager.
903              * This ensures the COM identity rules are not violated, by having a
904              * one-to-one mapping of objects on the proxy side to objects on the
905              * stub side, no matter which interface you view the object through */
906             hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
907                                               &ifproxy->proxy, &ifproxy->iface);
908             IPSFactoryBuffer_Release(psfb);
909             if (hr != S_OK)
910                 ERR("Could not create proxy for interface %s, error 0x%08x\n",
911                     debugstr_guid(riid), hr);
912         }
913         else
914             ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n",
915                 debugstr_guid(riid), hr);
916 
917         if (hr == S_OK)
918             hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
919     }
920 
921     if (hr == S_OK)