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