Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmarshal.c
Go to the documentation of this file.
00001 /* 00002 * Marshalling library 00003 * 00004 * Copyright 2002 Marcus Meissner 00005 * Copyright 2004 Mike Hearn, for CodeWeavers 00006 * Copyright 2004 Rob Shearman, for CodeWeavers 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 */ 00022 00023 #include <stdarg.h> 00024 #include <string.h> 00025 #include <assert.h> 00026 00027 #define COBJMACROS 00028 00029 #include "windef.h" 00030 #include "winbase.h" 00031 #include "winuser.h" 00032 #include "objbase.h" 00033 #include "ole2.h" 00034 #include "winerror.h" 00035 #include "wine/unicode.h" 00036 00037 #include "compobj_private.h" 00038 00039 #include "wine/debug.h" 00040 00041 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00042 00043 extern const CLSID CLSID_DfMarshal; 00044 00045 /* number of refs given out for normal marshaling */ 00046 #define NORMALEXTREFS 5 00047 00048 00049 /* private flag indicating that the object was marshaled as table-weak */ 00050 #define SORFP_TABLEWEAK SORF_OXRES1 00051 /* private flag indicating that the caller does not want to notify the stub 00052 * when the proxy disconnects or is destroyed */ 00053 #define SORFP_NOLIFETIMEMGMT SORF_OXRES2 00054 00055 /* imported object / proxy manager */ 00056 struct proxy_manager 00057 { 00058 const IMultiQIVtbl *lpVtbl; 00059 const IMarshalVtbl *lpVtblMarshal; 00060 const IClientSecurityVtbl *lpVtblCliSec; 00061 struct apartment *parent; /* owning apartment (RO) */ 00062 struct list entry; /* entry in apartment (CS parent->cs) */ 00063 OXID oxid; /* object exported ID (RO) */ 00064 OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */ 00065 OID oid; /* object ID (RO) */ 00066 struct list interfaces; /* imported interfaces (CS cs) */ 00067 LONG refs; /* proxy reference count (LOCK) */ 00068 CRITICAL_SECTION cs; /* thread safety for this object and children */ 00069 ULONG sorflags; /* STDOBJREF flags (RO) */ 00070 IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */ 00071 HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */ 00072 MSHCTX dest_context; /* context used for activating optimisations (LOCK) */ 00073 void *dest_context_data; /* reserved context value (LOCK) */ 00074 }; 00075 00076 static inline struct proxy_manager *impl_from_IMarshal( IMarshal *iface ) 00077 { 00078 return (struct proxy_manager *)((char*)iface - FIELD_OFFSET(struct proxy_manager, lpVtblMarshal)); 00079 } 00080 00081 static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity *iface ) 00082 { 00083 return (struct proxy_manager *)((char*)iface - FIELD_OFFSET(struct proxy_manager, lpVtblCliSec)); 00084 } 00085 00086 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, 00087 MSHCTX dest_context, void *dest_context_data, 00088 REFIID riid, const OXID_INFO *oxid_info, 00089 void **object); 00090 00091 /* Marshalling just passes a unique identifier to the remote client, 00092 * that makes it possible to find the passed interface again. 00093 * 00094 * So basically we need a set of values that make it unique. 00095 * 00096 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value! 00097 * 00098 * A triple is used: OXID (apt id), OID (stub manager id), 00099 * IPID (interface ptr/stub id). 00100 * 00101 * OXIDs identify an apartment and are network scoped 00102 * OIDs identify a stub manager and are apartment scoped 00103 * IPIDs identify an interface stub and are apartment scoped 00104 */ 00105 00106 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) 00107 { 00108 HRESULT hr; 00109 CLSID clsid; 00110 00111 if ((hr = CoGetPSClsid(riid, &clsid))) 00112 return hr; 00113 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER | WINE_CLSCTX_DONT_HOST, 00114 NULL, &IID_IPSFactoryBuffer, (LPVOID*)facbuf); 00115 } 00116 00117 /* marshals an object into a STDOBJREF structure */ 00118 HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, MSHLFLAGS mshlflags) 00119 { 00120 struct stub_manager *manager; 00121 struct ifstub *ifstub; 00122 BOOL tablemarshal; 00123 IRpcStubBuffer *stub = NULL; 00124 HRESULT hr; 00125 IUnknown *iobject = NULL; /* object of type riid */ 00126 00127 hr = apartment_getoxid(apt, &stdobjref->oxid); 00128 if (hr != S_OK) 00129 return hr; 00130 00131 hr = apartment_createwindowifneeded(apt); 00132 if (hr != S_OK) 00133 return hr; 00134 00135 hr = IUnknown_QueryInterface(object, riid, (void **)&iobject); 00136 if (hr != S_OK) 00137 { 00138 ERR("object doesn't expose interface %s, failing with error 0x%08x\n", 00139 debugstr_guid(riid), hr); 00140 return E_NOINTERFACE; 00141 } 00142 00143 /* IUnknown doesn't require a stub buffer, because it never goes out on 00144 * the wire */ 00145 if (!IsEqualIID(riid, &IID_IUnknown)) 00146 { 00147 IPSFactoryBuffer *psfb; 00148 00149 hr = get_facbuf_for_iid(riid, &psfb); 00150 if (hr != S_OK) 00151 { 00152 ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid)); 00153 IUnknown_Release(iobject); 00154 return hr; 00155 } 00156 00157 hr = IPSFactoryBuffer_CreateStub(psfb, riid, iobject, &stub); 00158 IPSFactoryBuffer_Release(psfb); 00159 if (hr != S_OK) 00160 { 00161 ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n", 00162 debugstr_guid(riid), hr); 00163 IUnknown_Release(iobject); 00164 return hr; 00165 } 00166 } 00167 00168 stdobjref->flags = SORF_NULL; 00169 if (mshlflags & MSHLFLAGS_TABLEWEAK) 00170 stdobjref->flags |= SORFP_TABLEWEAK; 00171 if (mshlflags & MSHLFLAGS_NOPING) 00172 stdobjref->flags |= SORF_NOPING; 00173 00174 if ((manager = get_stub_manager_from_object(apt, object))) 00175 TRACE("registering new ifstub on pre-existing manager\n"); 00176 else 00177 { 00178 TRACE("constructing new stub manager\n"); 00179 00180 manager = new_stub_manager(apt, object); 00181 if (!manager) 00182 { 00183 if (stub) IRpcStubBuffer_Release(stub); 00184 IUnknown_Release(iobject); 00185 return E_OUTOFMEMORY; 00186 } 00187 } 00188 stdobjref->oid = manager->oid; 00189 00190 tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK)); 00191 00192 /* make sure ifstub that we are creating is unique */ 00193 ifstub = stub_manager_find_ifstub(manager, riid, mshlflags); 00194 if (!ifstub) 00195 ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid, mshlflags); 00196 00197 if (stub) IRpcStubBuffer_Release(stub); 00198 IUnknown_Release(iobject); 00199 00200 if (!ifstub) 00201 { 00202 stub_manager_int_release(manager); 00203 /* destroy the stub manager if it has no ifstubs by releasing 00204 * zero external references */ 00205 stub_manager_ext_release(manager, 0, FALSE, TRUE); 00206 return E_OUTOFMEMORY; 00207 } 00208 00209 if (!tablemarshal) 00210 { 00211 stdobjref->cPublicRefs = NORMALEXTREFS; 00212 stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE); 00213 } 00214 else 00215 { 00216 stdobjref->cPublicRefs = 0; 00217 if (mshlflags & MSHLFLAGS_TABLESTRONG) 00218 stub_manager_ext_addref(manager, 1, FALSE); 00219 else 00220 stub_manager_ext_addref(manager, 0, TRUE); 00221 } 00222 00223 /* FIXME: check return value */ 00224 RPC_RegisterInterface(riid); 00225 00226 stdobjref->ipid = ifstub->ipid; 00227 00228 stub_manager_int_release(manager); 00229 return S_OK; 00230 } 00231 00232 00233 00234 /* Client-side identity of the server object */ 00235 00236 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk); 00237 static void proxy_manager_destroy(struct proxy_manager * This); 00238 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found); 00239 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv); 00240 00241 static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv) 00242 { 00243 HRESULT hr; 00244 MULTI_QI mqi; 00245 00246 TRACE("%s\n", debugstr_guid(riid)); 00247 00248 mqi.pIID = riid; 00249 hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi); 00250 *ppv = mqi.pItf; 00251 00252 return hr; 00253 } 00254 00255 static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface) 00256 { 00257 struct proxy_manager * This = (struct proxy_manager *)iface; 00258 TRACE("%p - before %d\n", iface, This->refs); 00259 return InterlockedIncrement(&This->refs); 00260 } 00261 00262 static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface) 00263 { 00264 struct proxy_manager * This = (struct proxy_manager *)iface; 00265 ULONG refs = InterlockedDecrement(&This->refs); 00266 TRACE("%p - after %d\n", iface, refs); 00267 if (!refs) 00268 proxy_manager_destroy(This); 00269 return refs; 00270 } 00271 00272 static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs) 00273 { 00274 struct proxy_manager * This = (struct proxy_manager *)iface; 00275 REMQIRESULT *qiresults = NULL; 00276 ULONG nonlocal_mqis = 0; 00277 ULONG i; 00278 ULONG successful_mqis = 0; 00279 IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids)); 00280 /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */ 00281 ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping)); 00282 00283 TRACE("cMQIs: %d\n", cMQIs); 00284 00285 /* try to get a local interface - this includes already active proxy 00286 * interfaces and also interfaces exposed by the proxy manager */ 00287 for (i = 0; i < cMQIs; i++) 00288 { 00289 TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); 00290 pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf); 00291 if (pMQIs[i].hr == S_OK) 00292 successful_mqis++; 00293 else 00294 { 00295 iids[nonlocal_mqis] = *pMQIs[i].pIID; 00296 mapping[nonlocal_mqis] = i; 00297 nonlocal_mqis++; 00298 } 00299 } 00300 00301 TRACE("%d interfaces not found locally\n", nonlocal_mqis); 00302 00303 /* if we have more than one interface not found locally then we must try 00304 * to query the remote object for it */ 00305 if (nonlocal_mqis != 0) 00306 { 00307 IRemUnknown *remunk; 00308 HRESULT hr; 00309 IPID *ipid; 00310 00311 /* get the ipid of the first entry */ 00312 /* FIXME: should we implement ClientIdentity on the ifproxies instead 00313 * of the proxy_manager so we use the correct ipid here? */ 00314 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid; 00315 00316 /* get IRemUnknown proxy so we can communicate with the remote object */ 00317 hr = proxy_manager_get_remunknown(This, &remunk); 00318 00319 if (SUCCEEDED(hr)) 00320 { 00321 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, 00322 nonlocal_mqis, iids, &qiresults); 00323 IRemUnknown_Release(remunk); 00324 if (FAILED(hr)) 00325 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr); 00326 } 00327 00328 /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of 00329 * the interfaces were returned */ 00330 if (SUCCEEDED(hr)) 00331 { 00332 /* try to unmarshal each object returned to us */ 00333 for (i = 0; i < nonlocal_mqis; i++) 00334 { 00335 ULONG index = mapping[i]; 00336 HRESULT hrobj = qiresults[i].hResult; 00337 if (hrobj == S_OK) 00338 hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(), 00339 This->dest_context, 00340 This->dest_context_data, 00341 pMQIs[index].pIID, &This->oxid_info, 00342 (void **)&pMQIs[index].pItf); 00343 00344 if (hrobj == S_OK) 00345 successful_mqis++; 00346 else 00347 ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); 00348 pMQIs[index].hr = hrobj; 00349 } 00350 } 00351 00352 /* free the memory allocated by the proxy */ 00353 CoTaskMemFree(qiresults); 00354 } 00355 00356 TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs); 00357 00358 HeapFree(GetProcessHeap(), 0, iids); 00359 HeapFree(GetProcessHeap(), 0, mapping); 00360 00361 if (successful_mqis == cMQIs) 00362 return S_OK; /* we got all requested interfaces */ 00363 else if (successful_mqis == 0) 00364 return E_NOINTERFACE; /* we didn't get any interfaces */ 00365 else 00366 return S_FALSE; /* we got some interfaces */ 00367 } 00368 00369 static const IMultiQIVtbl ClientIdentity_Vtbl = 00370 { 00371 ClientIdentity_QueryInterface, 00372 ClientIdentity_AddRef, 00373 ClientIdentity_Release, 00374 ClientIdentity_QueryMultipleInterfaces 00375 }; 00376 00377 /* FIXME: remove these */ 00378 static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid); 00379 static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize); 00380 static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv); 00381 static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm); 00382 static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved); 00383 00384 static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject) 00385 { 00386 struct proxy_manager *This = impl_from_IMarshal( iface ); 00387 return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject); 00388 } 00389 00390 static ULONG WINAPI Proxy_AddRef(IMarshal *iface) 00391 { 00392 struct proxy_manager *This = impl_from_IMarshal( iface ); 00393 return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); 00394 } 00395 00396 static ULONG WINAPI Proxy_Release(IMarshal *iface) 00397 { 00398 struct proxy_manager *This = impl_from_IMarshal( iface ); 00399 return IMultiQI_Release((IMultiQI *)&This->lpVtbl); 00400 } 00401 00402 static HRESULT WINAPI Proxy_MarshalInterface( 00403 LPMARSHAL iface, IStream *pStm, REFIID riid, void* pv, DWORD dwDestContext, 00404 void* pvDestContext, DWORD mshlflags) 00405 { 00406 struct proxy_manager *This = impl_from_IMarshal( iface ); 00407 HRESULT hr; 00408 struct ifproxy *ifproxy; 00409 00410 TRACE("(...,%s,...)\n", debugstr_guid(riid)); 00411 00412 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); 00413 if (SUCCEEDED(hr)) 00414 { 00415 STDOBJREF stdobjref = ifproxy->stdobjref; 00416 00417 stdobjref.cPublicRefs = 0; 00418 00419 if ((mshlflags != MSHLFLAGS_TABLEWEAK) && 00420 (mshlflags != MSHLFLAGS_TABLESTRONG)) 00421 { 00422 ULONG cPublicRefs = ifproxy->refs; 00423 ULONG cPublicRefsOld; 00424 /* optimization - share out proxy's public references if possible 00425 * instead of making new proxy do a roundtrip through the server */ 00426 do 00427 { 00428 ULONG cPublicRefsNew; 00429 cPublicRefsOld = cPublicRefs; 00430 stdobjref.cPublicRefs = cPublicRefs / 2; 00431 cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs; 00432 cPublicRefs = InterlockedCompareExchange( 00433 (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld); 00434 } while (cPublicRefs != cPublicRefsOld); 00435 } 00436 00437 /* normal and table-strong marshaling need at least one reference */ 00438 if (!stdobjref.cPublicRefs && (mshlflags != MSHLFLAGS_TABLEWEAK)) 00439 { 00440 IRemUnknown *remunk; 00441 hr = proxy_manager_get_remunknown(This, &remunk); 00442 if (hr == S_OK) 00443 { 00444 HRESULT hrref = S_OK; 00445 REMINTERFACEREF rif; 00446 rif.ipid = ifproxy->stdobjref.ipid; 00447 rif.cPublicRefs = (mshlflags == MSHLFLAGS_TABLESTRONG) ? 1 : NORMALEXTREFS; 00448 rif.cPrivateRefs = 0; 00449 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); 00450 IRemUnknown_Release(remunk); 00451 if (hr == S_OK && hrref == S_OK) 00452 { 00453 /* table-strong marshaling doesn't give the refs to the 00454 * client that unmarshals the STDOBJREF */ 00455 if (mshlflags != MSHLFLAGS_TABLESTRONG) 00456 stdobjref.cPublicRefs = rif.cPublicRefs; 00457 } 00458 else 00459 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref); 00460 } 00461 } 00462 00463 if (SUCCEEDED(hr)) 00464 { 00465 TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n", 00466 stdobjref.flags, stdobjref.cPublicRefs, 00467 wine_dbgstr_longlong(stdobjref.oxid), 00468 wine_dbgstr_longlong(stdobjref.oid), 00469 debugstr_guid(&stdobjref.ipid)); 00470 hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL); 00471 } 00472 } 00473 else 00474 { 00475 /* we don't have the interface already unmarshaled so we have to 00476 * request the object from the server */ 00477 IRemUnknown *remunk; 00478 IPID *ipid; 00479 REMQIRESULT *qiresults = NULL; 00480 IID iid = *riid; 00481 00482 /* get the ipid of the first entry */ 00483 /* FIXME: should we implement ClientIdentity on the ifproxies instead 00484 * of the proxy_manager so we use the correct ipid here? */ 00485 ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid; 00486 00487 /* get IRemUnknown proxy so we can communicate with the remote object */ 00488 hr = proxy_manager_get_remunknown(This, &remunk); 00489 00490 if (hr == S_OK) 00491 { 00492 hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, 00493 1, &iid, &qiresults); 00494 if (SUCCEEDED(hr)) 00495 { 00496 hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL); 00497 if (FAILED(hr)) 00498 { 00499 REMINTERFACEREF rif; 00500 rif.ipid = qiresults->std.ipid; 00501 rif.cPublicRefs = qiresults->std.cPublicRefs; 00502 rif.cPrivateRefs = 0; 00503 IRemUnknown_RemRelease(remunk, 1, &rif); 00504 } 00505 CoTaskMemFree(qiresults); 00506 } 00507 else 00508 ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr); 00509 IRemUnknown_Release(remunk); 00510 } 00511 } 00512 00513 return hr; 00514 } 00515 00516 static const IMarshalVtbl ProxyMarshal_Vtbl = 00517 { 00518 Proxy_QueryInterface, 00519 Proxy_AddRef, 00520 Proxy_Release, 00521 StdMarshalImpl_GetUnmarshalClass, 00522 StdMarshalImpl_GetMarshalSizeMax, 00523 Proxy_MarshalInterface, 00524 StdMarshalImpl_UnmarshalInterface, 00525 StdMarshalImpl_ReleaseMarshalData, 00526 StdMarshalImpl_DisconnectObject 00527 }; 00528 00529 static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject) 00530 { 00531 struct proxy_manager *This = impl_from_IClientSecurity( iface ); 00532 return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject); 00533 } 00534 00535 static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface) 00536 { 00537 struct proxy_manager *This = impl_from_IClientSecurity( iface ); 00538 return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); 00539 } 00540 00541 static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface) 00542 { 00543 struct proxy_manager *This = impl_from_IClientSecurity( iface ); 00544 return IMultiQI_Release((IMultiQI *)&This->lpVtbl); 00545 } 00546 00547 static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface, 00548 IUnknown *pProxy, 00549 DWORD *pAuthnSvc, 00550 DWORD *pAuthzSvc, 00551 OLECHAR **ppServerPrincName, 00552 DWORD *pAuthnLevel, 00553 DWORD *pImpLevel, 00554 void **pAuthInfo, 00555 DWORD *pCapabilities) 00556 { 00557 FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc, 00558 pAuthzSvc, ppServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo, 00559 pCapabilities); 00560 00561 if (pAuthnSvc) 00562 *pAuthnSvc = 0; 00563 if (pAuthzSvc) 00564 *pAuthzSvc = 0; 00565 if (ppServerPrincName) 00566 *ppServerPrincName = NULL; 00567 if (pAuthnLevel) 00568 *pAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT; 00569 if (pImpLevel) 00570 *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT; 00571 if (pAuthInfo) 00572 *pAuthInfo = NULL; 00573 if (pCapabilities) 00574 *pCapabilities = EOAC_NONE; 00575 00576 return E_NOTIMPL; 00577 } 00578 00579 static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface, 00580 IUnknown *pProxy, DWORD AuthnSvc, 00581 DWORD AuthzSvc, 00582 OLECHAR *pServerPrincName, 00583 DWORD AuthnLevel, DWORD ImpLevel, 00584 void *pAuthInfo, 00585 DWORD Capabilities) 00586 { 00587 FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc, 00588 pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "<default principal>" : debugstr_w(pServerPrincName), 00589 AuthnLevel, ImpLevel, pAuthInfo, Capabilities); 00590 return E_NOTIMPL; 00591 } 00592 00593 static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface, 00594 IUnknown *pProxy, IUnknown **ppCopy) 00595 { 00596 FIXME("(%p, %p): stub\n", pProxy, ppCopy); 00597 *ppCopy = NULL; 00598 return E_NOTIMPL; 00599 } 00600 00601 static const IClientSecurityVtbl ProxyCliSec_Vtbl = 00602 { 00603 ProxyCliSec_QueryInterface, 00604 ProxyCliSec_AddRef, 00605 ProxyCliSec_Release, 00606 ProxyCliSec_QueryBlanket, 00607 ProxyCliSec_SetBlanket, 00608 ProxyCliSec_CopyProxy 00609 }; 00610 00611 static HRESULT ifproxy_get_public_ref(struct ifproxy * This) 00612 { 00613 HRESULT hr = S_OK; 00614 00615 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) 00616 { 00617 ERR("Wait failed for ifproxy %p\n", This); 00618 return E_UNEXPECTED; 00619 } 00620 00621 if (This->refs == 0) 00622 { 00623 IRemUnknown *remunk = NULL; 00624 00625 TRACE("getting public ref for ifproxy %p\n", This); 00626 00627 hr = proxy_manager_get_remunknown(This->parent, &remunk); 00628 if (hr == S_OK) 00629 { 00630 HRESULT hrref = S_OK; 00631 REMINTERFACEREF rif; 00632 rif.ipid = This->stdobjref.ipid; 00633 rif.cPublicRefs = NORMALEXTREFS; 00634 rif.cPrivateRefs = 0; 00635 hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); 00636 IRemUnknown_Release(remunk); 00637 if (hr == S_OK && hrref == S_OK) 00638 InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS); 00639 else 00640 ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref); 00641 } 00642 } 00643 ReleaseMutex(This->parent->remoting_mutex); 00644 00645 return hr; 00646 } 00647 00648 static HRESULT ifproxy_release_public_refs(struct ifproxy * This) 00649 { 00650 HRESULT hr = S_OK; 00651 LONG public_refs; 00652 00653 if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) 00654 { 00655 ERR("Wait failed for ifproxy %p\n", This); 00656 return E_UNEXPECTED; 00657 } 00658 00659 public_refs = This->refs; 00660 if (public_refs > 0) 00661 { 00662 IRemUnknown *remunk = NULL; 00663 00664 TRACE("releasing %d refs\n", public_refs); 00665 00666 hr = proxy_manager_get_remunknown(This->parent, &remunk); 00667 if (hr == S_OK) 00668 { 00669 REMINTERFACEREF rif; 00670 rif.ipid = This->stdobjref.ipid; 00671 rif.cPublicRefs = public_refs; 00672 rif.cPrivateRefs = 0; 00673 hr = IRemUnknown_RemRelease(remunk, 1, &rif); 00674 IRemUnknown_Release(remunk); 00675 if (hr == S_OK) 00676 InterlockedExchangeAdd((LONG *)&This->refs, -public_refs); 00677 else if (hr == RPC_E_DISCONNECTED) 00678 WARN("couldn't release references because object was " 00679 "disconnected: oxid = %s, oid = %s\n", 00680 wine_dbgstr_longlong(This->parent->oxid), 00681 wine_dbgstr_longlong(This->parent->oid)); 00682 else 00683 ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr); 00684 } 00685 } 00686 ReleaseMutex(This->parent->remoting_mutex); 00687 00688 return hr; 00689 } 00690 00691 /* should be called inside This->parent->cs critical section */ 00692 static void ifproxy_disconnect(struct ifproxy * This) 00693 { 00694 ifproxy_release_public_refs(This); 00695 if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy); 00696 00697 IRpcChannelBuffer_Release(This->chan); 00698 This->chan = NULL; 00699 } 00700 00701 /* should be called in This->parent->cs critical section if it is an entry in parent's list */ 00702 static void ifproxy_destroy(struct ifproxy * This) 00703 { 00704 TRACE("%p\n", This); 00705 00706 /* release public references to this object so that the stub can know 00707 * when to destroy itself */ 00708 ifproxy_release_public_refs(This); 00709 00710 list_remove(&This->entry); 00711 00712 if (This->chan) 00713 { 00714 IRpcChannelBuffer_Release(This->chan); 00715 This->chan = NULL; 00716 } 00717 00718 if (This->proxy) IRpcProxyBuffer_Release(This->proxy); 00719 00720 HeapFree(GetProcessHeap(), 0, This); 00721 } 00722 00723 static HRESULT proxy_manager_construct( 00724 APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid, 00725 const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager) 00726 { 00727 struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 00728 if (!This) return E_OUTOFMEMORY; 00729 00730 This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL); 00731 if (!This->remoting_mutex) 00732 { 00733 HeapFree(GetProcessHeap(), 0, This); 00734 return HRESULT_FROM_WIN32(GetLastError()); 00735 } 00736 00737 if (oxid_info) 00738 { 00739 This->oxid_info.dwPid = oxid_info->dwPid; 00740 This->oxid_info.dwTid = oxid_info->dwTid; 00741 This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown; 00742 This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint; 00743 This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */; 00744 } 00745 else 00746 { 00747 HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info); 00748 if (FAILED(hr)) 00749 { 00750 CloseHandle(This->remoting_mutex); 00751 HeapFree(GetProcessHeap(), 0, This); 00752 return hr; 00753 } 00754 } 00755 00756 This->lpVtbl = &ClientIdentity_Vtbl; 00757 This->lpVtblMarshal = &ProxyMarshal_Vtbl; 00758 This->lpVtblCliSec = &ProxyCliSec_Vtbl; 00759 00760 list_init(&This->entry); 00761 list_init(&This->interfaces); 00762 00763 InitializeCriticalSection(&This->cs); 00764 DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager"); 00765 00766 /* the apartment the object was unmarshaled into */ 00767 This->parent = apt; 00768 00769 /* the source apartment and id of the object */ 00770 This->oxid = oxid; 00771 This->oid = oid; 00772 00773 This->refs = 1; 00774 00775 /* the DCOM draft specification states that the SORF_NOPING flag is 00776 * proxy manager specific, not ifproxy specific, so this implies that we 00777 * should store the STDOBJREF flags here in the proxy manager. */ 00778 This->sorflags = sorflags; 00779 00780 /* we create the IRemUnknown proxy on demand */ 00781 This->remunk = NULL; 00782 00783 /* initialise these values to the weakest values and they will be 00784 * overwritten in proxy_manager_set_context */ 00785 This->dest_context = MSHCTX_INPROC; 00786 This->dest_context_data = NULL; 00787 00788 EnterCriticalSection(&apt->cs); 00789 /* FIXME: we are dependent on the ordering in here to make sure a proxy's 00790 * IRemUnknown proxy doesn't get destroyed before the regual proxy does 00791 * because we need the IRemUnknown proxy during the destruction of the 00792 * regular proxy. Ideally, we should maintain a separate list for the 00793 * IRemUnknown proxies that need late destruction */ 00794 list_add_tail(&apt->proxies, &This->entry); 00795 LeaveCriticalSection(&apt->cs); 00796 00797 TRACE("%p created for OXID %s, OID %s\n", This, 00798 wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid)); 00799 00800 *proxy_manager = This; 00801 return S_OK; 00802 } 00803 00804 static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data) 00805 { 00806 MSHCTX old_dest_context = This->dest_context; 00807 MSHCTX new_dest_context; 00808 00809 do 00810 { 00811 new_dest_context = old_dest_context; 00812 /* "stronger" values overwrite "weaker" values. stronger values are 00813 * ones that disable more optimisations */ 00814 switch (old_dest_context) 00815 { 00816 case MSHCTX_INPROC: 00817 new_dest_context = dest_context; 00818 break; 00819 case MSHCTX_CROSSCTX: 00820 switch (dest_context) 00821 { 00822 case MSHCTX_INPROC: 00823 break; 00824 default: 00825 new_dest_context = dest_context; 00826 } 00827 break; 00828 case MSHCTX_LOCAL: 00829 switch (dest_context) 00830 { 00831 case MSHCTX_INPROC: 00832 case MSHCTX_CROSSCTX: 00833 break; 00834 default: 00835 new_dest_context = dest_context; 00836 } 00837 break; 00838 case MSHCTX_NOSHAREDMEM: 00839 switch (dest_context) 00840 { 00841 case MSHCTX_DIFFERENTMACHINE: 00842 new_dest_context = dest_context; 00843 break; 00844 default: 00845 break; 00846 } 00847 break; 00848 default: 00849 break; 00850 } 00851 00852 if (old_dest_context == new_dest_context) break; 00853 00854 old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context); 00855 } while (new_dest_context != old_dest_context); 00856 00857 if (dest_context_data) 00858 InterlockedExchangePointer(&This->dest_context_data, dest_context_data); 00859 } 00860 00861 static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv) 00862 { 00863 HRESULT hr; 00864 struct ifproxy * ifproxy; 00865 00866 TRACE("%s\n", debugstr_guid(riid)); 00867 00868 if (IsEqualIID(riid, &IID_IUnknown) || 00869 IsEqualIID(riid, &IID_IMultiQI)) 00870 { 00871 *ppv = &This->lpVtbl; 00872 IUnknown_AddRef((IUnknown *)*ppv); 00873 return S_OK; 00874 } 00875 if (IsEqualIID(riid, &IID_IMarshal)) 00876 { 00877 *ppv = &This->lpVtblMarshal; 00878 IUnknown_AddRef((IUnknown *)*ppv); 00879 return S_OK; 00880 } 00881 if (IsEqualIID(riid, &IID_IClientSecurity)) 00882 { 00883 *ppv = &This->lpVtblCliSec; 00884 IUnknown_AddRef((IUnknown *)*ppv); 00885 return S_OK; 00886 } 00887 00888 hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); 00889 if (hr == S_OK) 00890 { 00891 *ppv = ifproxy->iface; 00892 IUnknown_AddRef((IUnknown *)*ppv); 00893 return S_OK; 00894 } 00895 00896 *ppv = NULL; 00897 return E_NOINTERFACE; 00898 } 00899 00900 static HRESULT proxy_manager_create_ifproxy( 00901 struct proxy_manager * This, const STDOBJREF *stdobjref, REFIID riid, 00902 IRpcChannelBuffer * channel, struct ifproxy ** iif_out) 00903 { 00904 HRESULT hr; 00905 IPSFactoryBuffer * psfb; 00906 struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy)); 00907 if (!ifproxy) return E_OUTOFMEMORY; 00908 00909 list_init(&ifproxy->entry); 00910 00911 ifproxy->parent = This; 00912 ifproxy->stdobjref = *stdobjref; 00913 ifproxy->iid = *riid; 00914 ifproxy->refs = 0; 00915 ifproxy->proxy = NULL; 00916 00917 assert(channel); 00918 ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */ 00919 00920 /* the IUnknown interface is special because it does not have a 00921 * proxy associated with the ifproxy as we handle IUnknown ourselves */ 00922 if (IsEqualIID(riid, &IID_IUnknown)) 00923 { 00924 ifproxy->iface = &This->lpVtbl; 00925 IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); 00926 hr = S_OK; 00927 } 00928 else 00929 { 00930 hr = get_facbuf_for_iid(riid, &psfb); 00931 if (hr == S_OK) 00932 { 00933 /* important note: the outer unknown is set to the proxy manager. 00934 * This ensures the COM identity rules are not violated, by having a 00935 * one-to-one mapping of objects on the proxy side to objects on the 00936 * stub side, no matter which interface you view the object through */ 00937 hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid, 00938 &ifproxy->proxy, &ifproxy->iface); 00939 IPSFactoryBuffer_Release(psfb); 00940 if (hr != S_OK) 00941 ERR("Could not create proxy for interface %s, error 0x%08x\n", 00942 debugstr_guid(riid), hr); 00943 } 00944 else 00945 ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n", 00946 debugstr_guid(riid), hr); 00947 00948 if (hr == S_OK) 00949 hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan); 00950 } 00951 00952 if (hr == S_OK) 00953 { 00954 EnterCriticalSection(&This->cs); 00955 list_add_tail(&This->interfaces, &ifproxy->entry); 00956 LeaveCriticalSection(&This->cs); 00957 00958 *iif_out = ifproxy; 00959 TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n", 00960 ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs); 00961 } 00962 else 00963 ifproxy_destroy(ifproxy); 00964 00965 return hr; 00966 } 00967 00968 static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found) 00969 { 00970 HRESULT hr = E_NOINTERFACE; /* assume not found */ 00971 struct list * cursor; 00972 00973 EnterCriticalSection(&This->cs); 00974 LIST_FOR_EACH(cursor, &This->interfaces) 00975 { 00976 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); 00977 if (IsEqualIID(riid, &ifproxy->iid)) 00978 { 00979 *ifproxy_found = ifproxy; 00980 hr = S_OK; 00981 break; 00982 } 00983 } 00984 LeaveCriticalSection(&This->cs); 00985 00986 return hr; 00987 } 00988 00989 static void proxy_manager_disconnect(struct proxy_manager * This) 00990 { 00991 struct list * cursor; 00992 00993 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), 00994 wine_dbgstr_longlong(This->oid)); 00995 00996 EnterCriticalSection(&This->cs); 00997 00998 /* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be 00999 * disconnected - it won't do anything anyway, except cause 01000 * problems for other objects that depend on this proxy always 01001 * working */ 01002 if (!(This->sorflags & SORFP_NOLIFETIMEMGMT)) 01003 { 01004 LIST_FOR_EACH(cursor, &This->interfaces) 01005 { 01006 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); 01007 ifproxy_disconnect(ifproxy); 01008 } 01009 } 01010 01011 /* apartment is being destroyed so don't keep a pointer around to it */ 01012 This->parent = NULL; 01013 01014 LeaveCriticalSection(&This->cs); 01015 } 01016 01017 static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk) 01018 { 01019 HRESULT hr = S_OK; 01020 struct apartment *apt; 01021 BOOL called_in_original_apt; 01022 01023 /* we don't want to try and unmarshal or use IRemUnknown if we don't want 01024 * lifetime management */ 01025 if (This->sorflags & SORFP_NOLIFETIMEMGMT) 01026 return S_FALSE; 01027 01028 apt = COM_CurrentApt(); 01029 if (!apt) 01030 return CO_E_NOTINITIALIZED; 01031 01032 called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid); 01033 01034 EnterCriticalSection(&This->cs); 01035 /* only return the cached object if called from the original apartment. 01036 * in future, we might want to make the IRemUnknown proxy callable from any 01037 * apartment to avoid these checks */ 01038 if (This->remunk && called_in_original_apt) 01039 { 01040 /* already created - return existing object */ 01041 *remunk = This->remunk; 01042 IRemUnknown_AddRef(*remunk); 01043 } 01044 else if (!This->parent) 01045 /* disconnected - we can't create IRemUnknown */ 01046 hr = S_FALSE; 01047 else 01048 { 01049 STDOBJREF stdobjref; 01050 /* Don't want IRemUnknown lifetime management as this is IRemUnknown! 01051 * We also don't care about whether or not the stub is still alive */ 01052 stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING; 01053 stdobjref.cPublicRefs = 1; 01054 /* oxid of destination object */ 01055 stdobjref.oxid = This->oxid; 01056 /* FIXME: what should be used for the oid? The DCOM draft doesn't say */ 01057 stdobjref.oid = (OID)-1; 01058 stdobjref.ipid = This->oxid_info.ipidRemUnknown; 01059 01060 /* do the unmarshal */ 01061 hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context, 01062 This->dest_context_data, &IID_IRemUnknown, 01063 &This->oxid_info, (void**)remunk); 01064 if (hr == S_OK && called_in_original_apt) 01065 { 01066 This->remunk = *remunk; 01067 IRemUnknown_AddRef(This->remunk); 01068 } 01069 } 01070 LeaveCriticalSection(&This->cs); 01071 01072 TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr); 01073 01074 return hr; 01075 } 01076 01077 /* destroys a proxy manager, freeing the memory it used. 01078 * Note: this function should not be called from a list iteration in the 01079 * apartment, due to the fact that it removes itself from the apartment and 01080 * it could add a proxy to IRemUnknown into the apartment. */ 01081 static void proxy_manager_destroy(struct proxy_manager * This) 01082 { 01083 struct list * cursor; 01084 01085 TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), 01086 wine_dbgstr_longlong(This->oid)); 01087 01088 if (This->parent) 01089 { 01090 EnterCriticalSection(&This->parent->cs); 01091 01092 /* remove ourself from the list of proxy objects in the apartment */ 01093 LIST_FOR_EACH(cursor, &This->parent->proxies) 01094 { 01095 if (cursor == &This->entry) 01096 { 01097 list_remove(&This->entry); 01098 break; 01099 } 01100 } 01101 01102 LeaveCriticalSection(&This->parent->cs); 01103 } 01104 01105 /* destroy all of the interface proxies */ 01106 while ((cursor = list_head(&This->interfaces))) 01107 { 01108 struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); 01109 ifproxy_destroy(ifproxy); 01110 } 01111 01112 if (This->remunk) IRemUnknown_Release(This->remunk); 01113 CoTaskMemFree(This->oxid_info.psa); 01114 01115 DEBUG_CLEAR_CRITSEC_NAME(&This->cs); 01116 DeleteCriticalSection(&This->cs); 01117 01118 CloseHandle(This->remoting_mutex); 01119 01120 HeapFree(GetProcessHeap(), 0, This); 01121 } 01122 01123 /* finds the proxy manager corresponding to a given OXID and OID that has 01124 * been unmarshaled in the specified apartment. The caller must release the 01125 * reference to the proxy_manager when the object is no longer used. */ 01126 static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) 01127 { 01128 BOOL found = FALSE; 01129 struct list * cursor; 01130 01131 EnterCriticalSection(&apt->cs); 01132 LIST_FOR_EACH(cursor, &apt->proxies) 01133 { 01134 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); 01135 if ((oxid == proxy->oxid) && (oid == proxy->oid)) 01136 { 01137 /* be careful of a race with ClientIdentity_Release, which would 01138 * cause us to return a proxy which is in the process of being 01139 * destroyed */ 01140 if (ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl) != 0) 01141 { 01142 *proxy_found = proxy; 01143 found = TRUE; 01144 break; 01145 } 01146 } 01147 } 01148 LeaveCriticalSection(&apt->cs); 01149 return found; 01150 } 01151 01152 HRESULT apartment_disconnectproxies(struct apartment *apt) 01153 { 01154 struct list * cursor; 01155 01156 LIST_FOR_EACH(cursor, &apt->proxies) 01157 { 01158 struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); 01159 proxy_manager_disconnect(proxy); 01160 } 01161 01162 return S_OK; 01163 } 01164 01165 /********************** StdMarshal implementation ****************************/ 01166 typedef struct _StdMarshalImpl 01167 { 01168 const IMarshalVtbl *lpvtbl; 01169 LONG ref; 01170 01171 IID iid; 01172 DWORD dwDestContext; 01173 LPVOID pvDestContext; 01174 DWORD mshlflags; 01175 } StdMarshalImpl; 01176 01177 static HRESULT WINAPI 01178 StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv) 01179 { 01180 *ppv = NULL; 01181 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid)) 01182 { 01183 *ppv = iface; 01184 IUnknown_AddRef(iface); 01185 return S_OK; 01186 } 01187 FIXME("No interface for %s.\n", debugstr_guid(riid)); 01188 return E_NOINTERFACE; 01189 } 01190 01191 static ULONG WINAPI 01192 StdMarshalImpl_AddRef(LPMARSHAL iface) 01193 { 01194 StdMarshalImpl *This = (StdMarshalImpl *)iface; 01195 return InterlockedIncrement(&This->ref); 01196 } 01197 01198 static ULONG WINAPI 01199 StdMarshalImpl_Release(LPMARSHAL iface) 01200 { 01201 StdMarshalImpl *This = (StdMarshalImpl *)iface; 01202 ULONG ref = InterlockedDecrement(&This->ref); 01203 01204 if (!ref) HeapFree(GetProcessHeap(),0,This); 01205 return ref; 01206 } 01207 01208 static HRESULT WINAPI 01209 StdMarshalImpl_GetUnmarshalClass( 01210 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, 01211 void* pvDestContext, DWORD mshlflags, CLSID* pCid) 01212 { 01213 *pCid = CLSID_DfMarshal; 01214 return S_OK; 01215 } 01216 01217 static HRESULT WINAPI 01218 StdMarshalImpl_GetMarshalSizeMax( 01219 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, 01220 void* pvDestContext, DWORD mshlflags, DWORD* pSize) 01221 { 01222 *pSize = sizeof(STDOBJREF); 01223 return S_OK; 01224 } 01225 01226 static HRESULT WINAPI 01227 StdMarshalImpl_MarshalInterface( 01228 LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext, 01229 void* pvDestContext, DWORD mshlflags) 01230 { 01231 STDOBJREF stdobjref; 01232 ULONG res; 01233 HRESULT hres; 01234 APARTMENT *apt = COM_CurrentApt(); 01235 01236 TRACE("(...,%s,...)\n", debugstr_guid(riid)); 01237 01238 if (!apt) 01239 { 01240 ERR("Apartment not initialized\n"); 01241 return CO_E_NOTINITIALIZED; 01242 } 01243 01244 /* make sure this apartment can be reached from other threads / processes */ 01245 RPC_StartRemoting(apt); 01246 01247 hres = marshal_object(apt, &stdobjref, riid, pv, mshlflags); 01248 if (hres != S_OK) 01249 { 01250 ERR("Failed to create ifstub, hres=0x%x\n", hres); 01251 return hres; 01252 } 01253 01254 return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); 01255 } 01256 01257 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with 01258 * no questions asked about the rules surrounding same-apartment unmarshals 01259 * and table marshaling */ 01260 static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, 01261 MSHCTX dest_context, void *dest_context_data, 01262 REFIID riid, const OXID_INFO *oxid_info, 01263 void **object) 01264 { 01265 struct proxy_manager *proxy_manager = NULL; 01266 HRESULT hr = S_OK; 01267 01268 assert(apt); 01269 01270 TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n", 01271 stdobjref->flags, stdobjref->cPublicRefs, 01272 wine_dbgstr_longlong(stdobjref->oxid), 01273 wine_dbgstr_longlong(stdobjref->oid), 01274 debugstr_guid(&stdobjref->ipid)); 01275 01276 /* create a new proxy manager if one doesn't already exist for the 01277 * object */ 01278 if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager)) 01279 { 01280 hr = proxy_manager_construct(apt, stdobjref->flags, 01281 stdobjref->oxid, stdobjref->oid, oxid_info, 01282 &proxy_manager); 01283 } 01284 else 01285 TRACE("proxy manager already created, using\n"); 01286 01287 if (hr == S_OK) 01288 { 01289 struct ifproxy * ifproxy; 01290 01291 proxy_manager_set_context(proxy_manager, dest_context, dest_context_data); 01292 01293 hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy); 01294 if (hr == E_NOINTERFACE) 01295 { 01296 IRpcChannelBuffer *chanbuf; 01297 hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, 01298 &proxy_manager->oxid_info, 01299 proxy_manager->dest_context, 01300 proxy_manager->dest_context_data, 01301 &chanbuf); 01302 if (hr == S_OK) 01303 hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, 01304 riid, chanbuf, &ifproxy); 01305 } 01306 else 01307 IUnknown_AddRef((IUnknown *)ifproxy->iface); 01308 01309 if (hr == S_OK) 01310 { 01311 InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs); 01312 /* get at least one external reference to the object to keep it alive */ 01313 hr = ifproxy_get_public_ref(ifproxy); 01314 if (FAILED(hr)) 01315 ifproxy_destroy(ifproxy); 01316 } 01317 01318 if (hr == S_OK) 01319 *object = ifproxy->iface; 01320 } 01321 01322 /* release our reference to the proxy manager - the client/apartment 01323 * will hold on to the remaining reference for us */ 01324 if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl); 01325 01326 return hr; 01327 } 01328 01329 static HRESULT WINAPI 01330 StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) 01331 { 01332 StdMarshalImpl *This = (StdMarshalImpl *)iface; 01333 struct stub_manager *stubmgr = NULL; 01334 STDOBJREF stdobjref; 01335 ULONG res; 01336 HRESULT hres; 01337 APARTMENT *apt = COM_CurrentApt(); 01338 APARTMENT *stub_apt; 01339 OXID oxid; 01340 01341 TRACE("(...,%s,....)\n", debugstr_guid(riid)); 01342 01343 /* we need an apartment to unmarshal into */ 01344 if (!apt) 01345 { 01346 ERR("Apartment not initialized\n"); 01347 return CO_E_NOTINITIALIZED; 01348 } 01349 01350 /* read STDOBJREF from wire */ 01351 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); 01352 if (hres != S_OK) return STG_E_READFAULT; 01353 01354 hres = apartment_getoxid(apt, &oxid); 01355 if (hres != S_OK) return hres; 01356 01357 /* check if we're marshalling back to ourselves */ 01358 if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) 01359 { 01360 TRACE("Unmarshalling object marshalled in same apartment for iid %s, " 01361 "returning original object %p\n", debugstr_guid(riid), stubmgr->object); 01362 01363 hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv); 01364 01365 /* unref the ifstub. FIXME: only do this on success? */ 01366 if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid)) 01367 stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE); 01368 01369 stub_manager_int_release(stubmgr); 01370 return hres; 01371 } 01372 01373 /* notify stub manager about unmarshal if process-local object. 01374 * note: if the oxid is not found then we and native will quite happily 01375 * ignore table marshaling and normal marshaling rules regarding number of 01376 * unmarshals, etc, but if you abuse these rules then your proxy could end 01377 * up returning RPC_E_DISCONNECTED. */ 01378 if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) 01379 { 01380 if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid))) 01381 { 01382 if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid)) 01383 hres = CO_E_OBJNOTCONNECTED; 01384 } 01385 else 01386 { 01387 WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n", 01388 wine_dbgstr_longlong(stdobjref.oxid), 01389 wine_dbgstr_longlong(stdobjref.oid)); 01390 hres = CO_E_OBJNOTCONNECTED; 01391 } 01392 } 01393 else 01394 TRACE("Treating unmarshal from OXID %s as inter-process\n", 01395 wine_dbgstr_longlong(stdobjref.oxid)); 01396 01397 if (hres == S_OK) 01398 hres = unmarshal_object(&stdobjref, apt, This->dwDestContext, 01399 This->pvDestContext, riid, 01400 stubmgr ? &stubmgr->oxid_info : NULL, ppv); 01401 01402 if (stubmgr) stub_manager_int_release(stubmgr); 01403 if (stub_apt) apartment_release(stub_apt); 01404 01405 if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres); 01406 else TRACE("Successfully created proxy %p\n", *ppv); 01407 01408 return hres; 01409 } 01410 01411 static HRESULT WINAPI 01412 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) 01413 { 01414 STDOBJREF stdobjref; 01415 ULONG res; 01416 HRESULT hres; 01417 struct stub_manager *stubmgr; 01418 APARTMENT *apt; 01419 01420 TRACE("iface=%p, pStm=%p\n", iface, pStm); 01421 01422 hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); 01423 if (hres != S_OK) return STG_E_READFAULT; 01424 01425 TRACE("oxid = %s, oid = %s, ipid = %s\n", 01426 wine_dbgstr_longlong(stdobjref.oxid), 01427 wine_dbgstr_longlong(stdobjref.oid), 01428 wine_dbgstr_guid(&stdobjref.ipid)); 01429 01430 if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) 01431 { 01432 WARN("Could not map OXID %s to apartment object\n", 01433 wine_dbgstr_longlong(stdobjref.oxid)); 01434 return RPC_E_INVALID_OBJREF; 01435 } 01436 01437 if (!(stubmgr = get_stub_manager(apt, stdobjref.oid))) 01438 { 01439 ERR("could not map object ID to stub manager, oxid=%s, oid=%s\n", 01440 wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid)); 01441 return RPC_E_INVALID_OBJREF; 01442 } 01443 01444 stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK); 01445 01446 stub_manager_int_release(stubmgr); 01447 apartment_release(apt); 01448 01449 return S_OK; 01450 } 01451 01452 static HRESULT WINAPI 01453 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) 01454 { 01455 FIXME("(), stub!\n"); 01456 return S_OK; 01457 } 01458 01459 static const IMarshalVtbl VT_StdMarshal = 01460 { 01461 StdMarshalImpl_QueryInterface, 01462 StdMarshalImpl_AddRef, 01463 StdMarshalImpl_Release, 01464 StdMarshalImpl_GetUnmarshalClass, 01465 StdMarshalImpl_GetMarshalSizeMax, 01466 StdMarshalImpl_MarshalInterface, 01467 StdMarshalImpl_UnmarshalInterface, 01468 StdMarshalImpl_ReleaseMarshalData, 01469 StdMarshalImpl_DisconnectObject 01470 }; 01471 01472 static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject) 01473 { 01474 StdMarshalImpl * pStdMarshal = 01475 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl)); 01476 if (!pStdMarshal) 01477 return E_OUTOFMEMORY; 01478 pStdMarshal->lpvtbl = &VT_StdMarshal; 01479 pStdMarshal->ref = 0; 01480 return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject); 01481 } 01482 01483 /*********************************************************************** 01484 * CoGetStandardMarshal [OLE32.@] 01485 * 01486 * Gets or creates a standard marshal object. 01487 * 01488 * PARAMS 01489 * riid [I] Interface identifier of the pUnk object. 01490 * pUnk [I] Optional. Object to get the marshal object for. 01491 * dwDestContext [I] Destination. Used to enable or disable optimizations. 01492 * pvDestContext [I] Reserved. Must be NULL. 01493 * mshlflags [I] Flags affecting the marshaling process. 01494 * ppMarshal [O] Address where marshal object will be stored. 01495 * 01496 * RETURNS 01497 * Success: S_OK. 01498 * Failure: HRESULT code. 01499 * 01500 * NOTES 01501 * 01502 * The function retrieves the IMarshal object associated with an object if 01503 * that object is currently an active stub, otherwise a new marshal object is 01504 * created. 01505 */ 01506 HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, 01507 DWORD dwDestContext, LPVOID pvDestContext, 01508 DWORD mshlflags, LPMARSHAL *ppMarshal) 01509 { 01510 StdMarshalImpl *dm; 01511 01512 if (pUnk == NULL) 01513 { 01514 FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n", 01515 debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal); 01516 return E_NOTIMPL; 01517 } 01518 TRACE("(%s,%p,%x,%p,%x,%p)\n", 01519 debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal); 01520 *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); 01521 dm = (StdMarshalImpl*) *ppMarshal; 01522 if (!dm) return E_FAIL; 01523 dm->lpvtbl = &VT_StdMarshal; 01524 dm->ref = 1; 01525 01526 dm->iid = *riid; 01527 dm->dwDestContext = dwDestContext; 01528 dm->pvDestContext = pvDestContext; 01529 dm->mshlflags = mshlflags; 01530 return S_OK; 01531 } 01532 01533 /*********************************************************************** 01534 * get_marshaler [internal] 01535 * 01536 * Retrieves an IMarshal interface for an object. 01537 */ 01538 static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext, 01539 void *pvDestContext, DWORD mshlFlags, 01540 LPMARSHAL *pMarshal) 01541 { 01542 HRESULT hr; 01543 01544 if (!pUnk) 01545 return E_POINTER; 01546 hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal); 01547 if (hr != S_OK) 01548 hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext, 01549 mshlFlags, pMarshal); 01550 return hr; 01551 } 01552 01553 /*********************************************************************** 01554 * get_unmarshaler_from_stream [internal] 01555 * 01556 * Creates an IMarshal* object according to the data marshaled to the stream. 01557 * The function leaves the stream pointer at the start of the data written 01558 * to the stream by the IMarshal* object. 01559 */ 01560 static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid) 01561 { 01562 HRESULT hr; 01563 ULONG res; 01564 OBJREF objref; 01565 01566 /* read common OBJREF header */ 01567 hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); 01568 if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref))) 01569 { 01570 ERR("Failed to read common OBJREF header, 0x%08x\n", hr); 01571 return STG_E_READFAULT; 01572 } 01573 01574 /* sanity check on header */ 01575 if (objref.signature != OBJREF_SIGNATURE) 01576 { 01577 ERR("Bad OBJREF signature 0x%08x\n", objref.signature); 01578 return RPC_E_INVALID_OBJREF; 01579 } 01580 01581 if (iid) *iid = objref.iid; 01582 01583 /* FIXME: handler marshaling */ 01584 if (objref.flags & OBJREF_STANDARD) 01585 { 01586 TRACE("Using standard unmarshaling\n"); 01587 hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal); 01588 } 01589 else if (objref.flags & OBJREF_CUSTOM) 01590 { 01591 ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 01592 FIELD_OFFSET(OBJREF, u_objref.u_custom); 01593 TRACE("Using custom unmarshaling\n"); 01594 /* read constant sized OR_CUSTOM data from stream */ 01595 hr = IStream_Read(stream, &objref.u_objref.u_custom, 01596 custom_header_size, &res); 01597 if (hr != S_OK || (res != custom_header_size)) 01598 { 01599 ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr); 01600 return STG_E_READFAULT; 01601 } 01602 /* now create the marshaler specified in the stream */ 01603 hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL, 01604 CLSCTX_INPROC_SERVER, &IID_IMarshal, 01605 (LPVOID*)marshal); 01606 } 01607 else 01608 { 01609 FIXME("Invalid or unimplemented marshaling type specified: %x\n", 01610 objref.flags); 01611 return RPC_E_INVALID_OBJREF; 01612 } 01613 01614 if (hr != S_OK) 01615 ERR("Failed to create marshal, 0x%08x\n", hr); 01616 01617 return hr; 01618 } 01619 01620 /*********************************************************************** 01621 * CoGetMarshalSizeMax [OLE32.@] 01622 * 01623 * Gets the maximum amount of data that will be needed by a marshal. 01624 * 01625 * PARAMS 01626 * pulSize [O] Address where maximum marshal size will be stored. 01627 * riid [I] Identifier of the interface to marshal. 01628 * pUnk [I] Pointer to the object to marshal. 01629 * dwDestContext [I] Destination. Used to enable or disable optimizations. 01630 * pvDestContext [I] Reserved. Must be NULL. 01631 * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface(). 01632 * 01633 * RETURNS 01634 * Success: S_OK. 01635 * Failure: HRESULT code. 01636 * 01637 * SEE ALSO 01638 * CoMarshalInterface(). 01639 */ 01640 HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, 01641 DWORD dwDestContext, void *pvDestContext, 01642 DWORD mshlFlags) 01643 { 01644 HRESULT hr; 01645 LPMARSHAL pMarshal; 01646 CLSID marshaler_clsid; 01647 01648 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); 01649 if (hr != S_OK) 01650 return hr; 01651 01652 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, 01653 pvDestContext, mshlFlags, &marshaler_clsid); 01654 if (hr != S_OK) 01655 { 01656 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); 01657 IMarshal_Release(pMarshal); 01658 return hr; 01659 } 01660 01661 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, 01662 pvDestContext, mshlFlags, pulSize); 01663 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) 01664 /* add on the size of the common header */ 01665 *pulSize += FIELD_OFFSET(OBJREF, u_objref); 01666 else 01667 /* custom marshaling: add on the size of the whole OBJREF structure 01668 * like native does */ 01669 *pulSize += sizeof(OBJREF); 01670 01671 IMarshal_Release(pMarshal); 01672 return hr; 01673 } 01674 01675 01676 static void dump_MSHLFLAGS(MSHLFLAGS flags) 01677 { 01678 if (flags & MSHLFLAGS_TABLESTRONG) 01679 TRACE(" MSHLFLAGS_TABLESTRONG"); 01680 if (flags & MSHLFLAGS_TABLEWEAK) 01681 TRACE(" MSHLFLAGS_TABLEWEAK"); 01682 if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK))) 01683 TRACE(" MSHLFLAGS_NORMAL"); 01684 if (flags & MSHLFLAGS_NOPING) 01685 TRACE(" MSHLFLAGS_NOPING"); 01686 } 01687 01688 /*********************************************************************** 01689 * CoMarshalInterface [OLE32.@] 01690 * 01691 * Marshals an interface into a stream so that the object can then be 01692 * unmarshaled from another COM apartment and used remotely. 01693 * 01694 * PARAMS 01695 * pStream [I] Stream the object will be marshaled into. 01696 * riid [I] Identifier of the interface to marshal. 01697 * pUnk [I] Pointer to the object to marshal. 01698 * dwDestContext [I] Destination. Used to enable or disable optimizations. 01699 * pvDestContext [I] Reserved. Must be NULL. 01700 * mshlFlags [I] Flags that affect the marshaling. See notes. 01701 * 01702 * RETURNS 01703 * Success: S_OK. 01704 * Failure: HRESULT code. 01705 * 01706 * NOTES 01707 * 01708 * The mshlFlags parameter can take one or more of the following flags: 01709 *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release. 01710 *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called. 01711 *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release. 01712 *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic). 01713 * 01714 * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must 01715 * be called in order to release the resources used in the marshaling. 01716 * 01717 * SEE ALSO 01718 * CoUnmarshalInterface(), CoReleaseMarshalData(). 01719 */ 01720 HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, 01721 DWORD dwDestContext, void *pvDestContext, 01722 DWORD mshlFlags) 01723 { 01724 HRESULT hr; 01725 CLSID marshaler_clsid; 01726 OBJREF objref; 01727 LPMARSHAL pMarshal; 01728 01729 TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk, 01730 dwDestContext, pvDestContext); 01731 dump_MSHLFLAGS(mshlFlags); 01732 TRACE(")\n"); 01733 01734 if (!pUnk || !pStream) 01735 return E_INVALIDARG; 01736 01737 objref.signature = OBJREF_SIGNATURE; 01738 objref.iid = *riid; 01739 01740 /* get the marshaler for the specified interface */ 01741 hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); 01742 if (hr != S_OK) 01743 { 01744 ERR("Failed to get marshaller, 0x%08x\n", hr); 01745 return hr; 01746 } 01747 01748 hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, 01749 pvDestContext, mshlFlags, &marshaler_clsid); 01750 if (hr != S_OK) 01751 { 01752 ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); 01753 goto cleanup; 01754 } 01755 01756 /* FIXME: implement handler marshaling too */ 01757 if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) 01758 { 01759 TRACE("Using standard marshaling\n"); 01760 objref.flags = OBJREF_STANDARD; 01761 01762 /* write the common OBJREF header to the stream */ 01763 hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); 01764 if (hr != S_OK) 01765 { 01766 ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr); 01767 goto cleanup; 01768 } 01769 } 01770 else 01771 { 01772 TRACE("Using custom marshaling\n"); 01773 objref.flags = OBJREF_CUSTOM; 01774 objref.u_objref.u_custom.clsid = marshaler_clsid; 01775 objref.u_objref.u_custom.cbExtension = 0; 01776 objref.u_objref.u_custom.size = 0; 01777 hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, 01778 pvDestContext, mshlFlags, 01779 &objref.u_objref.u_custom.size); 01780 if (hr != S_OK) 01781 { 01782 ERR("Failed to get max size of marshal data, error 0x%08x\n", hr); 01783 goto cleanup; 01784 } 01785 /* write constant sized common header and OR_CUSTOM data into stream */ 01786 hr = IStream_Write(pStream, &objref, 01787 FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL); 01788 if (hr != S_OK) 01789 { 01790 ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr); 01791 goto cleanup; 01792 } 01793 } 01794 01795 TRACE("Calling IMarshal::MarshalInterace\n"); 01796 /* call helper object to do the actual marshaling */ 01797 hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext, 01798 pvDestContext, mshlFlags); 01799 01800 if (hr != S_OK) 01801 { 01802 ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr); 01803 goto cleanup; 01804 } 01805 01806 cleanup: 01807 IMarshal_Release(pMarshal); 01808 01809 TRACE("completed with hr 0x%08x\n", hr); 01810 01811 return hr; 01812 } 01813 01814 /*********************************************************************** 01815 * CoUnmarshalInterface [OLE32.@] 01816 * 01817 * Unmarshals an object from a stream by creating a proxy to the remote 01818 * object, if necessary. 01819 * 01820 * PARAMS 01821 * 01822 * pStream [I] Stream containing the marshaled object. 01823 * riid [I] Interface identifier of the object to create a proxy to. 01824 * ppv [O] Address where proxy will be stored. 01825 * 01826 * RETURNS 01827 * 01828 * Success: S_OK. 01829 * Failure: HRESULT code. 01830 * 01831 * SEE ALSO 01832 * CoMarshalInterface(). 01833 */ 01834 HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) 01835 { 01836 HRESULT hr; 01837 LPMARSHAL pMarshal; 01838 IID iid; 01839 IUnknown *object; 01840 01841 TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv); 01842 01843 if (!pStream || !ppv) 01844 return E_INVALIDARG; 01845 01846 hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid); 01847 if (hr != S_OK) 01848 return hr; 01849 01850 /* call the helper object to do the actual unmarshaling */ 01851 hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object); 01852 if (hr != S_OK) 01853 ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr); 01854 01855 if (hr == S_OK) 01856 { 01857 /* IID_NULL means use the interface ID of the marshaled object */ 01858 if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid)) 01859 { 01860 TRACE("requested interface != marshalled interface, additional QI needed\n"); 01861 hr = IUnknown_QueryInterface(object, riid, ppv); 01862 if (hr != S_OK) 01863 ERR("Couldn't query for interface %s, hr = 0x%08x\n", 01864 debugstr_guid(riid), hr); 01865 IUnknown_Release(object); 01866 } 01867 else 01868 { 01869 *ppv = object; 01870 } 01871 } 01872 01873 IMarshal_Release(pMarshal); 01874 01875 TRACE("completed with hr 0x%x\n", hr); 01876 01877 return hr; 01878 } 01879 01880 /*********************************************************************** 01881 * CoReleaseMarshalData [OLE32.@] 01882 * 01883 * Releases resources associated with an object that has been marshaled into 01884 * a stream. 01885 * 01886 * PARAMS 01887 * 01888 * pStream [I] The stream that the object has been marshaled into. 01889 * 01890 * RETURNS 01891 * Success: S_OK. 01892 * Failure: HRESULT error code. 01893 * 01894 * NOTES 01895 * 01896 * Call this function to release resources associated with a normal or 01897 * table-weak marshal that will not be unmarshaled, and all table-strong 01898 * marshals when they are no longer needed. 01899 * 01900 * SEE ALSO 01901 * CoMarshalInterface(), CoUnmarshalInterface(). 01902 */ 01903 HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) 01904 { 01905 HRESULT hr; 01906 LPMARSHAL pMarshal; 01907 01908 TRACE("(%p)\n", pStream); 01909 01910 hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL); 01911 if (hr != S_OK) 01912 return hr; 01913 01914 /* call the helper object to do the releasing of marshal data */ 01915 hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); 01916 if (hr != S_OK) 01917 ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr); 01918 01919 IMarshal_Release(pMarshal); 01920 return hr; 01921 } 01922 01923 01924 /*********************************************************************** 01925 * CoMarshalInterThreadInterfaceInStream [OLE32.@] 01926 * 01927 * Marshal an interface across threads in the same process. 01928 * 01929 * PARAMS 01930 * riid [I] Identifier of the interface to be marshalled. 01931 * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled. 01932 * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface. 01933 * 01934 * RETURNS 01935 * Success: S_OK 01936 * Failure: E_OUTOFMEMORY and other COM error codes 01937 * 01938 * SEE ALSO 01939 * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream() 01940 */ 01941 HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( 01942 REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm) 01943 { 01944 ULARGE_INTEGER xpos; 01945 LARGE_INTEGER seekto; 01946 HRESULT hres; 01947 01948 TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm); 01949 01950 hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm); 01951 if (FAILED(hres)) return hres; 01952 hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 01953 01954 if (SUCCEEDED(hres)) 01955 { 01956 memset(&seekto, 0, sizeof(seekto)); 01957 IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos); 01958 } 01959 else 01960 { 01961 IStream_Release(*ppStm); 01962 *ppStm = NULL; 01963 } 01964 01965 return hres; 01966 } 01967 01968 /*********************************************************************** 01969 * CoGetInterfaceAndReleaseStream [OLE32.@] 01970 * 01971 * Unmarshalls an interface from a stream and then releases the stream. 01972 * 01973 * PARAMS 01974 * pStm [I] Stream that contains the marshalled interface. 01975 * riid [I] Interface identifier of the object to unmarshall. 01976 * ppv [O] Address of pointer where the requested interface object will be stored. 01977 * 01978 * RETURNS 01979 * Success: S_OK 01980 * Failure: A COM error code 01981 * 01982 * SEE ALSO 01983 * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface() 01984 */ 01985 HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, 01986 LPVOID *ppv) 01987 { 01988 HRESULT hres; 01989 01990 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); 01991 01992 if(!pStm) return E_INVALIDARG; 01993 hres = CoUnmarshalInterface(pStm, riid, ppv); 01994 IStream_Release(pStm); 01995 return hres; 01996 } 01997 01998 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface, 01999 REFIID riid, LPVOID *ppv) 02000 { 02001 *ppv = NULL; 02002 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) 02003 { 02004 *ppv = iface; 02005 return S_OK; 02006 } 02007 return E_NOINTERFACE; 02008 } 02009 02010 static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface) 02011 { 02012 return 2; /* non-heap based object */ 02013 } 02014 02015 static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface) 02016 { 02017 return 1; /* non-heap based object */ 02018 } 02019 02020 static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface, 02021 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) 02022 { 02023 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) 02024 return StdMarshalImpl_Construct(riid, ppv); 02025 02026 FIXME("(%s), not supported.\n",debugstr_guid(riid)); 02027 return E_NOINTERFACE; 02028 } 02029 02030 static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) 02031 { 02032 FIXME("(%d), stub!\n",fLock); 02033 return S_OK; 02034 } 02035 02036 static const IClassFactoryVtbl StdMarshalCFVtbl = 02037 { 02038 StdMarshalCF_QueryInterface, 02039 StdMarshalCF_AddRef, 02040 StdMarshalCF_Release, 02041 StdMarshalCF_CreateInstance, 02042 StdMarshalCF_LockServer 02043 }; 02044 static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl; 02045 02046 HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv) 02047 { 02048 *ppv = &StdMarshalCF; 02049 return S_OK; 02050 } 02051 02052 /*********************************************************************** 02053 * CoMarshalHresult [OLE32.@] 02054 * 02055 * Marshals an HRESULT value into a stream. 02056 * 02057 * PARAMS 02058 * pStm [I] Stream that hresult will be marshalled into. 02059 * hresult [I] HRESULT to be marshalled. 02060 * 02061 * RETURNS 02062 * Success: S_OK 02063 * Failure: A COM error code 02064 * 02065 * SEE ALSO 02066 * CoUnmarshalHresult(). 02067 */ 02068 HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) 02069 { 02070 return IStream_Write(pStm, &hresult, sizeof(hresult), NULL); 02071 } 02072 02073 /*********************************************************************** 02074 * CoUnmarshalHresult [OLE32.@] 02075 * 02076 * Unmarshals an HRESULT value from a stream. 02077 * 02078 * PARAMS 02079 * pStm [I] Stream that hresult will be unmarshalled from. 02080 * phresult [I] Pointer to HRESULT where the value will be unmarshalled to. 02081 * 02082 * RETURNS 02083 * Success: S_OK 02084 * Failure: A COM error code 02085 * 02086 * SEE ALSO 02087 * CoMarshalHresult(). 02088 */ 02089 HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult) 02090 { 02091 return IStream_Read(pStm, phresult, sizeof(*phresult), NULL); 02092 } Generated on Sat May 26 2012 04:24:10 for ReactOS by
1.7.6.1
|