ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

stubmanager.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.