xref: /reactos/dll/win32/ole32/stubmanager.c (revision 85037eb7)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * A stub manager is an object that controls interface stubs. It is
3c2c66affSColin Finck  * identified by an OID (object identifier) and acts as the network
4c2c66affSColin Finck  * identity of the object. There can be many stub managers in a
5c2c66affSColin Finck  * process or apartment.
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * Copyright 2002 Marcus Meissner
8c2c66affSColin Finck  * Copyright 2004 Mike Hearn for CodeWeavers
9c2c66affSColin Finck  * Copyright 2004 Robert Shearman (for CodeWeavers)
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
12c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
13c2c66affSColin Finck  * License as published by the Free Software Foundation; either
14c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
17c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19c2c66affSColin Finck  * Lesser General Public License for more details.
20c2c66affSColin Finck  *
21c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
22c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
23c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24c2c66affSColin Finck  */
25c2c66affSColin Finck 
26c0f90872SAmine Khaldi #define COBJMACROS
27c2c66affSColin Finck 
28c0f90872SAmine Khaldi #include <assert.h>
29c0f90872SAmine Khaldi #include <stdarg.h>
30c0f90872SAmine Khaldi #include <limits.h>
31c0f90872SAmine Khaldi 
32c0f90872SAmine Khaldi #include "windef.h"
33c0f90872SAmine Khaldi #include "winbase.h"
34c0f90872SAmine Khaldi #include "winuser.h"
35c0f90872SAmine Khaldi #include "objbase.h"
36c0f90872SAmine Khaldi #include "rpc.h"
37c0f90872SAmine Khaldi 
38c0f90872SAmine Khaldi #include "wine/debug.h"
39c0f90872SAmine Khaldi #include "wine/exception.h"
40c0f90872SAmine Khaldi 
41c0f90872SAmine Khaldi #include "compobj_private.h"
42c2c66affSColin Finck 
43c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(ole);
44c2c66affSColin Finck 
45c0f90872SAmine Khaldi 
46c2c66affSColin Finck /* generates an ipid in the following format (similar to native version):
47c2c66affSColin Finck  * Data1 = apartment-local ipid counter
48c2c66affSColin Finck  * Data2 = apartment creator thread ID
49c2c66affSColin Finck  * Data3 = process ID
50c2c66affSColin Finck  * Data4 = random value
51c2c66affSColin Finck  */
generate_ipid(struct stub_manager * m,IPID * ipid)52c2c66affSColin Finck static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
53c2c66affSColin Finck {
54c2c66affSColin Finck     HRESULT hr;
55c2c66affSColin Finck     hr = UuidCreate(ipid);
56c2c66affSColin Finck     if (FAILED(hr))
57c2c66affSColin Finck     {
58c2c66affSColin Finck         ERR("couldn't create IPID for stub manager %p\n", m);
59c2c66affSColin Finck         UuidCreateNil(ipid);
60c2c66affSColin Finck         return hr;
61c2c66affSColin Finck     }
62c2c66affSColin Finck 
63c2c66affSColin Finck     ipid->Data1 = InterlockedIncrement(&m->apt->ipidc);
64c2c66affSColin Finck     ipid->Data2 = (USHORT)m->apt->tid;
65c2c66affSColin Finck     ipid->Data3 = (USHORT)GetCurrentProcessId();
66c2c66affSColin Finck     return S_OK;
67c2c66affSColin Finck }
68c2c66affSColin Finck 
69c2c66affSColin Finck /* registers a new interface stub COM object with the stub manager and returns registration record */
stub_manager_new_ifstub(struct stub_manager * m,IRpcStubBuffer * sb,REFIID iid,DWORD dest_context,void * dest_context_data,MSHLFLAGS flags)70c2c66affSColin Finck struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, REFIID iid, DWORD dest_context,
71c2c66affSColin Finck     void *dest_context_data, MSHLFLAGS flags)
72c2c66affSColin Finck {
73c2c66affSColin Finck     struct ifstub *stub;
74c2c66affSColin Finck     HRESULT hr;
75c2c66affSColin Finck 
76*85037eb7SAmine Khaldi     TRACE("oid=%s, stubbuffer=%p, iid=%s, dest_context=%x\n", wine_dbgstr_longlong(m->oid), sb,
77*85037eb7SAmine Khaldi           debugstr_guid(iid), dest_context);
78c2c66affSColin Finck 
79c2c66affSColin Finck     stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub));
80c2c66affSColin Finck     if (!stub) return NULL;
81c2c66affSColin Finck 
82c2c66affSColin Finck     hr = IUnknown_QueryInterface(m->object, iid, (void **)&stub->iface);
83c2c66affSColin Finck     if (hr != S_OK)
84c2c66affSColin Finck     {
85c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, stub);
86c2c66affSColin Finck         return NULL;
87c2c66affSColin Finck     }
88c2c66affSColin Finck 
89c2c66affSColin Finck     hr = RPC_CreateServerChannel(dest_context, dest_context_data, &stub->chan);
90c2c66affSColin Finck     if (hr != S_OK)
91c2c66affSColin Finck     {
92c2c66affSColin Finck         IUnknown_Release(stub->iface);
93c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, stub);
94c2c66affSColin Finck         return NULL;
95c2c66affSColin Finck     }
96c2c66affSColin Finck 
97c2c66affSColin Finck     stub->stubbuffer = sb;
98c2c66affSColin Finck     if (sb) IRpcStubBuffer_AddRef(sb);
99c2c66affSColin Finck 
100c2c66affSColin Finck     stub->flags = flags;
101c2c66affSColin Finck     stub->iid = *iid;
102c2c66affSColin Finck 
103c2c66affSColin Finck     /* FIXME: find a cleaner way of identifying that we are creating an ifstub
104c2c66affSColin Finck      * for the remunknown interface */
105c2c66affSColin Finck     if (flags & MSHLFLAGSP_REMUNKNOWN)
106c2c66affSColin Finck         stub->ipid = m->oxid_info.ipidRemUnknown;
107c2c66affSColin Finck     else
108c2c66affSColin Finck         generate_ipid(m, &stub->ipid);
109c2c66affSColin Finck 
110c2c66affSColin Finck     EnterCriticalSection(&m->lock);
111c2c66affSColin Finck     list_add_head(&m->ifstubs, &stub->entry);
112c2c66affSColin Finck     /* every normal marshal is counted so we don't allow more than we should */
113c2c66affSColin Finck     if (flags & MSHLFLAGS_NORMAL) m->norm_refs++;
114c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
115c2c66affSColin Finck 
116c2c66affSColin Finck     TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
117c2c66affSColin Finck 
118c2c66affSColin Finck     return stub;
119c2c66affSColin Finck }
120c2c66affSColin Finck 
stub_manager_delete_ifstub(struct stub_manager * m,struct ifstub * ifstub)121c2c66affSColin Finck static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub)
122c2c66affSColin Finck {
123c2c66affSColin Finck     TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid));
124c2c66affSColin Finck 
125c2c66affSColin Finck     list_remove(&ifstub->entry);
126c2c66affSColin Finck 
127c2c66affSColin Finck     if (!m->disconnected)
128c2c66affSColin Finck         RPC_UnregisterInterface(&ifstub->iid, TRUE);
129c2c66affSColin Finck 
130c2c66affSColin Finck     if (ifstub->stubbuffer) IRpcStubBuffer_Release(ifstub->stubbuffer);
131c2c66affSColin Finck     IUnknown_Release(ifstub->iface);
132c2c66affSColin Finck     IRpcChannelBuffer_Release(ifstub->chan);
133c2c66affSColin Finck 
134c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, ifstub);
135c2c66affSColin Finck }
136c2c66affSColin Finck 
stub_manager_ipid_to_ifstub(struct stub_manager * m,const IPID * ipid)137c2c66affSColin Finck static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
138c2c66affSColin Finck {
139c2c66affSColin Finck     struct list    *cursor;
140c2c66affSColin Finck     struct ifstub  *result = NULL;
141c2c66affSColin Finck 
142c2c66affSColin Finck     EnterCriticalSection(&m->lock);
143c2c66affSColin Finck     LIST_FOR_EACH( cursor, &m->ifstubs )
144c2c66affSColin Finck     {
145c2c66affSColin Finck         struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry );
146c2c66affSColin Finck 
147c2c66affSColin Finck         if (IsEqualGUID(ipid, &ifstub->ipid))
148c2c66affSColin Finck         {
149c2c66affSColin Finck             result = ifstub;
150c2c66affSColin Finck             break;
151c2c66affSColin Finck         }
152c2c66affSColin Finck     }
153c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
154c2c66affSColin Finck 
155c2c66affSColin Finck     return result;
156c2c66affSColin Finck }
157c2c66affSColin Finck 
stub_manager_find_ifstub(struct stub_manager * m,REFIID iid,MSHLFLAGS flags)158c2c66affSColin Finck struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags)
159c2c66affSColin Finck {
160c2c66affSColin Finck     struct ifstub  *result = NULL;
161c2c66affSColin Finck     struct ifstub  *ifstub;
162c2c66affSColin Finck 
163c2c66affSColin Finck     EnterCriticalSection(&m->lock);
164c2c66affSColin Finck     LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry )
165c2c66affSColin Finck     {
166c2c66affSColin Finck         if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags))
167c2c66affSColin Finck         {
168c2c66affSColin Finck             result = ifstub;
169c2c66affSColin Finck             break;
170c2c66affSColin Finck         }
171c2c66affSColin Finck     }
172c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
173c2c66affSColin Finck 
174c2c66affSColin Finck     return result;
175c2c66affSColin Finck }
176c2c66affSColin Finck 
177c2c66affSColin Finck /* creates a new stub manager and adds it into the apartment. caller must
178c2c66affSColin Finck  * release stub manager when it is no longer required. the apartment and
179c2c66affSColin Finck  * external refs together take one implicit ref */
new_stub_manager(APARTMENT * apt,IUnknown * object)180c2c66affSColin Finck static struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
181c2c66affSColin Finck {
182c2c66affSColin Finck     struct stub_manager *sm;
183c2c66affSColin Finck     HRESULT hres;
184c2c66affSColin Finck 
185c2c66affSColin Finck     assert( apt );
186c2c66affSColin Finck 
187c2c66affSColin Finck     sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager));
188c2c66affSColin Finck     if (!sm) return NULL;
189c2c66affSColin Finck 
190c2c66affSColin Finck     list_init(&sm->ifstubs);
191c2c66affSColin Finck 
192c2c66affSColin Finck     InitializeCriticalSection(&sm->lock);
193c2c66affSColin Finck     DEBUG_SET_CRITSEC_NAME(&sm->lock, "stub_manager");
194c2c66affSColin Finck 
195c2c66affSColin Finck     IUnknown_AddRef(object);
196c2c66affSColin Finck     sm->object = object;
197c2c66affSColin Finck     sm->apt    = apt;
198c2c66affSColin Finck 
199c2c66affSColin Finck     /* start off with 2 references because the stub is in the apartment
200c2c66affSColin Finck      * and the caller will also hold a reference */
201c2c66affSColin Finck     sm->refs   = 2;
202c2c66affSColin Finck     sm->weakrefs = 0;
203c2c66affSColin Finck 
204c2c66affSColin Finck     sm->oxid_info.dwPid = GetCurrentProcessId();
205c2c66affSColin Finck     sm->oxid_info.dwTid = GetCurrentThreadId();
206c2c66affSColin Finck     /*
207c2c66affSColin Finck      * FIXME: this is a hack for marshalling IRemUnknown. In real
208c2c66affSColin Finck      * DCOM, the IPID of the IRemUnknown interface is generated like
209c2c66affSColin Finck      * any other and passed to the OXID resolver which then returns it
210c2c66affSColin Finck      * when queried. We don't have an OXID resolver yet so instead we
211c2c66affSColin Finck      * use a magic IPID reserved for IRemUnknown.
212c2c66affSColin Finck      */
213c2c66affSColin Finck     sm->oxid_info.ipidRemUnknown.Data1 = 0xffffffff;
214c2c66affSColin Finck     sm->oxid_info.ipidRemUnknown.Data2 = 0xffff;
215c2c66affSColin Finck     sm->oxid_info.ipidRemUnknown.Data3 = 0xffff;
216c2c66affSColin Finck     assert(sizeof(sm->oxid_info.ipidRemUnknown.Data4) == sizeof(apt->oxid));
217c2c66affSColin Finck     memcpy(sm->oxid_info.ipidRemUnknown.Data4, &apt->oxid, sizeof(OXID));
218c2c66affSColin Finck     sm->oxid_info.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
219c2c66affSColin Finck     sm->oxid_info.psa = NULL /* FIXME */;
220c2c66affSColin Finck 
221c2c66affSColin Finck     /* Yes, that's right, this starts at zero. that's zero EXTERNAL
222c2c66affSColin Finck      * refs, i.e., nobody has unmarshalled anything yet. We can't have
223c2c66affSColin Finck      * negative refs because the stub manager cannot be explicitly
224c2c66affSColin Finck      * killed, it has to die by somebody unmarshalling then releasing
225c2c66affSColin Finck      * the marshalled ifptr.
226c2c66affSColin Finck      */
227c2c66affSColin Finck     sm->extrefs = 0;
228c2c66affSColin Finck     sm->disconnected = FALSE;
229c2c66affSColin Finck 
230c2c66affSColin Finck     hres = IUnknown_QueryInterface(object, &IID_IExternalConnection, (void**)&sm->extern_conn);
231c2c66affSColin Finck     if(FAILED(hres))
232c2c66affSColin Finck         sm->extern_conn = NULL;
233c2c66affSColin Finck 
234c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
235c2c66affSColin Finck     sm->oid = apt->oidc++;
236c2c66affSColin Finck     list_add_head(&apt->stubmgrs, &sm->entry);
237c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
238c2c66affSColin Finck 
239c2c66affSColin Finck     TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
240c2c66affSColin Finck 
241c2c66affSColin Finck     return sm;
242c2c66affSColin Finck }
243c2c66affSColin Finck 
stub_manager_disconnect(struct stub_manager * m)244c2c66affSColin Finck void stub_manager_disconnect(struct stub_manager *m)
245c2c66affSColin Finck {
246c2c66affSColin Finck     struct ifstub *ifstub;
247c2c66affSColin Finck 
248c2c66affSColin Finck     EnterCriticalSection(&m->lock);
249c2c66affSColin Finck     if (!m->disconnected)
250c2c66affSColin Finck     {
251c2c66affSColin Finck         LIST_FOR_EACH_ENTRY(ifstub, &m->ifstubs, struct ifstub, entry)
252c2c66affSColin Finck             RPC_UnregisterInterface(&ifstub->iid, FALSE);
253c2c66affSColin Finck 
254c2c66affSColin Finck         m->disconnected = TRUE;
255c2c66affSColin Finck     }
256c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
257c2c66affSColin Finck }
258c2c66affSColin Finck 
259c2c66affSColin Finck /* caller must remove stub manager from apartment prior to calling this function */
stub_manager_delete(struct stub_manager * m)260c2c66affSColin Finck static void stub_manager_delete(struct stub_manager *m)
261c2c66affSColin Finck {
262c2c66affSColin Finck     struct list *cursor;
263c2c66affSColin Finck 
264c2c66affSColin Finck     TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid));
265c2c66affSColin Finck 
266c2c66affSColin Finck     /* release every ifstub */
267c2c66affSColin Finck     while ((cursor = list_head(&m->ifstubs)))
268c2c66affSColin Finck     {
269c2c66affSColin Finck         struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry);
270c2c66affSColin Finck         stub_manager_delete_ifstub(m, ifstub);
271c2c66affSColin Finck     }
272c2c66affSColin Finck 
273c2c66affSColin Finck     if(m->extern_conn)
274c2c66affSColin Finck         IExternalConnection_Release(m->extern_conn);
275c2c66affSColin Finck 
276c2c66affSColin Finck     CoTaskMemFree(m->oxid_info.psa);
277c2c66affSColin Finck 
278c2c66affSColin Finck     /* Some broken apps crash in object destructors. We have a test showing
279c2c66affSColin Finck      * that on winxp+ those crashes are caught and ignored. */
280c2c66affSColin Finck     __TRY
281c2c66affSColin Finck     {
282c2c66affSColin Finck         IUnknown_Release(m->object);
283c2c66affSColin Finck     }
284c2c66affSColin Finck     __EXCEPT_PAGE_FAULT
285c2c66affSColin Finck     {
286c2c66affSColin Finck         ERR("Got page fault when releasing stub!\n");
287c2c66affSColin Finck     }
288c2c66affSColin Finck     __ENDTRY
289c2c66affSColin Finck 
290c2c66affSColin Finck     DEBUG_CLEAR_CRITSEC_NAME(&m->lock);
291c2c66affSColin Finck     DeleteCriticalSection(&m->lock);
292c2c66affSColin Finck 
293c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, m);
294c2c66affSColin Finck }
295c2c66affSColin Finck 
296c2c66affSColin Finck /* increments the internal refcount */
stub_manager_int_addref(struct stub_manager * This)297c2c66affSColin Finck static ULONG stub_manager_int_addref(struct stub_manager *This)
298c2c66affSColin Finck {
299c2c66affSColin Finck     ULONG refs;
300c2c66affSColin Finck 
301c2c66affSColin Finck     EnterCriticalSection(&This->apt->cs);
302c2c66affSColin Finck     refs = ++This->refs;
303c2c66affSColin Finck     LeaveCriticalSection(&This->apt->cs);
304c2c66affSColin Finck 
305c2c66affSColin Finck     TRACE("before %d\n", refs - 1);
306c2c66affSColin Finck 
307c2c66affSColin Finck     return refs;
308c2c66affSColin Finck }
309c2c66affSColin Finck 
310c2c66affSColin Finck /* decrements the internal refcount */
stub_manager_int_release(struct stub_manager * This)311c2c66affSColin Finck ULONG stub_manager_int_release(struct stub_manager *This)
312c2c66affSColin Finck {
313c2c66affSColin Finck     ULONG refs;
314c2c66affSColin Finck     APARTMENT *apt = This->apt;
315c2c66affSColin Finck 
316c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
317c2c66affSColin Finck     refs = --This->refs;
318c2c66affSColin Finck 
319c2c66affSColin Finck     TRACE("after %d\n", refs);
320c2c66affSColin Finck 
321c2c66affSColin Finck     /* remove from apartment so no other thread can access it... */
322c2c66affSColin Finck     if (!refs)
323c2c66affSColin Finck         list_remove(&This->entry);
324c2c66affSColin Finck 
325c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
326c2c66affSColin Finck 
327c2c66affSColin Finck     /* ... so now we can delete it without being inside the apartment critsec */
328c2c66affSColin Finck     if (!refs)
329c2c66affSColin Finck         stub_manager_delete(This);
330c2c66affSColin Finck 
331c2c66affSColin Finck     return refs;
332c2c66affSColin Finck }
333c2c66affSColin Finck 
334c2c66affSColin Finck /* gets the stub manager associated with an object - caller must have
335c2c66affSColin Finck  * a reference to the apartment while a reference to the stub manager is held.
336c2c66affSColin Finck  * it must also call release on the stub manager when it is no longer needed */
get_stub_manager_from_object(APARTMENT * apt,IUnknown * obj,BOOL alloc)337c2c66affSColin Finck struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, IUnknown *obj, BOOL alloc)
338c2c66affSColin Finck {
339c2c66affSColin Finck     struct stub_manager *result = NULL;
340c2c66affSColin Finck     struct list         *cursor;
341c2c66affSColin Finck     IUnknown *object;
342c2c66affSColin Finck     HRESULT hres;
343c2c66affSColin Finck 
344c2c66affSColin Finck     hres = IUnknown_QueryInterface(obj, &IID_IUnknown, (void**)&object);
345c2c66affSColin Finck     if (FAILED(hres)) {
346c2c66affSColin Finck         ERR("QueryInterface(IID_IUnknown failed): %08x\n", hres);
347c2c66affSColin Finck         return NULL;
348c2c66affSColin Finck     }
349c2c66affSColin Finck 
350c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
351c2c66affSColin Finck     LIST_FOR_EACH( cursor, &apt->stubmgrs )
352c2c66affSColin Finck     {
353c2c66affSColin Finck         struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
354c2c66affSColin Finck 
355c2c66affSColin Finck         if (m->object == object)
356c2c66affSColin Finck         {
357c2c66affSColin Finck             result = m;
358c2c66affSColin Finck             stub_manager_int_addref(result);
359c2c66affSColin Finck             break;
360c2c66affSColin Finck         }
361c2c66affSColin Finck     }
362c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
363c2c66affSColin Finck 
364c2c66affSColin Finck     if (result) {
365c2c66affSColin Finck         TRACE("found %p for object %p\n", result, object);
366c2c66affSColin Finck     }else if (alloc) {
367c2c66affSColin Finck         TRACE("not found, creating new stub manager...\n");
368c2c66affSColin Finck         result = new_stub_manager(apt, object);
369c2c66affSColin Finck     }else {
370c2c66affSColin Finck         TRACE("not found for object %p\n", object);
371c2c66affSColin Finck     }
372c2c66affSColin Finck 
373c2c66affSColin Finck     IUnknown_Release(object);
374c2c66affSColin Finck     return result;
375c2c66affSColin Finck }
376c2c66affSColin Finck 
377c2c66affSColin Finck /* gets the stub manager associated with an object id - caller must have
378c2c66affSColin Finck  * a reference to the apartment while a reference to the stub manager is held.
379c2c66affSColin Finck  * it must also call release on the stub manager when it is no longer needed */
get_stub_manager(APARTMENT * apt,OID oid)380c2c66affSColin Finck struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid)
381c2c66affSColin Finck {
382c2c66affSColin Finck     struct stub_manager *result = NULL;
383c2c66affSColin Finck     struct list         *cursor;
384c2c66affSColin Finck 
385c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
386c2c66affSColin Finck     LIST_FOR_EACH( cursor, &apt->stubmgrs )
387c2c66affSColin Finck     {
388c2c66affSColin Finck         struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
389c2c66affSColin Finck 
390c2c66affSColin Finck         if (m->oid == oid)
391c2c66affSColin Finck         {
392c2c66affSColin Finck             result = m;
393c2c66affSColin Finck             stub_manager_int_addref(result);
394c2c66affSColin Finck             break;
395c2c66affSColin Finck         }
396c2c66affSColin Finck     }
397c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
398c2c66affSColin Finck 
399c2c66affSColin Finck     if (result)
400c2c66affSColin Finck         TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid));
401c2c66affSColin Finck     else
402c2c66affSColin Finck         TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid));
403c2c66affSColin Finck 
404c2c66affSColin Finck     return result;
405c2c66affSColin Finck }
406c2c66affSColin Finck 
407c2c66affSColin Finck /* add some external references (ie from a client that unmarshaled an ifptr) */
stub_manager_ext_addref(struct stub_manager * m,ULONG refs,BOOL tableweak)408c2c66affSColin Finck ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak)
409c2c66affSColin Finck {
410c2c66affSColin Finck     BOOL first_extern_ref;
411c2c66affSColin Finck     ULONG rc;
412c2c66affSColin Finck 
413c2c66affSColin Finck     EnterCriticalSection(&m->lock);
414c2c66affSColin Finck 
415c2c66affSColin Finck     first_extern_ref = refs && !m->extrefs;
416c2c66affSColin Finck 
417c2c66affSColin Finck     /* make sure we don't overflow extrefs */
418c2c66affSColin Finck     refs = min(refs, (ULONG_MAX-1 - m->extrefs));
419c2c66affSColin Finck     rc = (m->extrefs += refs);
420c2c66affSColin Finck 
421c2c66affSColin Finck     if (tableweak)
422c2c66affSColin Finck         rc += ++m->weakrefs;
423c2c66affSColin Finck 
424c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
425c2c66affSColin Finck 
426c2c66affSColin Finck     TRACE("added %u refs to %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
427c2c66affSColin Finck 
428c2c66affSColin Finck     /*
429c2c66affSColin Finck      * NOTE: According to tests, creating a stub causes two AddConnection calls followed by
430c2c66affSColin Finck      * one ReleaseConnection call (with fLastReleaseCloses=FALSE).
431c2c66affSColin Finck      */
432c2c66affSColin Finck     if(first_extern_ref && m->extern_conn)
433c2c66affSColin Finck         IExternalConnection_AddConnection(m->extern_conn, EXTCONN_STRONG, 0);
434c2c66affSColin Finck 
435c2c66affSColin Finck     return rc;
436c2c66affSColin Finck }
437c2c66affSColin Finck 
438c2c66affSColin Finck /* remove some external references */
stub_manager_ext_release(struct stub_manager * m,ULONG refs,BOOL tableweak,BOOL last_unlock_releases)439c2c66affSColin Finck ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases)
440c2c66affSColin Finck {
441c2c66affSColin Finck     BOOL last_extern_ref;
442c2c66affSColin Finck     ULONG rc;
443c2c66affSColin Finck 
444c2c66affSColin Finck     EnterCriticalSection(&m->lock);
445c2c66affSColin Finck 
446c2c66affSColin Finck     /* make sure we don't underflow extrefs */
447c2c66affSColin Finck     refs = min(refs, m->extrefs);
448c2c66affSColin Finck     rc = (m->extrefs -= refs);
449c2c66affSColin Finck 
450c2c66affSColin Finck     if (tableweak)
451c2c66affSColin Finck         --m->weakrefs;
452c2c66affSColin Finck     if (!last_unlock_releases)
453c2c66affSColin Finck         rc += m->weakrefs;
454c2c66affSColin Finck 
455c2c66affSColin Finck     last_extern_ref = refs && !m->extrefs;
456c2c66affSColin Finck 
457c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
458c2c66affSColin Finck 
459c2c66affSColin Finck     TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
460c2c66affSColin Finck 
461c2c66affSColin Finck     if (last_extern_ref && m->extern_conn)
462c2c66affSColin Finck         IExternalConnection_ReleaseConnection(m->extern_conn, EXTCONN_STRONG, 0, last_unlock_releases);
463c2c66affSColin Finck 
464c2c66affSColin Finck     if (rc == 0)
465c2c66affSColin Finck         if (!(m->extern_conn && last_unlock_releases && m->weakrefs))
466c2c66affSColin Finck             stub_manager_int_release(m);
467c2c66affSColin Finck 
468c2c66affSColin Finck     return rc;
469c2c66affSColin Finck }
470c2c66affSColin Finck 
471c2c66affSColin Finck /* gets the stub manager associated with an ipid - caller must have
472c2c66affSColin Finck  * a reference to the apartment while a reference to the stub manager is held.
473c2c66affSColin Finck  * it must also call release on the stub manager when it is no longer needed */
get_stub_manager_from_ipid(APARTMENT * apt,const IPID * ipid,struct ifstub ** ifstub)474*85037eb7SAmine Khaldi static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid, struct ifstub **ifstub)
475c2c66affSColin Finck {
476c2c66affSColin Finck     struct stub_manager *result = NULL;
477c2c66affSColin Finck     struct list         *cursor;
478c2c66affSColin Finck 
479c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
480c2c66affSColin Finck     LIST_FOR_EACH( cursor, &apt->stubmgrs )
481c2c66affSColin Finck     {
482c2c66affSColin Finck         struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
483c2c66affSColin Finck 
484*85037eb7SAmine Khaldi         if ((*ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
485c2c66affSColin Finck         {
486c2c66affSColin Finck             result = m;
487c2c66affSColin Finck             stub_manager_int_addref(result);
488c2c66affSColin Finck             break;
489c2c66affSColin Finck         }
490c2c66affSColin Finck     }
491c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
492c2c66affSColin Finck 
493c2c66affSColin Finck     if (result)
494c2c66affSColin Finck         TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid));
495c2c66affSColin Finck     else
496c2c66affSColin Finck         ERR("not found for ipid %s\n", debugstr_guid(ipid));
497c2c66affSColin Finck 
498c2c66affSColin Finck     return result;
499c2c66affSColin Finck }
500c2c66affSColin Finck 
ipid_to_ifstub(const IPID * ipid,APARTMENT ** stub_apt,struct stub_manager ** stubmgr_ret,struct ifstub ** ifstub)501*85037eb7SAmine Khaldi static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt,
502*85037eb7SAmine Khaldi                               struct stub_manager **stubmgr_ret, struct ifstub **ifstub)
503c2c66affSColin Finck {
504c2c66affSColin Finck     /* FIXME: hack for IRemUnknown */
505c2c66affSColin Finck     if (ipid->Data2 == 0xffff)
506c2c66affSColin Finck         *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4, TRUE);
507c2c66affSColin Finck     else
508c2c66affSColin Finck         *stub_apt = apartment_findfromtid(ipid->Data2);
509c2c66affSColin Finck     if (!*stub_apt)
510c2c66affSColin Finck     {
511c2c66affSColin Finck         TRACE("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2);
512c2c66affSColin Finck         return RPC_E_INVALID_OBJECT;
513c2c66affSColin Finck     }
514*85037eb7SAmine Khaldi     *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid, ifstub);
515c2c66affSColin Finck     if (!*stubmgr_ret)
516c2c66affSColin Finck     {
517c2c66affSColin Finck         apartment_release(*stub_apt);
518c2c66affSColin Finck         *stub_apt = NULL;
519c2c66affSColin Finck         return RPC_E_INVALID_OBJECT;
520c2c66affSColin Finck     }
521c2c66affSColin Finck     return S_OK;
522c2c66affSColin Finck }
523c2c66affSColin Finck 
ipid_to_stub_manager(const IPID * ipid,APARTMENT ** stub_apt,struct stub_manager ** stub)524*85037eb7SAmine Khaldi static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stub)
525*85037eb7SAmine Khaldi {
526*85037eb7SAmine Khaldi     struct ifstub *ifstub;
527*85037eb7SAmine Khaldi     return ipid_to_ifstub(ipid, stub_apt, stub, &ifstub);
528*85037eb7SAmine Khaldi }
529*85037eb7SAmine Khaldi 
530c2c66affSColin Finck /* gets the apartment, stub and channel of an object. the caller must
531c2c66affSColin Finck  * release the references to all objects (except iface) if the function
532c2c66affSColin Finck  * returned success, otherwise no references are returned. */
ipid_get_dispatch_params(const IPID * ipid,APARTMENT ** stub_apt,struct stub_manager ** manager,IRpcStubBuffer ** stub,IRpcChannelBuffer ** chan,IID * iid,IUnknown ** iface)533c2c66affSColin Finck HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt,
534c2c66affSColin Finck                                  struct stub_manager **manager,
535c2c66affSColin Finck                                  IRpcStubBuffer **stub, IRpcChannelBuffer **chan,
536c2c66affSColin Finck                                  IID *iid, IUnknown **iface)
537c2c66affSColin Finck {
538c2c66affSColin Finck     struct stub_manager *stubmgr;
539c2c66affSColin Finck     struct ifstub *ifstub;
540c2c66affSColin Finck     APARTMENT *apt;
541c2c66affSColin Finck     HRESULT hr;
542c2c66affSColin Finck 
543*85037eb7SAmine Khaldi     hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub);
544c2c66affSColin Finck     if (hr != S_OK) return RPC_E_DISCONNECTED;
545c2c66affSColin Finck 
546c2c66affSColin Finck     *stub = ifstub->stubbuffer;
547c2c66affSColin Finck     IRpcStubBuffer_AddRef(*stub);
548c2c66affSColin Finck     *chan = ifstub->chan;
549c2c66affSColin Finck     IRpcChannelBuffer_AddRef(*chan);
550c2c66affSColin Finck     *stub_apt = apt;
551c2c66affSColin Finck     *iid = ifstub->iid;
552c2c66affSColin Finck     *iface = ifstub->iface;
553c2c66affSColin Finck 
554c2c66affSColin Finck     if (manager)
555c2c66affSColin Finck         *manager = stubmgr;
556c2c66affSColin Finck     else
557c2c66affSColin Finck         stub_manager_int_release(stubmgr);
558c2c66affSColin Finck     return S_OK;
559c2c66affSColin Finck }
560c2c66affSColin Finck 
561c2c66affSColin Finck /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */
stub_manager_notify_unmarshal(struct stub_manager * m,const IPID * ipid)562c2c66affSColin Finck BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
563c2c66affSColin Finck {
564c2c66affSColin Finck     BOOL ret = TRUE;
565c2c66affSColin Finck     struct ifstub *ifstub;
566c2c66affSColin Finck 
567c2c66affSColin Finck     if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
568c2c66affSColin Finck     {
569c2c66affSColin Finck         ERR("attempted unmarshal of unknown IPID %s\n", debugstr_guid(ipid));
570c2c66affSColin Finck         return FALSE;
571c2c66affSColin Finck     }
572c2c66affSColin Finck 
573c2c66affSColin Finck     EnterCriticalSection(&m->lock);
574c2c66affSColin Finck 
575c2c66affSColin Finck     /* track normal marshals so we can enforce rules whilst in-process */
576c2c66affSColin Finck     if (ifstub->flags & MSHLFLAGS_NORMAL)
577c2c66affSColin Finck     {
578c2c66affSColin Finck         if (m->norm_refs)
579c2c66affSColin Finck             m->norm_refs--;
580c2c66affSColin Finck         else
581c2c66affSColin Finck         {
582c2c66affSColin Finck             ERR("attempted invalid normal unmarshal, norm_refs is zero\n");
583c2c66affSColin Finck             ret = FALSE;
584c2c66affSColin Finck         }
585c2c66affSColin Finck     }
586c2c66affSColin Finck 
587c2c66affSColin Finck     LeaveCriticalSection(&m->lock);
588c2c66affSColin Finck 
589c2c66affSColin Finck     return ret;
590c2c66affSColin Finck }
591c2c66affSColin Finck 
592c2c66affSColin Finck /* handles refcounting for CoReleaseMarshalData */
stub_manager_release_marshal_data(struct stub_manager * m,ULONG refs,const IPID * ipid,BOOL tableweak)593c2c66affSColin Finck void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak)
594c2c66affSColin Finck {
595c2c66affSColin Finck     struct ifstub *ifstub;
596c2c66affSColin Finck 
597c2c66affSColin Finck     if (!(ifstub = stub_manager_ipid_to_ifstub(m, ipid)))
598c2c66affSColin Finck         return;
599c2c66affSColin Finck 
600c2c66affSColin Finck     if (ifstub->flags & MSHLFLAGS_TABLEWEAK)
601c2c66affSColin Finck         refs = 0;
602c2c66affSColin Finck     else if (ifstub->flags & MSHLFLAGS_TABLESTRONG)
603c2c66affSColin Finck         refs = 1;
604c2c66affSColin Finck 
605c2c66affSColin Finck     stub_manager_ext_release(m, refs, tableweak, !tableweak);
606c2c66affSColin Finck }
607c2c66affSColin Finck 
608c2c66affSColin Finck /* is an ifstub table marshaled? */
stub_manager_is_table_marshaled(struct stub_manager * m,const IPID * ipid)609c2c66affSColin Finck BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid)
610c2c66affSColin Finck {
611c2c66affSColin Finck     struct ifstub *ifstub = stub_manager_ipid_to_ifstub(m, ipid);
612c2c66affSColin Finck 
613c2c66affSColin Finck     assert( ifstub );
614c2c66affSColin Finck 
615c2c66affSColin Finck     return ifstub->flags & (MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK);
616c2c66affSColin Finck }
617c2c66affSColin Finck 
618c2c66affSColin Finck 
619c2c66affSColin Finck /*****************************************************************************
620c2c66affSColin Finck  *
621c2c66affSColin Finck  * IRemUnknown implementation
622c2c66affSColin Finck  *
623c2c66affSColin Finck  *
624c2c66affSColin Finck  * Note: this object is not related to the lifetime of a stub_manager, but it
625c2c66affSColin Finck  * interacts with stub managers.
626c2c66affSColin Finck  */
627c2c66affSColin Finck 
628c2c66affSColin Finck typedef struct rem_unknown
629c2c66affSColin Finck {
630c2c66affSColin Finck     IRemUnknown IRemUnknown_iface;
631c2c66affSColin Finck     LONG refs;
632c2c66affSColin Finck } RemUnknown;
633c2c66affSColin Finck 
634c2c66affSColin Finck static const IRemUnknownVtbl RemUnknown_Vtbl;
635c2c66affSColin Finck 
impl_from_IRemUnknown(IRemUnknown * iface)636c2c66affSColin Finck static inline RemUnknown *impl_from_IRemUnknown(IRemUnknown *iface)
637c2c66affSColin Finck {
638c2c66affSColin Finck     return CONTAINING_RECORD(iface, RemUnknown, IRemUnknown_iface);
639c2c66affSColin Finck }
640c2c66affSColin Finck 
641c2c66affSColin Finck 
642c2c66affSColin Finck /* construct an IRemUnknown object with one outstanding reference */
RemUnknown_Construct(IRemUnknown ** ppRemUnknown)643c2c66affSColin Finck static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown)
644c2c66affSColin Finck {
645c2c66affSColin Finck     RemUnknown *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
646c2c66affSColin Finck 
647c2c66affSColin Finck     if (!This) return E_OUTOFMEMORY;
648c2c66affSColin Finck 
649c2c66affSColin Finck     This->IRemUnknown_iface.lpVtbl = &RemUnknown_Vtbl;
650c2c66affSColin Finck     This->refs = 1;
651c2c66affSColin Finck 
652c2c66affSColin Finck     *ppRemUnknown = &This->IRemUnknown_iface;
653c2c66affSColin Finck     return S_OK;
654c2c66affSColin Finck }
655c2c66affSColin Finck 
RemUnknown_QueryInterface(IRemUnknown * iface,REFIID riid,void ** ppv)656c2c66affSColin Finck static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv)
657c2c66affSColin Finck {
658c2c66affSColin Finck     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
659c2c66affSColin Finck 
660c2c66affSColin Finck     if (IsEqualIID(riid, &IID_IUnknown) ||
661c2c66affSColin Finck         IsEqualIID(riid, &IID_IRemUnknown))
662c2c66affSColin Finck     {
663c2c66affSColin Finck         *ppv = iface;
664c2c66affSColin Finck         IRemUnknown_AddRef(iface);
665c2c66affSColin Finck         return S_OK;
666c2c66affSColin Finck     }
667c2c66affSColin Finck 
668c2c66affSColin Finck     if (!IsEqualIID(riid, &IID_IExternalConnection))
669c2c66affSColin Finck         FIXME("No interface for iid %s\n", debugstr_guid(riid));
670c2c66affSColin Finck 
671c2c66affSColin Finck     *ppv = NULL;
672c2c66affSColin Finck     return E_NOINTERFACE;
673c2c66affSColin Finck }
674c2c66affSColin Finck 
RemUnknown_AddRef(IRemUnknown * iface)675c2c66affSColin Finck static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface)
676c2c66affSColin Finck {
677c2c66affSColin Finck     ULONG refs;
678c2c66affSColin Finck     RemUnknown *This = impl_from_IRemUnknown(iface);
679c2c66affSColin Finck 
680c2c66affSColin Finck     refs = InterlockedIncrement(&This->refs);
681c2c66affSColin Finck 
682c2c66affSColin Finck     TRACE("%p before: %d\n", iface, refs-1);
683c2c66affSColin Finck     return refs;
684c2c66affSColin Finck }
685c2c66affSColin Finck 
RemUnknown_Release(IRemUnknown * iface)686c2c66affSColin Finck static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface)
687c2c66affSColin Finck {
688c2c66affSColin Finck     ULONG refs;
689c2c66affSColin Finck     RemUnknown *This = impl_from_IRemUnknown(iface);
690c2c66affSColin Finck 
691c2c66affSColin Finck     refs = InterlockedDecrement(&This->refs);
692c2c66affSColin Finck     if (!refs)
693c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, This);
694c2c66affSColin Finck 
695c2c66affSColin Finck     TRACE("%p after: %d\n", iface, refs);
696c2c66affSColin Finck     return refs;
697c2c66affSColin Finck }
698c2c66affSColin Finck 
RemUnknown_RemQueryInterface(IRemUnknown * iface,REFIPID ripid,ULONG cRefs,USHORT cIids,IID * iids,REMQIRESULT ** ppQIResults)699c2c66affSColin Finck static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface,
700c2c66affSColin Finck     REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */,
701c2c66affSColin Finck     REMQIRESULT **ppQIResults /* [size_is(,cIids)] */)
702c2c66affSColin Finck {
703c2c66affSColin Finck     HRESULT hr;
704c2c66affSColin Finck     USHORT i;
705c2c66affSColin Finck     USHORT successful_qis = 0;
706c2c66affSColin Finck     APARTMENT *apt;
707c2c66affSColin Finck     struct stub_manager *stubmgr;
708*85037eb7SAmine Khaldi     struct ifstub *ifstub;
709*85037eb7SAmine Khaldi     DWORD dest_context;
710*85037eb7SAmine Khaldi     void *dest_context_data;
711c2c66affSColin Finck 
712c2c66affSColin Finck     TRACE("(%p)->(%s, %d, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults);
713c2c66affSColin Finck 
714*85037eb7SAmine Khaldi     hr = ipid_to_ifstub(ripid, &apt, &stubmgr, &ifstub);
715c2c66affSColin Finck     if (hr != S_OK) return hr;
716c2c66affSColin Finck 
717*85037eb7SAmine Khaldi     IRpcChannelBuffer_GetDestCtx(ifstub->chan, &dest_context, &dest_context_data);
718*85037eb7SAmine Khaldi 
719c2c66affSColin Finck     *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids);
720c2c66affSColin Finck 
721c2c66affSColin Finck     for (i = 0; i < cIids; i++)
722c2c66affSColin Finck     {
723c2c66affSColin Finck         HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i],
724*85037eb7SAmine Khaldi                                        stubmgr->object, dest_context, dest_context_data, MSHLFLAGS_NORMAL);
725c2c66affSColin Finck         if (hrobj == S_OK)
726c2c66affSColin Finck             successful_qis++;
727c2c66affSColin Finck         (*ppQIResults)[i].hResult = hrobj;
728c2c66affSColin Finck     }
729c2c66affSColin Finck 
730c2c66affSColin Finck     stub_manager_int_release(stubmgr);
731c2c66affSColin Finck     apartment_release(apt);
732c2c66affSColin Finck 
733c2c66affSColin Finck     if (successful_qis == cIids)
734c2c66affSColin Finck         return S_OK; /* we got all requested interfaces */
735c2c66affSColin Finck     else if (successful_qis == 0)
736c2c66affSColin Finck         return E_NOINTERFACE; /* we didn't get any interfaces */
737c2c66affSColin Finck     else
738c2c66affSColin Finck         return S_FALSE; /* we got some interfaces */
739c2c66affSColin Finck }
740c2c66affSColin Finck 
RemUnknown_RemAddRef(IRemUnknown * iface,USHORT cInterfaceRefs,REMINTERFACEREF * InterfaceRefs,HRESULT * pResults)741c2c66affSColin Finck static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface,
742c2c66affSColin Finck     USHORT cInterfaceRefs,
743c2c66affSColin Finck     REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */,
744c2c66affSColin Finck     HRESULT *pResults /* [size_is(cInterfaceRefs)] */)
745c2c66affSColin Finck {
746c2c66affSColin Finck     HRESULT hr = S_OK;
747c2c66affSColin Finck     USHORT i;
748c2c66affSColin Finck 
749c2c66affSColin Finck     TRACE("(%p)->(%d, %p, %p)\n", iface, cInterfaceRefs, InterfaceRefs, pResults);
750c2c66affSColin Finck 
751c2c66affSColin Finck     for (i = 0; i < cInterfaceRefs; i++)
752c2c66affSColin Finck     {
753c2c66affSColin Finck         APARTMENT *apt;
754c2c66affSColin Finck         struct stub_manager *stubmgr;
755c2c66affSColin Finck 
756c2c66affSColin Finck         pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
757c2c66affSColin Finck         if (pResults[i] != S_OK)
758c2c66affSColin Finck         {
759c2c66affSColin Finck             hr = S_FALSE;
760c2c66affSColin Finck             continue;
761c2c66affSColin Finck         }
762c2c66affSColin Finck 
763c2c66affSColin Finck         stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE);
764c2c66affSColin Finck         if (InterfaceRefs[i].cPrivateRefs)
765c2c66affSColin Finck             FIXME("Adding %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
766c2c66affSColin Finck 
767c2c66affSColin Finck         stub_manager_int_release(stubmgr);
768c2c66affSColin Finck         apartment_release(apt);
769c2c66affSColin Finck     }
770c2c66affSColin Finck 
771c2c66affSColin Finck     return hr;
772c2c66affSColin Finck }
773c2c66affSColin Finck 
RemUnknown_RemRelease(IRemUnknown * iface,USHORT cInterfaceRefs,REMINTERFACEREF * InterfaceRefs)774c2c66affSColin Finck static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface,
775c2c66affSColin Finck     USHORT cInterfaceRefs,
776c2c66affSColin Finck     REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */)
777c2c66affSColin Finck {
778c2c66affSColin Finck     HRESULT hr = S_OK;
779c2c66affSColin Finck     USHORT i;
780c2c66affSColin Finck 
781c2c66affSColin Finck     TRACE("(%p)->(%d, %p)\n", iface, cInterfaceRefs, InterfaceRefs);
782c2c66affSColin Finck 
783c2c66affSColin Finck     for (i = 0; i < cInterfaceRefs; i++)
784c2c66affSColin Finck     {
785c2c66affSColin Finck         APARTMENT *apt;
786c2c66affSColin Finck         struct stub_manager *stubmgr;
787c2c66affSColin Finck 
788c2c66affSColin Finck         hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr);
789c2c66affSColin Finck         if (hr != S_OK)
790c2c66affSColin Finck         {
791c2c66affSColin Finck             hr = E_INVALIDARG;
792c2c66affSColin Finck             /* FIXME: we should undo any changes already made in this function */
793c2c66affSColin Finck             break;
794c2c66affSColin Finck         }
795c2c66affSColin Finck 
796c2c66affSColin Finck         stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE);
797c2c66affSColin Finck         if (InterfaceRefs[i].cPrivateRefs)
798c2c66affSColin Finck             FIXME("Releasing %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
799c2c66affSColin Finck 
800c2c66affSColin Finck         stub_manager_int_release(stubmgr);
801c2c66affSColin Finck         apartment_release(apt);
802c2c66affSColin Finck     }
803c2c66affSColin Finck 
804c2c66affSColin Finck     return hr;
805c2c66affSColin Finck }
806c2c66affSColin Finck 
807c2c66affSColin Finck static const IRemUnknownVtbl RemUnknown_Vtbl =
808c2c66affSColin Finck {
809c2c66affSColin Finck     RemUnknown_QueryInterface,
810c2c66affSColin Finck     RemUnknown_AddRef,
811c2c66affSColin Finck     RemUnknown_Release,
812c2c66affSColin Finck     RemUnknown_RemQueryInterface,
813c2c66affSColin Finck     RemUnknown_RemAddRef,
814c2c66affSColin Finck     RemUnknown_RemRelease
815c2c66affSColin Finck };
816c2c66affSColin Finck 
817c2c66affSColin Finck /* starts the IRemUnknown listener for the current apartment */
start_apartment_remote_unknown(APARTMENT * apt)818*85037eb7SAmine Khaldi HRESULT start_apartment_remote_unknown(APARTMENT *apt)
819c2c66affSColin Finck {
820c2c66affSColin Finck     IRemUnknown *pRemUnknown;
821c2c66affSColin Finck     HRESULT hr = S_OK;
822c2c66affSColin Finck 
823c2c66affSColin Finck     EnterCriticalSection(&apt->cs);
824c2c66affSColin Finck     if (!apt->remunk_exported)
825c2c66affSColin Finck     {
826c2c66affSColin Finck         /* create the IRemUnknown object */
827c2c66affSColin Finck         hr = RemUnknown_Construct(&pRemUnknown);
828c2c66affSColin Finck         if (hr == S_OK)
829c2c66affSColin Finck         {
830c2c66affSColin Finck             STDOBJREF stdobjref; /* dummy - not used */
831c2c66affSColin Finck             /* register it with the stub manager */
832c2c66affSColin Finck             hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHCTX_DIFFERENTMACHINE, NULL, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN);
833c2c66affSColin Finck             /* release our reference to the object as the stub manager will manage the life cycle for us */
834c2c66affSColin Finck             IRemUnknown_Release(pRemUnknown);
835c2c66affSColin Finck             if (hr == S_OK)
836c2c66affSColin Finck                 apt->remunk_exported = TRUE;
837c2c66affSColin Finck         }
838c2c66affSColin Finck     }
839c2c66affSColin Finck     LeaveCriticalSection(&apt->cs);
840c2c66affSColin Finck     return hr;
841c2c66affSColin Finck }
842