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