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
29 #define NONAMELESSUNION
40 #include "wine/rpcfc.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
49 static HRESULT (WINAPI
*COM_GetMarshalSizeMax
)(ULONG
*,REFIID
,LPUNKNOWN
,DWORD
,LPVOID
,DWORD
);
50 static HRESULT (WINAPI
*COM_MarshalInterface
)(LPSTREAM
,REFIID
,LPUNKNOWN
,DWORD
,LPVOID
,DWORD
);
51 static HRESULT (WINAPI
*COM_UnmarshalInterface
)(LPSTREAM
,REFIID
,LPVOID
*);
52 static HRESULT (WINAPI
*COM_ReleaseMarshalData
)(LPSTREAM
);
53 static HRESULT (WINAPI
*COM_GetClassObject
)(REFCLSID
,DWORD
,COSERVERINFO
*,REFIID
,LPVOID
*);
54 static HRESULT (WINAPI
*COM_GetPSClsid
)(REFIID
,CLSID
*);
55 static LPVOID (WINAPI
*COM_MemAlloc
)(ULONG
);
56 static void (WINAPI
*COM_MemFree
)(LPVOID
);
58 static HMODULE
LoadCOM(void)
60 if (hOLE
) return hOLE
;
61 hOLE
= LoadLibraryA("OLE32.DLL");
63 COM_GetMarshalSizeMax
= (LPVOID
)GetProcAddress(hOLE
, "CoGetMarshalSizeMax");
64 COM_MarshalInterface
= (LPVOID
)GetProcAddress(hOLE
, "CoMarshalInterface");
65 COM_UnmarshalInterface
= (LPVOID
)GetProcAddress(hOLE
, "CoUnmarshalInterface");
66 COM_ReleaseMarshalData
= (LPVOID
)GetProcAddress(hOLE
, "CoReleaseMarshalData");
67 COM_GetClassObject
= (LPVOID
)GetProcAddress(hOLE
, "CoGetClassObject");
68 COM_GetPSClsid
= (LPVOID
)GetProcAddress(hOLE
, "CoGetPSClsid");
69 COM_MemAlloc
= (LPVOID
)GetProcAddress(hOLE
, "CoTaskMemAlloc");
70 COM_MemFree
= (LPVOID
)GetProcAddress(hOLE
, "CoTaskMemFree");
74 /* CoMarshalInterface/CoUnmarshalInterface works on streams,
75 * so implement a simple stream on top of the RPC buffer
76 * (which also implements the MInterfacePointer structure) */
77 typedef struct RpcStreamImpl
79 IStream IStream_iface
;
81 PMIDL_STUB_MESSAGE pMsg
;
87 static inline RpcStreamImpl
*impl_from_IStream(IStream
*iface
)
89 return CONTAINING_RECORD(iface
, RpcStreamImpl
, IStream_iface
);
92 static HRESULT WINAPI
RpcStream_QueryInterface(LPSTREAM iface
,
96 if (IsEqualGUID(&IID_IUnknown
, riid
) ||
97 IsEqualGUID(&IID_ISequentialStream
, riid
) ||
98 IsEqualGUID(&IID_IStream
, riid
)) {
100 IStream_AddRef(iface
);
105 return E_NOINTERFACE
;
108 static ULONG WINAPI
RpcStream_AddRef(LPSTREAM iface
)
110 RpcStreamImpl
*This
= impl_from_IStream(iface
);
111 return InterlockedIncrement( &This
->RefCount
);
114 static ULONG WINAPI
RpcStream_Release(LPSTREAM iface
)
116 RpcStreamImpl
*This
= impl_from_IStream(iface
);
117 ULONG ref
= InterlockedDecrement( &This
->RefCount
);
119 TRACE("size=%d\n", *This
->size
);
120 This
->pMsg
->Buffer
= This
->data
+ *This
->size
;
121 HeapFree(GetProcessHeap(),0,This
);
126 static HRESULT WINAPI
RpcStream_Read(LPSTREAM iface
,
131 RpcStreamImpl
*This
= impl_from_IStream(iface
);
133 if (This
->pos
+ cb
> *This
->size
)
135 cb
= *This
->size
- This
->pos
;
139 memcpy(pv
, This
->data
+ This
->pos
, cb
);
142 if (pcbRead
) *pcbRead
= cb
;
146 static HRESULT WINAPI
RpcStream_Write(LPSTREAM iface
,
151 RpcStreamImpl
*This
= impl_from_IStream(iface
);
152 if (This
->data
+ cb
> (unsigned char *)This
->pMsg
->RpcMsg
->Buffer
+ This
->pMsg
->BufferLength
)
153 return STG_E_MEDIUMFULL
;
154 memcpy(This
->data
+ This
->pos
, pv
, cb
);
156 if (This
->pos
> *This
->size
) *This
->size
= This
->pos
;
157 if (pcbWritten
) *pcbWritten
= cb
;
161 static HRESULT WINAPI
RpcStream_Seek(LPSTREAM iface
,
164 ULARGE_INTEGER
*newPos
)
166 RpcStreamImpl
*This
= impl_from_IStream(iface
);
168 case STREAM_SEEK_SET
:
169 This
->pos
= move
.u
.LowPart
;
171 case STREAM_SEEK_CUR
:
172 This
->pos
= This
->pos
+ move
.u
.LowPart
;
174 case STREAM_SEEK_END
:
175 This
->pos
= *This
->size
+ move
.u
.LowPart
;
178 return STG_E_INVALIDFUNCTION
;
181 newPos
->u
.LowPart
= This
->pos
;
182 newPos
->u
.HighPart
= 0;
187 static HRESULT WINAPI
RpcStream_SetSize(LPSTREAM iface
,
188 ULARGE_INTEGER newSize
)
190 RpcStreamImpl
*This
= impl_from_IStream(iface
);
191 *This
->size
= newSize
.u
.LowPart
;
195 static HRESULT WINAPI
RpcStream_CopyTo(IStream
*iface
, IStream
*dest
,
196 ULARGE_INTEGER len
, ULARGE_INTEGER
*read
, ULARGE_INTEGER
*written
)
198 RpcStreamImpl
*This
= impl_from_IStream(iface
);
199 FIXME("(%p): stub\n", This
);
203 static HRESULT WINAPI
RpcStream_Commit(IStream
*iface
, DWORD flags
)
205 RpcStreamImpl
*This
= impl_from_IStream(iface
);
206 FIXME("(%p)->(0x%08x): stub\n", This
, flags
);
210 static HRESULT WINAPI
RpcStream_Revert(IStream
*iface
)
212 RpcStreamImpl
*This
= impl_from_IStream(iface
);
213 FIXME("(%p): stub\n", This
);
217 static HRESULT WINAPI
RpcStream_LockRegion(IStream
*iface
,
218 ULARGE_INTEGER offset
, ULARGE_INTEGER len
, DWORD locktype
)
220 RpcStreamImpl
*This
= impl_from_IStream(iface
);
221 FIXME("(%p): stub\n", This
);
225 static HRESULT WINAPI
RpcStream_UnlockRegion(IStream
*iface
,
226 ULARGE_INTEGER offset
, ULARGE_INTEGER len
, DWORD locktype
)
228 RpcStreamImpl
*This
= impl_from_IStream(iface
);
229 FIXME("(%p): stub\n", This
);
233 static HRESULT WINAPI
RpcStream_Stat(IStream
*iface
, STATSTG
*stat
, DWORD flag
)
235 RpcStreamImpl
*This
= impl_from_IStream(iface
);
236 FIXME("(%p): stub\n", This
);
240 static HRESULT WINAPI
RpcStream_Clone(IStream
*iface
, IStream
**cloned
)
242 RpcStreamImpl
*This
= impl_from_IStream(iface
);
243 FIXME("(%p): stub\n", This
);
247 static const IStreamVtbl RpcStream_Vtbl
=
249 RpcStream_QueryInterface
,
259 RpcStream_LockRegion
,
260 RpcStream_UnlockRegion
,
265 static HRESULT
RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg
, BOOL init
, ULONG
*size
, IStream
**stream
)
270 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(RpcStreamImpl
));
271 if (!This
) return E_OUTOFMEMORY
;
272 This
->IStream_iface
.lpVtbl
= &RpcStream_Vtbl
;
274 This
->pMsg
= pStubMsg
;
275 This
->size
= (LPDWORD
)pStubMsg
->Buffer
;
276 This
->data
= pStubMsg
->Buffer
+ sizeof(DWORD
);
278 if (init
) *This
->size
= 0;
279 TRACE("init size=%d\n", *This
->size
);
281 if (size
) *size
= *This
->size
;
282 *stream
= &This
->IStream_iface
;
286 static const IID
* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg
, unsigned char *pMemory
, PFORMAT_STRING pFormat
)
289 if (!pFormat
) return &IID_IUnknown
;
290 TRACE("format=%02x %02x\n", pFormat
[0], pFormat
[1]);
291 if (pFormat
[0] != RPC_FC_IP
) FIXME("format=%d\n", pFormat
[0]);
292 if (pFormat
[1] == RPC_FC_CONSTANT_IID
) {
293 riid
= (const IID
*)&pFormat
[2];
295 ComputeConformance(pStubMsg
, pMemory
, pFormat
+2, 0);
296 riid
= (const IID
*)pStubMsg
->MaxCount
;
298 if (!riid
) riid
= &IID_IUnknown
;
299 TRACE("got %s\n", debugstr_guid(riid
));
303 /***********************************************************************
304 * NdrInterfacePointerMarshall [RPCRT4.@]
306 unsigned char * WINAPI
NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg
,
307 unsigned char *pMemory
,
308 PFORMAT_STRING pFormat
)
310 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
314 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
315 pStubMsg
->MaxCount
= 0;
316 if (!LoadCOM()) return NULL
;
317 if (pStubMsg
->Buffer
+ sizeof(DWORD
) <= (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
318 hr
= RpcStream_Create(pStubMsg
, TRUE
, NULL
, &stream
);
321 hr
= COM_MarshalInterface(stream
, riid
, (LPUNKNOWN
)pMemory
,
322 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
324 IStream_Release(stream
);
328 RpcRaiseException(hr
);
333 /***********************************************************************
334 * NdrInterfacePointerUnmarshall [RPCRT4.@]
336 unsigned char * WINAPI
NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg
,
337 unsigned char **ppMemory
,
338 PFORMAT_STRING pFormat
,
339 unsigned char fMustAlloc
)
344 TRACE("(%p,%p,%p,%d)\n", pStubMsg
, ppMemory
, pFormat
, fMustAlloc
);
345 if (!LoadCOM()) return NULL
;
346 *(LPVOID
*)ppMemory
= NULL
;
347 if (pStubMsg
->Buffer
+ sizeof(DWORD
) < (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
350 hr
= RpcStream_Create(pStubMsg
, FALSE
, &size
, &stream
);
353 hr
= COM_UnmarshalInterface(stream
, &IID_NULL
, (LPVOID
*)ppMemory
);
355 IStream_Release(stream
);
359 RpcRaiseException(hr
);
364 /***********************************************************************
365 * NdrInterfacePointerBufferSize [RPCRT4.@]
367 void WINAPI
NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg
,
368 unsigned char *pMemory
,
369 PFORMAT_STRING pFormat
)
371 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
374 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
375 if (!LoadCOM()) return;
376 COM_GetMarshalSizeMax(&size
, riid
, (LPUNKNOWN
)pMemory
,
377 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
379 TRACE("size=%d\n", size
);
380 pStubMsg
->BufferLength
+= sizeof(DWORD
) + size
;
383 /***********************************************************************
384 * NdrInterfacePointerMemorySize [RPCRT4.@]
386 ULONG WINAPI
NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg
,
387 PFORMAT_STRING pFormat
)
391 TRACE("(%p,%p)\n", pStubMsg
, pFormat
);
393 size
= *(ULONG
*)pStubMsg
->Buffer
;
394 pStubMsg
->Buffer
+= 4;
395 pStubMsg
->MemorySize
+= 4;
397 pStubMsg
->Buffer
+= size
;
399 return pStubMsg
->MemorySize
;
402 /***********************************************************************
403 * NdrInterfacePointerFree [RPCRT4.@]
405 void WINAPI
NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg
,
406 unsigned char *pMemory
,
407 PFORMAT_STRING pFormat
)
409 LPUNKNOWN pUnk
= (LPUNKNOWN
)pMemory
;
410 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
411 if (pUnk
) IUnknown_Release(pUnk
);
414 /***********************************************************************
415 * NdrOleAllocate [RPCRT4.@]
417 void * WINAPI
NdrOleAllocate(SIZE_T Size
)
419 if (!LoadCOM()) return NULL
;
420 return COM_MemAlloc(Size
);
423 /***********************************************************************
424 * NdrOleFree [RPCRT4.@]
426 void WINAPI
NdrOleFree(void *NodeToFree
)
428 if (!LoadCOM()) return;
429 COM_MemFree(NodeToFree
);
432 /***********************************************************************
433 * Helper function to create a proxy.
434 * Probably similar to NdrpCreateProxy.
436 HRESULT
create_proxy(REFIID iid
, IUnknown
*pUnkOuter
, IRpcProxyBuffer
**pproxy
, void **ppv
)
439 IPSFactoryBuffer
*psfac
;
442 if(!LoadCOM()) return E_FAIL
;
444 r
= COM_GetPSClsid( iid
, &clsid
);
445 if(FAILED(r
)) return r
;
447 r
= COM_GetClassObject( &clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void**)&psfac
);
448 if(FAILED(r
)) return r
;
450 r
= IPSFactoryBuffer_CreateProxy(psfac
, pUnkOuter
, iid
, pproxy
, ppv
);
452 IPSFactoryBuffer_Release(psfac
);
456 /***********************************************************************
457 * Helper function to create a stub.
458 * This probably looks very much like NdrpCreateStub.
460 HRESULT
create_stub(REFIID iid
, IUnknown
*pUnk
, IRpcStubBuffer
**ppstub
)
463 IPSFactoryBuffer
*psfac
;
466 if(!LoadCOM()) return E_FAIL
;
468 r
= COM_GetPSClsid( iid
, &clsid
);
469 if(FAILED(r
)) return r
;
471 r
= COM_GetClassObject( &clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void**)&psfac
);
472 if(FAILED(r
)) return r
;
474 r
= IPSFactoryBuffer_CreateStub(psfac
, iid
, pUnk
, ppstub
);
476 IPSFactoryBuffer_Release(psfac
);