ole32: Don't pass incorrect iface pointer to StdMarshalImpl functions.
[wine.git] / dlls / ole32 / ftmarshal.c
blob3eb7f877aa5a6f2106bd28028de92a6b7c3ec1f6
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_inner;
43 IMarshal IMarshal_iface;
44 IUnknown *outer_unk;
45 LONG ref;
46 } FTMarshalImpl;
48 static inline FTMarshalImpl *impl_from_IUnknown(IUnknown *iface)
50 return CONTAINING_RECORD(iface, FTMarshalImpl, IUnknown_inner);
53 static inline FTMarshalImpl *impl_from_IMarshal( IMarshal *iface )
55 return CONTAINING_RECORD(iface, FTMarshalImpl, IMarshal_iface);
58 /* inner IUnknown to handle aggregation */
59 static HRESULT WINAPI
60 IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv)
63 FTMarshalImpl *This = impl_from_IUnknown(iface);
65 TRACE ("\n");
66 *ppv = NULL;
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;
76 IUnknown_AddRef ((IUnknown *) * ppv);
77 return S_OK;
80 static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface)
83 FTMarshalImpl *This = impl_from_IUnknown(iface);
85 TRACE ("\n");
86 return InterlockedIncrement (&This->ref);
89 static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface)
92 FTMarshalImpl *This = impl_from_IUnknown(iface);
94 TRACE ("\n");
95 if (InterlockedDecrement (&This->ref))
96 return This->ref;
97 HeapFree (GetProcessHeap (), 0, This);
98 return 0;
101 static const IUnknownVtbl iunkvt =
103 IiFTMUnknown_fnQueryInterface,
104 IiFTMUnknown_fnAddRef,
105 IiFTMUnknown_fnRelease
108 static HRESULT WINAPI
109 FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv)
112 FTMarshalImpl *This = impl_from_IMarshal(iface);
114 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv);
115 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
118 static ULONG WINAPI
119 FTMarshalImpl_AddRef (LPMARSHAL iface)
122 FTMarshalImpl *This = impl_from_IMarshal(iface);
124 TRACE ("\n");
125 return IUnknown_AddRef(This->outer_unk);
128 static ULONG WINAPI
129 FTMarshalImpl_Release (LPMARSHAL iface)
132 FTMarshalImpl *This = impl_from_IMarshal(iface);
134 TRACE ("\n");
135 return IUnknown_Release(This->outer_unk);
138 static HRESULT WINAPI
139 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
140 void *pvDestContext, DWORD mshlflags, CLSID * pCid)
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;
151 static HRESULT WINAPI
152 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
153 void *pvDestContext, DWORD mshlflags, DWORD * pSize)
156 IMarshal *pMarshal = NULL;
157 HRESULT hres;
159 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
160 dwDestContext, pvDestContext, mshlflags, pSize);
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;
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;
176 static HRESULT WINAPI
177 FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv,
178 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
181 IMarshal *pMarshal = NULL;
182 HRESULT hres;
184 TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm, debugstr_guid(riid), pv,
185 dwDestContext, pvDestContext, mshlflags);
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 };
194 hres = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
195 if (FAILED(hres))
196 return hres;
198 /* don't hold a reference to table-weak marshaled interfaces */
199 if (mshlflags & MSHLFLAGS_TABLEWEAK)
200 IUnknown_Release((IUnknown *)object);
202 hres = IStream_Write (pStm, &mshlflags, sizeof (mshlflags), NULL);
203 if (hres != S_OK) return STG_E_MEDIUMFULL;
205 hres = IStream_Write (pStm, &object, sizeof (object), NULL);
206 if (hres != S_OK) return STG_E_MEDIUMFULL;
208 if (sizeof(object) == sizeof(DWORD))
210 hres = IStream_Write (pStm, &constant, sizeof (constant), NULL);
211 if (hres != S_OK) return STG_E_MEDIUMFULL;
214 hres = IStream_Write (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
215 if (hres != S_OK) return STG_E_MEDIUMFULL;
217 return S_OK;
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;
227 static HRESULT WINAPI
228 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv)
230 DWORD mshlflags;
231 IUnknown *object;
232 DWORD constant;
233 GUID unknown_guid;
234 HRESULT hres;
236 TRACE ("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
238 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
239 if (hres != S_OK) return STG_E_READFAULT;
241 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
242 if (hres != S_OK) return STG_E_READFAULT;
244 if (sizeof(object) == sizeof(DWORD))
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);
252 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
253 if (hres != S_OK) return STG_E_READFAULT;
255 hres = IUnknown_QueryInterface(object, riid, ppv);
256 if (!(mshlflags & (MSHLFLAGS_TABLEWEAK|MSHLFLAGS_TABLESTRONG)))
257 IUnknown_Release(object);
258 return hres;
261 static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm)
263 DWORD mshlflags;
264 IUnknown *object;
265 DWORD constant;
266 GUID unknown_guid;
267 HRESULT hres;
269 TRACE ("(%p)\n", pStm);
271 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
272 if (hres != S_OK) return STG_E_READFAULT;
274 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
275 if (hres != S_OK) return STG_E_READFAULT;
277 if (sizeof(object) == sizeof(DWORD))
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);
285 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
286 if (hres != S_OK) return STG_E_READFAULT;
288 IUnknown_Release(object);
289 return S_OK;
292 static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved)
294 TRACE ("()\n");
295 /* nothing to do */
296 return S_OK;
299 static const IMarshalVtbl ftmvtbl =
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
312 /***********************************************************************
313 * CoCreateFreeThreadedMarshaler [OLE32.@]
315 * Creates a free-threaded marshaler.
317 * PARAMS
318 * punkOuter [I] Optional. Outer unknown.
319 * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
321 * RETURNS
322 * Success: S_OK
323 * Failure: E_OUTOFMEMORY if no memory available to create object.
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.
333 HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal)
336 FTMarshalImpl *ftm;
338 TRACE ("(%p %p)\n", punkOuter, ppunkMarshal);
340 ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl));
341 if (!ftm)
342 return E_OUTOFMEMORY;
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;
349 *ppunkMarshal = &ftm->IUnknown_inner;
350 return S_OK;
353 static HRESULT WINAPI FTMarshalCF_QueryInterface(LPCLASSFACTORY iface,
354 REFIID riid, LPVOID *ppv)
356 *ppv = NULL;
357 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
359 *ppv = iface;
360 IClassFactory_AddRef(iface);
361 return S_OK;
363 return E_NOINTERFACE;
366 static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface)
368 return 2; /* non-heap based object */
371 static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface)
373 return 1; /* non-heap based object */
376 static HRESULT WINAPI FTMarshalCF_CreateInstance(LPCLASSFACTORY iface,
377 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
379 IUnknown *pUnknown;
380 HRESULT hr;
382 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
384 *ppv = NULL;
386 hr = CoCreateFreeThreadedMarshaler(pUnk, &pUnknown);
388 if (SUCCEEDED(hr))
390 hr = IUnknown_QueryInterface(pUnknown, riid, ppv);
391 IUnknown_Release(pUnknown);
394 return hr;
397 static HRESULT WINAPI FTMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
399 FIXME("(%d), stub!\n",fLock);
400 return S_OK;
403 static const IClassFactoryVtbl FTMarshalCFVtbl =
405 FTMarshalCF_QueryInterface,
406 FTMarshalCF_AddRef,
407 FTMarshalCF_Release,
408 FTMarshalCF_CreateInstance,
409 FTMarshalCF_LockServer
411 static const IClassFactoryVtbl *FTMarshalCF = &FTMarshalCFVtbl;
413 HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv)
415 return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv);