Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstubmanager.c
Go to the documentation of this file.
00001 /* 00002 * A stub manager is an object that controls interface stubs. It is 00003 * identified by an OID (object identifier) and acts as the network 00004 * identity of the object. There can be many stub managers in a 00005 * process or apartment. 00006 * 00007 * Copyright 2002 Marcus Meissner 00008 * Copyright 2004 Mike Hearn for CodeWeavers 00009 * Copyright 2004 Robert Shearman (for CodeWeavers) 00010 * 00011 * This library is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU Lesser General Public 00013 * License as published by the Free Software Foundation; either 00014 * version 2.1 of the License, or (at your option) any later version. 00015 * 00016 * This library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with this library; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00024 */ 00025 00026 #define COBJMACROS 00027 #define NONAMELESSUNION 00028 #define NONAMELESSSTRUCT 00029 00030 #include <assert.h> 00031 #include <stdarg.h> 00032 #include <limits.h> 00033 00034 #include "windef.h" 00035 #include "winbase.h" 00036 #include "winuser.h" 00037 #include "objbase.h" 00038 #include "rpc.h" 00039 00040 #include "wine/debug.h" 00041 #include "compobj_private.h" 00042 00043 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00044 00045 00046 /* generates an ipid in the following format (similar to native version): 00047 * Data1 = apartment-local ipid counter 00048 * Data2 = apartment creator thread ID 00049 * Data3 = process ID 00050 * Data4 = random value 00051 */ 00052 static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) 00053 { 00054 HRESULT hr; 00055 hr = UuidCreate(ipid); 00056 if (FAILED(hr)) 00057 { 00058 ERR("couldn't create IPID for stub manager %p\n", m); 00059 UuidCreateNil(ipid); 00060 return hr; 00061 } 00062 00063 ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); 00064 ipid->Data2 = (USHORT)m->apt->tid; 00065 ipid->Data3 = (USHORT)GetCurrentProcessId(); 00066 return S_OK; 00067 } 00068 00069 /* registers a new interface stub COM object with the stub manager and returns registration record */ 00070 struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags) 00071 { 00072 struct ifstub *stub; 00073 HRESULT hr; 00074 00075 TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n", 00076 wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid)); 00077 00078 stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub)); 00079 if (!stub) return NULL; 00080 00081 hr = RPC_CreateServerChannel(&stub->chan); 00082 if (hr != S_OK) 00083 { 00084 HeapFree(GetProcessHeap(), 0, stub); 00085 return NULL; 00086 } 00087 00088 stub->stubbuffer = sb; 00089 if (sb) IRpcStubBuffer_AddRef(sb); 00090 00091 IUnknown_AddRef(iptr); 00092 stub->iface = iptr; 00093 stub->flags = flags; 00094 stub->iid = *iid; 00095 00096 /* FIXME: find a cleaner way of identifying that we are creating an ifstub 00097 * for the remunknown interface */ 00098 if (flags & MSHLFLAGSP_REMUNKNOWN) 00099 stub->ipid = m->oxid_info.ipidRemUnknown; 00100 else 00101 generate_ipid(m, &stub->ipid); 00102 00103 EnterCriticalSection(&m->lock); 00104 list_add_head(&m->ifstubs, &stub->entry); 00105 /* every normal marshal is counted so we don't allow more than we should */ 00106 if (flags & MSHLFLAGS_NORMAL) m->norm_refs++; 00107 LeaveCriticalSection(&m->lock); 00108 00109 TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid)); 00110 00111 return stub; 00112 } 00113 00114 static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) 00115 { 00116 TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); 00117 00118 list_remove(&ifstub->entry); 00119 00120 RPC_UnregisterInterface(&ifstub->iid); 00121 00122 if (ifstub->stubbuffer) IUnknown_Release(ifstub->stubbuffer); 00123 IUnknown_Release(ifstub->iface); 00124 IRpcChannelBuffer_Release(ifstub->chan); 00125 00126 HeapFree(GetProcessHeap(), 0, ifstub); 00127 } 00128 00129 static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid) 00130 { 00131 struct list *cursor; 00132 struct ifstub *result = NULL; 00133 00134 EnterCriticalSection(&m->lock); 00135 LIST_FOR_EACH( cursor, &m->ifstubs ) 00136 { 00137 struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry ); 00138 00139 if (IsEqualGUID(ipid, &ifstub->ipid)) 00140 { 00141 result = ifstub; 00142 break; 00143 } 00144 } 00145 LeaveCriticalSection(&m->lock); 00146 00147 return result; 00148 } 00149 00150 struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags) 00151 { 00152 struct ifstub *result = NULL; 00153 struct ifstub *ifstub; 00154 00155 EnterCriticalSection(&m->lock); 00156 LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry ) 00157 { 00158 if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags)) 00159 { 00160 result = ifstub; 00161 break; 00162 } 00163 } 00164 LeaveCriticalSection(&m->lock); 00165 00166 return result; 00167 } 00168 00169 /* creates a new stub manager and adds it into the apartment. caller must 00170 * release stub manager when it is no longer required. the apartment and 00171 * external refs together take one implicit ref */ 00172 struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object) 00173 { 00174 struct stub_manager *sm; 00175 00176 assert( apt ); 00177 00178 sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager)); 00179 if (!sm) return NULL; 00180 00181 list_init(&sm->ifstubs); 00182 00183 InitializeCriticalSection(&sm->lock); 00184 DEBUG_SET_CRITSEC_NAME(&sm->lock, "stub_manager"); 00185 00186 IUnknown_AddRef(object); 00187 sm->object = object; 00188 sm->apt = apt; 00189 00190 /* start off with 2 references because the stub is in the apartment 00191 * and the caller will also hold a reference */ 00192 sm->refs = 2; 00193 sm->weakrefs = 0; 00194 00195 sm->oxid_info.dwPid = GetCurrentProcessId(); 00196 sm->oxid_info.dwTid = GetCurrentThreadId(); 00197 /* 00198 * FIXME: this is a hack for marshalling IRemUnknown. In real 00199 * DCOM, the IPID of the IRemUnknown interface is generated like 00200 * any other and passed to the OXID resolver which then returns it 00201 * when queried. We don't have an OXID resolver yet so instead we 00202 * use a magic IPID reserved for IRemUnknown. 00203 */ 00204 sm->oxid_info.ipidRemUnknown.Data1 = 0xffffffff; 00205 sm->oxid_info.ipidRemUnknown.Data2 = 0xffff; 00206 sm->oxid_info.ipidRemUnknown.Data3 = 0xffff; 00207 assert(sizeof(sm->oxid_info.ipidRemUnknown.Data4) == sizeof(apt->oxid)); 00208 memcpy(sm->oxid_info.ipidRemUnknown.Data4, &apt->oxid, sizeof(OXID)); 00209 sm->oxid_info.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE; 00210 sm->oxid_info.psa = NULL /* FIXME */; 00211 00212 /* Yes, that's right, this starts at zero. that's zero EXTERNAL 00213 * refs, i.e., nobody has unmarshalled anything yet. We can't have 00214 * negative refs because the stub manager cannot be explicitly 00215 * killed, it has to die by somebody unmarshalling then releasing 00216 * the marshalled ifptr. 00217 */ 00218 sm->extrefs = 0; 00219 00220 EnterCriticalSection(&apt->cs); 00221 sm->oid = apt->oidc++; 00222 list_add_head(&apt->stubmgrs, &sm->entry); 00223 LeaveCriticalSection(&apt->cs); 00224 00225 TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object); 00226 00227 return sm; 00228 } 00229 00230 /* caller must remove stub manager from apartment prior to calling this function */ 00231 static void stub_manager_delete(struct stub_manager *m) 00232 { 00233 struct list *cursor; 00234 00235 TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid)); 00236 00237 /* release every ifstub */ 00238 while ((cursor = list_head(&m->ifstubs))) 00239 { 00240 struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry); 00241 stub_manager_delete_ifstub(m, ifstub); 00242 } 00243 00244 CoTaskMemFree(m->oxid_info.psa); 00245 IUnknown_Release(m->object); 00246 00247 DEBUG_CLEAR_CRITSEC_NAME(&m->lock); 00248 DeleteCriticalSection(&m->lock); 00249 00250 HeapFree(GetProcessHeap(), 0, m); 00251 } 00252 00253 /* increments the internal refcount */ 00254 static ULONG stub_manager_int_addref(struct stub_manager *This) 00255 { 00256 ULONG refs; 00257 00258 EnterCriticalSection(&This->apt->cs); 00259 refs = ++This->refs; 00260 LeaveCriticalSection(&This->apt->cs); 00261 00262 TRACE("before %d\n", refs - 1); 00263 00264 return refs; 00265 } 00266 00267 /* decrements the internal refcount */ 00268 ULONG stub_manager_int_release(struct stub_manager *This) 00269 { 00270 ULONG refs; 00271 APARTMENT *apt = This->apt; 00272 00273 EnterCriticalSection(&apt->cs); 00274 refs = --This->refs; 00275 00276 TRACE("after %d\n", refs); 00277 00278 /* remove from apartment so no other thread can access it... */ 00279 if (!refs) 00280 list_remove(&This->entry); 00281 00282 LeaveCriticalSection(&apt->cs); 00283 00284 /* ... so now we can delete it without being inside the apartment critsec */ 00285 if (!refs) 00286 stub_manager_delete(This); 00287 00288 return refs; 00289 } 00290 00291 /* gets the stub manager associated with an object - caller must have 00292 * a reference to the apartment while a reference to the stub manager is held. 00293 * it must also call release on the stub manager when it is no longer needed */ 00294 struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object) 00295 { 00296 struct stub_manager *result = NULL; 00297 struct list *cursor; 00298 00299 EnterCriticalSection(&apt->cs); 00300 LIST_FOR_EACH( cursor, &apt->stubmgrs ) 00301 { 00302 struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); 00303 00304 if (m->object == object) 00305 { 00306 result = m; 00307 stub_manager_int_addref(result); 00308 break; 00309 } 00310 } 00311 LeaveCriticalSection(&apt->cs); 00312 00313 if (result) 00314 TRACE("found %p for object %p\n", result, object); 00315 else 00316 TRACE("not found for object %p\n", object); 00317 00318 return result; 00319 } 00320 00321 /* removes the apartment reference to an object, destroying it when no other 00322 * threads have a reference to it */ 00323 void apartment_disconnectobject(struct apartment *apt, void *object) 00324 { 00325 int found = FALSE; 00326 struct stub_manager *stubmgr; 00327 00328 EnterCriticalSection(&apt->cs); 00329 LIST_FOR_EACH_ENTRY( stubmgr, &apt->stubmgrs, struct stub_manager, entry ) 00330 { 00331 if (stubmgr->object == object) 00332 { 00333 found = TRUE; 00334 stub_manager_int_release(stubmgr); 00335 break; 00336 } 00337 } 00338 LeaveCriticalSection(&apt->cs); 00339 00340 if (found) 00341 TRACE("disconnect object %p\n", object); 00342 else 00343 WARN("couldn't find object %p\n", object); 00344 } 00345 00346 /* gets the stub manager associated with an object id - caller must have 00347 * a reference to the apartment while a reference to the stub manager is held. 00348 * it must also call release on the stub manager when it is no longer needed */ 00349 struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) 00350 { 00351 struct stub_manager *result = NULL; 00352 struct list *cursor; 00353 00354 EnterCriticalSection(&apt->cs); 00355 LIST_FOR_EACH( cursor, &apt->stubmgrs ) 00356 { 00357 struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); 00358 00359 if (m->oid == oid) 00360 { 00361 result = m; 00362 stub_manager_int_addref(result); 00363 break; 00364 } 00365 } 00366 LeaveCriticalSection(&apt->cs); 00367 00368 if (result) 00369 TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid)); 00370 else 00371 TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid)); 00372 00373 return result; 00374 } 00375 00376 /* add some external references (ie from a client that unmarshaled an ifptr) */ 00377 ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak) 00378 { 00379 ULONG rc; 00380 00381 EnterCriticalSection(&m->lock); 00382 00383 /* make sure we don't overflow extrefs */ 00384 refs = min(refs, (ULONG_MAX-1 - m->extrefs)); 00385 rc = (m->extrefs += refs); 00386 00387 if (tableweak) 00388 rc += ++m->weakrefs; 00389 00390 LeaveCriticalSection(&m->lock); 00391 00392 TRACE("added %u refs to %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); 00393 00394 return rc; 00395 } 00396 00397 /* remove some external references */ 00398 ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases) 00399 { 00400 ULONG rc; 00401 00402 EnterCriticalSection(&m->lock); 00403 00404 /* make sure we don't underflow extrefs */ 00405 refs = min(refs, m->extrefs); 00406 rc = (m->extrefs -= refs); 00407 00408 if (tableweak) 00409 --m->weakrefs; 00410 if (!last_unlock_releases) 00411 rc += m->weakrefs; 00412 00413 LeaveCriticalSection(&m->lock); 00414 00415 TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); 00416 00417 if (rc == 0) 00418 stub_manager_int_release(m); 00419 00420 return rc; 00421 } 00422 00423 /* gets the stub manager associated with an ipid - caller must have 00424 * a reference to the apartment while a reference to the stub manager is held. 00425 * it must also call release on the stub manager when it is no longer needed */ 00426 static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid) 00427 { 00428 struct stub_manager *result = NULL; 00429 struct list *cursor; 00430 00431 EnterCriticalSection(&apt->cs); 00432 LIST_FOR_EACH( cursor, &apt->stubmgrs ) 00433 { 00434 struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); 00435 00436 if (stub_manager_ipid_to_ifstub(m, ipid)) 00437 { 00438 result = m; 00439 stub_manager_int_addref(result); 00440 break; 00441 } 00442 } 00443 LeaveCriticalSection(&apt->cs); 00444 00445 if (result) 00446 TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid)); 00447 else 00448 ERR("not found for ipid %s\n", debugstr_guid(ipid)); 00449 00450 return result; 00451 } 00452 00453 static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret) 00454 { 00455 /* FIXME: hack for IRemUnknown */ 00456 if (ipid->Data2 == 0xffff) 00457 *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4, TRUE); 00458 else 00459 *stub_apt = apartment_findfromtid(ipid->Data2); 00460 if (!*stub_apt) 00461 { 00462 TRACE("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2); 00463 return RPC_E_INVALID_OBJECT; 00464 } 00465 *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid); 00466 if (!*stubmgr_ret) 00467 { 00468 apartment_release(*stub_apt); 00469 *stub_apt = NULL; 00470 return RPC_E_INVALID_OBJECT; 00471 } 00472 return S_OK; 00473 } 00474 00475 /* gets the apartment, stub and channel of an object. the caller must 00476 * release the references to all objects (except iface) if the function 00477 * returned success, otherwise no references are returned. */ 00478 HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, 00479 IRpcStubBuffer **stub, IRpcChannelBuffer **chan, 00480 IID *iid, IUnknown **iface) 00481 { 00482 struct stub_manager *stubmgr; 00483 struct ifstub *ifstub; 00484 APARTMENT *apt; 00485 HRESULT hr; 00486 00487 hr = ipid_to_stub_manager(ipid, &apt, &stubmgr); 00488 if (hr != S_OK) return RPC_E_DISCONNECTED; 00489 00490 ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid); 00491 if (ifstub) 00492 { 00493 *stub = ifstub->stubbuffer; 00494 IRpcStubBuffer_AddRef(*stub); 00495 *chan = ifstub->chan; 00496 IRpcChannelBuffer_AddRef(*chan); 00497 *stub_apt = apt; 00498 *iid = ifstub->iid; 00499 *iface = ifstub->iface; 00500 00501 stub_manager_int_release(stubmgr); 00502 return S_OK; 00503 } 00504 else 00505 { 00506 stub_manager_int_release(stubmgr); 00507 apartment_release(apt); 00508 return RPC_E_DISCONNECTED; 00509 } 00510 } 00511 00512 /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */ 00513 BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid) 00514 { 00515 BOOL ret = TRUE; 00516 struct ifstub *ifstub; 00517 00518 if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid))) 00519 { 00520 ERR("attempted unmarshal of unknown IPID %s\n", debugstr_guid(ipid)); 00521 return FALSE; 00522 } 00523 00524 EnterCriticalSection(&m->lock); 00525 00526 /* track normal marshals so we can enforce rules whilst in-process */ 00527 if (ifstub->flags & MSHLFLAGS_NORMAL) 00528 { 00529 if (m->norm_refs) 00530 m->norm_refs--; 00531 else 00532 { 00533 ERR("attempted invalid normal unmarshal, norm_refs is zero\n"); 00534 ret = FALSE; 00535 } 00536 } 00537 00538 LeaveCriticalSection(&m->lock); 00539 00540 return ret; 00541 } 00542 00543 /* handles refcounting for CoReleaseMarshalData */ 00544 void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak) 00545 { 00546 struct ifstub *ifstub; 00547 00548 if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid))) 00549 return; 00550 00551 if (ifstub->flags & MSHLFLAGS_TABLEWEAK) 00552 refs = 0; 00553 else if (ifstub->flags & MSHLFLAGS_TABLESTRONG) 00554 refs = 1; 00555 00556 stub_manager_ext_release(m, refs, tableweak, FALSE); 00557 } 00558 00559 /* is an ifstub table marshaled? */ 00560 BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid) 00561 { 00562 struct ifstub *ifstub = stub_manager_ipid_to_ifstub(m, ipid); 00563 00564 assert( ifstub ); 00565 00566 return ifstub->flags & (MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK); 00567 } 00568 00569 00570 /***************************************************************************** 00571 * 00572 * IRemUnknown implementation 00573 * 00574 * 00575 * Note: this object is not related to the lifetime of a stub_manager, but it 00576 * interacts with stub managers. 00577 */ 00578 00579 typedef struct rem_unknown 00580 { 00581 IRemUnknown IRemUnknown_iface; 00582 LONG refs; 00583 } RemUnknown; 00584 00585 static const IRemUnknownVtbl RemUnknown_Vtbl; 00586 00587 static inline RemUnknown *impl_from_IRemUnknown(IRemUnknown *iface) 00588 { 00589 return CONTAINING_RECORD(iface, RemUnknown, IRemUnknown_iface); 00590 } 00591 00592 00593 /* construct an IRemUnknown object with one outstanding reference */ 00594 static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown) 00595 { 00596 RemUnknown *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 00597 00598 if (!This) return E_OUTOFMEMORY; 00599 00600 This->IRemUnknown_iface.lpVtbl = &RemUnknown_Vtbl; 00601 This->refs = 1; 00602 00603 *ppRemUnknown = &This->IRemUnknown_iface; 00604 return S_OK; 00605 } 00606 00607 static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv) 00608 { 00609 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 00610 00611 if (IsEqualIID(riid, &IID_IUnknown) || 00612 IsEqualIID(riid, &IID_IRemUnknown)) 00613 { 00614 *ppv = iface; 00615 IRemUnknown_AddRef(iface); 00616 return S_OK; 00617 } 00618 00619 FIXME("No interface for iid %s\n", debugstr_guid(riid)); 00620 00621 *ppv = NULL; 00622 return E_NOINTERFACE; 00623 } 00624 00625 static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface) 00626 { 00627 ULONG refs; 00628 RemUnknown *This = impl_from_IRemUnknown(iface); 00629 00630 refs = InterlockedIncrement(&This->refs); 00631 00632 TRACE("%p before: %d\n", iface, refs-1); 00633 return refs; 00634 } 00635 00636 static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface) 00637 { 00638 ULONG refs; 00639 RemUnknown *This = impl_from_IRemUnknown(iface); 00640 00641 refs = InterlockedDecrement(&This->refs); 00642 if (!refs) 00643 HeapFree(GetProcessHeap(), 0, This); 00644 00645 TRACE("%p after: %d\n", iface, refs); 00646 return refs; 00647 } 00648 00649 static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, 00650 REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */, 00651 REMQIRESULT **ppQIResults /* [size_is(,cIids)] */) 00652 { 00653 HRESULT hr; 00654 USHORT i; 00655 USHORT successful_qis = 0; 00656 APARTMENT *apt; 00657 struct stub_manager *stubmgr; 00658 00659 TRACE("(%p)->(%s, %d, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); 00660 00661 hr = ipid_to_stub_manager(ripid, &apt, &stubmgr); 00662 if (hr != S_OK) return hr; 00663 00664 *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids); 00665 00666 for (i = 0; i < cIids; i++) 00667 { 00668 HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i], 00669 stubmgr->object, MSHLFLAGS_NORMAL); 00670 if (hrobj == S_OK) 00671 successful_qis++; 00672 (*ppQIResults)[i].hResult = hrobj; 00673 } 00674 00675 stub_manager_int_release(stubmgr); 00676 apartment_release(apt); 00677 00678 if (successful_qis == cIids) 00679 return S_OK; /* we got all requested interfaces */ 00680 else if (successful_qis == 0) 00681 return E_NOINTERFACE; /* we didn't get any interfaces */ 00682 else 00683 return S_FALSE; /* we got some interfaces */ 00684 } 00685 00686 static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, 00687 USHORT cInterfaceRefs, 00688 REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */, 00689 HRESULT *pResults /* [size_is(cInterfaceRefs)] */) 00690 { 00691 HRESULT hr = S_OK; 00692 USHORT i; 00693 00694 TRACE("(%p)->(%d, %p, %p)\n", iface, cInterfaceRefs, InterfaceRefs, pResults); 00695 00696 for (i = 0; i < cInterfaceRefs; i++) 00697 { 00698 APARTMENT *apt; 00699 struct stub_manager *stubmgr; 00700 00701 pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); 00702 if (pResults[i] != S_OK) 00703 { 00704 hr = S_FALSE; 00705 continue; 00706 } 00707 00708 stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE); 00709 if (InterfaceRefs[i].cPrivateRefs) 00710 FIXME("Adding %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); 00711 00712 stub_manager_int_release(stubmgr); 00713 apartment_release(apt); 00714 } 00715 00716 return hr; 00717 } 00718 00719 static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, 00720 USHORT cInterfaceRefs, 00721 REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */) 00722 { 00723 HRESULT hr = S_OK; 00724 USHORT i; 00725 00726 TRACE("(%p)->(%d, %p)\n", iface, cInterfaceRefs, InterfaceRefs); 00727 00728 for (i = 0; i < cInterfaceRefs; i++) 00729 { 00730 APARTMENT *apt; 00731 struct stub_manager *stubmgr; 00732 00733 hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); 00734 if (hr != S_OK) 00735 { 00736 hr = E_INVALIDARG; 00737 /* FIXME: we should undo any changes already made in this function */ 00738 break; 00739 } 00740 00741 stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE); 00742 if (InterfaceRefs[i].cPrivateRefs) 00743 FIXME("Releasing %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); 00744 00745 stub_manager_int_release(stubmgr); 00746 apartment_release(apt); 00747 } 00748 00749 return hr; 00750 } 00751 00752 static const IRemUnknownVtbl RemUnknown_Vtbl = 00753 { 00754 RemUnknown_QueryInterface, 00755 RemUnknown_AddRef, 00756 RemUnknown_Release, 00757 RemUnknown_RemQueryInterface, 00758 RemUnknown_RemAddRef, 00759 RemUnknown_RemRelease 00760 }; 00761 00762 /* starts the IRemUnknown listener for the current apartment */ 00763 HRESULT start_apartment_remote_unknown(void) 00764 { 00765 IRemUnknown *pRemUnknown; 00766 HRESULT hr = S_OK; 00767 APARTMENT *apt = COM_CurrentApt(); 00768 00769 EnterCriticalSection(&apt->cs); 00770 if (!apt->remunk_exported) 00771 { 00772 /* create the IRemUnknown object */ 00773 hr = RemUnknown_Construct(&pRemUnknown); 00774 if (hr == S_OK) 00775 { 00776 STDOBJREF stdobjref; /* dummy - not used */ 00777 /* register it with the stub manager */ 00778 hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN); 00779 /* release our reference to the object as the stub manager will manage the life cycle for us */ 00780 IRemUnknown_Release(pRemUnknown); 00781 if (hr == S_OK) 00782 apt->remunk_exported = TRUE; 00783 } 00784 } 00785 LeaveCriticalSection(&apt->cs); 00786 return hr; 00787 } Generated on Sun May 27 2012 04:25:42 for ReactOS by
1.7.6.1
|