ole32: COM cleanup in classmoniker.c.
[wine] / dlls / ole32 / ftmarshal.c
1 /*
2  *      free threaded marshaller
3  *
4  *  Copyright 2002  Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "objbase.h"
34
35 #include "wine/debug.h"
36
37 #include "compobj_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40
41 typedef struct _FTMarshalImpl {
42         IUnknown IUnknown_iface;
43         LONG ref;
44         IMarshal IMarshal_iface;
45
46         IUnknown *pUnkOuter;
47 } FTMarshalImpl;
48
49 static inline FTMarshalImpl *impl_from_IUnknown(IUnknown *iface)
50 {
51     return CONTAINING_RECORD(iface, FTMarshalImpl, IUnknown_iface);
52 }
53
54 static inline FTMarshalImpl *impl_from_IMarshal( IMarshal *iface )
55 {
56     return CONTAINING_RECORD(iface, FTMarshalImpl, IMarshal_iface);
57 }
58
59 /* inner IUnknown to handle aggregation */
60 static HRESULT WINAPI
61 IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv)
62 {
63
64     FTMarshalImpl *This = impl_from_IUnknown(iface);
65
66     TRACE ("\n");
67     *ppv = NULL;
68
69     if (IsEqualIID (&IID_IUnknown, riid))
70         *ppv = &This->IUnknown_iface;
71     else if (IsEqualIID (&IID_IMarshal, riid))
72         *ppv = &This->IMarshal_iface;
73     else {
74         FIXME ("No interface for %s.\n", debugstr_guid (riid));
75         return E_NOINTERFACE;
76     }
77     IUnknown_AddRef ((IUnknown *) * ppv);
78     return S_OK;
79 }
80
81 static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface)
82 {
83
84     FTMarshalImpl *This = impl_from_IUnknown(iface);
85
86     TRACE ("\n");
87     return InterlockedIncrement (&This->ref);
88 }
89
90 static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface)
91 {
92
93     FTMarshalImpl *This = impl_from_IUnknown(iface);
94
95     TRACE ("\n");
96     if (InterlockedDecrement (&This->ref))
97         return This->ref;
98     HeapFree (GetProcessHeap (), 0, This);
99     return 0;
100 }
101
102 static const IUnknownVtbl iunkvt =
103 {
104         IiFTMUnknown_fnQueryInterface,
105         IiFTMUnknown_fnAddRef,
106         IiFTMUnknown_fnRelease
107 };
108
109 static HRESULT WINAPI
110 FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv)
111 {
112
113     FTMarshalImpl *This = impl_from_IMarshal(iface);
114
115     TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv);
116     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv);
117 }
118
119 static ULONG WINAPI
120 FTMarshalImpl_AddRef (LPMARSHAL iface)
121 {
122
123     FTMarshalImpl *This = impl_from_IMarshal(iface);
124
125     TRACE ("\n");
126     return IUnknown_AddRef (This->pUnkOuter);
127 }
128
129 static ULONG WINAPI
130 FTMarshalImpl_Release (LPMARSHAL iface)
131 {
132
133     FTMarshalImpl *This = impl_from_IMarshal(iface);
134
135     TRACE ("\n");
136     return IUnknown_Release (This->pUnkOuter);
137 }
138
139 static HRESULT WINAPI
140 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
141                                                 void *pvDestContext, DWORD mshlflags, CLSID * pCid)
142 {
143     TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
144         dwDestContext, pvDestContext, mshlflags, pCid);
145     if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX)
146         *pCid = CLSID_InProcFreeMarshaler;
147     else
148         *pCid = CLSID_DfMarshal;
149     return S_OK;
150 }
151
152 static HRESULT WINAPI
153 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
154                                                 void *pvDestContext, DWORD mshlflags, DWORD * pSize)
155 {
156
157     IMarshal *pMarshal = NULL;
158     HRESULT hres;
159
160     TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
161         dwDestContext, pvDestContext, mshlflags, pSize);
162
163     /* if the marshalling happens inside the same process the interface pointer is
164        copied between the apartments */
165     if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) {
166         *pSize = sizeof (mshlflags) + sizeof (pv) + sizeof (DWORD) + sizeof (GUID);
167         return S_OK;
168     }
169
170     /* use the standard marshaller to handle all other cases */
171     CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal);
172     hres = IMarshal_GetMarshalSizeMax (pMarshal, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize);
173     IMarshal_Release (pMarshal);
174     return hres;
175 }
176
177 static HRESULT WINAPI
178 FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv,
179                                DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
180 {
181
182     IMarshal *pMarshal = NULL;
183     HRESULT hres;
184
185     TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm, debugstr_guid(riid), pv,
186         dwDestContext, pvDestContext, mshlflags);
187
188     /* if the marshalling happens inside the same process the interface pointer is
189        copied between the apartments */
190     if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) {
191         void *object;
192         DWORD constant = 0;
193         GUID unknown_guid = { 0 };
194
195         hres = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
196         if (FAILED(hres))
197             return hres;
198
199         /* don't hold a reference to table-weak marshaled interfaces */
200         if (mshlflags & MSHLFLAGS_TABLEWEAK)
201             IUnknown_Release((IUnknown *)object);
202
203         hres = IStream_Write (pStm, &mshlflags, sizeof (mshlflags), NULL);
204         if (hres != S_OK) return STG_E_MEDIUMFULL;
205
206         hres = IStream_Write (pStm, &object, sizeof (object), NULL);
207         if (hres != S_OK) return STG_E_MEDIUMFULL;
208
209         if (sizeof(object) == sizeof(DWORD))
210         {
211             hres = IStream_Write (pStm, &constant, sizeof (constant), NULL);
212             if (hres != S_OK) return STG_E_MEDIUMFULL;
213         }
214
215         hres = IStream_Write (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
216         if (hres != S_OK) return STG_E_MEDIUMFULL;
217
218         return S_OK;
219     }
220
221     /* use the standard marshaler to handle all other cases */
222     CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal);
223     hres = IMarshal_MarshalInterface (pMarshal, pStm, riid, pv, dwDestContext, pvDestContext, mshlflags);
224     IMarshal_Release (pMarshal);
225     return hres;
226 }
227
228 static HRESULT WINAPI
229 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv)
230 {
231     DWORD mshlflags;
232     IUnknown *object;
233     DWORD constant;
234     GUID unknown_guid;
235     HRESULT hres;
236
237     TRACE ("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
238
239     hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
240     if (hres != S_OK) return STG_E_READFAULT;
241
242     hres = IStream_Read (pStm, &object, sizeof (object), NULL);
243     if (hres != S_OK) return STG_E_READFAULT;
244
245     if (sizeof(object) == sizeof(DWORD))
246     {
247         hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
248         if (hres != S_OK) return STG_E_READFAULT;
249         if (constant != 0)
250             FIXME("constant is 0x%x instead of 0\n", constant);
251     }
252
253     hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
254     if (hres != S_OK) return STG_E_READFAULT;
255
256     hres = IUnknown_QueryInterface(object, riid, ppv);
257     if (!(mshlflags & (MSHLFLAGS_TABLEWEAK|MSHLFLAGS_TABLESTRONG)))
258         IUnknown_Release(object);
259     return hres;
260 }
261
262 static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm)
263 {
264     DWORD mshlflags;
265     IUnknown *object;
266     DWORD constant;
267     GUID unknown_guid;
268     HRESULT hres;
269
270     TRACE ("(%p)\n", pStm);
271
272     hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
273     if (hres != S_OK) return STG_E_READFAULT;
274
275     hres = IStream_Read (pStm, &object, sizeof (object), NULL);
276     if (hres != S_OK) return STG_E_READFAULT;
277
278     if (sizeof(object) == sizeof(DWORD))
279     {
280         hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
281         if (hres != S_OK) return STG_E_READFAULT;
282         if (constant != 0)
283             FIXME("constant is 0x%x instead of 0\n", constant);
284     }
285
286     hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
287     if (hres != S_OK) return STG_E_READFAULT;
288
289     IUnknown_Release(object);
290     return S_OK;
291 }
292
293 static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved)
294 {
295     TRACE ("()\n");
296     /* nothing to do */
297     return S_OK;
298 }
299
300 static const IMarshalVtbl ftmvtbl =
301 {
302         FTMarshalImpl_QueryInterface,
303         FTMarshalImpl_AddRef,
304         FTMarshalImpl_Release,
305         FTMarshalImpl_GetUnmarshalClass,
306         FTMarshalImpl_GetMarshalSizeMax,
307         FTMarshalImpl_MarshalInterface,
308         FTMarshalImpl_UnmarshalInterface,
309         FTMarshalImpl_ReleaseMarshalData,
310         FTMarshalImpl_DisconnectObject
311 };
312
313 /***********************************************************************
314  *          CoCreateFreeThreadedMarshaler [OLE32.@]
315  *
316  * Creates a free-threaded marshaler.
317  *
318  * PARAMS
319  *  punkOuter    [I] Optional. Outer unknown.
320  *  ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
321  *
322  * RETURNS
323  *  Success: S_OK
324  *  Failure: E_OUTOFMEMORY if no memory available to create object.
325  *
326  * NOTES
327  *  Objects that ensure their state is maintained consistent when used by
328  *  multiple threads and reference no single-threaded objects are known as
329  *  free-threaded. The free-threaded marshaler enables these objects to be
330  *  efficiently marshaled within the same process, by not creating proxies
331  *  (as they aren't needed for the object to be safely used), whilst still
332  *  allowing the object to be used in inter-process and inter-machine contexts.
333  */
334 HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal)
335 {
336
337     FTMarshalImpl *ftm;
338
339     TRACE ("(%p %p)\n", punkOuter, ppunkMarshal);
340
341     ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl));
342     if (!ftm)
343         return E_OUTOFMEMORY;
344
345     ftm->IUnknown_iface.lpVtbl = &iunkvt;
346     ftm->IMarshal_iface.lpVtbl = &ftmvtbl;
347     ftm->ref = 1;
348     ftm->pUnkOuter = punkOuter ? punkOuter : &ftm->IUnknown_iface;
349
350     *ppunkMarshal = &ftm->IUnknown_iface;
351     return S_OK;
352 }
353
354 static HRESULT WINAPI FTMarshalCF_QueryInterface(LPCLASSFACTORY iface,
355                                                   REFIID riid, LPVOID *ppv)
356 {
357     *ppv = NULL;
358     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
359     {
360         *ppv = iface;
361         IUnknown_AddRef(iface);
362         return S_OK;
363     }
364     return E_NOINTERFACE;
365 }
366
367 static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface)
368 {
369     return 2; /* non-heap based object */
370 }
371
372 static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface)
373 {
374     return 1; /* non-heap based object */
375 }
376
377 static HRESULT WINAPI FTMarshalCF_CreateInstance(LPCLASSFACTORY iface,
378     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
379 {
380     IUnknown *pUnknown;
381     HRESULT  hr;
382
383     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
384
385     *ppv = NULL;
386
387     hr = CoCreateFreeThreadedMarshaler(pUnk, &pUnknown);
388
389     if (SUCCEEDED(hr))
390     {
391         hr = IUnknown_QueryInterface(pUnknown, riid, ppv);
392         IUnknown_Release(pUnknown);
393     }
394
395     return hr;
396 }
397
398 static HRESULT WINAPI FTMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
399 {
400     FIXME("(%d), stub!\n",fLock);
401     return S_OK;
402 }
403
404 static const IClassFactoryVtbl FTMarshalCFVtbl =
405 {
406     FTMarshalCF_QueryInterface,
407     FTMarshalCF_AddRef,
408     FTMarshalCF_Release,
409     FTMarshalCF_CreateInstance,
410     FTMarshalCF_LockServer
411 };
412 static const IClassFactoryVtbl *FTMarshalCF = &FTMarshalCFVtbl;
413
414 HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv)
415 {
416     return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv);
417 }