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 <stdlib.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #define COBJMACROS
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "objbase.h"
32
33 #include "wine/debug.h"
34
35 #include "compobj_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38
39 typedef struct _FTMarshalImpl {
40 IUnknown IUnknown_inner;
41 IMarshal IMarshal_iface;
42 IUnknown *outer_unk;
43 LONG ref;
44 } FTMarshalImpl;
45
impl_from_IUnknown(IUnknown * iface)46 static inline FTMarshalImpl *impl_from_IUnknown(IUnknown *iface)
47 {
48 return CONTAINING_RECORD(iface, FTMarshalImpl, IUnknown_inner);
49 }
50
impl_from_IMarshal(IMarshal * iface)51 static inline FTMarshalImpl *impl_from_IMarshal( IMarshal *iface )
52 {
53 return CONTAINING_RECORD(iface, FTMarshalImpl, IMarshal_iface);
54 }
55
56 /* inner IUnknown to handle aggregation */
57 static HRESULT WINAPI
IiFTMUnknown_fnQueryInterface(IUnknown * iface,REFIID riid,LPVOID * ppv)58 IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv)
59 {
60
61 FTMarshalImpl *This = impl_from_IUnknown(iface);
62
63 TRACE ("\n");
64 *ppv = NULL;
65
66 if (IsEqualIID (&IID_IUnknown, riid))
67 *ppv = &This->IUnknown_inner;
68 else if (IsEqualIID (&IID_IMarshal, riid))
69 *ppv = &This->IMarshal_iface;
70 else {
71 FIXME ("No interface for %s.\n", debugstr_guid (riid));
72 return E_NOINTERFACE;
73 }
74 IUnknown_AddRef ((IUnknown *) * ppv);
75 return S_OK;
76 }
77
IiFTMUnknown_fnAddRef(IUnknown * iface)78 static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface)
79 {
80
81 FTMarshalImpl *This = impl_from_IUnknown(iface);
82
83 TRACE ("\n");
84 return InterlockedIncrement (&This->ref);
85 }
86
IiFTMUnknown_fnRelease(IUnknown * iface)87 static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface)
88 {
89
90 FTMarshalImpl *This = impl_from_IUnknown(iface);
91
92 TRACE ("\n");
93 if (InterlockedDecrement (&This->ref))
94 return This->ref;
95 HeapFree (GetProcessHeap (), 0, This);
96 return 0;
97 }
98
99 static const IUnknownVtbl iunkvt =
100 {
101 IiFTMUnknown_fnQueryInterface,
102 IiFTMUnknown_fnAddRef,
103 IiFTMUnknown_fnRelease
104 };
105
106 static HRESULT WINAPI
FTMarshalImpl_QueryInterface(LPMARSHAL iface,REFIID riid,LPVOID * ppv)107 FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv)
108 {
109
110 FTMarshalImpl *This = impl_from_IMarshal(iface);
111
112 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv);
113 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
114 }
115
116 static ULONG WINAPI
FTMarshalImpl_AddRef(LPMARSHAL iface)117 FTMarshalImpl_AddRef (LPMARSHAL iface)
118 {
119
120 FTMarshalImpl *This = impl_from_IMarshal(iface);
121
122 TRACE ("\n");
123 return IUnknown_AddRef(This->outer_unk);
124 }
125
126 static ULONG WINAPI
FTMarshalImpl_Release(LPMARSHAL iface)127 FTMarshalImpl_Release (LPMARSHAL iface)
128 {
129
130 FTMarshalImpl *This = impl_from_IMarshal(iface);
131
132 TRACE ("\n");
133 return IUnknown_Release(This->outer_unk);
134 }
135
136 static HRESULT WINAPI
FTMarshalImpl_GetUnmarshalClass(LPMARSHAL iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,CLSID * pCid)137 FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
138 void *pvDestContext, DWORD mshlflags, CLSID * pCid)
139 {
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;
144 else
145 *pCid = CLSID_StdMarshal;
146 return S_OK;
147 }
148
149 static HRESULT WINAPI
FTMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,DWORD * pSize)150 FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext,
151 void *pvDestContext, DWORD mshlflags, DWORD * pSize)
152 {
153
154 IMarshal *pMarshal = NULL;
155 HRESULT hres;
156
157 TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv,
158 dwDestContext, pvDestContext, mshlflags, pSize);
159
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);
164 return S_OK;
165 }
166
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);
171 return hres;
172 }
173
174 static HRESULT WINAPI
FTMarshalImpl_MarshalInterface(LPMARSHAL iface,IStream * pStm,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags)175 FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv,
176 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
177 {
178
179 IMarshal *pMarshal = NULL;
180 HRESULT hres;
181
182 TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm, debugstr_guid(riid), pv,
183 dwDestContext, pvDestContext, mshlflags);
184
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) {
188 void *object;
189 DWORD constant = 0;
190 GUID unknown_guid = { 0 };
191
192 hres = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
193 if (FAILED(hres))
194 return hres;
195
196 /* don't hold a reference to table-weak marshaled interfaces */
197 if (mshlflags & MSHLFLAGS_TABLEWEAK)
198 IUnknown_Release((IUnknown *)object);
199
200 hres = IStream_Write (pStm, &mshlflags, sizeof (mshlflags), NULL);
201 if (hres != S_OK) return STG_E_MEDIUMFULL;
202
203 hres = IStream_Write (pStm, &object, sizeof (object), NULL);
204 if (hres != S_OK) return STG_E_MEDIUMFULL;
205
206 if (sizeof(object) == sizeof(DWORD))
207 {
208 hres = IStream_Write (pStm, &constant, sizeof (constant), NULL);
209 if (hres != S_OK) return STG_E_MEDIUMFULL;
210 }
211
212 hres = IStream_Write (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
213 if (hres != S_OK) return STG_E_MEDIUMFULL;
214
215 return S_OK;
216 }
217
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);
222 return hres;
223 }
224
225 static HRESULT WINAPI
FTMarshalImpl_UnmarshalInterface(LPMARSHAL iface,IStream * pStm,REFIID riid,void ** ppv)226 FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv)
227 {
228 DWORD mshlflags;
229 IUnknown *object;
230 DWORD constant;
231 GUID unknown_guid;
232 HRESULT hres;
233
234 TRACE ("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
235
236 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
237 if (hres != S_OK) return STG_E_READFAULT;
238
239 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
240 if (hres != S_OK) return STG_E_READFAULT;
241
242 if (sizeof(object) == sizeof(DWORD))
243 {
244 hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
245 if (hres != S_OK) return STG_E_READFAULT;
246 if (constant != 0)
247 FIXME("constant is 0x%x instead of 0\n", constant);
248 }
249
250 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
251 if (hres != S_OK) return STG_E_READFAULT;
252
253 hres = IUnknown_QueryInterface(object, riid, ppv);
254 if (!(mshlflags & (MSHLFLAGS_TABLEWEAK|MSHLFLAGS_TABLESTRONG)))
255 IUnknown_Release(object);
256 return hres;
257 }
258
FTMarshalImpl_ReleaseMarshalData(LPMARSHAL iface,IStream * pStm)259 static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm)
260 {
261 DWORD mshlflags;
262 IUnknown *object;
263 DWORD constant;
264 GUID unknown_guid;
265 HRESULT hres;
266
267 TRACE ("(%p)\n", pStm);
268
269 hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL);
270 if (hres != S_OK) return STG_E_READFAULT;
271
272 hres = IStream_Read (pStm, &object, sizeof (object), NULL);
273 if (hres != S_OK) return STG_E_READFAULT;
274
275 if (sizeof(object) == sizeof(DWORD))
276 {
277 hres = IStream_Read (pStm, &constant, sizeof (constant), NULL);
278 if (hres != S_OK) return STG_E_READFAULT;
279 if (constant != 0)
280 FIXME("constant is 0x%x instead of 0\n", constant);
281 }
282
283 hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL);
284 if (hres != S_OK) return STG_E_READFAULT;
285
286 IUnknown_Release(object);
287 return S_OK;
288 }
289
FTMarshalImpl_DisconnectObject(LPMARSHAL iface,DWORD dwReserved)290 static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved)
291 {
292 TRACE ("()\n");
293 /* nothing to do */
294 return S_OK;
295 }
296
297 static const IMarshalVtbl ftmvtbl =
298 {
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
308 };
309
310 /***********************************************************************
311 * CoCreateFreeThreadedMarshaler [OLE32.@]
312 *
313 * Creates a free-threaded marshaler.
314 *
315 * PARAMS
316 * punkOuter [I] Optional. Outer unknown.
317 * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler.
318 *
319 * RETURNS
320 * Success: S_OK
321 * Failure: E_OUTOFMEMORY if no memory available to create object.
322 *
323 * NOTES
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.
330 */
CoCreateFreeThreadedMarshaler(LPUNKNOWN punkOuter,LPUNKNOWN * ppunkMarshal)331 HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal)
332 {
333
334 FTMarshalImpl *ftm;
335
336 TRACE ("(%p %p)\n", punkOuter, ppunkMarshal);
337
338 ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl));
339 if (!ftm)
340 return E_OUTOFMEMORY;
341
342 ftm->IUnknown_inner.lpVtbl = &iunkvt;
343 ftm->IMarshal_iface.lpVtbl = &ftmvtbl;
344 ftm->ref = 1;
345 ftm->outer_unk = punkOuter ? punkOuter : &ftm->IUnknown_inner;
346
347 *ppunkMarshal = &ftm->IUnknown_inner;
348 return S_OK;
349 }
350
FTMarshalCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppv)351 static HRESULT WINAPI FTMarshalCF_QueryInterface(LPCLASSFACTORY iface,
352 REFIID riid, LPVOID *ppv)
353 {
354 *ppv = NULL;
355 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
356 {
357 *ppv = iface;
358 IClassFactory_AddRef(iface);
359 return S_OK;
360 }
361 return E_NOINTERFACE;
362 }
363
FTMarshalCF_AddRef(LPCLASSFACTORY iface)364 static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface)
365 {
366 return 2; /* non-heap based object */
367 }
368
FTMarshalCF_Release(LPCLASSFACTORY iface)369 static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface)
370 {
371 return 1; /* non-heap based object */
372 }
373
FTMarshalCF_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnk,REFIID riid,LPVOID * ppv)374 static HRESULT WINAPI FTMarshalCF_CreateInstance(LPCLASSFACTORY iface,
375 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
376 {
377 IUnknown *pUnknown;
378 HRESULT hr;
379
380 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
381
382 *ppv = NULL;
383
384 hr = CoCreateFreeThreadedMarshaler(pUnk, &pUnknown);
385
386 if (SUCCEEDED(hr))
387 {
388 hr = IUnknown_QueryInterface(pUnknown, riid, ppv);
389 IUnknown_Release(pUnknown);
390 }
391
392 return hr;
393 }
394
FTMarshalCF_LockServer(LPCLASSFACTORY iface,BOOL fLock)395 static HRESULT WINAPI FTMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
396 {
397 FIXME("(%d), stub!\n",fLock);
398 return S_OK;
399 }
400
401 static const IClassFactoryVtbl FTMarshalCFVtbl =
402 {
403 FTMarshalCF_QueryInterface,
404 FTMarshalCF_AddRef,
405 FTMarshalCF_Release,
406 FTMarshalCF_CreateInstance,
407 FTMarshalCF_LockServer
408 };
409 static const IClassFactoryVtbl *FTMarshalCF = &FTMarshalCFVtbl;
410
FTMarshalCF_Create(REFIID riid,LPVOID * ppv)411 HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv)
412 {
413 return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv);
414 }
415