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