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