3eb7f877aa5a6f2106bd28028de92a6b7c3ec1f6
[reactos.git] / dll / win32 / 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_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_DfMarshal;
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 }