d3d10/tests: Add a test for effect compilation containing empty buffers.
[wine.git] / dlls / rpcrt4 / ndr_ole.c
blobaa7ca1ab765192520f548a25137797df9a3ca015
1 /*
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
20 * TODO:
21 * - fix the wire-protocol to match MS/RPC
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
28 #define COBJMACROS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
33 #include "objbase.h"
35 #include "ndr_misc.h"
36 #include "rpcndr.h"
37 #include "ndrtypes.h"
38 #include "rpcproxy.h"
39 #include "cpsf.h"
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;
51 LONG RefCount;
52 PMIDL_STUB_MESSAGE pMsg;
53 LPDWORD size;
54 unsigned char *data;
55 DWORD pos;
56 } RpcStreamImpl;
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,
64 REFIID riid,
65 LPVOID *obj)
67 if (IsEqualGUID(&IID_IUnknown, riid) ||
68 IsEqualGUID(&IID_ISequentialStream, riid) ||
69 IsEqualGUID(&IID_IStream, riid)) {
70 *obj = iface;
71 IStream_AddRef(iface);
72 return S_OK;
75 *obj = NULL;
76 return E_NOINTERFACE;
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 );
89 if (!ref) {
90 TRACE("size=%ld\n", *This->size);
91 This->pMsg->Buffer = This->data + *This->size;
92 free(This);
94 return ref;
97 static HRESULT WINAPI RpcStream_Read(LPSTREAM iface,
98 void *pv,
99 ULONG cb,
100 ULONG *pcbRead)
102 RpcStreamImpl *This = impl_from_IStream(iface);
103 HRESULT hr = S_OK;
104 if (This->pos + cb > *This->size)
106 cb = *This->size - This->pos;
107 hr = S_FALSE;
109 if (cb) {
110 memcpy(pv, This->data + This->pos, cb);
111 This->pos += cb;
113 if (pcbRead) *pcbRead = cb;
114 return hr;
117 static HRESULT WINAPI RpcStream_Write(LPSTREAM iface,
118 const void *pv,
119 ULONG cb,
120 ULONG *pcbWritten)
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);
126 This->pos += cb;
127 if (This->pos > *This->size) *This->size = This->pos;
128 if (pcbWritten) *pcbWritten = cb;
129 return S_OK;
132 static HRESULT WINAPI RpcStream_Seek(LPSTREAM iface,
133 LARGE_INTEGER move,
134 DWORD origin,
135 ULARGE_INTEGER *newPos)
137 RpcStreamImpl *This = impl_from_IStream(iface);
138 switch (origin) {
139 case STREAM_SEEK_SET:
140 This->pos = move.LowPart;
141 break;
142 case STREAM_SEEK_CUR:
143 This->pos = This->pos + move.LowPart;
144 break;
145 case STREAM_SEEK_END:
146 This->pos = *This->size + move.LowPart;
147 break;
148 default:
149 return STG_E_INVALIDFUNCTION;
151 if (newPos) {
152 newPos->u.LowPart = This->pos;
153 newPos->u.HighPart = 0;
155 return S_OK;
158 static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface,
159 ULARGE_INTEGER newSize)
161 RpcStreamImpl *This = impl_from_IStream(iface);
162 *This->size = newSize.LowPart;
163 return S_OK;
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);
171 return E_NOTIMPL;
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);
178 return E_NOTIMPL;
181 static HRESULT WINAPI RpcStream_Revert(IStream *iface)
183 RpcStreamImpl *This = impl_from_IStream(iface);
184 FIXME("(%p): stub\n", This);
185 return E_NOTIMPL;
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);
193 return E_NOTIMPL;
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);
201 return E_NOTIMPL;
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);
208 return E_NOTIMPL;
211 static HRESULT WINAPI RpcStream_Clone(IStream *iface, IStream **cloned)
213 RpcStreamImpl *This = impl_from_IStream(iface);
214 FIXME("(%p): stub\n", This);
215 return E_NOTIMPL;
218 static const IStreamVtbl RpcStream_Vtbl =
220 RpcStream_QueryInterface,
221 RpcStream_AddRef,
222 RpcStream_Release,
223 RpcStream_Read,
224 RpcStream_Write,
225 RpcStream_Seek,
226 RpcStream_SetSize,
227 RpcStream_CopyTo,
228 RpcStream_Commit,
229 RpcStream_Revert,
230 RpcStream_LockRegion,
231 RpcStream_UnlockRegion,
232 RpcStream_Stat,
233 RpcStream_Clone
236 static HRESULT RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init, ULONG *size, IStream **stream)
238 RpcStreamImpl *This;
240 *stream = NULL;
241 This = malloc(sizeof(RpcStreamImpl));
242 if (!This) return E_OUTOFMEMORY;
243 This->IStream_iface.lpVtbl = &RpcStream_Vtbl;
244 This->RefCount = 1;
245 This->pMsg = pStubMsg;
246 This->size = (LPDWORD)pStubMsg->Buffer;
247 This->data = pStubMsg->Buffer + sizeof(DWORD);
248 This->pos = 0;
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;
254 return S_OK;
257 static const IID* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
259 const IID *riid;
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];
265 } else {
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));
271 return 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);
282 LPSTREAM stream;
283 HRESULT hr;
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);
289 if (hr == S_OK) {
290 if (pMemory)
291 hr = CoMarshalInterface(stream, riid, (IUnknown *)pMemory,
292 pStubMsg->dwDestContext, pStubMsg->pvDestContext,
293 MSHLFLAGS_NORMAL);
294 IStream_Release(stream);
297 if (FAILED(hr))
298 RpcRaiseException(hr);
300 return NULL;
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;
312 LPSTREAM stream;
313 HRESULT hr;
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);
321 *unk = NULL;
322 if (pStubMsg->Buffer + sizeof(DWORD) < (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) {
323 ULONG size;
325 hr = RpcStream_Create(pStubMsg, FALSE, &size, &stream);
326 if (hr == S_OK) {
327 if (size != 0)
328 hr = CoUnmarshalInterface(stream, &IID_NULL, (void **)unk);
330 IStream_Release(stream);
333 if (FAILED(hr))
334 RpcRaiseException(hr);
336 return NULL;
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);
347 ULONG size = 0;
349 TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
350 CoGetMarshalSizeMax(&size, riid, (IUnknown *)pMemory,
351 pStubMsg->dwDestContext, pStubMsg->pvDestContext,
352 MSHLFLAGS_NORMAL);
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)
363 ULONG size;
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)
410 CLSID clsid;
411 IPSFactoryBuffer *psfac;
412 HRESULT r;
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);
423 return r;
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)
432 CLSID clsid;
433 IPSFactoryBuffer *psfac;
434 HRESULT r;
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);
445 return r;