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
33 #include "wine/debug.h"
35 #include "compobj_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
39 typedef struct _FTMarshalImpl
{
40 IUnknown IUnknown_inner
;
41 IMarshal IMarshal_iface
;
46 static inline FTMarshalImpl
*impl_from_IUnknown(IUnknown
*iface
)
48 return CONTAINING_RECORD(iface
, FTMarshalImpl
, IUnknown_inner
);
51 static inline FTMarshalImpl
*impl_from_IMarshal( IMarshal
*iface
)
53 return CONTAINING_RECORD(iface
, FTMarshalImpl
, IMarshal_iface
);
56 /* inner IUnknown to handle aggregation */
58 IiFTMUnknown_fnQueryInterface (IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
61 FTMarshalImpl
*This
= impl_from_IUnknown(iface
);
66 if (IsEqualIID (&IID_IUnknown
, riid
))
67 *ppv
= &This
->IUnknown_inner
;
68 else if (IsEqualIID (&IID_IMarshal
, riid
))
69 *ppv
= &This
->IMarshal_iface
;
71 FIXME ("No interface for %s.\n", debugstr_guid (riid
));
74 IUnknown_AddRef ((IUnknown
*) * ppv
);
78 static ULONG WINAPI
IiFTMUnknown_fnAddRef (IUnknown
* iface
)
81 FTMarshalImpl
*This
= impl_from_IUnknown(iface
);
84 return InterlockedIncrement (&This
->ref
);
87 static ULONG WINAPI
IiFTMUnknown_fnRelease (IUnknown
* iface
)
90 FTMarshalImpl
*This
= impl_from_IUnknown(iface
);
93 if (InterlockedDecrement (&This
->ref
))
95 HeapFree (GetProcessHeap (), 0, This
);
99 static const IUnknownVtbl iunkvt
=
101 IiFTMUnknown_fnQueryInterface
,
102 IiFTMUnknown_fnAddRef
,
103 IiFTMUnknown_fnRelease
106 static HRESULT WINAPI
107 FTMarshalImpl_QueryInterface (LPMARSHAL iface
, REFIID riid
, LPVOID
* ppv
)
110 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
112 TRACE ("(%p)->(%s,%p)\n", This
, debugstr_guid (riid
), ppv
);
113 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
117 FTMarshalImpl_AddRef (LPMARSHAL iface
)
120 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
123 return IUnknown_AddRef(This
->outer_unk
);
127 FTMarshalImpl_Release (LPMARSHAL iface
)
130 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
133 return IUnknown_Release(This
->outer_unk
);
136 static HRESULT WINAPI
137 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface
, REFIID riid
, void *pv
, DWORD dwDestContext
,
138 void *pvDestContext
, DWORD mshlflags
, CLSID
* pCid
)
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
;
145 *pCid
= CLSID_StdMarshal
;
149 static HRESULT WINAPI
150 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface
, REFIID riid
, void *pv
, DWORD dwDestContext
,
151 void *pvDestContext
, DWORD mshlflags
, DWORD
* pSize
)
154 IMarshal
*pMarshal
= NULL
;
157 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid
), pv
,
158 dwDestContext
, pvDestContext
, mshlflags
, pSize
);
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
);
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
);
174 static HRESULT WINAPI
175 FTMarshalImpl_MarshalInterface (LPMARSHAL iface
, IStream
* pStm
, REFIID riid
, void *pv
,
176 DWORD dwDestContext
, void *pvDestContext
, DWORD mshlflags
)
179 IMarshal
*pMarshal
= NULL
;
182 TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm
, debugstr_guid(riid
), pv
,
183 dwDestContext
, pvDestContext
, mshlflags
);
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
) {
190 GUID unknown_guid
= { 0 };
192 hres
= IUnknown_QueryInterface((IUnknown
*)pv
, riid
, &object
);
196 /* don't hold a reference to table-weak marshaled interfaces */
197 if (mshlflags
& MSHLFLAGS_TABLEWEAK
)
198 IUnknown_Release((IUnknown
*)object
);
200 hres
= IStream_Write (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
201 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
203 hres
= IStream_Write (pStm
, &object
, sizeof (object
), NULL
);
204 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
206 if (sizeof(object
) == sizeof(DWORD
))
208 hres
= IStream_Write (pStm
, &constant
, sizeof (constant
), NULL
);
209 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
212 hres
= IStream_Write (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
213 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
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
);
225 static HRESULT WINAPI
226 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface
, IStream
* pStm
, REFIID riid
, void **ppv
)
234 TRACE ("(%p, %s, %p)\n", pStm
, debugstr_guid(riid
), ppv
);
236 hres
= IStream_Read (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
237 if (hres
!= S_OK
) return STG_E_READFAULT
;
239 hres
= IStream_Read (pStm
, &object
, sizeof (object
), NULL
);
240 if (hres
!= S_OK
) return STG_E_READFAULT
;
242 if (sizeof(object
) == sizeof(DWORD
))
244 hres
= IStream_Read (pStm
, &constant
, sizeof (constant
), NULL
);
245 if (hres
!= S_OK
) return STG_E_READFAULT
;
247 FIXME("constant is 0x%x instead of 0\n", constant
);
250 hres
= IStream_Read (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
251 if (hres
!= S_OK
) return STG_E_READFAULT
;
253 hres
= IUnknown_QueryInterface(object
, riid
, ppv
);
254 if (!(mshlflags
& (MSHLFLAGS_TABLEWEAK
|MSHLFLAGS_TABLESTRONG
)))
255 IUnknown_Release(object
);
259 static HRESULT WINAPI
FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface
, IStream
* pStm
)
267 TRACE ("(%p)\n", pStm
);
269 hres
= IStream_Read (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
270 if (hres
!= S_OK
) return STG_E_READFAULT
;
272 hres
= IStream_Read (pStm
, &object
, sizeof (object
), NULL
);
273 if (hres
!= S_OK
) return STG_E_READFAULT
;
275 if (sizeof(object
) == sizeof(DWORD
))
277 hres
= IStream_Read (pStm
, &constant
, sizeof (constant
), NULL
);
278 if (hres
!= S_OK
) return STG_E_READFAULT
;
280 FIXME("constant is 0x%x instead of 0\n", constant
);
283 hres
= IStream_Read (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
284 if (hres
!= S_OK
) return STG_E_READFAULT
;
286 IUnknown_Release(object
);
290 static HRESULT WINAPI
FTMarshalImpl_DisconnectObject (LPMARSHAL iface
, DWORD dwReserved
)
297 static const IMarshalVtbl ftmvtbl
=
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
310 /***********************************************************************
311 * CoCreateFreeThreadedMarshaler [OLE32.@]
313 * Creates a free-threaded marshaler.
316 * punkOuter [I] Optional. Outer unknown.
317 * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
321 * Failure: E_OUTOFMEMORY if no memory available to create object.
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.
331 HRESULT WINAPI
CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter
, LPUNKNOWN
* ppunkMarshal
)
336 TRACE ("(%p %p)\n", punkOuter
, ppunkMarshal
);
338 ftm
= HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl
));
340 return E_OUTOFMEMORY
;
342 ftm
->IUnknown_inner
.lpVtbl
= &iunkvt
;
343 ftm
->IMarshal_iface
.lpVtbl
= &ftmvtbl
;
345 ftm
->outer_unk
= punkOuter
? punkOuter
: &ftm
->IUnknown_inner
;
347 *ppunkMarshal
= &ftm
->IUnknown_inner
;
351 static HRESULT WINAPI
FTMarshalCF_QueryInterface(LPCLASSFACTORY iface
,
352 REFIID riid
, LPVOID
*ppv
)
355 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IClassFactory
))
358 IClassFactory_AddRef(iface
);
361 return E_NOINTERFACE
;
364 static ULONG WINAPI
FTMarshalCF_AddRef(LPCLASSFACTORY iface
)
366 return 2; /* non-heap based object */
369 static ULONG WINAPI
FTMarshalCF_Release(LPCLASSFACTORY iface
)
371 return 1; /* non-heap based object */
374 static HRESULT WINAPI
FTMarshalCF_CreateInstance(LPCLASSFACTORY iface
,
375 LPUNKNOWN pUnk
, REFIID riid
, LPVOID
*ppv
)
380 TRACE("(%p, %s, %p)\n", pUnk
, debugstr_guid(riid
), ppv
);
384 hr
= CoCreateFreeThreadedMarshaler(pUnk
, &pUnknown
);
388 hr
= IUnknown_QueryInterface(pUnknown
, riid
, ppv
);
389 IUnknown_Release(pUnknown
);
395 static HRESULT WINAPI
FTMarshalCF_LockServer(LPCLASSFACTORY iface
, BOOL fLock
)
397 FIXME("(%d), stub!\n",fLock
);
401 static const IClassFactoryVtbl FTMarshalCFVtbl
=
403 FTMarshalCF_QueryInterface
,
406 FTMarshalCF_CreateInstance
,
407 FTMarshalCF_LockServer
409 static const IClassFactoryVtbl
*FTMarshalCF
= &FTMarshalCFVtbl
;
411 HRESULT
FTMarshalCF_Create(REFIID riid
, LPVOID
*ppv
)
413 return IClassFactory_QueryInterface((IClassFactory
*)&FTMarshalCF
, riid
, ppv
);