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