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