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