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