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
22 * - finish RpcStream_Vtbl
25 #define WIN32_NO_STATUS
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
38 //#include "winerror.h"
44 //#include "rpcproxy.h"
45 #include <wine/rpcfc.h>
48 #include <wine/debug.h>
50 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
54 static HRESULT (WINAPI
*COM_GetMarshalSizeMax
)(ULONG
*,REFIID
,LPUNKNOWN
,DWORD
,LPVOID
,DWORD
);
55 static HRESULT (WINAPI
*COM_MarshalInterface
)(LPSTREAM
,REFIID
,LPUNKNOWN
,DWORD
,LPVOID
,DWORD
);
56 static HRESULT (WINAPI
*COM_UnmarshalInterface
)(LPSTREAM
,REFIID
,LPVOID
*);
57 static HRESULT (WINAPI
*COM_ReleaseMarshalData
)(LPSTREAM
);
58 static HRESULT (WINAPI
*COM_GetClassObject
)(REFCLSID
,DWORD
,COSERVERINFO
*,REFIID
,LPVOID
*);
59 static HRESULT (WINAPI
*COM_GetPSClsid
)(REFIID
,CLSID
*);
60 static LPVOID (WINAPI
*COM_MemAlloc
)(ULONG
);
61 static void (WINAPI
*COM_MemFree
)(LPVOID
);
63 static HMODULE
LoadCOM(void)
65 if (hOLE
) return hOLE
;
66 hOLE
= LoadLibraryA("OLE32.DLL");
68 COM_GetMarshalSizeMax
= (LPVOID
)GetProcAddress(hOLE
, "CoGetMarshalSizeMax");
69 COM_MarshalInterface
= (LPVOID
)GetProcAddress(hOLE
, "CoMarshalInterface");
70 COM_UnmarshalInterface
= (LPVOID
)GetProcAddress(hOLE
, "CoUnmarshalInterface");
71 COM_ReleaseMarshalData
= (LPVOID
)GetProcAddress(hOLE
, "CoReleaseMarshalData");
72 COM_GetClassObject
= (LPVOID
)GetProcAddress(hOLE
, "CoGetClassObject");
73 COM_GetPSClsid
= (LPVOID
)GetProcAddress(hOLE
, "CoGetPSClsid");
74 COM_MemAlloc
= (LPVOID
)GetProcAddress(hOLE
, "CoTaskMemAlloc");
75 COM_MemFree
= (LPVOID
)GetProcAddress(hOLE
, "CoTaskMemFree");
79 /* CoMarshalInterface/CoUnmarshalInterface works on streams,
80 * so implement a simple stream on top of the RPC buffer
81 * (which also implements the MInterfacePointer structure) */
82 typedef struct RpcStreamImpl
84 IStream IStream_iface
;
86 PMIDL_STUB_MESSAGE pMsg
;
92 static inline RpcStreamImpl
*impl_from_IStream(IStream
*iface
)
94 return CONTAINING_RECORD(iface
, RpcStreamImpl
, IStream_iface
);
97 static HRESULT WINAPI
RpcStream_QueryInterface(LPSTREAM iface
,
101 RpcStreamImpl
*This
= impl_from_IStream(iface
);
102 if (IsEqualGUID(&IID_IUnknown
, riid
) ||
103 IsEqualGUID(&IID_ISequentialStream
, riid
) ||
104 IsEqualGUID(&IID_IStream
, riid
)) {
106 InterlockedIncrement( &This
->RefCount
);
109 return E_NOINTERFACE
;
112 static ULONG WINAPI
RpcStream_AddRef(LPSTREAM iface
)
114 RpcStreamImpl
*This
= impl_from_IStream(iface
);
115 return InterlockedIncrement( &This
->RefCount
);
118 static ULONG WINAPI
RpcStream_Release(LPSTREAM iface
)
120 RpcStreamImpl
*This
= impl_from_IStream(iface
);
121 ULONG ref
= InterlockedDecrement( &This
->RefCount
);
123 TRACE("size=%d\n", *This
->size
);
124 This
->pMsg
->Buffer
= This
->data
+ *This
->size
;
125 HeapFree(GetProcessHeap(),0,This
);
131 static HRESULT WINAPI
RpcStream_Read(LPSTREAM iface
,
136 RpcStreamImpl
*This
= impl_from_IStream(iface
);
138 if (This
->pos
+ cb
> *This
->size
)
140 cb
= *This
->size
- This
->pos
;
144 memcpy(pv
, This
->data
+ This
->pos
, cb
);
147 if (pcbRead
) *pcbRead
= cb
;
151 static HRESULT WINAPI
RpcStream_Write(LPSTREAM iface
,
156 RpcStreamImpl
*This
= impl_from_IStream(iface
);
157 if (This
->data
+ cb
> (unsigned char *)This
->pMsg
->RpcMsg
->Buffer
+ This
->pMsg
->BufferLength
)
158 return STG_E_MEDIUMFULL
;
159 memcpy(This
->data
+ This
->pos
, pv
, cb
);
161 if (This
->pos
> *This
->size
) *This
->size
= This
->pos
;
162 if (pcbWritten
) *pcbWritten
= cb
;
166 static HRESULT WINAPI
RpcStream_Seek(LPSTREAM iface
,
169 ULARGE_INTEGER
*newPos
)
171 RpcStreamImpl
*This
= impl_from_IStream(iface
);
173 case STREAM_SEEK_SET
:
174 This
->pos
= move
.u
.LowPart
;
176 case STREAM_SEEK_CUR
:
177 This
->pos
= This
->pos
+ move
.u
.LowPart
;
179 case STREAM_SEEK_END
:
180 This
->pos
= *This
->size
+ move
.u
.LowPart
;
183 return STG_E_INVALIDFUNCTION
;
186 newPos
->u
.LowPart
= This
->pos
;
187 newPos
->u
.HighPart
= 0;
192 static HRESULT WINAPI
RpcStream_SetSize(LPSTREAM iface
,
193 ULARGE_INTEGER newSize
)
195 RpcStreamImpl
*This
= impl_from_IStream(iface
);
196 *This
->size
= newSize
.u
.LowPart
;
200 static const IStreamVtbl RpcStream_Vtbl
=
202 RpcStream_QueryInterface
,
212 NULL
, /* LockRegion */
213 NULL
, /* UnlockRegion */
218 static LPSTREAM
RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg
, BOOL init
)
221 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(RpcStreamImpl
));
222 if (!This
) return NULL
;
223 This
->IStream_iface
.lpVtbl
= &RpcStream_Vtbl
;
225 This
->pMsg
= pStubMsg
;
226 This
->size
= (LPDWORD
)pStubMsg
->Buffer
;
227 This
->data
= (unsigned char*)(This
->size
+ 1);
229 if (init
) *This
->size
= 0;
230 TRACE("init size=%d\n", *This
->size
);
231 return (LPSTREAM
)This
;
234 static const IID
* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg
, unsigned char *pMemory
, PFORMAT_STRING pFormat
)
237 if (!pFormat
) return &IID_IUnknown
;
238 TRACE("format=%02x %02x\n", pFormat
[0], pFormat
[1]);
239 if (pFormat
[0] != RPC_FC_IP
) FIXME("format=%d\n", pFormat
[0]);
240 if (pFormat
[1] == RPC_FC_CONSTANT_IID
) {
241 riid
= (const IID
*)&pFormat
[2];
243 ComputeConformance(pStubMsg
, pMemory
, pFormat
+2, 0);
244 riid
= (const IID
*)pStubMsg
->MaxCount
;
246 if (!riid
) riid
= &IID_IUnknown
;
247 TRACE("got %s\n", debugstr_guid(riid
));
251 /***********************************************************************
252 * NdrInterfacePointerMarshall [RPCRT4.@]
254 unsigned char * WINAPI
NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg
,
255 unsigned char *pMemory
,
256 PFORMAT_STRING pFormat
)
258 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
262 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
263 pStubMsg
->MaxCount
= 0;
264 if (!LoadCOM()) return NULL
;
265 if (pStubMsg
->Buffer
+ sizeof(DWORD
) <= (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
266 stream
= RpcStream_Create(pStubMsg
, TRUE
);
269 hr
= COM_MarshalInterface(stream
, riid
, (LPUNKNOWN
)pMemory
,
270 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
275 IStream_Release(stream
);
277 RpcRaiseException(hr
);
283 /***********************************************************************
284 * NdrInterfacePointerUnmarshall [RPCRT4.@]
286 unsigned char * WINAPI
NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg
,
287 unsigned char **ppMemory
,
288 PFORMAT_STRING pFormat
,
289 unsigned char fMustAlloc
)
294 TRACE("(%p,%p,%p,%d)\n", pStubMsg
, ppMemory
, pFormat
, fMustAlloc
);
295 if (!LoadCOM()) return NULL
;
296 *(LPVOID
*)ppMemory
= NULL
;
297 if (pStubMsg
->Buffer
+ sizeof(DWORD
) < (unsigned char *)pStubMsg
->RpcMsg
->Buffer
+ pStubMsg
->BufferLength
) {
298 stream
= RpcStream_Create(pStubMsg
, FALSE
);
299 if (!stream
) RpcRaiseException(E_OUTOFMEMORY
);
300 if (*((RpcStreamImpl
*)stream
)->size
!= 0)
301 hr
= COM_UnmarshalInterface(stream
, &IID_NULL
, (LPVOID
*)ppMemory
);
304 IStream_Release(stream
);
306 RpcRaiseException(hr
);
311 /***********************************************************************
312 * NdrInterfacePointerBufferSize [RPCRT4.@]
314 void WINAPI
NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg
,
315 unsigned char *pMemory
,
316 PFORMAT_STRING pFormat
)
318 const IID
*riid
= get_ip_iid(pStubMsg
, pMemory
, pFormat
);
321 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
322 if (!LoadCOM()) return;
323 COM_GetMarshalSizeMax(&size
, riid
, (LPUNKNOWN
)pMemory
,
324 pStubMsg
->dwDestContext
, pStubMsg
->pvDestContext
,
326 TRACE("size=%d\n", size
);
327 pStubMsg
->BufferLength
+= sizeof(DWORD
) + size
;
330 /***********************************************************************
331 * NdrInterfacePointerMemorySize [RPCRT4.@]
333 ULONG WINAPI
NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg
,
334 PFORMAT_STRING pFormat
)
338 TRACE("(%p,%p)\n", pStubMsg
, pFormat
);
340 size
= *(ULONG
*)pStubMsg
->Buffer
;
341 pStubMsg
->Buffer
+= 4;
342 pStubMsg
->MemorySize
+= 4;
344 pStubMsg
->Buffer
+= size
;
346 return pStubMsg
->MemorySize
;
349 /***********************************************************************
350 * NdrInterfacePointerFree [RPCRT4.@]
352 void WINAPI
NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg
,
353 unsigned char *pMemory
,
354 PFORMAT_STRING pFormat
)
356 LPUNKNOWN pUnk
= (LPUNKNOWN
)pMemory
;
357 TRACE("(%p,%p,%p)\n", pStubMsg
, pMemory
, pFormat
);
358 if (pUnk
) IUnknown_Release(pUnk
);
361 /***********************************************************************
362 * NdrOleAllocate [RPCRT4.@]
364 void * WINAPI
NdrOleAllocate(SIZE_T Size
)
366 if (!LoadCOM()) return NULL
;
367 return COM_MemAlloc(Size
);
370 /***********************************************************************
371 * NdrOleFree [RPCRT4.@]
373 void WINAPI
NdrOleFree(void *NodeToFree
)
375 if (!LoadCOM()) return;
376 COM_MemFree(NodeToFree
);
379 /***********************************************************************
380 * Helper function to create a proxy.
381 * Probably similar to NdrpCreateProxy.
383 HRESULT
create_proxy(REFIID iid
, IUnknown
*pUnkOuter
, IRpcProxyBuffer
**pproxy
, void **ppv
)
386 IPSFactoryBuffer
*psfac
;
389 if(!LoadCOM()) return E_FAIL
;
391 r
= COM_GetPSClsid( iid
, &clsid
);
392 if(FAILED(r
)) return r
;
394 r
= COM_GetClassObject( &clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void**)&psfac
);
395 if(FAILED(r
)) return r
;
397 r
= IPSFactoryBuffer_CreateProxy(psfac
, pUnkOuter
, iid
, pproxy
, ppv
);
399 IPSFactoryBuffer_Release(psfac
);
403 /***********************************************************************
404 * Helper function to create a stub.
405 * This probably looks very much like NdrpCreateStub.
407 HRESULT
create_stub(REFIID iid
, IUnknown
*pUnk
, IRpcStubBuffer
**ppstub
)
410 IPSFactoryBuffer
*psfac
;
413 if(!LoadCOM()) return E_FAIL
;
415 r
= COM_GetPSClsid( iid
, &clsid
);
416 if(FAILED(r
)) return r
;
418 r
= COM_GetClassObject( &clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IPSFactoryBuffer
, (void**)&psfac
);
419 if(FAILED(r
)) return r
;
421 r
= IPSFactoryBuffer_CreateStub(psfac
, iid
, pUnk
, ppstub
);
423 IPSFactoryBuffer_Release(psfac
);