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