ntdll/tests: Extend the FILE_APPEND_DATA test.
[wine.git] / dlls / ole32 / ftmarshal.c
blob21d9c9ab0595d202ae8f5c897535a97cf9178dba
1 /*
2 * free threaded marshaller
4 * Copyright 2002 Juergen Schmied
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.
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.
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
29 #define COBJMACROS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "objbase.h"
35 #include "wine/debug.h"
37 #include "compobj_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41 typedef struct _FTMarshalImpl {
42 IUnknown IUnknown_iface;
43 LONG ref;
44 IMarshal IMarshal_iface;
46 IUnknown *pUnkOuter;
47 } FTMarshalImpl;
49 static inline FTMarshalImpl *impl_from_IUnknown(IUnknown *iface)
51 return CONTAINING_RECORD(iface, FTMarshalImpl, IUnknown_iface);
54 static inline FTMarshalImpl *impl_from_IMarshal( IMarshal *iface )
56 return CONTAINING_RECORD(iface, FTMarshalImpl, IMarshal_iface);
59 /* inner IUnknown to handle aggregation */
60 static HRESULT WINAPI
61 IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv)
64 FTMarshalImpl *This = impl_from_IUnknown(iface);
66 TRACE ("\n");
67 *ppv = NULL;
69 if (IsEqualIID (&IID_IUnknown, riid))
70 *ppv = &This->IUnknown_iface;
71 else if (IsEqualIID (&IID_IMarshal, riid))
72 *ppv = &This->IMarshal_iface;
73 else {
74 FIXME ("No interface for %s.\n", debugstr_guid (riid));
75 return E_NOINTERFACE;
77 IUnknown_AddRef ((IUnknown *) * ppv);
78 return S_OK;
81 static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface)
84 FTMarshalImpl *This = impl_from_IUnknown(iface);
86 TRACE ("\n");
87 return InterlockedIncrement (&This->ref);
90 static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface)
93 FTMarshalImpl *This = impl_from_IUnknown(iface);
95 TRACE ("\n");
96 if (InterlockedDecrement (&This->ref))
97 return This->ref;
98 HeapFree (GetProcessHeap (), 0, This);
99 return 0;
102 static const IUnknownVtbl iunkvt =
104 IiFTMUnknown_fnQueryInterface,
105 IiFTMUnknown_fnAddRef,
106 IiFTMUnknown_fnRelease
109 static HRESULT WINAPI
110 FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv)
113 FTMarshalImpl *This = impl_from_IMarshal(iface);
115 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv);
116 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv);
119 static ULONG WINAPI
120 FTMarshalImpl_AddRef (LPMARSHAL iface)
123 FTMarshalImpl *This = impl_from_IMarshal(iface);
125 TRACE ("\n");
126 return IUnknown_AddRef (This->pUnkOuter);
129 static ULONG WINAPI
130 FTMarshalImpl_Release (LPMARSHAL iface)
133 FTMarshalImpl *This = impl_from_IMarshal(iface);
135 TRACE ("\n");
136 return IUnknown_Release (This->pUnkOuter);
139 static HRESULT WINAPI
140 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
141 void *pvDestContext, DWORD mshlflags, CLSID * pCid)
143 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
144 dwDestContext, pvDestContext, mshlflags, pCid);
145 if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX)
146 *pCid = CLSID_InProcFreeMarshaler;
147 else
148 *pCid = CLSID_DfMarshal;
149 return S_OK;
152 static HRESULT WINAPI
153 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
154 void *pvDestContext, DWORD mshlflags, DWORD * pSize)
157 IMarshal *pMarshal = NULL;
158 HRESULT hres;
160 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
161 dwDestContext, pvDestContext, mshlflags, pSize);
163 /* if the marshalling happens inside the same process the interface pointer is
164 copied between the apartments */
165 if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) {
166 *pSize = sizeof (mshlflags) + sizeof (pv) + sizeof (DWORD) + sizeof (GUID);
167 return S_OK;
170 /* use the standard marshaller to handle all other cases */
171 CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal);
172 hres = IMarshal_GetMarshalSizeMax (pMarshal, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize);
173 IMarshal_Release (pMarshal);
174 return hres;
177 static HRESULT WINAPI
178 FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv,
179 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
182 IMarshal *pMarshal = NULL;
183 HRESULT hres;
185 TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm, debugstr_guid(riid), pv,
186 dwDestContext, pvDestContext, mshlflags);
188 /* if the marshalling happens inside the same process the interface pointer is
189 copied between the apartments */
190 if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) {
191 void *object;
192 DWORD constant = 0;
193 GUID unknown_guid = { 0 };
195 hres = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
196 if (FAILED(hres))
197 return hres;
199 /* don't hold a reference to table-weak marshaled interfaces */
200 if (mshlflags & MSHLFLAGS_TABLEWEAK)
201 IUnknown_Release((IUnknown *)object);
203 hres = IStream_Write (pStm, &mshlflags, sizeof (mshlflags), NULL);
204 if (hres != S_OK) return STG_E_MEDIUMFULL;
206 hres = IStream_Write (pStm, &object, sizeof (object), NULL);
207 if (hres != S_OK) return STG_E_MEDIUMFULL;
209 if (sizeof(object) == sizeof(DWORD))
211 hres = IStream_Write (pStm, &constant, sizeof (constant), NULL);
212 if (hres != S_OK) return STG_E_MEDIUMFULL;
215 hres = IStream_Write (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
216 if (hres != S_OK) return STG_E_MEDIUMFULL;
218 return S_OK;
221 /* use the standard marshaler to handle all other cases */
222 CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal);
223 hres = IMarshal_MarshalInterface (pMarshal, pStm, riid, pv, dwDestContext, pvDestContext, mshlflags);
224 IMarshal_Release (pMarshal);
225 return hres;
228 static HRESULT WINAPI
229 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv)
231 DWORD mshlflags;
232 IUnknown *object;
233 DWORD constant;
234 GUID unknown_guid;
235 HRESULT hres;
237 TRACE ("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
239 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
240 if (hres != S_OK) return STG_E_READFAULT;
242 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
243 if (hres != S_OK) return STG_E_READFAULT;
245 if (sizeof(object) == sizeof(DWORD))
247 hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
248 if (hres != S_OK) return STG_E_READFAULT;
249 if (constant != 0)
250 FIXME("constant is 0x%x instead of 0\n", constant);
253 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
254 if (hres != S_OK) return STG_E_READFAULT;
256 hres = IUnknown_QueryInterface(object, riid, ppv);
257 if (!(mshlflags & (MSHLFLAGS_TABLEWEAK|MSHLFLAGS_TABLESTRONG)))
258 IUnknown_Release(object);
259 return hres;
262 static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm)
264 DWORD mshlflags;
265 IUnknown *object;
266 DWORD constant;
267 GUID unknown_guid;
268 HRESULT hres;
270 TRACE ("(%p)\n", pStm);
272 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
273 if (hres != S_OK) return STG_E_READFAULT;
275 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
276 if (hres != S_OK) return STG_E_READFAULT;
278 if (sizeof(object) == sizeof(DWORD))
280 hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
281 if (hres != S_OK) return STG_E_READFAULT;
282 if (constant != 0)
283 FIXME("constant is 0x%x instead of 0\n", constant);
286 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
287 if (hres != S_OK) return STG_E_READFAULT;
289 IUnknown_Release(object);
290 return S_OK;
293 static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved)
295 TRACE ("()\n");
296 /* nothing to do */
297 return S_OK;
300 static const IMarshalVtbl ftmvtbl =
302 FTMarshalImpl_QueryInterface,
303 FTMarshalImpl_AddRef,
304 FTMarshalImpl_Release,
305 FTMarshalImpl_GetUnmarshalClass,
306 FTMarshalImpl_GetMarshalSizeMax,
307 FTMarshalImpl_MarshalInterface,
308 FTMarshalImpl_UnmarshalInterface,
309 FTMarshalImpl_ReleaseMarshalData,
310 FTMarshalImpl_DisconnectObject
313 /***********************************************************************
314 * CoCreateFreeThreadedMarshaler [OLE32.@]
316 * Creates a free-threaded marshaler.
318 * PARAMS
319 * punkOuter [I] Optional. Outer unknown.
320 * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
322 * RETURNS
323 * Success: S_OK
324 * Failure: E_OUTOFMEMORY if no memory available to create object.
326 * NOTES
327 * Objects that ensure their state is maintained consistent when used by
328 * multiple threads and reference no single-threaded objects are known as
329 * free-threaded. The free-threaded marshaler enables these objects to be
330 * efficiently marshaled within the same process, by not creating proxies
331 * (as they aren't needed for the object to be safely used), whilst still
332 * allowing the object to be used in inter-process and inter-machine contexts.
334 HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal)
337 FTMarshalImpl *ftm;
339 TRACE ("(%p %p)\n", punkOuter, ppunkMarshal);
341 ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl));
342 if (!ftm)
343 return E_OUTOFMEMORY;
345 ftm->IUnknown_iface.lpVtbl = &iunkvt;
346 ftm->IMarshal_iface.lpVtbl = &ftmvtbl;
347 ftm->ref = 1;
348 ftm->pUnkOuter = punkOuter ? punkOuter : &ftm->IUnknown_iface;
350 *ppunkMarshal = &ftm->IUnknown_iface;
351 return S_OK;
354 static HRESULT WINAPI FTMarshalCF_QueryInterface(LPCLASSFACTORY iface,
355 REFIID riid, LPVOID *ppv)
357 *ppv = NULL;
358 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
360 *ppv = iface;
361 IClassFactory_AddRef(iface);
362 return S_OK;
364 return E_NOINTERFACE;
367 static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface)
369 return 2; /* non-heap based object */
372 static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface)
374 return 1; /* non-heap based object */
377 static HRESULT WINAPI FTMarshalCF_CreateInstance(LPCLASSFACTORY iface,
378 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
380 IUnknown *pUnknown;
381 HRESULT hr;
383 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
385 *ppv = NULL;
387 hr = CoCreateFreeThreadedMarshaler(pUnk, &pUnknown);
389 if (SUCCEEDED(hr))
391 hr = IUnknown_QueryInterface(pUnknown, riid, ppv);
392 IUnknown_Release(pUnknown);
395 return hr;
398 static HRESULT WINAPI FTMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
400 FIXME("(%d), stub!\n",fLock);
401 return S_OK;
404 static const IClassFactoryVtbl FTMarshalCFVtbl =
406 FTMarshalCF_QueryInterface,
407 FTMarshalCF_AddRef,
408 FTMarshalCF_Release,
409 FTMarshalCF_CreateInstance,
410 FTMarshalCF_LockServer
412 static const IClassFactoryVtbl *FTMarshalCF = &FTMarshalCFVtbl;
414 HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv)
416 return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv);