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