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 46 static inline FTMarshalImpl *impl_from_IUnknown(IUnknown *iface) 47 { 48 return CONTAINING_RECORD(iface, FTMarshalImpl, IUnknown_inner); 49 } 50 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 364 static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface) 365 { 366 return 2; /* non-heap based object */ 367 } 368 369 static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface) 370 { 371 return 1; /* non-heap based object */ 372 } 373 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 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 411 HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv) 412 { 413 return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv); 414 } 415