diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index d542e125738..301feeafa30 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -15,6 +15,7 @@ C_SRCS = \ cpsf.c \ cstub.c \ ndr_midl.c \ + ndr_ole.c \ ndr_stubless.c \ rpc_binding.c \ rpc_message.c \ diff --git a/dlls/rpcrt4/ndr_ole.c b/dlls/rpcrt4/ndr_ole.c new file mode 100644 index 00000000000..80a03aa0452 --- /dev/null +++ b/dlls/rpcrt4/ndr_ole.c @@ -0,0 +1,332 @@ +/* + * OLE32 callouts, COM interface marshalling + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + * - what are the marshalling functions supposed to return? + * - finish RpcStream_Vtbl + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "wine/obj_base.h" +#include "wine/obj_storage.h" +#include "wine/obj_marshal.h" +#include "wine/obj_channel.h" + +#include "rpcndr.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static HMODULE hOLE; + +static HRESULT WINAPI (*COM_GetMarshalSizeMax)(ULONG *,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT WINAPI (*COM_MarshalInterface)(LPSTREAM,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT WINAPI (*COM_UnmarshalInterface)(LPSTREAM,REFIID,LPVOID*); +static HRESULT WINAPI (*COM_ReleaseMarshalData)(LPSTREAM); +static HRESULT WINAPI (*COM_GetClassObject)(REFCLSID,DWORD,COSERVERINFO *,REFIID,LPVOID *); +static HRESULT WINAPI (*COM_GetPSClsid)(REFIID,CLSID *); +static LPVOID WINAPI (*COM_MemAlloc)(ULONG); +static void WINAPI (*COM_MemFree)(LPVOID); + +static HMODULE LoadCOM(void) +{ + if (hOLE) return hOLE; + hOLE = LoadLibraryA("OLE32.DLL"); + if (!hOLE) return 0; + COM_GetMarshalSizeMax = (LPVOID)GetProcAddress(hOLE, "CoGetMarshalSizeMax"); + COM_MarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoMarshalInterface"); + COM_UnmarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoUnmarshalInterface"); + COM_ReleaseMarshalData = (LPVOID)GetProcAddress(hOLE, "CoReleaseMarshalData"); + COM_GetClassObject = (LPVOID)GetProcAddress(hOLE, "CoGetClassObject"); + COM_GetPSClsid = (LPVOID)GetProcAddress(hOLE, "CoGetPSClsid"); + COM_MemAlloc = (LPVOID)GetProcAddress(hOLE, "CoTaskMemAlloc"); + COM_MemFree = (LPVOID)GetProcAddress(hOLE, "CoTaskMemFree"); + return hOLE; +} + +/* CoMarshalInterface/CoUnmarshalInterface works on streams, + * so implement a simple stream on top of the RPC buffer + * (which also implements the MInterfacePointer structure) */ +typedef struct RpcStreamImpl +{ + ICOM_VFIELD(IStream); + DWORD RefCount; + PMIDL_STUB_MESSAGE pMsg; + LPDWORD size; + char *data; + DWORD pos; +} RpcStreamImpl; + +static HRESULT WINAPI RpcStream_QueryInterface(LPSTREAM iface, + REFIID riid, + LPVOID *obj) +{ + ICOM_THIS(RpcStreamImpl, iface); + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_ISequentialStream, riid) || + IsEqualGUID(&IID_IStream, riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RpcStream_AddRef(LPSTREAM iface) +{ + ICOM_THIS(RpcStreamImpl, iface); + return ++(This->RefCount); +} + +static ULONG WINAPI RpcStream_Release(LPSTREAM iface) +{ + ICOM_THIS(RpcStreamImpl, iface); + if (!--(This->RefCount)) { + TRACE("size=%ld\n", *This->size); + This->pMsg->Buffer = This->data + *This->size; + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->RefCount; +} + +static HRESULT WINAPI RpcStream_Read(LPSTREAM iface, + void *pv, + ULONG cb, + ULONG *pcbRead) +{ + ICOM_THIS(RpcStreamImpl, iface); + if (This->pos + cb > *This->size) cb = *This->size - This->pos; + if (cb) { + memcpy(pv, This->data + This->pos, cb); + This->pos += cb; + } + if (pcbRead) *pcbRead = cb; + return S_OK; +} + +static HRESULT WINAPI RpcStream_Write(LPSTREAM iface, + const void *pv, + ULONG cb, + ULONG *pcbWritten) +{ + ICOM_THIS(RpcStreamImpl, iface); + memcpy(This->data + This->pos, pv, cb); + This->pos += cb; + if (This->pos > *This->size) *This->size = This->pos; + if (pcbWritten) *pcbWritten = cb; + return S_OK; +} + +static HRESULT WINAPI RpcStream_Seek(LPSTREAM iface, + LARGE_INTEGER move, + DWORD origin, + ULARGE_INTEGER *newPos) +{ + ICOM_THIS(RpcStreamImpl, iface); + switch (origin) { + case STREAM_SEEK_SET: + This->pos = move.s.LowPart; + break; + case STREAM_SEEK_CUR: + This->pos = This->pos + move.s.LowPart; + break; + case STREAM_SEEK_END: + This->pos = *This->size + move.s.LowPart; + break; + default: + return STG_E_INVALIDFUNCTION; + } + if (newPos) { + newPos->s.LowPart = This->pos; + newPos->s.HighPart = 0; + } + return S_OK; +} + +static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface, + ULARGE_INTEGER newSize) +{ + ICOM_THIS(RpcStreamImpl, iface); + *This->size = newSize.s.LowPart; + return S_OK; +} + +static ICOM_VTABLE(IStream) RpcStream_Vtbl = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + RpcStream_QueryInterface, + RpcStream_AddRef, + RpcStream_Release, + RpcStream_Read, + RpcStream_Write, + RpcStream_Seek, + RpcStream_SetSize, + NULL, /* CopyTo */ + NULL, /* Commit */ + NULL, /* Revert */ + NULL, /* LockRegion */ + NULL, /* UnlockRegion */ + NULL, /* Stat */ + NULL /* Clone */ +}; + +static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init) +{ + RpcStreamImpl *This; + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(RpcStreamImpl)); + if (!This) return NULL; + This->lpVtbl = &RpcStream_Vtbl; + This->RefCount = 1; + This->pMsg = pStubMsg; + This->size = (LPDWORD)pStubMsg->Buffer; + This->data = (char*)(This->size + 1); + This->pos = 0; + if (init) *This->size = 0; + TRACE("init size=%ld\n", *This->size); + return (LPSTREAM)This; +} + +/*********************************************************************** + * NdrInterfacePointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = (const IID *)pStubMsg->MaxCount; + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (!riid) riid = &IID_IUnknown; + pStubMsg->MaxCount = 0; + if (!LoadCOM()) return NULL; + stream = RpcStream_Create(pStubMsg, TRUE); + hr = COM_MarshalInterface(stream, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + IStream_Release(stream); + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (!LoadCOM()) return NULL; + *(LPVOID*)ppMemory = NULL; + stream = RpcStream_Create(pStubMsg, FALSE); + hr = COM_UnmarshalInterface(stream, &IID_NULL, (LPVOID*)ppMemory); + IStream_Release(stream); + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = (const IID *)pStubMsg->MaxCount; + ULONG size = 0; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (!riid) riid = &IID_IUnknown; + if (!LoadCOM()) return; + hr = COM_GetMarshalSizeMax(&size, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + TRACE("size=%ld\n", size); + pStubMsg->BufferLength += sizeof(DWORD) + size; +} + +/*********************************************************************** + * NdrInterfacePointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + return 0; +} + +/*********************************************************************** + * NdrInterfacePointerFree [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + LPUNKNOWN pUnk = (LPUNKNOWN)pMemory; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pUnk) IUnknown_Release(pUnk); +} + +/*********************************************************************** + * NdrOleAllocate [RPCRT4.@] + */ +void * WINAPI NdrOleAllocate(size_t Size) +{ + if (!LoadCOM()) return NULL; + return COM_MemAlloc(Size); +} + +/*********************************************************************** + * NdrOleFree [RPCRT4.@] + */ +void WINAPI NdrOleFree(void *NodeToFree) +{ + if (!LoadCOM()) return; + COM_MemFree(NodeToFree); +} + +/* internal */ +HRESULT RPCRT4_GetPSFactory(REFIID riid, LPPSFACTORYBUFFER *pPS) +{ + HRESULT hr; + CLSID clsid; + + if (!LoadCOM()) return RPC_E_UNEXPECTED; + hr = COM_GetPSClsid(riid, &clsid); + if (FAILED(hr)) return hr; + hr = COM_GetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, + &IID_IPSFactoryBuffer, (LPVOID *)pPS); + return hr; +} diff --git a/dlls/rpcrt4/rpcrt4.spec b/dlls/rpcrt4/rpcrt4.spec index a99e7b14063..f3b1d0d010b 100644 --- a/dlls/rpcrt4/rpcrt4.spec +++ b/dlls/rpcrt4/rpcrt4.spec @@ -245,8 +245,8 @@ init RPCRT4_LibMain @ stub NdrMesTypeFree2 @ stub NdrNsGetBuffer @ stub NdrNsSendReceive -@ stub NdrOleAllocate -@ stub NdrOleFree +@ stdcall NdrOleAllocate(long) NdrOleAllocate +@ stdcall NdrOleFree(ptr) NdrOleFree @ stub NdrPipePull @ stub NdrPipePush @ stub NdrPipeSendReceive @@ -326,11 +326,11 @@ init RPCRT4_LibMain @ stub NdrHardStructMarshall @ stub NdrHardStructMemorySize @ stub NdrHardStructUnmarshall -@ stub NdrInterfacePointerBufferSize -@ stub NdrInterfacePointerFree -@ stub NdrInterfacePointerMarshall -@ stub NdrInterfacePointerMemorySize -@ stub NdrInterfacePointerUnmarshall +@ stdcall NdrInterfacePointerBufferSize(ptr ptr ptr) NdrInterfacePointerBufferSize +@ stdcall NdrInterfacePointerFree(ptr ptr ptr) NdrInterfacePointerFree +@ stdcall NdrInterfacePointerMarshall(ptr ptr ptr) NdrInterfacePointerMarshall +@ stdcall NdrInterfacePointerMemorySize(ptr ptr) NdrInterfacePointerMemorySize +@ stdcall NdrInterfacePointerUnmarshall(ptr ptr ptr long) NdrInterfacePointerUnmarshall @ stub NdrNonConformantStringBufferSize @ stub NdrNonConformantStringMarshall @ stub NdrNonConformantStringMemorySize