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