2 * OLE32 callouts, COM interface marshalling
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
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.
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.
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
21 * - fix the wire-protocol to match MS/RPC
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
45 /* CoMarshalInterface/CoUnmarshalInterface works on streams,
46 * so implement a simple stream on top of the RPC buffer
47 * (which also implements the MInterfacePointer structure) */
48 typedef struct RpcStreamImpl
50 IStream IStream_iface
;
52 PMIDL_STUB_MESSAGE pMsg
;
58 static inline RpcStreamImpl
*impl_from_IStream(IStream
*iface
)
60 return CONTAINING_RECORD(iface
, RpcStreamImpl
, IStream_iface
);
63 static HRESULT WINAPI
RpcStream_QueryInterface(LPSTREAM iface
,
67 if (IsEqualGUID(&IID_IUnknown
, riid
) ||
68 IsEqualGUID(&IID_ISequentialStream
, riid
) ||
69 IsEqualGUID(&IID_IStream
, riid
)) {
71 IStream_AddRef(iface
);
79 static ULONG WINAPI
RpcStream_AddRef(LPSTREAM iface
)
81 RpcStreamImpl
*This
= impl_from_IStream(iface
);
82 return InterlockedIncrement( &This
->RefCount
);
85 static ULONG WINAPI
RpcStream_Release(LPSTREAM iface
)
87 RpcStreamImpl
*This
= impl_from_IStream(iface
);
88 ULONG ref
= InterlockedDecrement( &This
->RefCount
);
90 TRACE("size=%ld\n", *This
->size
);
91 This
->pMsg
->Buffer
= This
->data
+ *This
->size
;
97 static HRESULT WINAPI
RpcStream_Read(LPSTREAM iface
,
102 RpcStreamImpl
*This
= impl_from_IStream(iface
);
104 if (This
->pos
+ cb
> *This
->size
)
106 cb
= *This
->size
- This
->pos
;
110 memcpy(pv
, This
->data
+ This
->pos
, cb
);
113 if (pcbRead
) *pcbRead
= cb
;
117 static HRESULT WINAPI
RpcStream_Write(LPSTREAM iface
,
122 RpcStreamImpl
*This
= impl_from_IStream(iface
);
123 if (This
->data
+ cb
> (unsigned char *)This
->pMsg
->RpcMsg
->Buffer
+ This
->pMsg
->BufferLength
)
124 return STG_E_MEDIUMFULL
;
125 memcpy(This
->data
+ This
->pos
, pv
, cb
);
127 if (This
->pos
> *This
->size
) *This
->size
= This
->pos
;
128 if (pcbWritten
) *pcbWritten
= cb
;
132 static HRESULT WINAPI
RpcStream_Seek(LPSTREAM iface
,
135 ULARGE_INTEGER
*newPos
)
137 RpcStreamImpl
*This
= impl_from_IStream(iface
);
139 case STREAM_SEEK_SET
:
140 This
->pos
= move
.LowPart
;
142 case STREAM_SEEK_CUR
:
143 This
->pos
= This
->pos
+ move
.LowPart
;
145 case STREAM_SEEK_END
:
146 This
->pos
= *This
->size
+ move
.LowPart
;
149 return STG_E_INVALIDFUNCTION
;
152 newPos
->u
.LowPart
= This
->pos
;
153 newPos
->u
.HighPart
= 0;
158 static HRESULT WINAPI
RpcStream_SetSize(LPSTREAM iface
,
159 ULARGE_INTEGER newSize
)
161 RpcStreamImpl
*This
= impl_from_IStream(iface
);
162 *This
->size
= newSize
.LowPart
;
166 static HRESULT WINAPI
RpcStream_CopyTo(IStream
*iface
, IStream
*dest
,
167 ULARGE_INTEGER len
, ULARGE_INTEGER
*read
, ULARGE_INTEGER
*written
)
169 RpcStreamImpl
*This
= impl_from_IStream(iface
);
170 FIXME("(%p): stub\n", This
);
174 static HRESULT WINAPI
RpcStream_Commit(IStream
*iface
, DWORD flags
)
176 RpcStreamImpl
*This
= impl_from_IStream(iface
);
177 FIXME("(%p)->(0x%08lx): stub\n", This
, flags
);
181 static HRESULT WINAPI
RpcStream_Revert(IStream
*iface
)
183 RpcStreamImpl
*This
= impl_from_IStream(iface
);
184 FIXME("(%p): stub\n", This
);
188 static HRESULT WINAPI
RpcStream_LockRegion(IStream
*iface
,
189 ULARGE_INTEGER offset
, ULARGE_INTEGER len
, DWORD locktype
)
191 RpcStreamImpl
*This
= impl_from_IStream(iface
);
192 FIXME("(%p): stub\n", This
);
196 static HRESULT WINAPI
RpcStream_UnlockRegion(IStream
*iface
,
197 ULARGE_INTEGER offset
, ULARGE_INTEGER len
, DWORD locktype
)
199 RpcStreamImpl
*This
= impl_from_IStream(iface
);
200 FIXME("(%p): stub\n", This
);
204 static HRESULT WINAPI
RpcStream_Stat(IStream
*iface
, STATSTG
*stat
, DWORD flag
)
206 RpcStreamImpl
*This
= impl_from_IStream(iface
);
207 FIXME("(%p): stub\n", This
);
211 static HRESULT WINAPI
RpcStream_Clone(IStream
*iface
, IStream
**cloned
)
213 RpcStreamImpl
*This
= impl_from_IStream(iface
);
214 FIXME("(%p): stub\n", This
);
218 static const IStreamVtbl RpcStream_Vtbl
=
220 RpcStream_QueryInterface
,
230 RpcStream_LockRegion
,
231 RpcStream_UnlockRegion
,
236 static HRESULT
RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg
, BOOL init
, ULONG
*size
, IStream
**stream
)
241 This
= malloc(sizeof(RpcStreamImpl
));
242 if (!This
) return E_OUTOFMEMORY
;
243 This
->IStream_iface
.lpVtbl
= &RpcStream_Vtbl
;
245 This
->pMsg
= pStubMsg
;
246 This
->size
= (LPDWORD
)pStubMsg
->Buffer
;
247 This
->data
= pStubMsg
->Buffer
+ sizeof(DWORD
);
249 if (init
) *This
->size
= 0;
250 TRACE("init size=%ld\n", *This
->size
);
252 if (size
) *size
= *This
->size
;
253 *stream
= &This
->IStream_iface
;
257 static const IID
* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg
, unsigned char *pMemory
, PFORMAT_STRING pFormat
)
260 if (!pFormat
) return &IID_IUnknown
;
261 TRACE("format=%02x %02x\n", pFormat
[0], pFormat
[1]);
262 if (pFormat
[0] != FC_IP
) FIXME("format=%d\n", pFormat
[0]);
263 if (pFormat
[1] == FC_CONSTANT_IID
) {
264 riid
= (const IID
*)&pFormat
[2];
266 ComputeConformance(pStubMsg
, pMemory
, pFormat
+2, 0);
267 riid
= (const IID
*)pStubMsg
->MaxCount
;
269 if (!riid
) riid
= &IID_IUnknown
;
270 TRACE("got %s\n", debugstr_guid(riid
));
274 /***********************************************************************
275 * NdrInterfacePointerMarshall [RPCRT4.@]
277 unsigned char * WINAPI
NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg
,
278 unsigned char *pMemory
,
279 PFORMAT_STRING pFormat
)
281 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
285 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
286 pStubMsg
->MaxCount
= 0;
287 if (pStubMsg
->Buffer
+ sizeof(DWORD
) <= (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
288 hr
= RpcStream_Create(pStubMsg
, TRUE
, NULL
, &stream
);
291 hr
= CoMarshalInterface(stream
, riid
, (IUnknown
*)pMemory
,
292 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
294 IStream_Release(stream
);
298 RpcRaiseException(hr
);
303 /***********************************************************************
304 * NdrInterfacePointerUnmarshall [RPCRT4.@]
306 unsigned char * WINAPI
NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg
,
307 unsigned char **ppMemory
,
308 PFORMAT_STRING pFormat
,
309 unsigned char fMustAlloc
)
311 IUnknown
**unk
= (IUnknown
**)ppMemory
;
315 TRACE("(%p,%p,%p,%d)\n", pStubMsg
, ppMemory
, pFormat
, fMustAlloc
);
317 /* Avoid reference leaks for [in, out] pointers. */
318 if (pStubMsg
->IsClient
&& *unk
)
319 IUnknown_Release(*unk
);
322 if (pStubMsg
->Buffer
+ sizeof(DWORD
) < (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
325 hr
= RpcStream_Create(pStubMsg
, FALSE
, &size
, &stream
);
328 hr
= CoUnmarshalInterface(stream
, &IID_NULL
, (void **)unk
);
330 IStream_Release(stream
);
334 RpcRaiseException(hr
);
339 /***********************************************************************
340 * NdrInterfacePointerBufferSize [RPCRT4.@]
342 void WINAPI
NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg
,
343 unsigned char *pMemory
,
344 PFORMAT_STRING pFormat
)
346 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
349 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
350 CoGetMarshalSizeMax(&size
, riid
, (IUnknown
*)pMemory
,
351 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
353 TRACE("size=%ld\n", size
);
354 pStubMsg
->BufferLength
+= sizeof(DWORD
) + size
;
357 /***********************************************************************
358 * NdrInterfacePointerMemorySize [RPCRT4.@]
360 ULONG WINAPI
NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg
,
361 PFORMAT_STRING pFormat
)
365 TRACE("(%p,%p)\n", pStubMsg
, pFormat
);
367 size
= *(ULONG
*)pStubMsg
->Buffer
;
368 pStubMsg
->Buffer
+= 4;
369 pStubMsg
->MemorySize
+= 4;
371 pStubMsg
->Buffer
+= size
;
373 return pStubMsg
->MemorySize
;
376 /***********************************************************************
377 * NdrInterfacePointerFree [RPCRT4.@]
379 void WINAPI
NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg
,
380 unsigned char *pMemory
,
381 PFORMAT_STRING pFormat
)
383 LPUNKNOWN pUnk
= (LPUNKNOWN
)pMemory
;
384 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
385 if (pUnk
) IUnknown_Release(pUnk
);
388 /***********************************************************************
389 * NdrOleAllocate [RPCRT4.@]
391 void * WINAPI
NdrOleAllocate(SIZE_T Size
)
393 return CoTaskMemAlloc(Size
);
396 /***********************************************************************
397 * NdrOleFree [RPCRT4.@]
399 void WINAPI
NdrOleFree(void *NodeToFree
)
401 CoTaskMemFree(NodeToFree
);
404 /***********************************************************************
405 * Helper function to create a proxy.
406 * Probably similar to NdrpCreateProxy.
408 HRESULT
create_proxy(REFIID iid
, IUnknown
*pUnkOuter
, IRpcProxyBuffer
**pproxy
, void **ppv
)
411 IPSFactoryBuffer
*psfac
;
414 r
= CoGetPSClsid(iid
, &clsid
);
415 if(FAILED(r
)) return r
;
417 r
= CoGetClassObject(&clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void **)&psfac
);
418 if(FAILED(r
)) return r
;
420 r
= IPSFactoryBuffer_CreateProxy(psfac
, pUnkOuter
, iid
, pproxy
, ppv
);
422 IPSFactoryBuffer_Release(psfac
);
426 /***********************************************************************
427 * Helper function to create a stub.
428 * This probably looks very much like NdrpCreateStub.
430 HRESULT
create_stub(REFIID iid
, IUnknown
*pUnk
, IRpcStubBuffer
**ppstub
)
433 IPSFactoryBuffer
*psfac
;
436 r
= CoGetPSClsid(iid
, &clsid
);
437 if(FAILED(r
)) return r
;
439 r
= CoGetClassObject(&clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void **)&psfac
);
440 if(FAILED(r
)) return r
;
442 r
= IPSFactoryBuffer_CreateStub(psfac
, iid
, pUnk
, ppstub
);
444 IPSFactoryBuffer_Release(psfac
);