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
35 #include "wine/debug.h"
37 #include "compobj_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
41 typedef struct _FTMarshalImpl
{
42 const IUnknownVtbl
*lpVtbl
;
44 const IMarshalVtbl
*lpvtblFTM
;
49 #define _IFTMUnknown_(This)(IUnknown*)&(This->lpVtbl)
50 #define _IFTMarshal_(This) (IMarshal*)&(This->lpvtblFTM)
52 static inline FTMarshalImpl
*impl_from_IMarshal( IMarshal
*iface
)
54 return (FTMarshalImpl
*)((char*)iface
- FIELD_OFFSET(FTMarshalImpl
, lpvtblFTM
));
57 /* inner IUnknown to handle aggregation */
59 IiFTMUnknown_fnQueryInterface (IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
62 FTMarshalImpl
*This
= (FTMarshalImpl
*)iface
;
67 if (IsEqualIID (&IID_IUnknown
, riid
))
68 *ppv
= _IFTMUnknown_ (This
);
69 else if (IsEqualIID (&IID_IMarshal
, riid
))
70 *ppv
= _IFTMarshal_ (This
);
72 FIXME ("No interface for %s.\n", debugstr_guid (riid
));
75 IUnknown_AddRef ((IUnknown
*) * ppv
);
79 static ULONG WINAPI
IiFTMUnknown_fnAddRef (IUnknown
* iface
)
82 FTMarshalImpl
*This
= (FTMarshalImpl
*)iface
;
85 return InterlockedIncrement (&This
->ref
);
88 static ULONG WINAPI
IiFTMUnknown_fnRelease (IUnknown
* iface
)
91 FTMarshalImpl
*This
= (FTMarshalImpl
*)iface
;
94 if (InterlockedDecrement (&This
->ref
))
96 HeapFree (GetProcessHeap (), 0, This
);
100 static const IUnknownVtbl iunkvt
=
102 IiFTMUnknown_fnQueryInterface
,
103 IiFTMUnknown_fnAddRef
,
104 IiFTMUnknown_fnRelease
107 static HRESULT WINAPI
108 FTMarshalImpl_QueryInterface (LPMARSHAL iface
, REFIID riid
, LPVOID
* ppv
)
111 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
113 TRACE ("(%p)->(\n\tIID:\t%s,%p)\n", This
, debugstr_guid (riid
), ppv
);
114 return IUnknown_QueryInterface (This
->pUnkOuter
, riid
, ppv
);
118 FTMarshalImpl_AddRef (LPMARSHAL iface
)
121 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
124 return IUnknown_AddRef (This
->pUnkOuter
);
128 FTMarshalImpl_Release (LPMARSHAL iface
)
131 FTMarshalImpl
*This
= impl_from_IMarshal(iface
);
134 return IUnknown_Release (This
->pUnkOuter
);
137 static HRESULT WINAPI
138 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface
, REFIID riid
, void *pv
, DWORD dwDestContext
,
139 void *pvDestContext
, DWORD mshlflags
, CLSID
* pCid
)
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 memcpy(pCid
, &CLSID_InProcFreeMarshaler
, sizeof(CLSID_InProcFreeMarshaler
));
146 memcpy(pCid
, &CLSID_DfMarshal
, sizeof(CLSID_InProcFreeMarshaler
));
150 static HRESULT WINAPI
151 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface
, REFIID riid
, void *pv
, DWORD dwDestContext
,
152 void *pvDestContext
, DWORD mshlflags
, DWORD
* pSize
)
155 IMarshal
*pMarshal
= NULL
;
158 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid
), pv
,
159 dwDestContext
, pvDestContext
, mshlflags
, pSize
);
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
);
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
);
175 static HRESULT WINAPI
176 FTMarshalImpl_MarshalInterface (LPMARSHAL iface
, IStream
* pStm
, REFIID riid
, void *pv
,
177 DWORD dwDestContext
, void *pvDestContext
, DWORD mshlflags
)
180 IMarshal
*pMarshal
= NULL
;
183 TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm
, debugstr_guid(riid
), pv
,
184 dwDestContext
, pvDestContext
, mshlflags
);
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
) {
191 GUID unknown_guid
= { 0 };
193 hres
= IUnknown_QueryInterface((IUnknown
*)pv
, riid
, &object
);
197 /* don't hold a reference to table-weak marshaled interfaces */
198 if (mshlflags
& MSHLFLAGS_TABLEWEAK
)
199 IUnknown_Release((IUnknown
*)object
);
201 hres
= IStream_Write (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
202 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
204 hres
= IStream_Write (pStm
, &object
, sizeof (object
), NULL
);
205 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
207 hres
= IStream_Write (pStm
, &constant
, sizeof (constant
), NULL
);
208 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
210 hres
= IStream_Write (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
211 if (hres
!= S_OK
) return STG_E_MEDIUMFULL
;
216 /* use the standard marshaler to handle all other cases */
217 CoGetStandardMarshal (riid
, pv
, dwDestContext
, pvDestContext
, mshlflags
, &pMarshal
);
218 hres
= IMarshal_MarshalInterface (pMarshal
, pStm
, riid
, pv
, dwDestContext
, pvDestContext
, mshlflags
);
219 IMarshal_Release (pMarshal
);
223 static HRESULT WINAPI
224 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface
, IStream
* pStm
, REFIID riid
, void **ppv
)
232 TRACE ("(%p, %s, %p)\n", pStm
, debugstr_guid(riid
), ppv
);
234 hres
= IStream_Read (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
235 if (hres
!= S_OK
) return STG_E_READFAULT
;
237 hres
= IStream_Read (pStm
, &object
, sizeof (object
), NULL
);
238 if (hres
!= S_OK
) return STG_E_READFAULT
;
240 hres
= IStream_Read (pStm
, &constant
, sizeof (constant
), NULL
);
241 if (hres
!= S_OK
) return STG_E_READFAULT
;
243 FIXME("constant is 0x%x instead of 0\n", constant
);
245 hres
= IStream_Read (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
246 if (hres
!= S_OK
) return STG_E_READFAULT
;
248 hres
= IUnknown_QueryInterface(object
, riid
, ppv
);
249 if (!(mshlflags
& (MSHLFLAGS_TABLEWEAK
|MSHLFLAGS_TABLESTRONG
)))
250 IUnknown_Release(object
);
254 static HRESULT WINAPI
FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface
, IStream
* pStm
)
262 TRACE ("(%p)\n", pStm
);
264 hres
= IStream_Read (pStm
, &mshlflags
, sizeof (mshlflags
), NULL
);
265 if (hres
!= S_OK
) return STG_E_READFAULT
;
267 hres
= IStream_Read (pStm
, &object
, sizeof (object
), NULL
);
268 if (hres
!= S_OK
) return STG_E_READFAULT
;
270 hres
= IStream_Read (pStm
, &constant
, sizeof (constant
), NULL
);
271 if (hres
!= S_OK
) return STG_E_READFAULT
;
273 FIXME("constant is 0x%x instead of 0\n", constant
);
275 hres
= IStream_Read (pStm
, &unknown_guid
, sizeof (unknown_guid
), NULL
);
276 if (hres
!= S_OK
) return STG_E_READFAULT
;
278 IUnknown_Release(object
);
282 static HRESULT WINAPI
FTMarshalImpl_DisconnectObject (LPMARSHAL iface
, DWORD dwReserved
)
289 static const IMarshalVtbl ftmvtbl
=
291 FTMarshalImpl_QueryInterface
,
292 FTMarshalImpl_AddRef
,
293 FTMarshalImpl_Release
,
294 FTMarshalImpl_GetUnmarshalClass
,
295 FTMarshalImpl_GetMarshalSizeMax
,
296 FTMarshalImpl_MarshalInterface
,
297 FTMarshalImpl_UnmarshalInterface
,
298 FTMarshalImpl_ReleaseMarshalData
,
299 FTMarshalImpl_DisconnectObject
302 /***********************************************************************
303 * CoCreateFreeThreadedMarshaler [OLE32.@]
305 * Creates a free-threaded marshaler.
308 * punkOuter [I] Optional. Outer unknown.
309 * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
313 * Failure: E_OUTOFMEMORY if no memory available to create object.
316 * Objects that ensure their state is maintained consistent when used by
317 * multiple threads and reference no single-threaded objects are known as
318 * free-threaded. The free-threaded marshaler enables these objects to be
319 * efficiently marshaled within the same process, by not creating proxies
320 * (as they aren't needed for the object to be safely used), whilst still
321 * allowing the object to be used in inter-process and inter-machine contexts.
323 HRESULT WINAPI
CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter
, LPUNKNOWN
* ppunkMarshal
)
328 TRACE ("(%p %p)\n", punkOuter
, ppunkMarshal
);
330 ftm
= HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl
));
332 return E_OUTOFMEMORY
;
334 ftm
->lpVtbl
= &iunkvt
;
335 ftm
->lpvtblFTM
= &ftmvtbl
;
337 ftm
->pUnkOuter
= punkOuter
? punkOuter
: _IFTMUnknown_(ftm
);
339 *ppunkMarshal
= _IFTMUnknown_ (ftm
);
343 static HRESULT WINAPI
FTMarshalCF_QueryInterface(LPCLASSFACTORY iface
,
344 REFIID riid
, LPVOID
*ppv
)
347 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IClassFactory
))
350 IUnknown_AddRef(iface
);
353 return E_NOINTERFACE
;
356 static ULONG WINAPI
FTMarshalCF_AddRef(LPCLASSFACTORY iface
)
358 return 2; /* non-heap based object */
361 static ULONG WINAPI
FTMarshalCF_Release(LPCLASSFACTORY iface
)
363 return 1; /* non-heap based object */
366 static HRESULT WINAPI
FTMarshalCF_CreateInstance(LPCLASSFACTORY iface
,
367 LPUNKNOWN pUnk
, REFIID riid
, LPVOID
*ppv
)
372 TRACE("(%p, %s, %p)\n", pUnk
, debugstr_guid(riid
), ppv
);
376 hr
= CoCreateFreeThreadedMarshaler(pUnk
, &pUnknown
);
380 hr
= IUnknown_QueryInterface(pUnknown
, riid
, ppv
);
381 IUnknown_Release(pUnknown
);
387 static HRESULT WINAPI
FTMarshalCF_LockServer(LPCLASSFACTORY iface
, BOOL fLock
)
389 FIXME("(%d), stub!\n",fLock
);
393 static const IClassFactoryVtbl FTMarshalCFVtbl
=
395 FTMarshalCF_QueryInterface
,
398 FTMarshalCF_CreateInstance
,
399 FTMarshalCF_LockServer
401 static const IClassFactoryVtbl
*FTMarshalCF
= &FTMarshalCFVtbl
;
403 HRESULT
FTMarshalCF_Create(REFIID riid
, LPVOID
*ppv
)
405 return IClassFactory_QueryInterface((IClassFactory
*)&FTMarshalCF
, riid
, ppv
);