From: Gé van Geldorp Date: Fri, 31 Dec 2004 15:52:05 +0000 (+0000) Subject: Import and merge Wine-20041201 X-Git-Tag: backups/ext2@33480~260 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=995dc47fd0bca344700dfeb2a75cda84f35de533 Import and merge Wine-20041201 svn path=/trunk/; revision=12595 --- diff --git a/reactos/lib/rpcrt4/Makefile b/reactos/lib/rpcrt4/Makefile new file mode 100644 index 00000000000..63b677ffcf6 --- /dev/null +++ b/reactos/lib/rpcrt4/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile 9303 2004-05-04 20:10:07Z navaraf $ + +PATH_TO_TOP = ../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/rpcrt4/Makefile.in b/reactos/lib/rpcrt4/Makefile.in new file mode 100644 index 00000000000..b0df10c1eb9 --- /dev/null +++ b/reactos/lib/rpcrt4/Makefile.in @@ -0,0 +1,29 @@ +EXTRADEFS = -D_RPCRT4_ -DCOM_NO_WINDOWS_H -DMSWMSG +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = rpcrt4.dll +IMPORTS = iphlpapi advapi32 kernel32 ntdll +EXTRALIBS = -luuid + +C_SRCS = \ + cproxy.c \ + cpsf.c \ + cstub.c \ + ndr_marshall.c \ + ndr_midl.c \ + ndr_ole.c \ + ndr_stubless.c \ + rpc_binding.c \ + rpc_epmap.c \ + rpc_message.c \ + rpc_server.c \ + rpcrt4_main.c \ + rpcss_np_client.c + +SUBDIRS = tests + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/rpcrt4/Makefile.ros-template b/reactos/lib/rpcrt4/Makefile.ros-template new file mode 100644 index 00000000000..8ffa50640c1 --- /dev/null +++ b/reactos/lib/rpcrt4/Makefile.ros-template @@ -0,0 +1,22 @@ +# $Id: Makefile.ros-template 11910 2004-12-03 23:37:44Z blight $ + +TARGET_NAME = rpcrt4 + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ -Wall + +TARGET_SDKLIBS = @IMPORTS@ winmm.a wine.a wine_uuid.a ntdll.a + +TARGET_BASE = $(TARGET_BASE_LIB_RPCRT4) + +TARGET_RC_BINSRC = @RC_BINSRC@ +TARGET_RC_BINARIES = @RC_BINARIES@ + +TARGET_NORC = yes + +default: all + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/rpcrt4/cproxy.c b/reactos/lib/rpcrt4/cproxy.c new file mode 100644 index 00000000000..f5645ab79df --- /dev/null +++ b/reactos/lib/rpcrt4/cproxy.c @@ -0,0 +1,342 @@ +/* + * COM proxy implementation + * + * 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: Handle non-i386 architectures + * Get rid of #if 0'ed code. + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" +#include "rpcproxy.h" + +#include "cpsf.h" +#include "ndr_misc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +struct StublessThunk; + +/* I don't know what MS's std proxy structure looks like, + so this probably doesn't match, but that shouldn't matter */ +typedef struct { + IRpcProxyBufferVtbl *lpVtbl; + LPVOID *PVtbl; + DWORD RefCount; + const MIDL_STUBLESS_PROXY_INFO *stubless; + const IID* piid; + LPUNKNOWN pUnkOuter; + PCInterfaceName name; + LPPSFACTORYBUFFER pPSFactory; + LPRPCCHANNELBUFFER pChannel; + struct StublessThunk *thunks; +} StdProxyImpl; + +static IRpcProxyBufferVtbl StdProxy_Vtbl; + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +/* How the Windows stubless proxy thunks work is explained at + * http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, + * but I'll use a slightly different method, to make life easier */ + +#if defined(__i386__) + +#include "pshpack1.h" + +struct StublessThunk { + BYTE push; + DWORD index; + BYTE call; + LONG handler; + BYTE ret; + WORD bytes; + BYTE pad[3]; +}; + +#include "poppack.h" + +/* adjust the stack size since we don't use Windows's method */ +#define STACK_ADJUST sizeof(DWORD) + +#define FILL_STUBLESS(x,idx,stk) \ + x->push = 0x68; /* pushl [immediate] */ \ + x->index = (idx); \ + x->call = 0xe8; /* call [near] */ \ + x->handler = (char*)ObjectStubless - (char*)&x->ret; \ + x->ret = 0xc2; /* ret [immediate] */ \ + x->bytes = stk; \ + x->pad[0] = 0x8d; /* leal (%esi),%esi */ \ + x->pad[1] = 0x76; \ + x->pad[2] = 0x00; + +static HRESULT WINAPI ObjectStubless(DWORD index) +{ + char *args = (char*)(&index + 2); + LPVOID iface = *(LPVOID*)args; + + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + + PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("(%p)->(%ld)([%d bytes]) ret=%08lx\n", iface, index, bytes, *(DWORD*)(args+bytes)); + + return RPCRT4_NdrClientCall2(This->stubless->pStubDesc, fs, args); +} + +#else /* __i386__ */ + +/* can't do that on this arch */ +struct StublessThunk { int dummy; }; +#define FILL_STUBLESS(x,idx,stk) \ + ERR("stubless proxies are not supported on this architecture\n"); +#define STACK_ADJUST 0 + +#endif /* __i386__ */ + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + PCInterfaceName name, + CInterfaceProxyVtbl *vtbl, + CInterfaceStubVtbl *svtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj) +{ + StdProxyImpl *This; + const MIDL_STUBLESS_PROXY_INFO *stubless = NULL; + + TRACE("(%p,%p,%p,%p,%p) %s\n", pUnkOuter, vtbl, pPSFactory, ppProxy, ppvObj, name); + + /* I can't find any other way to detect stubless proxies than this hack */ + if (!IsEqualGUID(vtbl->header.piid, riid)) { + stubless = *(const void **)vtbl; + vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1); + TRACE("stubless=%p\n", stubless); + } + + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during proxy creation\n"); + return RPC_E_UNEXPECTED; + } + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl)); + if (!This) return E_OUTOFMEMORY; + + if (stubless) { + unsigned i, count = svtbl->header.DispatchTableCount; + /* Maybe the original vtbl is just modified directly to point at + * ObjectStublessClientXXX thunks in real Windows, but I don't like it + */ + TRACE("stubless thunks: count=%d\n", count); + This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); + This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); + for (i=0; ithunks[i]; + if (vtbl->Vtbl[i] == (LPVOID)-1) { + PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("method %d: stacksize=%d\n", i, bytes); + FILL_STUBLESS(thunk, i, bytes) + This->PVtbl[i] = thunk; + } + else { + memset(thunk, 0, sizeof(struct StublessThunk)); + This->PVtbl[i] = vtbl->Vtbl[i]; + } + } + } + else + This->PVtbl = vtbl->Vtbl; + + This->lpVtbl = &StdProxy_Vtbl; + /* 1 reference for the proxy and 1 for the object */ + This->RefCount = 2; + This->stubless = stubless; + This->piid = vtbl->header.piid; + This->pUnkOuter = pUnkOuter; + This->name = name; + This->pPSFactory = pPSFactory; + This->pChannel = NULL; + *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; + *ppvObj = &This->PVtbl; + IPSFactoryBuffer_AddRef(pPSFactory); + + return S_OK; +} + +static void WINAPI StdProxy_Destruct(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + + if (This->pChannel) + IRpcProxyBuffer_Disconnect(iface); + + IPSFactoryBuffer_Release(This->pPSFactory); + if (This->thunks) { + HeapFree(GetProcessHeap(),0,This->PVtbl); + HeapFree(GetProcessHeap(),0,This->thunks); + } + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(This->piid,riid)) { + *obj = &This->PVtbl; + This->RefCount++; + return S_OK; + } + + if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) { + *obj = &This->lpVtbl; + This->RefCount++; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->AddRef()\n",This); + + return ++(This->RefCount); +} + +static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Release()\n",This); + + if (!--(This->RefCount)) { + StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); + return 0; + } + return This->RefCount; +} + +static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, + LPRPCCHANNELBUFFER pChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Connect(%p)\n",This,pChannel); + + This->pChannel = pChannel; + IRpcChannelBuffer_AddRef(pChannel); + return S_OK; +} + +static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Disconnect()\n",This); + + IRpcChannelBuffer_Release(This->pChannel); + This->pChannel = NULL; +} + +static IRpcProxyBufferVtbl StdProxy_Vtbl = +{ + StdProxy_QueryInterface, + StdProxy_AddRef, + StdProxy_Release, + StdProxy_Connect, + StdProxy_Disconnect +}; + +HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name); + + *ppChannel = This->pChannel; + return S_OK; +} + +HRESULT WINAPI StdProxy_GetIID(LPVOID iface, + const IID **ppiid) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name); + + *ppiid = This->piid; + return S_OK; +} + +HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface, + REFIID riid, + LPVOID *ppvObj) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p) %s\n",This,debugstr_guid(riid),ppvObj,This->name); + return IUnknown_QueryInterface(This->pUnkOuter,riid,ppvObj); +} + +ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->AddRef() %s\n",This,This->name); +#if 0 /* interface refcounting */ + return ++(This->RefCount); +#else /* object refcounting */ + return IUnknown_AddRef(This->pUnkOuter); +#endif +} + +ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->Release() %s\n",This,This->name); +#if 0 /* interface refcounting */ + if (!--(This->RefCount)) { + StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); + return 0; + } + return This->RefCount; +#else /* object refcounting */ + return IUnknown_Release(This->pUnkOuter); +#endif +} + +HRESULT WINAPI +CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid, + LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv ) +{ + FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv); + return E_NOTIMPL; +} diff --git a/reactos/lib/rpcrt4/cpsf.c b/reactos/lib/rpcrt4/cpsf.c new file mode 100644 index 00000000000..0bd8eca326c --- /dev/null +++ b/reactos/lib/rpcrt4/cpsf.c @@ -0,0 +1,263 @@ +/* + * COM proxy/stub factory (CStdPSFactory) implementation + * + * 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 + */ + +#include +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static BOOL FindProxyInfo(const ProxyFileInfo **pProxyFileList, REFIID riid, const ProxyFileInfo **pProxyInfo, int *pIndex) +{ + while (*pProxyFileList) { + if ((*pProxyFileList)->pIIDLookupRtn(riid, pIndex)) { + *pProxyInfo = *pProxyFileList; + TRACE("found: ProxyInfo %p Index %d\n", *pProxyInfo, *pIndex); + return TRUE; + } + pProxyFileList++; + } + TRACE("not found\n"); + return FALSE; +} + +static HRESULT WINAPI CStdPSFactory_QueryInterface(LPPSFACTORYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",iface,debugstr_guid(riid),obj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IPSFactoryBuffer,riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI CStdPSFactory_AddRef(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->AddRef()\n",iface); + return ++(This->RefCount); +} + +static ULONG WINAPI CStdPSFactory_Release(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->Release()\n",iface); + return --(This->RefCount); +} + +static HRESULT WINAPI CStdPSFactory_CreateProxy(LPPSFACTORYBUFFER iface, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppv) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateProxy(%p,%s,%p,%p)\n",iface,pUnkOuter, + debugstr_guid(riid),ppProxy,ppv); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + return StdProxy_Construct(riid, pUnkOuter, ProxyInfo->pNamesArray[Index], + ProxyInfo->pProxyVtblList[Index], + ProxyInfo->pStubVtblList[Index], iface, ppProxy, ppv); +} + +static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, + REFIID riid, + LPUNKNOWN pUnkServer, + LPRPCSTUBBUFFER *ppStub) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateStub(%s,%p,%p)\n",iface,debugstr_guid(riid), + pUnkServer,ppStub); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], iface, ppStub); +} + +static IPSFactoryBufferVtbl CStdPSFactory_Vtbl = +{ + CStdPSFactory_QueryInterface, + CStdPSFactory_AddRef, + CStdPSFactory_Release, + CStdPSFactory_CreateProxy, + CStdPSFactory_CreateStub +}; + +/*********************************************************************** + * NdrDllGetClassObject [RPCRT4.@] + */ +HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid, + CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + *ppv = NULL; + if (!pPSFactoryBuffer->lpVtbl) { + pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; + pPSFactoryBuffer->RefCount = 0; + pPSFactoryBuffer->pProxyFileList = pProxyFileList; + } + if (IsEqualGUID(rclsid, pclsid)) + return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} + +/*********************************************************************** + * NdrDllCanUnloadNow [RPCRT4.@] + */ +HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + return !(pPSFactoryBuffer->RefCount); +} + +/*********************************************************************** + * NdrDllRegisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + HKEY key, subkey; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* register interfaces to point to clsid */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("registering %s %s => %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + if (name) + RegSetValueExA(key, NULL, 0, REG_SZ, name, strlen(name)); + if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + snprintf(module, sizeof(module), "{%s}", clsid); + RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + pProxyFileList++; + } + + /* register clsid to point to module */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("registering CLSID %s => %s\n", clsid, module); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} + +/*********************************************************************** + * NdrDllUnregisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllUnregisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* unregister interfaces */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("unregistering %s %s <= %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + pProxyFileList++; + } + + /* unregister clsid */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("unregistering CLSID %s <= %s\n", clsid, module); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} diff --git a/reactos/lib/rpcrt4/cpsf.h b/reactos/lib/rpcrt4/cpsf.h new file mode 100644 index 00000000000..12f33757f64 --- /dev/null +++ b/reactos/lib/rpcrt4/cpsf.h @@ -0,0 +1,44 @@ +/* + * COM proxy definitions + * + * 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 + */ + +#ifndef __WINE_CPSF_H +#define __WINE_CPSF_H + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + PCInterfaceName name, + CInterfaceProxyVtbl *vtbl, + CInterfaceStubVtbl *svtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj); +HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel); +HRESULT WINAPI StdProxy_GetIID(LPVOID iface, + const IID **piid); + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); + +#endif /* __WINE_CPSF_H */ diff --git a/reactos/lib/rpcrt4/cstub.c b/reactos/lib/rpcrt4/cstub.c new file mode 100644 index 00000000000..bf590d8ea17 --- /dev/null +++ b/reactos/lib/rpcrt4/cstub.c @@ -0,0 +1,169 @@ +/* + * COM stub (CStdStubBuffer) implementation + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define STUB_HEADER(This) (((CInterfaceStubHeader*)((This)->lpVtbl))[-1]) + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) +{ + CStdStubBuffer *This; + + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer)); + if (!This) return E_OUTOFMEMORY; + + This->lpVtbl = &vtbl->Vtbl; + This->RefCount = 1; + This->pvServerObject = pUnkServer; + This->pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)This; + + IUnknown_AddRef(This->pvServerObject); + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + +HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IRpcStubBuffer,riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->AddRef()\n",This); + return ++(This->RefCount); +} + +ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, + LPPSFACTORYBUFFER pPSF) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Release()\n",This); + + if (!--(This->RefCount)) { + if(This->pvServerObject) + IUnknown_Release(This->pvServerObject); + if(This->pPSFactory) + IPSFactoryBuffer_Release(This->pPSFactory); + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->RefCount; +} + +HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); + This->pvServerObject = lpUnkServer; + return S_OK; +} + +void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Disconnect()\n",This); + This->pvServerObject = NULL; +} + +HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, + PRPCOLEMESSAGE pMsg, + LPRPCCHANNELBUFFER pChannel) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + DWORD dwPhase = STUB_UNMARSHAL; + TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel); + + STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + return S_OK; +} + +LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface, + REFIID riid) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->IsIIDSupported(%s)\n",This,debugstr_guid(riid)); + return IsEqualGUID(STUB_HEADER(This).piid, riid) ? iface : NULL; +} + +ULONG WINAPI CStdStubBuffer_CountRefs(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->CountRefs()\n",This); + return This->RefCount; +} + +HRESULT WINAPI CStdStubBuffer_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, + LPVOID *ppv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); + return S_OK; +} + +void WINAPI CStdStubBuffer_DebugServerRelease(LPRPCSTUBBUFFER iface, + LPVOID pv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerRelease(%p)\n",This,pv); +} diff --git a/reactos/lib/rpcrt4/ndr_marshall.c b/reactos/lib/rpcrt4/ndr_marshall.c new file mode 100644 index 00000000000..33ff8f59ddd --- /dev/null +++ b/reactos/lib/rpcrt4/ndr_marshall.c @@ -0,0 +1,2118 @@ +/* + * NDR data marshalling + * + * Copyright 2002 Greg Turner + * + * 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 + */ + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "ndr_misc.h" +#include "rpcndr.h" + +#include "wine/unicode.h" +#include "wine/rpcfc.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define BUFFER_PARANOIA 20 + +#if defined(__i386__) + #define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((UINT32 *)(pchar)) = (uint32)) + + #define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (*((UINT32 *)(pchar))) +#else + /* these would work for i386 too, but less efficient */ + #define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*(pchar) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+1) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+2) = LOBYTE(HIWORD(uint32)), \ + *((pchar)+3) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + + #define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*(pchar), *((pchar)+1)), \ + MAKEWORD(*((pchar)+2), *((pchar)+3)))) +#endif + +#define BIG_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((pchar)+3) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+2) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+1) = LOBYTE(HIWORD(uint32)), \ + *(pchar) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + +#define BIG_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*((pchar)+3), *((pchar)+2)), \ + MAKEWORD(*((pchar)+1), *(pchar)))) + +#ifdef NDR_LOCAL_IS_BIG_ENDIAN + #define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + BIG_ENDIAN_UINT32_WRITE(pchar, uint32) + #define NDR_LOCAL_UINT32_READ(pchar) \ + BIG_ENDIAN_UINT32_READ(pchar) +#else + #define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) + #define NDR_LOCAL_UINT32_READ(pchar) \ + LITTLE_ENDIAN_UINT32_READ(pchar) +#endif + +/* _Align must be the desired alignment minus 1, + * e.g. ALIGN_LENGTH(len, 3) to align on a dword boundary. */ +#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) +#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) +#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) +#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) + +#define STD_OVERFLOW_CHECK(_Msg) do { \ + TRACE("buffer=%d/%ld\n", _Msg->Buffer - _Msg->BufferStart, _Msg->BufferLength); \ + if (_Msg->Buffer > _Msg->BufferEnd) ERR("buffer overflow %d bytes\n", _Msg->Buffer - _Msg->BufferEnd); \ + } while (0) + +#define NDR_TABLE_SIZE 128 +#define NDR_TABLE_MASK 127 + +NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerMarshall, NdrPointerMarshall, + NdrPointerMarshall, NdrPointerMarshall, + /* 0x15 */ + NdrSimpleStructMarshall, NdrSimpleStructMarshall, + 0, 0, 0, + NdrComplexStructMarshall, + /* 0x1b */ + NdrConformantArrayMarshall, 0, 0, 0, 0, 0, + NdrComplexArrayMarshall, + /* 0x22 */ + NdrConformantStringMarshall, 0, 0, + NdrConformantStringMarshall, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerMarshall, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalMarshall +}; +NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerUnmarshall, NdrPointerUnmarshall, + NdrPointerUnmarshall, NdrPointerUnmarshall, + /* 0x15 */ + NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, + 0, 0, 0, + NdrComplexStructUnmarshall, + /* 0x1b */ + NdrConformantArrayUnmarshall, 0, 0, 0, 0, 0, + NdrComplexArrayUnmarshall, + /* 0x22 */ + NdrConformantStringUnmarshall, 0, 0, + NdrConformantStringUnmarshall, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerUnmarshall, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalUnmarshall +}; +NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerBufferSize, NdrPointerBufferSize, + NdrPointerBufferSize, NdrPointerBufferSize, + /* 0x15 */ + NdrSimpleStructBufferSize, NdrSimpleStructBufferSize, + 0, 0, 0, + NdrComplexStructBufferSize, + /* 0x1b */ + NdrConformantArrayBufferSize, 0, 0, 0, 0, 0, + NdrComplexArrayBufferSize, + /* 0x22 */ + NdrConformantStringBufferSize, 0, 0, + NdrConformantStringBufferSize, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerBufferSize, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalBufferSize +}; +NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerMemorySize, NdrPointerMemorySize, + NdrPointerMemorySize, NdrPointerMemorySize, + /* 0x15 */ + NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, + 0, 0, 0, + NdrComplexStructMemorySize, + /* 0x1b */ + NdrConformantArrayMemorySize, 0, 0, 0, 0, 0, + NdrComplexArrayMemorySize, + /* 0x22 */ + NdrConformantStringMemorySize, 0, 0, + NdrConformantStringMemorySize, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerMemorySize, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalMemorySize +}; +NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerFree, NdrPointerFree, + NdrPointerFree, NdrPointerFree, + /* 0x15 */ + NdrSimpleStructFree, NdrSimpleStructFree, + 0, 0, 0, + NdrComplexStructFree, + /* 0x1b */ + NdrConformantArrayFree, 0, 0, 0, 0, 0, + NdrComplexArrayFree, + /* 0x22 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerFree, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalFree +}; + +void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len) +{ + /* hmm, this is probably supposed to do more? */ + return pStubMsg->pfnAllocate(len); +} + +static void WINAPI NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer) +{ + pStubMsg->pfnFree(Pointer); +} + +PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +{ + pStubMsg->MaxCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + TRACE("unmarshalled conformance is %ld\n", pStubMsg->MaxCount); + return pFormat+4; +} + +PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def) +{ + BYTE dtype = pFormat[0] & 0xf; + DWORD ofs = (DWORD)pFormat[2] | ((DWORD)pFormat[3] << 8); + LPVOID ptr = NULL; + DWORD data = 0; + + if (pFormat[0] == 0xff) { + /* null descriptor */ + pStubMsg->MaxCount = def; + goto finish_conf; + } + + switch (pFormat[0] & 0xf0) { + case RPC_FC_NORMAL_CONFORMANCE: + TRACE("normal conformance, ofs=%ld\n", ofs); + ptr = pMemory + ofs; + break; + case RPC_FC_POINTER_CONFORMANCE: + TRACE("pointer conformance, ofs=%ld\n", ofs); + ptr = pStubMsg->Memory + ofs; + break; + case RPC_FC_TOP_LEVEL_CONFORMANCE: + TRACE("toplevel conformance, ofs=%ld\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop + ofs; + } + else { + /* -Os mode, MaxCount is already set */ + goto finish_conf; + } + break; + case RPC_FC_CONSTANT_CONFORMANCE: + data = ofs | ((DWORD)pFormat[1] << 16); + TRACE("constant conformance, val=%ld\n", data); + pStubMsg->MaxCount = data; + goto finish_conf; + case RPC_FC_TOP_LEVEL_MULTID_CONFORMANCE: + FIXME("toplevel multidimensional conformance, ofs=%ld\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop + ofs; + } + else { + /* ? */ + goto done_conf_grab; + } + break; + default: + FIXME("unknown conformance type %x\n", pFormat[0] & 0xf0); + } + + switch (pFormat[1]) { + case RPC_FC_DEREFERENCE: + ptr = *(LPVOID*)ptr; + break; + case RPC_FC_CALLBACK: + /* ofs is index into StubDesc->apfnExprEval */ + FIXME("handle callback\n"); + goto finish_conf; + default: + break; + } + + switch (dtype) { + case RPC_FC_LONG: + case RPC_FC_ULONG: + data = *(DWORD*)ptr; + break; + case RPC_FC_SHORT: + data = *(SHORT*)ptr; + break; + case RPC_FC_USHORT: + data = *(USHORT*)ptr; + break; + case RPC_FC_SMALL: + data = *(CHAR*)ptr; + break; + case RPC_FC_USMALL: + data = *(UCHAR*)ptr; + break; + default: + FIXME("unknown conformance data type %x\n", dtype); + goto done_conf_grab; + } + TRACE("dereferenced data type %x at %p, got %ld\n", dtype, ptr, data); + +done_conf_grab: + switch (pFormat[1]) { + case 0: /* no op */ + pStubMsg->MaxCount = data; + break; + case RPC_FC_DEREFERENCE: + /* already handled */ + break; + default: + FIXME("unknown conformance op %d\n", pFormat[1]); + goto finish_conf; + } + +finish_conf: + TRACE("resulting conformance is %ld\n", pStubMsg->MaxCount); + return pFormat+4; +} + + +/* + * NdrConformantString: + * + * What MS calls a ConformantString is, in DCE terminology, + * a Varying-Conformant String. + * [ + * maxlen: DWORD (max # of CHARTYPE characters, inclusive of '\0') + * offset: DWORD (actual string data begins at (offset) CHARTYPE's + * into unmarshalled string) + * length: DWORD (# of CHARTYPE characters, inclusive of '\0') + * [ + * data: CHARTYPE[maxlen] + * ] + * ], where CHARTYPE is the appropriate character type (specified externally) + * + */ + +/*********************************************************************** + * NdrConformantStringMarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, + unsigned char *pszMessage, PFORMAT_STRING pFormat) +{ + unsigned long len, esize; + unsigned char *c; + + TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat); + + assert(pFormat); + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a(pszMessage)); + len = strlen(pszMessage)+1; + esize = 1; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage)); + len = strlenW((LPWSTR)pszMessage)+1; + esize = 2; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception. */ + return NULL; + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + assert( (pStubMsg->BufferLength >= (len*esize + 13)) && (pStubMsg->Buffer != NULL) ); + + c = pStubMsg->Buffer; + memset(c, 0, 12); + NDR_LOCAL_UINT32_WRITE(c, len); /* max length: strlen + 1 (for '\0') */ + c += 8; /* offset: 0 */ + NDR_LOCAL_UINT32_WRITE(c, len); /* actual length: (same) */ + c += 4; + memcpy(c, pszMessage, len*esize); /* the string itself */ + c += len*esize; + pStubMsg->Buffer = c; + + STD_OVERFLOW_CHECK(pStubMsg); + + /* success */ + return NULL; /* is this always right? */ +} + +/*********************************************************************** + * NdrConformantStringBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat) +{ + TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat); + + assert(pFormat); + if (*pFormat == RPC_FC_C_CSTRING) { + /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 1 octet for '\0' */ + TRACE("string=%s\n", debugstr_a(pMemory)); + pStubMsg->BufferLength += strlen(pMemory) + 13 + BUFFER_PARANOIA; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 2 octets for L'\0' */ + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory)); + pStubMsg->BufferLength += strlenW((LPWSTR)pMemory)*2 + 14 + BUFFER_PARANOIA; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } +} + +/************************************************************************ + * NdrConformantStringMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + unsigned long rslt = 0; + + TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); + + assert(pStubMsg && pFormat); + + if (*pFormat == RPC_FC_C_CSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); /* maxlen */ + } + else if (*pFormat == RPC_FC_C_WSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer)*2; /* maxlen */ + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + TRACE(" --> %lu\n", rslt); + return rslt; +} + +/************************************************************************ + * NdrConformantStringUnmarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ) +{ + unsigned long len, esize, ofs; + unsigned char *pMem; + + TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n", + pStubMsg, *ppMemory, pFormat, fMustAlloc); + + assert(pFormat && ppMemory && pStubMsg); + + pStubMsg->Buffer += 4; + ofs = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + len = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + + if (*pFormat == RPC_FC_C_CSTRING) esize = 1; + else if (*pFormat == RPC_FC_C_WSTRING) esize = 2; + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + esize = 0; + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, len*esize + BUFFER_PARANOIA); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer - ofs*esize; + /* for clients, memory should be provided by caller */ + } + + pMem = *ppMemory + ofs*esize; + + if (pMem != pStubMsg->Buffer) + memcpy(pMem, pStubMsg->Buffer, len*esize); + + pStubMsg->Buffer += len*esize; + + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a(pMem)); + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pMem)); + } + + return NULL; /* FIXME: is this always right? */ +} + +/*********************************************************************** + * PointerMarshall + */ +void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MARSHALL m; + + TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + *(LPVOID*)Buffer = 0; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no marshaller for data type=%02x\n", *desc); + + STD_OVERFLOW_CHECK(pStubMsg); +} + +/*********************************************************************** + * PointerUnmarshall + */ +void WINAPI PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char **pPointer, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + + TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pFormat, fMustAlloc); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + pPointer = *(unsigned char***)pPointer; + TRACE("deref => %p\n", pPointer); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + *pPointer = NULL; + + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pPointer, desc, fMustAlloc); + else FIXME("no unmarshaller for data type=%02x\n", *desc); + TRACE("pointer=%p\n", *pPointer); +} + +/*********************************************************************** + * PointerBufferSize + */ +void WINAPI PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no buffersizer for data type=%02x\n", *desc); +} + +/*********************************************************************** + * PointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MEMORYSIZE m; + + FIXME("(%p,%p,%p): stub\n", pStubMsg, Buffer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + TRACE("deref\n"); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, desc); + else FIXME("no memorysizer for data type=%02x\n", *desc); + + return 0; +} + +/*********************************************************************** + * PointerFree [RPCRT4.@] + */ +void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_FREE m; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + if (attr & RPC_FC_P_DONTFREE) return; + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + if (!Pointer) return; + + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + + /* hmm... is this sensible? + * perhaps we should check if the memory comes from NdrAllocate, + * and deallocate only if so - checking if the pointer is between + * BufferStart and BufferEnd is probably no good since the buffer + * may be reallocated when the server wants to marshal the reply */ + switch (*desc) { + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_BOGUS_ARRAY: + case RPC_FC_USER_MARSHAL: + break; + default: + FIXME("unhandled data type=%02x\n", *desc); + case RPC_FC_CARRAY: + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + if (pStubMsg->ReuseBuffer) goto notfree; + break; + case RPC_FC_IP: + goto notfree; + } + + if (attr & RPC_FC_P_ONSTACK) { + TRACE("not freeing stack ptr %p\n", Pointer); + return; + } + TRACE("freeing %p\n", Pointer); + NdrFree(pStubMsg, Pointer); + return; +notfree: + TRACE("not freeing %p\n", Pointer); +} + +/*********************************************************************** + * EmbeddedPointerMarshall + */ +unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char *Mark = pStubMsg->BufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; uBufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = *ppMemory + xofs; + unsigned u; + for (u=0; uOffset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; uOffset; + unsigned char *Mark = pStubMsg->BufferMark; + unsigned ofs, rep, count, stride, xofs; + + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (*pFormat != RPC_FC_PP) return 0; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned u; + for (u=0; uOffset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; uBufferMark = pStubMsg->Buffer; + PointerMarshall(pStubMsg, pStubMsg->Buffer, pMemory, pFormat); + pStubMsg->Buffer += 4; + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrPointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pStubMsg->BufferMark = pStubMsg->Buffer; + PointerUnmarshall(pStubMsg, pStubMsg->Buffer, ppMemory, pFormat, fMustAlloc); + pStubMsg->Buffer += 4; + + return NULL; +} + +/*********************************************************************** + * NdrPointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->BufferLength += 4; + PointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrPointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + PointerMemorySize(pStubMsg, pStubMsg->Buffer, pFormat); + return 0; +} + +/*********************************************************************** + * NdrPointerFree [RPCRT4.@] + */ +void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + PointerFree(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrSimpleStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + memcpy(pStubMsg->Buffer, pMemory, size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrSimpleStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, size); + memcpy(*ppMemory, pStubMsg->Buffer, size); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer; + else + /* for clients, memory should be provided by caller */ + memcpy(*ppMemory, pStubMsg->Buffer, size); + } + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat+4, fMustAlloc); + + return NULL; +} + + +/*********************************************************************** + * NdrSimpleStructUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + FIXME("stub\n"); +} + + +/*********************************************************************** + * NdrSimpleStructUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + FIXME("stub\n"); +} + + +/*********************************************************************** + * NdrSimpleStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->BufferLength += size; + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4); +} + +/*********************************************************************** + * NdrSimpleStructMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMemorySize(pStubMsg, pFormat+4); + return 0; +} + +/*********************************************************************** + * NdrSimpleStructFree [RPCRT4.@] + */ +void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4); +} + + +unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + switch (*pFormat) { + case RPC_FC_STRUCT: + case RPC_FC_PSTRUCT: + case RPC_FC_CSTRUCT: + case RPC_FC_BOGUS_STRUCT: + return *(const WORD*)&pFormat[2]; + case RPC_FC_USER_MARSHAL: + return *(const WORD*)&pFormat[4]; + default: + FIXME("unhandled embedded type %02x\n", *pFormat); + } + return 0; +} + + +unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_MARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + TRACE("short=%d <= %p\n", *(WORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 2); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + TRACE("long=%ld <= %p\n", *(DWORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 4); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); + NdrPointerMarshall(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) <= %p\n", size, pMemory); + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no marshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %02x\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer, + unsigned char fMustAlloc) +{ + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + memcpy(pMemory, pStubMsg->Buffer, 2); + TRACE("short=%d => %p\n", *(WORD*)pMemory, pMemory); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + memcpy(pMemory, pStubMsg->Buffer, 4); + TRACE("long=%ld => %p\n", *(DWORD*)pMemory, pMemory); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + *(unsigned char**)pMemory = NULL; + TRACE("pointer => %p\n", pMemory); + NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, fMustAlloc); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) => %p\n", size, pMemory); + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + memset(pMemory, 0, size); /* just in case */ + if (m) m(pStubMsg, &pMemory, desc, fMustAlloc); + else FIXME("no unmarshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pStubMsg->BufferLength += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + pStubMsg->BufferLength += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + NdrPointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no buffersizer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_FREE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + pMemory += 4; + break; + case RPC_FC_POINTER: + NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no freer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned long WINAPI ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING desc; + unsigned long size = 0; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + size += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + size += 4; + break; + case RPC_FC_POINTER: + size += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_LENGTH(size, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_LENGTH(size, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + size += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size += EmbeddedComplexSize(pStubMsg, desc); + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return size; +} + +/*********************************************************************** + * NdrComplexStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *pMemory; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc); + + if (conf_array) + NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; +} + +/*********************************************************************** + * NdrComplexStructMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + return 0; +} + +/*********************************************************************** + * NdrComplexStructFree [RPCRT4.@] + */ +void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayFree(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; +} + +/*********************************************************************** + * NdrConformantArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + size = pStubMsg->MaxCount; + + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); + pStubMsg->Buffer += 4; + + memcpy(pStubMsg->Buffer, pMemory, size*esize); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size*esize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + size = pStubMsg->MaxCount; + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, size*esize); + memcpy(*ppMemory, pStubMsg->Buffer, size*esize); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer; + else + /* for clients, memory should be provided by caller */ + memcpy(*ppMemory, pStubMsg->Buffer, size*esize); + } + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size*esize; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + size = pStubMsg->MaxCount; + + pStubMsg->BufferLength += size*esize; + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrConformantArrayMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + DWORD size = 0; + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + size = pStubMsg->MaxCount; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return 0; +} + +/*********************************************************************** + * NdrConformantArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayUnmarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc ) +{ + FIXME( "stub\n" ); + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); + return 0; +} + + +/*********************************************************************** + * NdrComplexArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, count, def; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); + pStubMsg->Buffer += 4; + + for (count=0; countMaxCount; + TRACE("conformance=%ld\n", size); + + pFormat += 4; + + esize = ComplexStructSize(pStubMsg, pFormat); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size*esize); + + pMemory = *ppMemory; + for (count=0; countMaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + for (count=0; countMaxCount; + TRACE("conformance=%ld\n", size); + + pFormat += 4; + + return 0; +} + +/*********************************************************************** + * NdrComplexArrayFree [RPCRT4.@] + */ +void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, count, def; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + for (count=0; countdwDestContext, + pStubMsg->RpcMsg->DataRepresentation); +} + +/*********************************************************************** + * NdrUserMarshalMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1]; */ + unsigned index = *(const WORD*)&pFormat[2]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( + &uflag, pStubMsg->Buffer, pMemory); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ +/* unsigned flags = pFormat[1];*/ + unsigned index = *(const WORD*)&pFormat[2]; + DWORD memsize = *(const WORD*)&pFormat[4]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + TRACE("index=%d\n", index); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, memsize); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall( + &uflag, pStubMsg->Buffer, *ppMemory); + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalBufferSize [RPCRT4.@] + */ +void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1];*/ + unsigned index = *(const WORD*)&pFormat[2]; + DWORD bufsize = *(const WORD*)&pFormat[6]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + if (bufsize) { + TRACE("size=%ld\n", bufsize); + pStubMsg->BufferLength += bufsize; + return; + } + + pStubMsg->BufferLength = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( + &uflag, pStubMsg->BufferLength, pMemory); +} + +/*********************************************************************** + * NdrUserMarshalMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned index = *(const WORD*)&pFormat[2]; +/* DWORD memsize = *(const WORD*)&pFormat[4]; */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + TRACE("index=%d\n", index); + + return 0; +} + +/*********************************************************************** + * NdrUserMarshalFree [RPCRT4.@] + */ +void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1]; */ + unsigned index = *(const WORD*)&pFormat[2]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnFree( + &uflag, pMemory); +} + +/*********************************************************************** + * NdrClearOutParameters [RPCRT4.@] + */ +void WINAPI NdrClearOutParameters(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat, + void *ArgAddr) +{ + FIXME("(%p,%p,%p): stub\n", pStubMsg, pFormat, ArgAddr); +} + +/*********************************************************************** + * NdrConvert [RPCRT4.@] + */ +void WINAPI NdrConvert( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p): stub.\n", pStubMsg, pFormat); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} + +/*********************************************************************** + * NdrConvert2 [RPCRT4.@] + */ +void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, long NumberParams ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %ld): stub.\n", + pStubMsg, pFormat, NumberParams); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} diff --git a/reactos/lib/rpcrt4/ndr_midl.c b/reactos/lib/rpcrt4/ndr_midl.c new file mode 100644 index 00000000000..9804b7c8963 --- /dev/null +++ b/reactos/lib/rpcrt4/ndr_midl.c @@ -0,0 +1,282 @@ +/* + * MIDL proxy/stub stuff + * + * Copyright 2002 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 + */ + +#include +#include +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" +#include "ndr_misc.h" +#include "rpcndr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * NdrProxyInitialize [RPCRT4.@] + */ +void WINAPI NdrProxyInitialize(void *This, + PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + unsigned int ProcNum) +{ + HRESULT hr; + + TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + if (This) StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); + if (pStubMsg->pRpcChannelBuffer) { + hr = IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, + &pStubMsg->dwDestContext, + &pStubMsg->pvDestContext); + } + TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); +} + +/*********************************************************************** + * NdrProxyGetBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyGetBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + const IID *riid = NULL; + + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + pStubMsg->dwStubPhase = PROXY_GETBUFFER; + hr = StdProxy_GetIID(This, &riid); + hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + riid); + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + pStubMsg->dwStubPhase = PROXY_MARSHAL; +} + +/*********************************************************************** + * NdrProxySendReceive [RPCRT4.@] + */ +void WINAPI NdrProxySendReceive(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + ULONG Status = 0; + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; + hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + &Status); + pStubMsg->dwStubPhase = PROXY_UNMARSHAL; + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); +} + +/*********************************************************************** + * NdrProxyFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyFreeBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg); +} + +/*********************************************************************** + * NdrProxyErrorHandler [RPCRT4.@] + */ +HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) +{ + FIXME("(0x%08lx): semi-stub\n", dwExceptionCode); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, RPC_S_CALL_FAILED); +} + +/*********************************************************************** + * NdrStubInitialize [RPCRT4.@] + */ +void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + LPRPCCHANNELBUFFER pRpcChannelBuffer) +{ + TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); + NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; +} + +/*********************************************************************** + * NdrStubGetBuffer [RPCRT4.@] + */ +void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER This, + LPRPCCHANNELBUFFER pRpcChannelBuffer, + PMIDL_STUB_MESSAGE pStubMsg) +{ + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + I_RpcGetBuffer(pStubMsg->RpcMsg); /* ? */ + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; +} + +/************************************************************************ + * NdrClientInitializeNew [RPCRT4.@] + */ +void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) +{ + TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", + pRpcMessage, pStubMsg, pStubDesc, ProcNum); + + assert( pRpcMessage && pStubMsg && pStubDesc ); + + memset(pRpcMessage, 0, sizeof(RPC_MESSAGE)); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = FALSE; + pStubMsg->IsClient = TRUE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMessage; + + pRpcMessage->ProcNum = ProcNum; + pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; +} + +/*********************************************************************** + * NdrServerInitializeNew [RPCRT4.@] + */ +unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc ) +{ + TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); + + assert( pRpcMsg && pStubMsg && pStubDesc ); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = TRUE; + pStubMsg->IsClient = FALSE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMsg; + pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; + pStubMsg->BufferLength = pRpcMsg->BufferLength; + pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; + + /* FIXME: determine the proper return value */ + return NULL; +} + +/*********************************************************************** + * NdrGetBuffer [RPCRT4.@] + */ +unsigned char *WINAPI NdrGetBuffer(MIDL_STUB_MESSAGE *stubmsg, unsigned long buflen, RPC_BINDING_HANDLE handle) +{ + TRACE("(stubmsg == ^%p, buflen == %lu, handle == %p): wild guess.\n", stubmsg, buflen, handle); + + assert( stubmsg && stubmsg->RpcMsg ); + + /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ + stubmsg->RpcMsg->Handle = handle; + + stubmsg->RpcMsg->BufferLength = buflen; + if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) + return NULL; + + stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; + return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); +} +/*********************************************************************** + * NdrFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrFreeBuffer(MIDL_STUB_MESSAGE *pStubMsg) +{ + TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); + I_RpcFreeBuffer(pStubMsg->RpcMsg); + pStubMsg->BufferLength = 0; + pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); +} + +/************************************************************************ + * NdrSendReceive [RPCRT4.@] + */ +unsigned char *WINAPI NdrSendReceive( MIDL_STUB_MESSAGE *stubmsg, unsigned char *buffer ) +{ + TRACE("(stubmsg == ^%p, buffer == ^%p)\n", stubmsg, buffer); + + /* FIXME: how to handle errors? (raise exception?) */ + if (!stubmsg) { + ERR("NULL stub message. No action taken.\n"); + return NULL; + } + if (!stubmsg->RpcMsg) { + ERR("RPC Message not present in stub message. No action taken.\n"); + return NULL; + } + + /* FIXME: Seems wrong. Where should this really come from, and when? */ + stubmsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + + if (I_RpcSendReceive(stubmsg->RpcMsg) != RPC_S_OK) { + WARN("I_RpcSendReceive did not return success.\n"); + /* FIXME: raise exception? */ + } + + /* FIXME: is this the right return value? */ + return NULL; +} diff --git a/reactos/lib/rpcrt4/ndr_misc.h b/reactos/lib/rpcrt4/ndr_misc.h new file mode 100644 index 00000000000..9ffeed2448e --- /dev/null +++ b/reactos/lib/rpcrt4/ndr_misc.h @@ -0,0 +1,53 @@ +/* + * NDR definitions + * + * 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 + */ + +#ifndef __WINE_NDR_MISC_H +#define __WINE_NDR_MISC_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "rpc.h" +#include "rpcndr.h" + +struct IPSFactoryBuffer; + +LONG_PTR RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, va_list args ); + +HRESULT RPCRT4_GetPSFactory(REFIID riid, struct IPSFactoryBuffer **ppPS); + +PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def); + +typedef unsigned char* (WINAPI *NDR_MARSHALL) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef unsigned char* (WINAPI *NDR_UNMARSHALL)(PMIDL_STUB_MESSAGE, unsigned char**,PFORMAT_STRING, unsigned char); +typedef void (WINAPI *NDR_BUFFERSIZE)(PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef unsigned long (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +typedef void (WINAPI *NDR_FREE) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); + +extern NDR_MARSHALL NdrMarshaller[]; +extern NDR_UNMARSHALL NdrUnmarshaller[]; +extern NDR_BUFFERSIZE NdrBufferSizer[]; +extern NDR_MEMORYSIZE NdrMemorySizer[]; +extern NDR_FREE NdrFreer[]; + +#endif /* __WINE_NDR_MISC_H */ diff --git a/reactos/lib/rpcrt4/ndr_ole.c b/reactos/lib/rpcrt4/ndr_ole.c new file mode 100644 index 00000000000..aef1c9485d3 --- /dev/null +++ b/reactos/lib/rpcrt4/ndr_ole.c @@ -0,0 +1,350 @@ +/* + * 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 + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "ndr_misc.h" +#include "rpcndr.h" +#include "wine/rpcfc.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 +{ + IStreamVtbl *lpVtbl; + DWORD RefCount; + PMIDL_STUB_MESSAGE pMsg; + LPDWORD size; + char *data; + DWORD pos; +} RpcStreamImpl; + +static HRESULT WINAPI RpcStream_QueryInterface(LPSTREAM iface, + REFIID riid, + LPVOID *obj) +{ + RpcStreamImpl *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) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + return ++(This->RefCount); +} + +static ULONG WINAPI RpcStream_Release(LPSTREAM iface) +{ + RpcStreamImpl *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) +{ + RpcStreamImpl *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) +{ + RpcStreamImpl *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) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + switch (origin) { + case STREAM_SEEK_SET: + This->pos = move.u.LowPart; + break; + case STREAM_SEEK_CUR: + This->pos = This->pos + move.u.LowPart; + break; + case STREAM_SEEK_END: + This->pos = *This->size + move.u.LowPart; + break; + default: + return STG_E_INVALIDFUNCTION; + } + if (newPos) { + newPos->u.LowPart = This->pos; + newPos->u.HighPart = 0; + } + return S_OK; +} + +static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface, + ULARGE_INTEGER newSize) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + *This->size = newSize.u.LowPart; + return S_OK; +} + +static IStreamVtbl RpcStream_Vtbl = +{ + 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; +} + +const IID* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + const IID *riid; + if (!pFormat) return &IID_IUnknown; + TRACE("format=%02x %02x\n", pFormat[0], pFormat[1]); + if (pFormat[0] != RPC_FC_IP) FIXME("format=%d\n", pFormat[0]); + if (pFormat[1] == RPC_FC_CONSTANT_IID) { + riid = (const IID *)&pFormat[2]; + } else { + ComputeConformance(pStubMsg, pMemory, pFormat+2, 0); + riid = (const IID *)pStubMsg->MaxCount; + } + if (!riid) riid = &IID_IUnknown; + TRACE("got %s\n", debugstr_guid(riid)); + return riid; +} + +/*********************************************************************** + * NdrInterfacePointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + 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 = get_ip_iid(pStubMsg, pMemory, pFormat); + ULONG size = 0; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + 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/reactos/lib/rpcrt4/ndr_stubless.c b/reactos/lib/rpcrt4/ndr_stubless.c new file mode 100644 index 00000000000..b6bb11d8890 --- /dev/null +++ b/reactos/lib/rpcrt4/ndr_stubless.c @@ -0,0 +1,99 @@ +/* + * NDR client stuff + * + * 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: + * - Exception handling + * - Context stuff + * - Who knows + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "ndr_misc.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +LONG_PTR /* CLIENT_CALL_RETURN */ RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, va_list args) +{ + + RPC_CLIENT_INTERFACE *rpc_cli_if = (RPC_CLIENT_INTERFACE *)(pStubDesc->RpcInterfaceInformation); + LONG_PTR ret = 0; +/* + RPC_BINDING_HANDLE handle = 0; + RPC_MESSAGE rpcmsg; + MIDL_STUB_MESSAGE stubmsg; +*/ + + FIXME("(pStubDec == ^%p,pFormat = ^%p,...): stub\n", pStubDesc, pFormat); + if (rpc_cli_if) /* NULL for objects */ { + TRACE(" *rpc_cli_if (== ^%p) == (RPC_CLIENT_INTERFACE):\n", pStubDesc); + TRACE(" Length == %d\n", rpc_cli_if->Length); + TRACE(" InterfaceID == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->InterfaceId.SyntaxGUID), + rpc_cli_if->InterfaceId.SyntaxVersion.MajorVersion, rpc_cli_if->InterfaceId.SyntaxVersion.MinorVersion); + TRACE(" TransferSyntax == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->TransferSyntax.SyntaxGUID), + rpc_cli_if->TransferSyntax.SyntaxVersion.MajorVersion, rpc_cli_if->TransferSyntax.SyntaxVersion.MinorVersion); + TRACE(" DispatchTable == ^%p\n", rpc_cli_if->DispatchTable); + TRACE(" RpcProtseqEndpointCount == ^%d\n", rpc_cli_if->RpcProtseqEndpointCount); + TRACE(" RpcProtseqEndpoint == ^%p\n", rpc_cli_if->RpcProtseqEndpoint); + TRACE(" Flags == ^%d\n", rpc_cli_if->Flags); + } + + /* for now, while these functons are under development, this is too sketchy. commented out. */ + /* + NdrClientInitializeNew( &rpcmsg, &stubmsg, pStubDesc, 0 ); + + handle = (RPC_BINDING_HANDLE)0xdeadbeef; */ /* FIXME */ + + /* stubmsg.BufferLength = 0;*/ /* FIXME */ + /* + NdrGetBuffer( &stubmsg, stubmsg.BufferLength, handle ); + NdrSendReceive( &stubmsg, stubmsg.Buffer ); + NdrFreeBuffer( &stubmsg ); + */ + return ret; +} + +/*********************************************************************** + * NdrClientCall2 [RPCRT4.@] + */ +LONG_PTR /* CLIENT_CALL_RETURN */ WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, ...) +{ + LONG_PTR ret; + va_list args; + + TRACE("(%p,%p,...)\n", pStubDesc, pFormat); + + va_start(args, pFormat); + ret = RPCRT4_NdrClientCall2(pStubDesc, pFormat, args); + va_end(args); + return ret; +} diff --git a/reactos/lib/rpcrt4/rpc_binding.c b/reactos/lib/rpcrt4/rpc_binding.c new file mode 100644 index 00000000000..32b71433e86 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_binding.c @@ -0,0 +1,1096 @@ +/* + * RPC binding API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2003 Mike Hearn + * Copyright 2004 Filip Navara + * + * 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: + * - a whole lot + */ + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_message.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +LPSTR RPCRT4_strndupA(LPCSTR src, INT slen) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlen(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, len+1); + memcpy(s, src, len); + s[len] = 0; + return s; +} + +LPSTR RPCRT4_strdupWtoA(LPWSTR src) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + s = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL); + return s; +} + +LPWSTR RPCRT4_strdupAtoW(LPSTR src) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, src, -1, s, len); + return s; +} + +LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlenW(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + memcpy(s, src, len*sizeof(WCHAR)); + s[len] = 0; + return s; +} + +void RPCRT4_strfree(LPSTR src) +{ + if (src) HeapFree(GetProcessHeap(), 0, src); +} + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding) +{ + RpcConnection* NewConnection; + + NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection)); + NewConnection->server = server; + NewConnection->Protseq = RPCRT4_strdupA(Protseq); + NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); + NewConnection->Used = Binding; + NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; + + TRACE("connection: %p\n", NewConnection); + *Connection = NewConnection; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) +{ + TRACE("connection: %p\n", Connection); + + RPCRT4_CloseConnection(Connection); + RPCRT4_strfree(Connection->Endpoint); + RPCRT4_strfree(Connection->NetworkAddr); + RPCRT4_strfree(Connection->Protseq); + HeapFree(GetProcessHeap(), 0, Connection); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (!Connection->conn) { + if (Connection->server) { /* server */ + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + if (strcmp(Connection->Protseq, "ncalrpc") == 0) { + static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; + LPSTR pname; + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("listening on %s\n", pname); + Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) { + WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(Connection->ovl.hEvent); + return RPC_S_OK; + } else if (GetLastError() == ERROR_IO_PENDING) { + return RPC_S_OK; + } + return RPC_S_SERVER_UNAVAILABLE; + } + } + /* protseq=ncacn_np: named pipes */ + else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { + static LPCSTR prefix = "\\\\."; + LPSTR pname; + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("listening on %s\n", pname); + Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) { + WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(Connection->ovl.hEvent); + return RPC_S_OK; + } + return RPC_S_SERVER_UNAVAILABLE; + } + } + else { + ERR("protseq %s not supported\n", Connection->Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + } + else { /* client */ + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + if (strcmp(Connection->Protseq, "ncalrpc") == 0) { + static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; + LPSTR pname; + HANDLE conn; + DWORD err; + DWORD dwMode; + + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("connecting to %s\n", pname); + while (TRUE) { + if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { + conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, 0); + if (conn != INVALID_HANDLE_VALUE) break; + err = GetLastError(); + if (err == ERROR_PIPE_BUSY) continue; + TRACE("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + return RPC_S_SERVER_TOO_BUSY; + } else { + err = GetLastError(); + TRACE("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + return RPC_S_SERVER_UNAVAILABLE; + } + } + + /* success */ + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); + Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + Connection->conn = conn; + } + /* protseq=ncacn_np: named pipes */ + else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { + static LPCSTR prefix = "\\\\."; + LPSTR pname; + HANDLE conn; + DWORD err; + DWORD dwMode; + + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("connecting to %s\n", pname); + conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, 0); + if (conn == INVALID_HANDLE_VALUE) { + err = GetLastError(); + /* we don't need to handle ERROR_PIPE_BUSY here, + * the doc says that it is returned to the app */ + TRACE("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + if (err == ERROR_PIPE_BUSY) + return RPC_S_SERVER_TOO_BUSY; + else + return RPC_S_SERVER_UNAVAILABLE; + } + + /* success */ + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); + Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + Connection->conn = conn; + } else { + ERR("protseq %s not supported\n", Connection->Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + } + } + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (Connection->conn) { + CancelIo(Connection->conn); + CloseHandle(Connection->conn); + Connection->conn = 0; + } + if (Connection->ovl.hEvent) { + CloseHandle(Connection->ovl.hEvent); + Connection->ovl.hEvent = 0; + } + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) +{ + RpcConnection* NewConnection; + RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq, + OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL); + if (err == RPC_S_OK) { + /* because of the way named pipes work, we'll transfer the connected pipe + * to the child, then reopen the server binding to continue listening */ + NewConnection->conn = OldConnection->conn; + NewConnection->ovl = OldConnection->ovl; + OldConnection->conn = 0; + memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl)); + *Connection = NewConnection; + RPCRT4_OpenConnection(OldConnection); + } + return err; +} + +RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) +{ + RpcBinding* NewBinding; + + NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding)); + NewBinding->refs = 1; + NewBinding->server = server; + + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions) +{ + TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + if (!Binding->Endpoint) ERR("out of memory?\n"); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions) +{ + TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + if (!Binding->Endpoint) ERR("out of memory?\n"); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint) +{ + TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint); + + RPCRT4_strfree(Binding->Endpoint); + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid) +{ + TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); + if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID)); + else UuidCreateNil(&Binding->ObjectUuid); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection) +{ + RpcBinding* NewBinding; + TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding, Connection); + + RPCRT4_AllocBinding(&NewBinding, Connection->server); + NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq); + NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr); + NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint); + NewBinding->FromConn = Connection; + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding) +{ + InterlockedIncrement(&OldBinding->refs); + *Binding = OldBinding; + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) +{ + if (InterlockedDecrement(&Binding->refs)) + return RPC_S_OK; + + TRACE("binding: %p\n", Binding); + /* FIXME: release connections */ + RPCRT4_strfree(Binding->Endpoint); + RPCRT4_strfree(Binding->NetworkAddr); + RPCRT4_strfree(Binding->Protseq); + HeapFree(GetProcessHeap(), 0, Binding); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, + PRPC_SYNTAX_IDENTIFIER TransferSyntax, + PRPC_SYNTAX_IDENTIFIER InterfaceId) +{ + RpcConnection* NewConnection; + RPC_STATUS status; + + TRACE("(Binding == ^%p)\n", Binding); + + /* if we try to bind a new interface and the connection is already opened, + * close the current connection and create a new with the new binding. */ + if (!Binding->server && Binding->FromConn && + memcmp(&Binding->FromConn->ActiveInterface, InterfaceId, + sizeof(RPC_SYNTAX_IDENTIFIER))) { + + TRACE("releasing pre-existing connection\n"); + RPCRT4_DestroyConnection(Binding->FromConn); + Binding->FromConn = NULL; + } else { + /* we already have an connection with acceptable binding, so use it */ + if (Binding->FromConn) { + *Connection = Binding->FromConn; + return RPC_S_OK; + } + } + + /* create a new connection */ + RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding); + *Connection = NewConnection; + status = RPCRT4_OpenConnection(NewConnection); + if (status != RPC_S_OK) { + return status; + } + + /* we need to send a binding packet if we are client. */ + if (!(*Connection)->server) { + RpcPktHdr *hdr; + DWORD count; + BYTE *response; + RpcPktHdr *response_hdr; + + TRACE("sending bind request to server\n"); + + hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, + InterfaceId, TransferSyntax); + + status = RPCRT4_Send(*Connection, hdr, NULL, 0); + if (status != RPC_S_OK) { + RPCRT4_DestroyConnection(*Connection); + return status; + } + + response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE); + if (response == NULL) { + WARN("Can't allocate memory for binding response\n"); + RPCRT4_DestroyConnection(*Connection); + return E_OUTOFMEMORY; + } + + /* get a reply */ + if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + if (count < sizeof(response_hdr->common)) { + WARN("received invalid header\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + response_hdr = (RpcPktHdr*)response; + + if (response_hdr->common.rpc_ver != RPC_VER_MAJOR || + response_hdr->common.rpc_ver_minor != RPC_VER_MINOR || + response_hdr->common.ptype != PKT_BIND_ACK) { + WARN("invalid protocol version or rejection packet\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { + WARN("server doesn't allow large enough packets\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + /* FIXME: do more checks? */ + + (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + (*Connection)->ActiveInterface = *InterfaceId; + } + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) +{ + TRACE("(Binding == ^%p)\n", Binding); + if (!Connection) return RPC_S_OK; + if (Binding->FromConn == Connection) return RPC_S_OK; + return RPCRT4_DestroyConnection(Connection); +} + +/* utility functions for string composing and parsing */ +static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src) +{ + unsigned len = strlen(src); + memcpy(data, src, len*sizeof(CHAR)); + return len; +} + +static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src) +{ + unsigned len = strlenW(src); + memcpy(data, src, len*sizeof(WCHAR)); + return len; +} + +static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src) +{ + DWORD len = strlen(dst), slen = strlen(src); + LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, slen+1); + return ndst; +} + +static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src) +{ + DWORD len = strlenW(dst), slen = strlenW(src); + LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR)); + return ndst; +} + + +/*********************************************************************** + * RpcStringBindingComposeA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq, + unsigned char *NetworkAddr, unsigned char *Endpoint, + unsigned char *Options, unsigned char** StringBinding ) +{ + DWORD len = 1; + LPSTR data; + + TRACE( "(%s,%s,%s,%s,%s,%p)\n", + debugstr_a( ObjUuid ), debugstr_a( Protseq ), + debugstr_a( NetworkAddr ), debugstr_a( Endpoint ), + debugstr_a( Options ), StringBinding ); + + if (ObjUuid && *ObjUuid) len += strlen(ObjUuid) + 1; + if (Protseq && *Protseq) len += strlen(Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlen(NetworkAddr); + if (Endpoint && *Endpoint) len += strlen(Endpoint) + 2; + if (Options && *Options) len += strlen(Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len); + *StringBinding = data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyA(data, ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyA(data, Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) + data += RPCRT4_strcopyA(data, NetworkAddr); + + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyA(data, Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyA(data, Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcStringBindingComposeW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq, + LPWSTR NetworkAddr, LPWSTR Endpoint, + LPWSTR Options, LPWSTR* StringBinding ) +{ + DWORD len = 1; + LPWSTR data; + + TRACE("(%s,%s,%s,%s,%s,%p)\n", + debugstr_w( ObjUuid ), debugstr_w( Protseq ), + debugstr_w( NetworkAddr ), debugstr_w( Endpoint ), + debugstr_w( Options ), StringBinding); + + if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1; + if (Protseq && *Protseq) len += strlenW(Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr); + if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2; + if (Options && *Options) len += strlenW(Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + *StringBinding = data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyW(data, ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyW(data, Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) { + data += RPCRT4_strcopyW(data, NetworkAddr); + } + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyW(data, Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyW(data, Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + + +/*********************************************************************** + * RpcStringBindingParseA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid, + unsigned char **Protseq, unsigned char **NetworkAddr, + unsigned char **Endpoint, unsigned char **Options) +{ + CHAR *data, *next; + static const char ep_opt[] = "endpoint="; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = StringBinding; + + next = strchr(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, ':'); + if (next) { + if (Protseq) *Protseq = RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, '['); + if (next) { + CHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = RPCRT4_strndupA(data, next - data); + data = next+1; + close = strchr(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchr(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupA(data, next - data); + data = next+1; + + /* parse option */ + next = strchr(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = opt; + } else { + if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = RPCRT4_strdupA(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = RPCRT4_strconcatA(*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } + else if (NetworkAddr) + *NetworkAddr = RPCRT4_strdupA(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid); + if (Protseq) RpcStringFreeA((unsigned char**)Protseq); + if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr); + if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint); + if (Options) RpcStringFreeA((unsigned char**)Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcStringBindingParseW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid, + LPWSTR *Protseq, LPWSTR *NetworkAddr, + LPWSTR *Endpoint, LPWSTR *Options) +{ + WCHAR *data, *next; + static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0}; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = StringBinding; + + next = strchrW(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, ':'); + if (next) { + if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, '['); + if (next) { + WCHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data); + data = next+1; + close = strchrW(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchrW(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupW(data, next - data); + data = next+1; + + /* parse option */ + next = strchrW(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = opt; + } else { + if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = RPCRT4_strdupW(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = RPCRT4_strconcatW(*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } else if (NetworkAddr) + *NetworkAddr = RPCRT4_strdupW(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeW(ObjUuid); + if (Protseq) RpcStringFreeW(Protseq); + if (NetworkAddr) RpcStringFreeW(NetworkAddr); + if (Endpoint) RpcStringFreeW(Endpoint); + if (Options) RpcStringFreeW(Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcBindingFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS status; + TRACE("(%p) = %p\n", Binding, *Binding); + status = RPCRT4_DestroyBinding(*Binding); + if (status == RPC_S_OK) *Binding = 0; + return status; +} + +/*********************************************************************** + * RpcBindingVectorFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + unsigned long c; + + TRACE("(%p)\n", BindingVector); + for (c=0; c<(*BindingVector)->Count; c++) { + status = RpcBindingFree(&(*BindingVector)->BindingH[c]); + } + HeapFree(GetProcessHeap(), 0, *BindingVector); + *BindingVector = NULL; + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingInqObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid)); + memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID)); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingSetObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid)); + if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; + return RPCRT4_SetBindingObject(Binding, ObjectUuid); +} + +/*********************************************************************** + * RpcBindingFromStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_a(StringBinding), Binding); + + ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringA(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingA(&bind, FALSE, Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingA(bind, NetworkAddr, Endpoint, Options); + + RpcStringFreeA((unsigned char**)&Options); + RpcStringFreeA((unsigned char**)&Endpoint); + RpcStringFreeA((unsigned char**)&NetworkAddr); + RpcStringFreeA((unsigned char**)&Protseq); + RpcStringFreeA((unsigned char**)&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingFromStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding); + + ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringW(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options); + + RpcStringFreeW(&Options); + RpcStringFreeW(&Endpoint); + RpcStringFreeW(&NetworkAddr); + RpcStringFreeW(&Protseq); + RpcStringFreeW(&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding ) +{ + RPC_STATUS ret; + RpcBinding* bind = (RpcBinding*)Binding; + LPSTR ObjectUuid; + + TRACE("(%p,%p)\n", Binding, StringBinding); + + ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid); + if (ret != RPC_S_OK) return ret; + + ret = RpcStringBindingComposeA(ObjectUuid, bind->Protseq, bind->NetworkAddr, + bind->Endpoint, NULL, StringBinding); + + RpcStringFreeA((unsigned char**)&ObjectUuid); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding ) +{ + RPC_STATUS ret; + unsigned char *str = NULL; + TRACE("(%p,%p)\n", Binding, StringBinding); + ret = RpcBindingToStringBindingA(Binding, &str); + *StringBinding = RPCRT4_strdupAtoW(str); + RpcStringFreeA((unsigned char**)&str); + return ret; +} + +/*********************************************************************** + * I_RpcBindingSetAsync (RPCRT4.@) + * NOTES + * Exists in win9x and winNT, but with different number of arguments + * (9x version has 3 arguments, NT has 2). + */ +RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE( "(%p,%p): stub\n", Binding, BlockingFn ); + + bind->BlockingFn = BlockingFn; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) { + UNICODE_STRING protseqW; + + if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ + + if (RtlCreateUnicodeStringFromAsciiz(&protseqW, protseq)) { + RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); + RtlFreeUnicodeString(&protseqW); + return ret; + } else return RPC_S_OUT_OF_MEMORY; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidW (RPCRT4.@) + * + * Checks if the given protocol sequence is known by the RPC system. + * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. + * + * We currently support: + * ncalrpc local-only rpc over LPC (LPC is not really used) + * ncacn_np rpc over named pipes + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) { + static const WCHAR protseqsW[][15] = { + {'n','c','a','l','r','p','c',0}, + {'n','c','a','c','n','_','n','p',0} + }; + static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]); + int i; + + if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ + + for (i = 0; i < count; i++) { + if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK; + } + + FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq)); + return RPC_S_PROTSEQ_NOT_SUPPORTED; +} diff --git a/reactos/lib/rpcrt4/rpc_binding.h b/reactos/lib/rpcrt4/rpc_binding.h new file mode 100644 index 00000000000..0d7daa50000 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_binding.h @@ -0,0 +1,86 @@ +/* + * RPC binding API + * + * 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 + */ + +#ifndef __WINE_RPC_BINDING_H +#define __WINE_RPC_BINDING_H + +#include "wine/rpcss_shared.h" + +typedef struct _RpcConnection +{ + struct _RpcConnection* Next; + struct _RpcBinding* Used; + BOOL server; + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + HANDLE conn, thread; + OVERLAPPED ovl; + USHORT MaxTransmissionSize; + /* The active interface bound to server. */ + RPC_SYNTAX_IDENTIFIER ActiveInterface; +} RpcConnection; + +/* don't know what MS's structure looks like */ +typedef struct _RpcBinding +{ + DWORD refs; + struct _RpcBinding* Next; + BOOL server; + UUID ObjectUuid; + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + RPC_BLOCKING_FN BlockingFn; + ULONG ServerTid; + RpcConnection* FromConn; +} RpcBinding; + +LPSTR RPCRT4_strndupA(LPCSTR src, INT len); +LPWSTR RPCRT4_strndupW(LPWSTR src, INT len); +LPSTR RPCRT4_strdupWtoA(LPWSTR src); +LPWSTR RPCRT4_strdupAtoW(LPSTR src); +void RPCRT4_strfree(LPSTR src); + +#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) +#define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding); +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); + +RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq); +RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq); +RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions); +RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions); +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint); +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid); +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection); +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding); +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, PRPC_SYNTAX_IDENTIFIER TransferSyntax, PRPC_SYNTAX_IDENTIFIER InterfaceId); +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection); +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply); +HANDLE RPCRT4_GetMasterMutex(void); +HANDLE RPCRT4_RpcssNPConnect(void); + +#endif diff --git a/reactos/lib/rpcrt4/rpc_defs.h b/reactos/lib/rpcrt4/rpc_defs.h new file mode 100644 index 00000000000..f2fc382ac10 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_defs.h @@ -0,0 +1,183 @@ +/* + * RPC definitions + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * 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 + */ + +#ifndef __WINE_RPC_DEFS_H +#define __WINE_RPC_DEFS_H + +/* info from http://www.microsoft.com/msj/0398/dcomtextfigs.htm */ + +typedef struct +{ + unsigned char rpc_ver; /* RPC major version (5) */ + unsigned char rpc_ver_minor; /* RPC minor version (0) */ + unsigned char ptype; /* Packet type (PKT_*) */ + unsigned char flags; + unsigned char drep[4]; /* Data representation */ + unsigned short frag_len; /* Data size in bytes including header and tail. */ + unsigned short auth_len; /* Authentication length */ + unsigned long call_id; /* Call identifier. */ +} RpcPktCommonHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned short opnum; +} RpcPktRequestHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char cancel_count; + unsigned char reserved; +} RpcPktResponseHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char alert_count; /* Pending alert count */ + unsigned char padding[3]; /* Force alignment! */ + unsigned long status; /* Runtime fault code (RPC_STATUS) */ + unsigned long reserved; +} RpcPktFaultHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + unsigned char num_elements; /* Number of elements */ + unsigned char padding[3]; /* Force alignment! */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char num_syntaxes; /* Number of syntaxes */ + RPC_SYNTAX_IDENTIFIER abstract; + RPC_SYNTAX_IDENTIFIER transfer; +} RpcPktBindHdr; + +#include "pshpack1.h" +typedef struct +{ + unsigned short length; /* Length of the string including null terminator */ + char string[1]; /* String data in single byte, null terminated form */ +} RpcAddressString; +#include "poppack.h" + +typedef struct +{ + unsigned char padding1[2]; /* Force alignment! */ + unsigned char num_results; /* Number of results */ + unsigned char padding2[3]; /* Force alignment! */ + struct { + unsigned short result; + unsigned short reason; + } results[1]; +} RpcResults; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + /* + * Following this header are these fields: + * RpcAddressString server_address; + * RpcResults results; + * RPC_SYNTAX_IDENTIFIER transfer; + */ +} RpcPktBindAckHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short reject_reason; + unsigned char protocols_count; + struct { + unsigned char rpc_ver; + unsigned char rpc_ver_minor; + } protocols[1]; +} RpcPktBindNAckHdr; + +/* Union representing all possible packet headers */ +typedef union +{ + RpcPktCommonHdr common; + RpcPktRequestHdr request; + RpcPktResponseHdr response; + RpcPktFaultHdr fault; + RpcPktBindHdr bind; + RpcPktBindAckHdr bind_ack; + RpcPktBindNAckHdr bind_nack; +} RpcPktHdr; + +#define RPC_VER_MAJOR 5 +#define RPC_VER_MINOR 0 + +#define RPC_FLG_FIRST 1 +#define RPC_FLG_LAST 2 +#define RPC_FLG_OBJECT_UUID 0x80 + +#define RPC_MIN_PACKET_SIZE 0x1000 +#define RPC_MAX_PACKET_SIZE 0x16D0 + +#define PKT_REQUEST 0 +#define PKT_PING 1 +#define PKT_RESPONSE 2 +#define PKT_FAULT 3 +#define PKT_WORKING 4 +#define PKT_NOCALL 5 +#define PKT_REJECT 6 +#define PKT_ACK 7 +#define PKT_CL_CANCEL 8 +#define PKT_FACK 9 +#define PKT_CANCEL_ACK 10 +#define PKT_BIND 11 +#define PKT_BIND_ACK 12 +#define PKT_BIND_NACK 13 +#define PKT_ALTER_CONTEXT 14 +#define PKT_ALTER_CONTEXT_RESP 15 +#define PKT_SHUTDOWN 17 +#define PKT_CO_CANCEL 18 +#define PKT_ORPHANED 19 + +#define RESULT_ACCEPT 0 + +#define NO_REASON 0 + +#define NCADG_IP_UDP 0x08 +#define NCACN_IP_TCP 0x07 +#define NCADG_IPX 0x0E +#define NCACN_SPX 0x0C +#define NCACN_NB_NB 0x12 +#define NCACN_NB_IPX 0x0D +#define NCACN_DNET_NSP 0x04 +#define NCACN_HTTP 0x1F + +/* FreeDCE: TWR_C_FLR_PROT_ID_IP */ +#define TWR_IP 0x09 + +#endif /* __WINE_RPC_DEFS_H */ diff --git a/reactos/lib/rpcrt4/rpc_epmap.c b/reactos/lib/rpcrt4/rpc_epmap.c new file mode 100644 index 00000000000..1986ec65eb4 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_epmap.c @@ -0,0 +1,247 @@ +/* + * RPC endpoint mapper + * + * Copyright 2002 Greg Turner + * 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: + * - actually do things right + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* The "real" RPC portmapper endpoints that I know of are: + * + * ncadg_ip_udp: 135 + * ncacn_ip_tcp: 135 + * ncacn_np: \\pipe\epmapper (?) + * ncalrpc: epmapper + * + * If the user's machine ran a DCE RPC daemon, it would + * probably be possible to connect to it, but there are many + * reasons not to, like: + * - the user probably does *not* run one, and probably + * shouldn't be forced to run one just for local COM + * - very few Unix systems use DCE RPC... if they run a RPC + * daemon at all, it's usually Sun RPC + * - DCE RPC registrations are persistent and saved on disk, + * while MS-RPC registrations are documented as non-persistent + * and stored only in RAM, and auto-destroyed when the process + * dies (something DCE RPC can't do) + * + * Of course, if the user *did* want to run a DCE RPC daemon anyway, + * there would be interoperability advantages, like the possibility + * of running a fully functional DCOM server using Wine... + */ + +/*********************************************************************** + * RpcEpRegisterA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector, unsigned char *Annotation ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a(Annotation)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; cCount; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; cCount; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* FIXME: Do something with annotation. */ + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG; + msg.message.registerepmsg.iface = If->InterfaceId; + msg.message.registerepmsg.no_replace = 0; + + msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.registerepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.registerepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpUnregister (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; cCount; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; cCount; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG; + msg.message.unregisterepmsg.iface = If->InterfaceId; + + msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.unregisterepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.unregisterepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpResolveBinding (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p)\n", Binding, IfSpec); + TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); + TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + + /* FIXME: totally untested */ + + /* just return for fully bound handles */ + if (bind->Endpoint && (bind->Endpoint[0] != '\0')) + return RPC_S_OK; + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; + msg.message.resolveepmsg.iface = If->InterfaceId; + msg.message.resolveepmsg.object = bind->ObjectUuid; + + msg.vardata_payload_size = strlen(bind->Protseq) + 1; + + /* send the message */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply)) + return RPC_S_OUT_OF_MEMORY; + + /* empty-string result means not registered */ + if (reply.as_string[0] == '\0') + return EPT_S_NOT_REGISTERED; + + /* otherwise we fully bind the handle & return RPC_S_OK */ + return RPCRT4_ResolveBinding(Binding, reply.as_string); +} diff --git a/reactos/lib/rpcrt4/rpc_message.c b/reactos/lib/rpcrt4/rpc_message.c new file mode 100644 index 00000000000..6a2b8365138 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_message.c @@ -0,0 +1,612 @@ +/* + * RPC messages + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * 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 + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "rpcdcep.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_misc.h" +#include "rpc_defs.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) +{ + static const DWORD header_sizes[] = { + sizeof(Header->request), 0, sizeof(Header->response), + sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), + sizeof(Header->bind_ack), sizeof(Header->bind_nack), + 0, 0, 0, 0, 0 + }; + ULONG ret = 0; + + if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) { + ret = header_sizes[Header->common.ptype]; + if (ret == 0) + FIXME("unhandled packet type\n"); + if (Header->common.flags & RPC_FLG_OBJECT_UUID) + ret += sizeof(UUID); + } else { + TRACE("invalid packet type\n"); + } + + return ret; +} + +VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, + unsigned long DataRepresentation) +{ + Header->common.rpc_ver = RPC_VER_MAJOR; + Header->common.rpc_ver_minor = RPC_VER_MINOR; + Header->common.ptype = PacketType; + Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation)); + Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation)); + Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation)); + Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation)); + Header->common.auth_len = 0; + Header->common.call_id = 1; + Header->common.flags = 0; + /* Flags and fragment length are computed in RPCRT4_Send. */ +} + +RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, + unsigned long BufferLength, + unsigned short ProcNum, + UUID *ObjectUuid) +{ + RpcPktHdr *header; + BOOL has_object; + RPC_STATUS status; + + has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status)); + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->request) + (has_object ? sizeof(UUID) : 0)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation); + header->common.frag_len = sizeof(header->request); + header->request.alloc_hint = BufferLength; + header->request.context_id = 0; + header->request.opnum = ProcNum; + if (has_object) { + header->common.flags |= RPC_FLG_OBJECT_UUID; + header->common.frag_len += sizeof(UUID); + memcpy(&header->request + 1, ObjectUuid, sizeof(UUID)); + } + + return header; +} + +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, + unsigned long BufferLength) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation); + header->common.frag_len = sizeof(header->response); + header->response.alloc_hint = BufferLength; + + return header; +} + +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, + RPC_STATUS Status) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation); + header->common.frag_len = sizeof(header->fault); + header->fault.status = Status; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + RPC_SYNTAX_IDENTIFIER *AbstractId, + RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation); + header->common.frag_len = sizeof(header->bind); + header->bind.max_tsize = MaxTransmissionSize; + header->bind.max_rsize = MaxReceiveSize; + header->bind.num_elements = 1; + header->bind.num_syntaxes = 1; + memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER)); + memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, + unsigned char RpcVersion, + unsigned char RpcVersionMinor) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation); + header->common.frag_len = sizeof(header->bind_nack); + header->bind_nack.protocols_count = 1; + header->bind_nack.protocols[0].rpc_ver = RpcVersion; + header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + LPSTR ServerAddress, + unsigned long Result, + unsigned long Reason, + RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + unsigned long header_size; + RpcAddressString *server_address; + RpcResults *results; + RPC_SYNTAX_IDENTIFIER *transfer_id; + + header_size = sizeof(header->bind_ack) + sizeof(RpcResults) + + sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) + + strlen(ServerAddress); + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation); + header->common.frag_len = header_size; + header->bind_ack.max_tsize = MaxTransmissionSize; + header->bind_ack.max_rsize = MaxReceiveSize; + server_address = (RpcAddressString*)(&header->bind_ack + 1); + server_address->length = strlen(ServerAddress) + 1; + strcpy(server_address->string, ServerAddress); + results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1); + results->num_results = 1; + results->results[0].result = Result; + results->results[0].reason = Reason; + transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1); + memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +VOID RPCRT4_FreeHeader(RpcPktHdr *Header) +{ + HeapFree(GetProcessHeap(), 0, Header); +} + +/*********************************************************************** + * RPCRT4_Send (internal) + * + * Transmit a packet over connection in acceptable fragments. + */ +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength) +{ + PUCHAR buffer_pos; + DWORD hdr_size, count; + + buffer_pos = Buffer; + /* The packet building functions save the packet header size, so we can use it. */ + hdr_size = Header->common.frag_len; + Header->common.flags |= RPC_FLG_FIRST; + Header->common.flags &= ~RPC_FLG_LAST; + while (!(Header->common.flags & RPC_FLG_LAST)) { + /* decide if we need to split the packet into fragments */ + if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) { + Header->common.flags |= RPC_FLG_LAST; + Header->common.frag_len = BufferLength + hdr_size; + } else { + Header->common.frag_len = Connection->MaxTransmissionSize; + buffer_pos += Header->common.frag_len - hdr_size; + BufferLength -= Header->common.frag_len - hdr_size; + } + + /* transmit packet header */ + if (!WriteFile(Connection->conn, Header, hdr_size, &count, NULL)) { + WARN("WriteFile failed with error %ld\n", GetLastError()); + return GetLastError(); + } + + /* fragment consisted of header only and is the last one */ + if (hdr_size == Header->common.frag_len && + Header->common.flags & RPC_FLG_LAST) { + return RPC_S_OK; + } + + /* send the fragment data */ + if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, NULL)) { + WARN("WriteFile failed with error %ld\n", GetLastError()); + return GetLastError(); + } + + Header->common.flags &= ~RPC_FLG_FIRST; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_Receive (internal) + * + * Receive a packet from connection and merge the fragments. + */ +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, + PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + DWORD dwRead, hdr_length; + unsigned short first_flag; + unsigned long data_length; + unsigned long buffer_length; + unsigned char *buffer_ptr; + RpcPktCommonHdr common_hdr; + + *Header = NULL; + + TRACE("(%p, %p, %p)\n", Connection, Header, pMsg); + + /* read packet common header */ + if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, NULL)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != sizeof(common_hdr)) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* verify if the header really makes sense */ + if (common_hdr.rpc_ver != RPC_VER_MAJOR || + common_hdr.rpc_ver_minor != RPC_VER_MINOR) { + WARN("unhandled packet version\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); + if (hdr_length == 0) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); + memcpy(*Header, &common_hdr, sizeof(common_hdr)); + + /* read the rest of packet header */ + if (!ReadFile(Connection->conn, &(*Header)->common + 1, + hdr_length - sizeof(common_hdr), &dwRead, NULL)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != hdr_length - sizeof(common_hdr)) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* read packet body */ + switch (common_hdr.ptype) { + case PKT_RESPONSE: + pMsg->BufferLength = (*Header)->response.alloc_hint; + break; + case PKT_REQUEST: + pMsg->BufferLength = (*Header)->request.alloc_hint; + break; + default: + pMsg->BufferLength = common_hdr.frag_len - hdr_length; + } + status = I_RpcGetBuffer(pMsg); + if (status != RPC_S_OK) goto fail; + + first_flag = RPC_FLG_FIRST; + buffer_length = 0; + buffer_ptr = pMsg->Buffer; + while (buffer_length < pMsg->BufferLength) + { + data_length = (*Header)->common.frag_len - hdr_length; + if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag || + data_length + buffer_length > pMsg->BufferLength) { + TRACE("invalid packet flags or buffer length\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (data_length == 0) dwRead = 0; else + if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, NULL)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != data_length) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (buffer_length == pMsg->BufferLength && + ((*Header)->common.flags & RPC_FLG_LAST) == 0) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + buffer_length += data_length; + if (buffer_length < pMsg->BufferLength) { + TRACE("next header\n"); + + /* read the header of next packet */ + if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, NULL)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = GetLastError(); + goto fail; + } + } + if (dwRead != hdr_length) { + WARN("invalid packet header size (%ld)\n", dwRead); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + buffer_ptr += data_length; + first_flag = 0; + } + } + + /* success */ + status = RPC_S_OK; + +fail: + if (status != RPC_S_OK && *Header) { + RPCRT4_FreeHeader(*Header); + *Header = NULL; + } + return status; +} + +/*********************************************************************** + * I_RpcGetBuffer [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + + TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); + /* FIXME: pfnAllocate? */ + if (bind->server) { + /* it turns out that the original buffer data must still be available + * while the RPC server is marshalling a reply, so we should not deallocate + * it, we'll leave deallocating the original buffer to the RPC server */ + pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); + } else { + if (pMsg->Buffer) + HeapFree(GetProcessHeap(), 0, pMsg->Buffer); + pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); + } + TRACE("Buffer=%p\n", pMsg->Buffer); + /* FIXME: which errors to return? */ + return pMsg->Buffer ? S_OK : E_OUTOFMEMORY; +} + +/*********************************************************************** + * I_RpcFreeBuffer [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); + /* FIXME: pfnFree? */ + if (pMsg->Buffer != NULL) { + HeapFree(GetProcessHeap(), 0, pMsg->Buffer); + } + pMsg->Buffer = NULL; + return S_OK; +} + +/*********************************************************************** + * I_RpcSend [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr; + + TRACE("(%p)\n", pMsg); + if (!bind) return RPC_S_INVALID_BINDING; + + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, + &sif->InterfaceId); + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + } + + if (status != RPC_S_OK) return status; + + if (bind->server) { + if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) { + hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation, + RPC_S_CALL_FAILED); + } else { + hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation, + pMsg->BufferLength); + } + } else { + hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, + pMsg->BufferLength, pMsg->ProcNum, + &bind->ObjectUuid); + } + + status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); + + RPCRT4_FreeHeader(hdr); + + /* success */ + if (!bind->server) { + /* save the connection, so the response can be read from it */ + pMsg->ReservedForRuntime = conn; + return RPC_S_OK; + } + RPCRT4_CloseBinding(bind, conn); + status = RPC_S_OK; + + return status; +} + +/*********************************************************************** + * I_RpcReceive [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr = NULL; + + TRACE("(%p)\n", pMsg); + if (!bind) return RPC_S_INVALID_BINDING; + + if (pMsg->ReservedForRuntime) { + conn = pMsg->ReservedForRuntime; + pMsg->ReservedForRuntime = NULL; + } else { + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, + &sif->InterfaceId); + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + } + if (status != RPC_S_OK) return status; + } + + status = RPCRT4_Receive(conn, &hdr, pMsg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + goto fail; + } + + status = RPC_S_PROTOCOL_ERROR; + + switch (hdr->common.ptype) { + case PKT_RESPONSE: + if (bind->server) goto fail; + break; + case PKT_REQUEST: + if (!bind->server) goto fail; + break; + case PKT_FAULT: + pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + ERR ("we got fault packet with status %lx\n", hdr->fault.status); + status = RPC_S_CALL_FAILED; /* ? */ + goto fail; + default: + goto fail; + } + + /* success */ + status = RPC_S_OK; + +fail: + if (hdr) { + RPCRT4_FreeHeader(hdr); + } + RPCRT4_CloseBinding(bind, conn); + return status; +} + +/*********************************************************************** + * I_RpcSendReceive [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + + TRACE("(%p)\n", pMsg); + status = I_RpcSend(pMsg); + if (status == RPC_S_OK) + status = I_RpcReceive(pMsg); + return status; +} diff --git a/reactos/lib/rpcrt4/rpc_message.h b/reactos/lib/rpcrt4/rpc_message.h new file mode 100644 index 00000000000..9b463992105 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_message.h @@ -0,0 +1,38 @@ +/* + * RPC message API + * + * Copyright 2004 Filip Navara + * + * 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 + */ + +#ifndef __WINE_RPC_MESSAGE_H +#define __WINE_RPC_MESSAGE_H + +#include "wine/rpcss_shared.h" +#include "rpc_defs.h" + +VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, unsigned long DataRepresentation); +RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, unsigned long BufferLength, unsigned short ProcNum, UUID *ObjectUuid); +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, unsigned long BufferLength); +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS Status); +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, RPC_SYNTAX_IDENTIFIER *AbstractId, RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, LPSTR ServerAddress, unsigned long Result, unsigned long Reason, RPC_SYNTAX_IDENTIFIER *TransferId); +VOID RPCRT4_FreeHeader(RpcPktHdr *Header); +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength); +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg); + +#endif diff --git a/reactos/lib/rpcrt4/rpc_misc.h b/reactos/lib/rpcrt4/rpc_misc.h new file mode 100644 index 00000000000..c94d72a6ea4 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_misc.h @@ -0,0 +1,28 @@ +/* + * RPC definitions + * + * Copyright 2003 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 + * + */ + +#ifndef __WINE_RPC_MISC_H +#define __WINE_RPC_MISC_H + +/* flags for RPC_MESSAGE.RpcFlags */ +#define WINE_RPCFLAG_EXCEPTION 0x0001 + +#endif /* __WINE_RPC_MISC_H */ diff --git a/reactos/lib/rpcrt4/rpc_server.c b/reactos/lib/rpcrt4/rpc_server.c new file mode 100644 index 00000000000..57eb4abbd30 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_server.c @@ -0,0 +1,1032 @@ +/* + * RPC server API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * 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: + * - a whole lot + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "ntstatus.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "excpt.h" + +#include "wine/debug.h" +#include "wine/exception.h" + +#include "rpc_server.h" +#include "rpc_misc.h" +#include "rpc_message.h" +#include "rpc_defs.h" + +#define MAX_THREADS 128 + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +typedef struct _RpcPacket +{ + struct _RpcPacket* next; + struct _RpcConnection* conn; + RpcPktHdr* hdr; + RPC_MESSAGE* msg; +} RpcPacket; + +typedef struct _RpcObjTypeMap +{ + /* FIXME: a hash table would be better. */ + struct _RpcObjTypeMap *next; + UUID Object; + UUID Type; +} RpcObjTypeMap; + +static RpcObjTypeMap *RpcObjTypeMaps; + +static RpcServerProtseq* protseqs; +static RpcServerInterface* ifs; + +static CRITICAL_SECTION server_cs; +static CRITICAL_SECTION_DEBUG server_cs_debug = +{ + 0, 0, &server_cs, + { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") } +}; +static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION listen_cs; +static CRITICAL_SECTION_DEBUG listen_cs_debug = +{ + 0, 0, &listen_cs, + { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") } +}; +static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 }; + +static BOOL std_listen; +static LONG listen_count = -1; +static HANDLE mgr_event, server_thread; + +static CRITICAL_SECTION spacket_cs; +static CRITICAL_SECTION_DEBUG spacket_cs_debug = +{ + 0, 0, &spacket_cs, + { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") } +}; +static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 }; + +static RpcPacket* spacket_head; +static RpcPacket* spacket_tail; +static HANDLE server_sem; + +static DWORD worker_count, worker_free, worker_tls; + +static UUID uuid_nil; + +inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) +{ + RpcObjTypeMap *rslt = RpcObjTypeMaps; + RPC_STATUS dummy; + + while (rslt) { + if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break; + rslt = rslt->next; + } + + return rslt; +} + +inline static UUID *LookupObjType(UUID *ObjUuid) +{ + RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid); + if (map) + return &map->Type; + else + return &uuid_nil; +} + +static RpcServerInterface* RPCRT4_find_interface(UUID* object, + RPC_SYNTAX_IDENTIFIER* if_id, + BOOL check_object) +{ + UUID* MgrType = NULL; + RpcServerInterface* cif = NULL; + RPC_STATUS status; + + if (check_object) + MgrType = LookupObjType(object); + EnterCriticalSection(&server_cs); + cif = ifs; + while (cif) { + if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && + (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && + (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break; + cif = cif->Next; + } + LeaveCriticalSection(&server_cs); + TRACE("returning %p for %s\n", cif, debugstr_guid(object)); + return cif; +} + +static void RPCRT4_push_packet(RpcPacket* packet) +{ + packet->next = NULL; + EnterCriticalSection(&spacket_cs); + if (spacket_tail) { + spacket_tail->next = packet; + spacket_tail = packet; + } else { + spacket_head = packet; + spacket_tail = packet; + } + LeaveCriticalSection(&spacket_cs); +} + +static RpcPacket* RPCRT4_pop_packet(void) +{ + RpcPacket* packet; + EnterCriticalSection(&spacket_cs); + packet = spacket_head; + if (packet) { + spacket_head = packet->next; + if (!spacket_head) spacket_tail = NULL; + } + LeaveCriticalSection(&spacket_cs); + if (packet) packet->next = NULL; + return packet; +} + +#ifndef __REACTOS__ +typedef struct { + PRPC_MESSAGE msg; + void* buf; +} packet_state; + +static WINE_EXCEPTION_FILTER(rpc_filter) +{ + packet_state* state; + PRPC_MESSAGE msg; + state = TlsGetValue(worker_tls); + msg = state->msg; + if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg); + msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + msg->BufferLength = sizeof(DWORD); + I_RpcGetBuffer(msg); + *(DWORD*)msg->Buffer = GetExceptionCode(); + WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer); + TRACE("returning failure packet\n"); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) +{ + RpcServerInterface* sif; + RPC_DISPATCH_FUNCTION func; +#ifndef __REACTOS__ + packet_state state; +#endif + UUID *object_uuid; + RpcPktHdr *response; + void *buf = msg->Buffer; + RPC_STATUS status; + +#ifndef __REACTOS__ + state.msg = msg; + state.buf = buf; + TlsSetValue(worker_tls, &state); +#endif + + switch (hdr->common.ptype) { + case PKT_BIND: + TRACE("got bind packet\n"); + + /* FIXME: do more checks! */ + if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE || + !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + TRACE("packet size less than min size, or active interface syntax guid non-null\n"); + sif = NULL; + } else { + sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE); + } + if (sif == NULL) { + TRACE("rejecting bind request on connection %p\n", conn); + /* Report failure to client. */ + response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_VER_MAJOR, RPC_VER_MINOR); + } else { + TRACE("accepting bind request on connection %p\n", conn); + + /* accept. */ + response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, + RPC_MAX_PACKET_SIZE, + conn->Endpoint, + RESULT_ACCEPT, NO_REASON, + &sif->If->TransferSyntax); + + /* save the interface for later use */ + conn->ActiveInterface = hdr->bind.abstract; + conn->MaxTransmissionSize = hdr->bind.max_tsize; + } + + if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK) + goto fail; + + break; + + case PKT_REQUEST: + TRACE("got request packet\n"); + + /* fail if the connection isn't bound with an interface */ + if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, + status); + + RPCRT4_Send(conn, response, NULL, 0); + break; + } + + if (hdr->common.flags & RPC_FLG_OBJECT_UUID) { + object_uuid = (UUID*)(&hdr->request + 1); + } else { + object_uuid = NULL; + } + + sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); + msg->RpcInterfaceInformation = sif->If; + /* copy the endpoint vector from sif to msg so that midl-generated code will use it */ + msg->ManagerEpv = sif->MgrEpv; + if (object_uuid != NULL) { + RPCRT4_SetBindingObject(msg->Handle, object_uuid); + } + + /* find dispatch function */ + msg->ProcNum = hdr->request.opnum; + if (sif->Flags & RPC_IF_OLE) { + /* native ole32 always gives us a dispatch table with a single entry + * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */ + func = *sif->If->DispatchTable->DispatchTable; + } else { + if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) { + ERR("invalid procnum\n"); + func = NULL; + } + func = sif->If->DispatchTable->DispatchTable[msg->ProcNum]; + } + + /* put in the drep. FIXME: is this more universally applicable? + perhaps we should move this outward... */ + msg->DataRepresentation = + MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]), + MAKEWORD(hdr->common.drep[2], hdr->common.drep[3])); + + /* dispatch */ +#ifndef __REACTOS__ + __TRY { + if (func) func(msg); + } __EXCEPT(rpc_filter) { + /* failure packet was created in rpc_filter */ + } __ENDTRY +#else + if (func) func(msg); +#endif + + /* send response packet */ + I_RpcSend(msg); + + msg->RpcInterfaceInformation = NULL; + + break; + + default: + FIXME("unhandled packet type\n"); + break; + } + +fail: + /* clean up */ + if (msg->Buffer == buf) msg->Buffer = NULL; + TRACE("freeing Buffer=%p\n", buf); + HeapFree(GetProcessHeap(), 0, buf); + RPCRT4_DestroyBinding(msg->Handle); + msg->Handle = 0; + I_RpcFreeBuffer(msg); + msg->Buffer = NULL; + RPCRT4_FreeHeader(hdr); +#ifndef __REACTOS__ + TlsSetValue(worker_tls, NULL); +#endif +} + +static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) +{ + DWORD obj; + RpcPacket* pkt; + + for (;;) { + /* idle timeout after 5s */ + obj = WaitForSingleObject(server_sem, 5000); + if (obj == WAIT_TIMEOUT) { + /* if another idle thread exist, self-destruct */ + if (worker_free > 1) break; + continue; + } + pkt = RPCRT4_pop_packet(); + if (!pkt) continue; + InterlockedDecrement(&worker_free); + for (;;) { + RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); + HeapFree(GetProcessHeap(), 0, pkt); + /* try to grab another packet here without waiting + * on the semaphore, in case it hits max */ + pkt = RPCRT4_pop_packet(); + if (!pkt) break; + /* decrement semaphore */ + WaitForSingleObject(server_sem, 0); + } + InterlockedIncrement(&worker_free); + } + InterlockedDecrement(&worker_free); + InterlockedDecrement(&worker_count); + return 0; +} + +static void RPCRT4_create_worker_if_needed(void) +{ + if (!worker_free && worker_count < MAX_THREADS) { + HANDLE thread; + InterlockedIncrement(&worker_count); + InterlockedIncrement(&worker_free); + thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL); + if (thread) CloseHandle(thread); + else { + InterlockedDecrement(&worker_free); + InterlockedDecrement(&worker_count); + } + } +} + +static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) +{ + RpcConnection* conn = (RpcConnection*)the_arg; + RpcPktHdr *hdr; + RpcBinding *pbind; + RPC_MESSAGE *msg; + RPC_STATUS status; + RpcPacket *packet; + + TRACE("(%p)\n", conn); + + for (;;) { + msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); + + /* create temporary binding for dispatch, it will be freed in + * RPCRT4_process_packet */ + RPCRT4_MakeBinding(&pbind, conn); + msg->Handle = (RPC_BINDING_HANDLE)pbind; + + status = RPCRT4_Receive(conn, &hdr, msg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + break; + } + +#if 0 + RPCRT4_process_packet(conn, hdr, msg); +#else + packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket)); + packet->conn = conn; + packet->hdr = hdr; + packet->msg = msg; + RPCRT4_create_worker_if_needed(); + RPCRT4_push_packet(packet); + ReleaseSemaphore(server_sem, 1, NULL); +#endif + msg = NULL; + } + if (msg) HeapFree(GetProcessHeap(), 0, msg); + RPCRT4_DestroyConnection(conn); + return 0; +} + +static void RPCRT4_new_client(RpcConnection* conn) +{ + HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL); + if (!thread) { + DWORD err = GetLastError(); + ERR("failed to create thread, error=%08lx\n", err); + RPCRT4_DestroyConnection(conn); + } + /* we could set conn->thread, but then we'd have to make the io_thread wait + * for that, otherwise the thread might finish, destroy the connection, and + * free the memory we'd write to before we did, causing crashes and stuff - + * so let's implement that later, when we really need conn->thread */ + + CloseHandle( thread ); +} + +static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) +{ + HANDLE m_event = mgr_event, b_handle; + HANDLE *objs = NULL; + DWORD count, res; + RpcServerProtseq* cps; + RpcConnection* conn; + RpcConnection* cconn; + + TRACE("(the_arg == ^%p)\n", the_arg); + + for (;;) { + EnterCriticalSection(&server_cs); + /* open and count connections */ + count = 1; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + RPCRT4_OpenConnection(conn); + if (conn->ovl.hEvent) count++; + conn = conn->Next; + } + cps = cps->Next; + } + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE)); + + objs[0] = m_event; + count = 1; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + if (conn->ovl.hEvent) objs[count++] = conn->ovl.hEvent; + conn = conn->Next; + } + cps = cps->Next; + } + LeaveCriticalSection(&server_cs); + + /* start waiting */ + res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); + if (res == WAIT_OBJECT_0) { + ResetEvent(m_event); + if (!std_listen) break; + } + else if (res == WAIT_FAILED) { + ERR("wait failed\n"); + } + else { + b_handle = objs[res - WAIT_OBJECT_0]; + /* find which connection got a RPC */ + EnterCriticalSection(&server_cs); + conn = NULL; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + if (conn->ovl.hEvent == b_handle) break; + conn = conn->Next; + } + if (conn) break; + cps = cps->Next; + } + cconn = NULL; + if (conn) RPCRT4_SpawnConnection(&cconn, conn); + LeaveCriticalSection(&server_cs); + if (!conn) { + ERR("failed to locate connection for handle %p\n", b_handle); + } + if (cconn) RPCRT4_new_client(cconn); + } + } + HeapFree(GetProcessHeap(), 0, objs); + EnterCriticalSection(&server_cs); + /* close connections */ + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + RPCRT4_CloseConnection(conn); + conn = conn->Next; + } + cps = cps->Next; + } + LeaveCriticalSection(&server_cs); + return 0; +} + +static void RPCRT4_start_listen(void) +{ + TRACE("\n"); + + EnterCriticalSection(&listen_cs); + if (! ++listen_count) { + if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL); + if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL); + if (!worker_tls) worker_tls = TlsAlloc(); + std_listen = TRUE; + server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); + LeaveCriticalSection(&listen_cs); + } else { + LeaveCriticalSection(&listen_cs); + SetEvent(mgr_event); + } +} + +static void RPCRT4_stop_listen(void) +{ + EnterCriticalSection(&listen_cs); + if (listen_count == -1) + LeaveCriticalSection(&listen_cs); + else if (--listen_count == -1) { + std_listen = FALSE; + LeaveCriticalSection(&listen_cs); + SetEvent(mgr_event); + } else + LeaveCriticalSection(&listen_cs); + assert(listen_count > -2); +} + +static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps) +{ + RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL); + + EnterCriticalSection(&server_cs); + ps->Next = protseqs; + protseqs = ps; + LeaveCriticalSection(&server_cs); + + if (std_listen) SetEvent(mgr_event); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerInqBindings (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + DWORD count; + RpcServerProtseq* ps; + RpcConnection* conn; + + if (BindingVector) + TRACE("(*BindingVector == ^%p)\n", *BindingVector); + else + ERR("(BindingVector == NULL!!?)\n"); + + EnterCriticalSection(&server_cs); + /* count connections */ + count = 0; + ps = protseqs; + while (ps) { + conn = ps->conn; + while (conn) { + count++; + conn = conn->Next; + } + ps = ps->Next; + } + if (count) { + /* export bindings */ + *BindingVector = HeapAlloc(GetProcessHeap(), 0, + sizeof(RPC_BINDING_VECTOR) + + sizeof(RPC_BINDING_HANDLE)*(count-1)); + (*BindingVector)->Count = count; + count = 0; + ps = protseqs; + while (ps) { + conn = ps->conn; + while (conn) { + RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], + conn); + count++; + conn = conn->Next; + } + ps = ps->Next; + } + status = RPC_S_OK; + } else { + *BindingVector = NULL; + status = RPC_S_NO_BINDINGS; + } + LeaveCriticalSection(&server_cs); + return status; +} + +/*********************************************************************** + * RpcServerUseProtseqEpA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * RpcServerUseProtseqEpW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * RpcServerUseProtseqEpExA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + RpcServerProtseq* ps; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls, + debugstr_a( Endpoint ), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); + ps->MaxCalls = MaxCalls; + ps->Protseq = RPCRT4_strdupA(Protseq); + ps->Endpoint = RPCRT4_strdupA(Endpoint); + + return RPCRT4_use_protseq(ps); +} + +/*********************************************************************** + * RpcServerUseProtseqEpExW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + RpcServerProtseq* ps; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls, + debugstr_w( Endpoint ), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); + ps->MaxCalls = MaxCalls; + ps->Protseq = RPCRT4_strdupWtoA(Protseq); + ps->Endpoint = RPCRT4_strdupWtoA(Endpoint); + + return RPCRT4_use_protseq(ps); +} + +/*********************************************************************** + * RpcServerUseProtseqA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a(Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerUseProtseqW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerRegisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv ) +{ + TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL ); +} + +/*********************************************************************** + * RpcServerRegisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn ); +} + +/*********************************************************************** + * RpcServerRegisterIf2 (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + RpcServerInterface* sif; + unsigned int i; + + TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, + MaxRpcSize, IfCallbackFn); + TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID), + If->InterfaceId.SyntaxVersion.MajorVersion, + If->InterfaceId.SyntaxVersion.MinorVersion); + TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), + If->TransferSyntax.SyntaxVersion.MajorVersion, + If->TransferSyntax.SyntaxVersion.MinorVersion); + TRACE(" dispatch table: %p\n", If->DispatchTable); + if (If->DispatchTable) { + TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount); + for (i=0; iDispatchTable->DispatchTableCount; i++) { + TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]); + } + TRACE(" reserved: %ld\n", If->DispatchTable->Reserved); + } + TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount); + TRACE(" default manager epv: %p\n", If->DefaultManagerEpv); + TRACE(" interpreter info: %p\n", If->InterpreterInfo); + + sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface)); + sif->If = If; + if (MgrTypeUuid) { + memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID)); + sif->MgrEpv = MgrEpv; + } else { + memset(&sif->MgrTypeUuid, 0, sizeof(UUID)); + sif->MgrEpv = If->DefaultManagerEpv; + } + sif->Flags = Flags; + sif->MaxCalls = MaxCalls; + sif->MaxRpcSize = MaxRpcSize; + sif->IfCallbackFn = IfCallbackFn; + + EnterCriticalSection(&server_cs); + sif->Next = ifs; + ifs = sif; + LeaveCriticalSection(&server_cs); + + if (sif->Flags & RPC_IF_AUTOLISTEN) { + /* well, start listening, I think... */ + RPCRT4_start_listen(); + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) +{ + FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n", + IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles ) +{ + FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n", + IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcObjectSetType (RPCRT4.@) + * + * PARAMS + * ObjUuid [I] "Object" UUID + * TypeUuid [I] "Type" UUID + * + * RETURNS + * RPC_S_OK The call succeeded + * RPC_S_INVALID_OBJECT The provided object (nil) is not valid + * RPC_S_ALREADY_REGISTERED The provided object is already registered + * + * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type + * resets the mapping for the specified object UUID to nil (the default). + * The nil object is always associated with the nil type and cannot be + * reassigned. Servers can support multiple implementations on the same + * interface by registering different end-point vectors for the different + * types. There's no need to call this if a server only supports the nil + * type, as is typical. + */ +RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid ) +{ + RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL; + RPC_STATUS dummy; + + TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid)); + if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) { + /* nil uuid cannot be remapped */ + return RPC_S_INVALID_OBJECT; + } + + /* find the mapping for this object if there is one ... */ + while (map) { + if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break; + prev = map; + map = map->next; + } + if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) { + /* ... and drop it from the list */ + if (map) { + if (prev) + prev->next = map->next; + else + RpcObjTypeMaps = map->next; + HeapFree(GetProcessHeap(), 0, map); + } + } else { + /* ... , fail if we found it ... */ + if (map) + return RPC_S_ALREADY_REGISTERED; + /* ... otherwise create a new one and add it in. */ + map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap)); + memcpy(&map->Object, ObjUuid, sizeof(UUID)); + memcpy(&map->Type, TypeUuid, sizeof(UUID)); + map->next = NULL; + if (prev) + prev->next = map; /* prev is the last map in the linklist */ + else + RpcObjTypeMaps = map; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait ) +{ + TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait); + + if (!protseqs) + return RPC_S_NO_PROTSEQS_REGISTERED; + + EnterCriticalSection(&listen_cs); + + if (std_listen) { + LeaveCriticalSection(&listen_cs); + return RPC_S_ALREADY_LISTENING; + } + + RPCRT4_start_listen(); + + LeaveCriticalSection(&listen_cs); + + if (DontWait) return RPC_S_OK; + + return RpcMgmtWaitServerListen(); +} + +/*********************************************************************** + * RpcMgmtServerWaitListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) +{ + RPC_STATUS rslt = RPC_S_OK; + + TRACE("\n"); + + EnterCriticalSection(&listen_cs); + + if (!std_listen) + if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK ) { + LeaveCriticalSection(&listen_cs); + return rslt; + } + + LeaveCriticalSection(&listen_cs); + + while (std_listen) { + WaitForSingleObject(mgr_event, INFINITE); + if (!std_listen) { + Sleep(100); /* don't spin violently */ + TRACE("spinning.\n"); + } + } + + return rslt; +} + +/*********************************************************************** + * RpcMgmtStopServerListening (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding ) +{ + TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding); + + if (Binding) { + FIXME("client-side invocation not implemented.\n"); + return RPC_S_WRONG_KIND_OF_BINDING; + } + + /* hmm... */ + EnterCriticalSection(&listen_cs); + while (std_listen) + RPCRT4_stop_listen(); + LeaveCriticalSection(&listen_cs); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStartListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd ) +{ + FIXME( "(%p): stub\n", hWnd ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStopListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStopListening( void ) +{ + FIXME( "(): stub\n" ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcWindowProc (RPCRT4.@) + */ +UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam ) +{ + FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam ); + + return 0; +} diff --git a/reactos/lib/rpcrt4/rpc_server.h b/reactos/lib/rpcrt4/rpc_server.h new file mode 100644 index 00000000000..df950bb0599 --- /dev/null +++ b/reactos/lib/rpcrt4/rpc_server.h @@ -0,0 +1,47 @@ +/* + * RPC server API + * + * 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 + */ + +#ifndef __WINE_RPC_SERVER_H +#define __WINE_RPC_SERVER_H + +#include "rpc_binding.h" + +typedef struct _RpcServerProtseq +{ + struct _RpcServerProtseq* Next; + LPSTR Protseq; + LPSTR Endpoint; + UINT MaxCalls; + RpcConnection* conn; +} RpcServerProtseq; + +typedef struct _RpcServerInterface +{ + struct _RpcServerInterface* Next; + RPC_SERVER_INTERFACE* If; + UUID MgrTypeUuid; + RPC_MGR_EPV* MgrEpv; + UINT Flags; + UINT MaxCalls; + UINT MaxRpcSize; + RPC_IF_CALLBACK_FN* IfCallbackFn; +} RpcServerInterface; + +#endif /* __WINE_RPC_SERVER_H */ diff --git a/reactos/lib/rpcrt4/rpcrt4.spec b/reactos/lib/rpcrt4/rpcrt4.spec new file mode 100644 index 00000000000..72efb417851 --- /dev/null +++ b/reactos/lib/rpcrt4/rpcrt4.spec @@ -0,0 +1,581 @@ +@ stub DceErrorInqTextA +@ stub DceErrorInqTextW +@ stdcall -private DllRegisterServer() RPCRT4_DllRegisterServer + +@ stub MesBufferHandleReset +@ stub MesDecodeBufferHandleCreate +@ stub MesDecodeIncrementalHandleCreate +@ stub MesEncodeDynBufferHandleCreate +@ stub MesEncodeFixedBufferHandleCreate +@ stub MesEncodeIncrementalHandleCreate +@ stub MesHandleFree +@ stub MesIncrementalHandleReset +@ stub MesInqProcEncodingId + +@ stub MqGetContext # win9x +@ stub MqRegisterQueue # win9x + +@ stub RpcAbortAsyncCall +@ stub RpcAsyncAbortCall +@ stub RpcAsyncCancelCall +@ stub RpcAsyncCompleteCall +@ stub RpcAsyncGetCallStatus +@ stub RpcAsyncInitializeHandle +@ stub RpcAsyncRegisterInfo +@ stub RpcBindingCopy +@ stdcall RpcBindingFree(ptr) +@ stdcall RpcBindingFromStringBindingA(str ptr) +@ stdcall RpcBindingFromStringBindingW(wstr ptr) +@ stub RpcBindingInqAuthClientA +@ stub RpcBindingInqAuthClientW +@ stub RpcBindingInqAuthClientExA +@ stub RpcBindingInqAuthClientExW +@ stub RpcBindingInqAuthInfoA +@ stub RpcBindingInqAuthInfoW +@ stub RpcBindingInqAuthInfoExA +@ stub RpcBindingInqAuthInfoExW +@ stdcall RpcBindingInqObject(ptr ptr) +@ stub RpcBindingInqOption +@ stub RpcBindingReset +@ stub RpcBindingServerFromClient +@ stub RpcBindingSetAuthInfoA +@ stub RpcBindingSetAuthInfoW +@ stub RpcBindingSetAuthInfoExA +@ stub RpcBindingSetAuthInfoExW +@ stdcall RpcBindingSetObject(ptr ptr) +@ stub RpcBindingSetOption +@ stdcall RpcBindingToStringBindingA(ptr ptr) +@ stdcall RpcBindingToStringBindingW(ptr ptr) +@ stdcall RpcBindingVectorFree(ptr) +@ stub RpcCancelAsyncCall +@ stub RpcCancelThread +@ stub RpcCancelThreadEx +@ stub RpcCertGeneratePrincipalNameA +@ stub RpcCertGeneratePrincipalNameW +@ stub RpcCompleteAsyncCall +@ stdcall RpcEpRegisterA(ptr ptr ptr str) +@ stub RpcEpRegisterW +@ stub RpcEpRegisterNoReplaceA +@ stub RpcEpRegisterNoReplaceW +@ stdcall RpcEpResolveBinding(ptr ptr) +@ stdcall RpcEpUnregister(ptr ptr ptr) +@ stub RpcErrorAddRecord # wxp +@ stub RpcErrorClearInformation # wxp +@ stub RpcErrorEndEnumeration # wxp +@ stub RpcErrorGetNextRecord # wxp +@ stub RpcErrorNumberOfRecords # wxp +@ stub RpcErrorLoadErrorInfo # wxp +@ stub RpcErrorResetEnumeration # wxp +@ stub RpcErrorSaveErrorInfo # wxp +@ stub RpcErrorStartEnumeration # wxp +@ stub RpcFreeAuthorizationContext # wxp +@ stub RpcGetAsyncCallStatus +@ stub RpcIfIdVectorFree +@ stub RpcIfInqId +@ stub RpcImpersonateClient +@ stub RpcInitializeAsyncHandle +@ stub RpcMgmtBindingInqParameter # win9x +@ stub RpcMgmtBindingSetParameter # win9x +@ stub RpcMgmtEnableIdleCleanup +@ stub RpcMgmtEpEltInqBegin +@ stub RpcMgmtEpEltInqDone +@ stub RpcMgmtEpEltInqNextA +@ stub RpcMgmtEpEltInqNextW +@ stub RpcMgmtEpUnregister +@ stub RpcMgmtInqComTimeout +@ stub RpcMgmtInqDefaultProtectLevel +@ stub RpcMgmtInqIfIds +@ stub RpcMgmtInqParameter # win9x +@ stub RpcMgmtInqServerPrincNameA +@ stub RpcMgmtInqServerPrincNameW +@ stub RpcMgmtInqStats +@ stub RpcMgmtIsServerListening +@ stub RpcMgmtSetAuthorizationFn +@ stub RpcMgmtSetCancelTimeout +@ stub RpcMgmtSetComTimeout +@ stub RpcMgmtSetParameter # win9x +@ stub RpcMgmtSetServerStackSize +@ stub RpcMgmtStatsVectorFree +@ stdcall RpcMgmtStopServerListening(ptr) +@ stdcall RpcMgmtWaitServerListen() +@ stub RpcNetworkInqProtseqsA +@ stub RpcNetworkInqProtseqsW +@ stdcall RpcNetworkIsProtseqValidA(ptr) +@ stdcall RpcNetworkIsProtseqValidW(ptr) +@ stub RpcNsBindingInqEntryNameA +@ stub RpcNsBindingInqEntryNameW +@ stub RpcObjectInqType +@ stub RpcObjectSetInqFn +@ stdcall RpcObjectSetType(ptr ptr) +@ stub RpcProtseqVectorFreeA +@ stub RpcProtseqVectorFreeW +@ stdcall RpcRaiseException(long) +@ stub RpcRegisterAsyncInfo +@ stub RpcRevertToSelf +@ stub RpcRevertToSelfEx +@ stdcall RpcServerInqBindings(ptr) +@ stub RpcServerInqCallAttributesA # wxp +@ stub RpcServerInqCallAttributesW # wxp +@ stub RpcServerInqDefaultPrincNameA +@ stub RpcServerInqDefaultPrincNameW +@ stub RpcServerInqIf +@ stdcall RpcServerListen(long long long) +@ stdcall RpcServerRegisterAuthInfoA(str long ptr ptr) +@ stdcall RpcServerRegisterAuthInfoW(wstr long ptr ptr) +@ stdcall RpcServerRegisterIf(ptr ptr ptr) +@ stdcall RpcServerRegisterIfEx(ptr ptr ptr long long ptr) +@ stdcall RpcServerRegisterIf2(ptr ptr ptr long long long ptr) +@ stub RpcServerTestCancel +@ stdcall RpcServerUnregisterIf(ptr ptr long) +@ stdcall RpcServerUnregisterIfEx(ptr ptr long) +@ stub RpcServerUseAllProtseqs +@ stub RpcServerUseAllProtseqsEx +@ stub RpcServerUseAllProtseqsIf +@ stub RpcServerUseAllProtseqsIfEx +@ stdcall RpcServerUseProtseqA(str long ptr) +@ stdcall RpcServerUseProtseqW(wstr long ptr) +@ stub RpcServerUseProtseqExA +@ stub RpcServerUseProtseqExW +@ stdcall RpcServerUseProtseqEpA(str long str ptr) +@ stdcall RpcServerUseProtseqEpW(wstr long wstr ptr) +@ stdcall RpcServerUseProtseqEpExA(str long str ptr ptr) +@ stdcall RpcServerUseProtseqEpExW(wstr long wstr ptr ptr) +@ stub RpcServerUseProtseqIfA +@ stub RpcServerUseProtseqIfW +@ stub RpcServerUseProtseqIfExA +@ stub RpcServerUseProtseqIfExW +@ stub RpcServerYield +@ stub RpcSmAllocate +@ stub RpcSmClientFree +@ stub RpcSmDestroyClientContext +@ stub RpcSmDisableAllocate +@ stub RpcSmEnableAllocate +@ stub RpcSmFree +@ stub RpcSmGetThreadHandle +@ stub RpcSmSetClientAllocFree +@ stub RpcSmSetThreadHandle +@ stub RpcSmSwapClientAllocFree +@ stub RpcSsAllocate +@ stub RpcSsContextLockExclusive # wxp +@ stub RpcSsContextLockShared # wxp +@ stub RpcSsDestroyClientContext +@ stub RpcSsDisableAllocate +@ stub RpcSsDontSerializeContext +@ stub RpcSsEnableAllocate +@ stub RpcSsFree +@ stub RpcSsGetContextBinding +@ stub RpcSsGetThreadHandle +@ stub RpcSsSetClientAllocFree +@ stub RpcSsSetThreadHandle +@ stub RpcSsSwapClientAllocFree +@ stdcall RpcStringBindingComposeA(str str str str str ptr) +@ stdcall RpcStringBindingComposeW(wstr wstr wstr wstr wstr ptr) +@ stdcall RpcStringBindingParseA(str ptr ptr ptr ptr ptr) +@ stdcall RpcStringBindingParseW(wstr ptr ptr ptr ptr ptr) +@ stdcall RpcStringFreeA(ptr) +@ stdcall RpcStringFreeW(ptr) +@ stub RpcTestCancel +@ stub RpcUserFree # wxp + +@ stub TowerConstruct +@ stub TowerExplode + +@ stub SimpleTypeAlignment # wxp +@ stub SimpleTypeBufferSize # wxp +@ stub SimpleTypeMemorySize # wxp + +@ stub pfnFreeRoutines # wxp +@ stub pfnMarshallRouteines # wxp +@ stub pfnSizeRoutines # wxp +@ stub pfnUnmarshallRouteines # wxp + +@ stdcall UuidCompare(ptr ptr ptr) +@ stdcall UuidCreate(ptr) +@ stdcall UuidCreateSequential(ptr) # win 2000 +@ stdcall UuidCreateNil(ptr) +@ stdcall UuidEqual(ptr ptr ptr) +@ stdcall UuidFromStringA(str ptr) +@ stdcall UuidFromStringW(wstr ptr) +@ stdcall UuidHash(ptr ptr) +@ stdcall UuidIsNil(ptr ptr) +@ stdcall UuidToStringA(ptr ptr) +@ stdcall UuidToStringW(ptr ptr) + +@ stdcall CStdStubBuffer_QueryInterface(ptr ptr ptr) +@ stdcall CStdStubBuffer_AddRef(ptr) +@ stdcall CStdStubBuffer_Connect(ptr ptr) +@ stdcall CStdStubBuffer_Disconnect(ptr) +@ stdcall CStdStubBuffer_Invoke(ptr ptr ptr) +@ stdcall CStdStubBuffer_IsIIDSupported(ptr ptr) +@ stdcall CStdStubBuffer_CountRefs(ptr) +@ stdcall CStdStubBuffer_DebugServerQueryInterface(ptr ptr) +@ stdcall CStdStubBuffer_DebugServerRelease(ptr ptr) +@ stdcall NdrCStdStubBuffer_Release(ptr ptr) +@ stub NdrCStdStubBuffer2_Release + +@ stdcall IUnknown_QueryInterface_Proxy(ptr ptr ptr) +@ stdcall IUnknown_AddRef_Proxy(ptr) +@ stdcall IUnknown_Release_Proxy(ptr) + +@ stdcall NdrDllCanUnloadNow(ptr) +@ stdcall NdrDllGetClassObject(ptr ptr ptr ptr ptr ptr) +@ stdcall NdrDllRegisterProxy(long ptr ptr) +@ stdcall NdrDllUnregisterProxy(long ptr ptr) + +@ stdcall NdrAllocate(ptr long) +@ stub NdrAsyncClientCall +@ stub NdrAsyncServerCall +@ stdcall NdrClearOutParameters(ptr ptr ptr) +@ stub NdrClientCall +@ varargs NdrClientCall2(ptr ptr) +@ stub NdrClientInitialize +@ stdcall NdrClientInitializeNew(ptr ptr ptr long) +@ stub NdrContextHandleInitialize +@ stub NdrContextHandleSize +@ stdcall NdrConvert(ptr ptr) +@ stdcall NdrConvert2(ptr ptr long) +@ stub NdrCorrelationFree +@ stub NdrCorrelationInitialize +@ stub NdrCorrelationPass +@ stub CreateServerInterfaceFromStub # wxp +@ stub NdrDcomAsyncClientCall +@ stub NdrDcomAsyncStubCall +@ stdcall NdrFreeBuffer(ptr) +@ stub NdrFullPointerFree +@ stub NdrFullPointerInsertRefId +@ stub NdrFullPointerQueryPointer +@ stub NdrFullPointerQueryRefId +@ stub NdrFullPointerXlatFree +@ stub NdrFullPointerXlatInit +@ stdcall NdrGetBuffer(ptr long ptr) +@ stub NdrGetDcomProtocolVersion +@ stub NdrGetSimpleTypeBufferAlignment # wxp +@ stub NdrGetSimpleTypeBufferSize # wxp +@ stub NdrGetSimpleTypeMemorySize # wxp +@ stub NdrGetTypeFlags # wxp +@ stub NdrGetPartialBuffer +@ stub NdrGetPipeBuffer +@ stub NdrGetUserMarshallInfo +@ stub NdrIsAppDoneWithPipes +@ stub NdrMapCommAndFaultStatus +@ stub NdrMarkNextActivePipe +@ stub NdrMesProcEncodeDecode +@ stub NdrMesProcEncodeDecode2 +@ stub NdrMesSimpleTypeAlignSize +@ stub NdrMesSimpleTypeDecode +@ stub NdrMesSimpleTypeEncode +@ stub NdrMesTypeAlignSize +@ stub NdrMesTypeAlignSize2 +@ stub NdrMesTypeDecode +@ stub NdrMesTypeDecode2 +@ stub NdrMesTypeEncode +@ stub NdrMesTypeEncode2 +@ stub NdrMesTypeFree2 +@ stub NdrNsGetBuffer +@ stub NdrNsSendReceive +@ stdcall NdrOleAllocate(long) +@ stdcall NdrOleFree(ptr) +@ stub NdrOutInit # wxp +@ stub NdrPartialIgnoreClientBufferSize # wxp +@ stub NdrPartialIgnoreClientMarshall # wxp +@ stub NdrPartialIgnoreServerInitialize # wxp +@ stub NdrPartialIgnoreServerUnmarshall # wxp +@ stub NdrPipePull +@ stub NdrPipePush +@ stub NdrPipeSendReceive +@ stub NdrPipesDone +@ stub NdrPipesInitialize +@ stdcall NdrProxyErrorHandler(long) +@ stdcall NdrProxyFreeBuffer(ptr ptr) +@ stdcall NdrProxyGetBuffer(ptr ptr) +@ stdcall NdrProxyInitialize(ptr ptr ptr ptr long) +@ stdcall NdrProxySendReceive(ptr ptr) +@ stub NdrRangeUnmarshall +@ stub NdrRpcSmClientAllocate +@ stub NdrRpcSmClientFree +@ stub NdrRpcSmSetClientToOsf +@ stub NdrRpcSsDefaultAllocate +@ stub NdrRpcSsDefaultFree +@ stub NdrRpcSsDisableAllocate +@ stub NdrRpcSsEnableAllocate +@ stdcall NdrSendReceive(ptr ptr) +@ stub NdrServerCall +@ stub NdrServerCall2 +@ stub NdrStubCall +@ stub NdrStubCall2 +@ stub NdrStubForwardingFunction +@ stdcall NdrStubGetBuffer(ptr ptr ptr) +@ stdcall NdrStubInitialize(ptr ptr ptr ptr) +@ stub NdrStubInitializeMarshall +@ stub NdrpCreateProxy # wxp +@ stub NdrpCreateStub # wxp +@ stub NdrpGetProcFormatString # wxp +@ stub NdrpGetTypeFormatString # wxp +@ stub NdrpGetTypeGenCookie # wxp +@ stub NdrpMemoryIncrement # wxp +@ stub NdrpReleaseTypeFormatString # wxp +@ stub NdrpReleaseTypeGenCookie # wxp +@ stub NdrpSetRpcSsDefaults +@ stub NdrpVarVtOfTypeDesc # wxp +@ stub NdrTypeFlags # wxp +@ stub NdrTypeFree # wxp +@ stub NdrTypeMarshall # wxp +@ stub NdrTypeSize # wxp +@ stub NdrTypeUnmarshall # wxp +@ stub NdrUnmarshallBasetypeInline # wxp + +@ stub NdrByteCountPointerBufferSize +@ stub NdrByteCountPointerFree +@ stub NdrByteCountPointerMarshall +@ stub NdrByteCountPointerUnmarshall +@ stub NdrClientContextMarshall +@ stub NdrClientContextUnmarshall +@ stdcall NdrComplexArrayBufferSize(ptr ptr ptr) +@ stdcall NdrComplexArrayFree(ptr ptr ptr) +@ stdcall NdrComplexArrayMarshall(ptr ptr ptr) +@ stdcall NdrComplexArrayMemorySize(ptr ptr) +@ stdcall NdrComplexArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrComplexStructBufferSize(ptr ptr ptr) +@ stdcall NdrComplexStructFree(ptr ptr ptr) +@ stdcall NdrComplexStructMarshall(ptr ptr ptr) +@ stdcall NdrComplexStructMemorySize(ptr ptr) +@ stdcall NdrComplexStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantArrayBufferSize(ptr ptr ptr) +@ stdcall NdrConformantArrayFree(ptr ptr ptr) +@ stdcall NdrConformantArrayMarshall(ptr ptr ptr) +@ stdcall NdrConformantArrayMemorySize(ptr ptr) +@ stdcall NdrConformantArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantStringBufferSize(ptr ptr ptr) +@ stdcall NdrConformantStringMarshall(ptr ptr ptr) +@ stdcall NdrConformantStringMemorySize(ptr ptr) +@ stdcall NdrConformantStringUnmarshall(ptr ptr ptr long) +@ stub NdrConformantStructBufferSize +@ stub NdrConformantStructFree +@ stub NdrConformantStructMarshall +@ stub NdrConformantStructMemorySize +@ stub NdrConformantStructUnmarshall +@ stdcall NdrConformantVaryingArrayBufferSize(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayFree(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayMarshall(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayMemorySize(ptr ptr) +@ stdcall NdrConformantVaryingArrayUnmarshall(ptr ptr ptr long) +@ stub NdrConformantVaryingStructBufferSize +@ stub NdrConformantVaryingStructFree +@ stub NdrConformantVaryingStructMarshall +@ stub NdrConformantVaryingStructMemorySize +@ stub NdrConformantVaryingStructUnmarshall +@ stub NdrEncapsulatedUnionBufferSize +@ stub NdrEncapsulatedUnionFree +@ stub NdrEncapsulatedUnionMarshall +@ stub NdrEncapsulatedUnionMemorySize +@ stub NdrEncapsulatedUnionUnmarshall +@ stub NdrFixedArrayBufferSize +@ stub NdrFixedArrayFree +@ stub NdrFixedArrayMarshall +@ stub NdrFixedArrayMemorySize +@ stub NdrFixedArrayUnmarshall +@ stub NdrHardStructBufferSize +@ stub NdrHardStructFree +@ stub NdrHardStructMarshall +@ stub NdrHardStructMemorySize +@ stub NdrHardStructUnmarshall +@ stdcall NdrInterfacePointerBufferSize(ptr ptr ptr) +@ stdcall NdrInterfacePointerFree(ptr ptr ptr) +@ stdcall NdrInterfacePointerMarshall(ptr ptr ptr) +@ stdcall NdrInterfacePointerMemorySize(ptr ptr) +@ stdcall NdrInterfacePointerUnmarshall(ptr ptr ptr long) +@ stub NdrNonConformantStringBufferSize +@ stub NdrNonConformantStringMarshall +@ stub NdrNonConformantStringMemorySize +@ stub NdrNonConformantStringUnmarshall +@ stub NdrNonEncapsulatedUnionBufferSize +@ stub NdrNonEncapsulatedUnionFree +@ stub NdrNonEncapsulatedUnionMarshall +@ stub NdrNonEncapsulatedUnionMemorySize +@ stub NdrNonEncapsulatedUnionUnmarshall +@ stdcall NdrPointerBufferSize(ptr ptr ptr) +@ stdcall NdrPointerFree(ptr ptr ptr) +@ stdcall NdrPointerMarshall(ptr ptr ptr) +@ stdcall NdrPointerMemorySize(ptr ptr) +@ stdcall NdrPointerUnmarshall(ptr ptr ptr long) +@ stub NdrServerContextMarshall +@ stub NdrServerContextUnmarshall +@ stub NdrServerContextNewMarshall # wxp +@ stub NdrServerContextNewUnmarshall # wxp +@ stub NdrServerInitialize +@ stub NdrServerInitializeMarshall +@ stdcall NdrServerInitializeNew(ptr ptr ptr) +@ stub NdrServerInitializePartial # wxp +@ stub NdrServerInitializeUnmarshall +@ stub NdrServerMarshall +@ stub NdrServerUnmarshall +@ stdcall NdrSimpleStructBufferSize(ptr ptr ptr) +@ stdcall NdrSimpleStructFree(ptr ptr ptr) +@ stdcall NdrSimpleStructMarshall(ptr ptr ptr) +@ stdcall NdrSimpleStructMemorySize(ptr ptr) +@ stdcall NdrSimpleStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrSimpleTypeMarshall(ptr ptr long) +@ stdcall NdrSimpleTypeUnmarshall(ptr ptr long) +@ stdcall NdrUserMarshalBufferSize(ptr ptr ptr) +@ stdcall NdrUserMarshalFree(ptr ptr ptr) +@ stdcall NdrUserMarshalMarshall(ptr ptr ptr) +@ stdcall NdrUserMarshalMemorySize(ptr ptr) +@ stub NdrUserMarshalSimpleTypeConvert +@ stdcall NdrUserMarshalUnmarshall(ptr ptr ptr long) +@ stub NdrVaryingArrayBufferSize +@ stub NdrVaryingArrayFree +@ stub NdrVaryingArrayMarshall +@ stub NdrVaryingArrayMemorySize +@ stub NdrVaryingArrayUnmarshall +@ stub NdrXmitOrRepAsBufferSize +@ stub NdrXmitOrRepAsFree +@ stub NdrXmitOrRepAsMarshall +@ stub NdrXmitOrRepAsMemorySize +@ stub NdrXmitOrRepAsUnmarshall + +@ stub NDRCContextBinding +@ stub NDRCContextMarshall +@ stub NDRCContextUnmarshall +@ stub NDRSContextMarshall +@ stub NDRSContextUnmarshall +@ stub NDRSContextMarshallEx +@ stub NDRSContextUnmarshallEx +@ stub NDRSContextMarshall2 +@ stub NDRSContextUnmarshall2 +@ stub NDRcopy + +@ stub MIDL_wchar_strcpy +@ stub MIDL_wchar_strlen +@ stub char_array_from_ndr +@ stub char_from_ndr +@ stub data_from_ndr +@ stub data_into_ndr +@ stub data_size_ndr +@ stub double_array_from_ndr +@ stub double_from_ndr +@ stub enum_from_ndr +@ stub float_array_from_ndr +@ stub float_from_ndr +@ stub long_array_from_ndr +@ stub long_from_ndr +@ stub long_from_ndr_temp +@ stub short_array_from_ndr +@ stub short_from_ndr +@ stub short_from_ndr_temp +@ stub tree_into_ndr +@ stub tree_peek_ndr +@ stub tree_size_ndr + +@ stub I_RpcAbortAsyncCall +@ stub I_RpcAllocate +@ stub I_RpcAsyncAbortCall +@ stub I_RpcAsyncSendReceive # NT4 +@ stub I_RpcAsyncSetHandle +@ stub I_RpcBCacheAllocate +@ stub I_RpcBCacheFree +@ stub I_RpcBindingCopy +@ stub I_RpcBindingInqConnId +@ stub I_RpcBindingInqDynamicEndPoint +@ stub I_RpcBindingInqDynamicEndPointA +@ stub I_RpcBindingInqDynamicEndPointW +@ stub I_RpcBindingInqLocalClientPID # wxp +@ stub I_RpcBindingInqSecurityContext +@ stub I_RpcBindingInqTransportType +@ stub I_RpcBindingInqWireIdForSnego +@ stub I_RpcBindingIsClientLocal +@ stub I_RpcBindingToStaticStringBindingW +@ stdcall I_RpcBindingSetAsync(ptr ptr) +# 9x version of I_RpcBindingSetAsync has 3 arguments, not 2 +@ stub I_RpcClearMutex +@ stub I_RpcConnectionInqSockBuffSize +@ stub I_RpcConnectionInqSockBuffSize2 +@ stub I_RpcConnectionSetSockBuffSize +@ stub I_RpcDeleteMutex +@ stub I_RpcEnableWmiTrace # wxp +@ stub I_RpcExceptionFilter # wxp +@ stub I_RpcFree +@ stdcall I_RpcFreeBuffer(ptr) +@ stub I_RpcFreePipeBuffer +@ stub I_RpcGetAssociationContext +@ stdcall I_RpcGetBuffer(ptr) +@ stub I_RpcGetBufferWithObject +@ stub I_RpcGetCurrentCallHandle +@ stub I_RpcGetExtendedError +@ stub I_RpcGetServerContextList +@ stub I_RpcGetThreadEvent # win9x +@ stub I_RpcGetThreadWindowHandle # win9x +@ stub I_RpcIfInqTransferSyntaxes +@ stub I_RpcLaunchDatagramReceiveThread # win9x +@ stub I_RpcLogEvent +@ stub I_RpcMapWin32Status +@ stub I_RpcMonitorAssociation +@ stub I_RpcNegotiateTransferSyntax # wxp +@ stub I_RpcNsBindingSetEntryName +@ stub I_RpcNsBindingSetEntryNameA +@ stub I_RpcNsBindingSetEntryNameW +@ stub I_RpcNsInterfaceExported +@ stub I_RpcNsInterfaceUnexported +@ stub I_RpcParseSecurity +@ stub I_RpcPauseExecution +@ stub I_RpcProxyNewConnection # wxp +@ stub I_RpcReallocPipeBuffer +@ stdcall I_RpcReceive(ptr) +@ stub I_RpcRequestMutex +@ stdcall I_RpcSend(ptr) +@ stdcall I_RpcSendReceive(ptr) +@ stub I_RpcServerAllocateIpPort +@ stub I_RpcServerInqAddressChangeFn +@ stub I_RpcServerInqLocalConnAddress # wxp +@ stub I_RpcServerInqTransportType +@ stub I_RpcServerRegisterForwardFunction +@ stub I_RpcServerSetAddressChangeFn +@ stdcall I_RpcServerStartListening(ptr) # win9x +@ stdcall I_RpcServerStopListening() # win9x +@ stub I_RpcServerUnregisterEndpointA # win9x +@ stub I_RpcServerUnregisterEndpointW # win9x +@ stub I_RpcServerUseProtseq2A +@ stub I_RpcServerUseProtseq2W +@ stub I_RpcServerUseProtseqEp2A +@ stub I_RpcServerUseProtseqEp2W +@ stub I_RpcSetAsyncHandle +@ stub I_RpcSetAssociationContext # win9x +@ stub I_RpcSetServerContextList +@ stub I_RpcSetThreadParams # win9x +@ stub I_RpcSetWMsgEndpoint # NT4 +@ stub I_RpcSsDontSerializeContext +@ stub I_RpcSystemFunction001 # wxp (oh, brother!) +@ stub I_RpcStopMonitorAssociation +@ stub I_RpcTransCancelMigration # win9x +@ stub I_RpcTransClientMaxFrag # win9x +@ stub I_RpcTransClientReallocBuffer # win9x +@ stub I_RpcTransConnectionAllocatePacket +@ stub I_RpcTransConnectionFreePacket +@ stub I_RpcTransConnectionReallocPacket +@ stub I_RpcTransDatagramAllocate +@ stub I_RpcTransDatagramAllocate2 +@ stub I_RpcTransDatagramFree +@ stub I_RpcTransGetAddressList +@ stub I_RpcTransGetThreadEvent +@ stub I_RpcTransIoCancelled +@ stub I_RpcTransMaybeMakeReceiveAny # win9x +@ stub I_RpcTransMaybeMakeReceiveDirect # win9x +@ stub I_RpcTransPingServer # win9x +@ stub I_RpcTransServerFindConnection # win9x +@ stub I_RpcTransServerFreeBuffer # win9x +@ stub I_RpcTransServerMaxFrag # win9x +@ stub I_RpcTransServerNewConnection +@ stub I_RpcTransServerProtectThread # win9x +@ stub I_RpcTransServerReallocBuffer # win9x +@ stub I_RpcTransServerReceiveDirectReady # win9x +@ stub I_RpcTransServerUnprotectThread # win9x +@ stub I_RpcTurnOnEEInfoPropagation # wxp +@ stdcall I_RpcWindowProc(ptr long long long) # win9x +@ stub I_RpcltDebugSetPDUFilter +@ stub I_UuidCreate + +@ stdcall CreateProxyFromTypeInfo(ptr ptr ptr ptr ptr) +@ stub CreateStubFromTypeInfo +@ stub PerformRpcInitialization +@ stub StartServiceIfNecessary # win9x +@ stub GlobalMutexClearExternal +@ stub GlobalMutexRequestExternal diff --git a/reactos/lib/rpcrt4/rpcrt4_main.c b/reactos/lib/rpcrt4/rpcrt4_main.c new file mode 100644 index 00000000000..baf7914e2b6 --- /dev/null +++ b/reactos/lib/rpcrt4/rpcrt4_main.c @@ -0,0 +1,750 @@ +/* + * RPCRT4 + * + * Copyright 2000 Huw D M Davies for CodeWeavers + * + * 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 + * + * WINE RPC TODO's (and a few TODONT's) + * + * - Ove's decreasingly incomplete widl is an IDL compiler for wine. For widl + * to be wine's only IDL compiler, a fair bit of work remains to be done. + * until then we have used some midl-generated stuff. (What?) + * widl currently doesn't generate stub/proxy files required by wine's (O)RPC + * capabilities -- nor does it make those lovely format strings :( + * The MS MIDL compiler does some really esoteric stuff. Of course Ove has + * started with the less esoteric stuff. There are also lots of nice + * comments in there if you want to flex your bison and help build this monster. + * + * - RPC has a quite featureful error handling mechanism; basically none of this is + * implemented right now. We also have deficiencies on the compiler side, where + * wine's __TRY / __EXCEPT / __FINALLY macros are not even used for RpcTryExcept & co, + * due to syntactic differences! (we can fix it with widl by using __TRY) + * + * - There are several different memory allocation schemes for MSRPC. + * I don't even understand what they all are yet, much less have them + * properly implemented. Surely we are supposed to be doing something with + * the user-provided allocation/deallocation functions, but so far, + * I don't think we are doing this... + * + * - MSRPC provides impersonation capabilities which currently are not possible + * to implement in wine. At the very least we should implement the authorization + * API's & gracefully ignore the irrelevant stuff (to an extent we already do). + * + * - Some transports are not yet implemented. The existing transport implementations + * are incomplete and may be bug-infested. + * + * - The various transports that we do support ought to be supported in a more + * object-oriented manner, as in DCE's RPC implementation, instead of cluttering + * up the code with conditionals like we do now. + * + * - Data marshalling: So far, only the beginnings of a full implementation + * exist in wine. NDR protocol itself is documented, but the MS API's to + * convert data-types in memory into NDR are not. This is challenging work, + * and has supposedly been "at the top of Greg's queue" for several months now. + * + * - ORPC is RPC for OLE; once we have a working RPC framework, we can + * use it to implement out-of-process OLE client/server communications. + * ATM there is maybe a disconnect between the marshalling in the OLE DLL's + * and the marshalling going on here [TODO: well, is there or not?] + * + * - In-source API Documentation, at least for those functions which we have + * implemented, but preferably for everything we can document, would be nice, + * since some of this stuff is quite obscure. + * + * - Name services... [TODO: what about them] + * + * - Protocol Towers: Totally unimplemented.... I think. + * + * - Context Handle Rundown: whatever that is. + * + * - Nested RPC's: Totally unimplemented. + * + * - Statistics: we are supposed to be keeping various counters. we aren't. + * + * - Async RPC: Unimplemented. + * + * - XML/http RPC: Somewhere there's an XML fiend that wants to do this! Betcha + * we could use these as a transport for RPC's across computers without a + * permissions and/or licensing crisis. + * + * - The NT "ports" API, aka LPC. Greg claims this is on his radar. Might (or + * might not) enable users to get some kind of meaningful result out of + * NT-based native rpcrt4's. Commonly-used transport for self-to-self RPC's. + * + * - ...? More stuff I haven't thought of. If you think of more RPC todo's + * drop me an e-mail or send a patch to the + * wine-patches mailing list. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "winuser.h" +#include "iptypes.h" +#include "iphlpapi.h" +#include "wine/unicode.h" +#include "rpc.h" + +#include "ole2.h" +#include "rpcndr.h" +#include "rpcproxy.h" + +#include "rpc_binding.h" +#include "rpcss_np_client.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static UUID uuid_nil; +static HANDLE master_mutex; + +HANDLE RPCRT4_GetMasterMutex(void) +{ + return master_mutex; +} + +static CRITICAL_SECTION uuid_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &uuid_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": uuid_cs") } +}; +static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +/*********************************************************************** + * DllMain + * + * PARAMS + * hinstDLL [I] handle to the DLL's instance + * fdwReason [I] + * lpvReserved [I] reserved, must be NULL + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); + if (!master_mutex) + ERR("Failed to create master mutex\n"); + break; + + case DLL_PROCESS_DETACH: + CloseHandle(master_mutex); + master_mutex = NULL; + break; + } + + return TRUE; +} + +/************************************************************************* + * RpcStringFreeA [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeA(unsigned char** String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcStringFreeW [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeW(unsigned short** String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcRaiseException [RPCRT4.@] + * + * Raises an exception. + */ +void WINAPI RpcRaiseException(RPC_STATUS exception) +{ + /* FIXME: translate exception? */ + RaiseException(exception, 0, 0, NULL); +} + +/************************************************************************* + * UuidCompare [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * -1 if Uuid1 is less than Uuid2 + * 0 if Uuid1 and Uuid2 are equal + * 1 if Uuid1 is greater than Uuid2 + */ +int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + int i; + + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + + *Status = RPC_S_OK; + + if (!Uuid1) Uuid1 = &uuid_nil; + if (!Uuid2) Uuid2 = &uuid_nil; + + if (Uuid1 == Uuid2) return 0; + + if (Uuid1->Data1 != Uuid2->Data1) + return Uuid1->Data1 < Uuid2->Data1 ? -1 : 1; + + if (Uuid1->Data2 != Uuid2->Data2) + return Uuid1->Data2 < Uuid2->Data2 ? -1 : 1; + + if (Uuid1->Data3 != Uuid2->Data3) + return Uuid1->Data3 < Uuid2->Data3 ? -1 : 1; + + for (i = 0; i < 8; i++) { + if (Uuid1->Data4[i] < Uuid2->Data4[i]) + return -1; + if (Uuid1->Data4[i] > Uuid2->Data4[i]) + return 1; + } + + return 0; +} + +/************************************************************************* + * UuidEqual [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + return !UuidCompare(Uuid1, Uuid2, Status); +} + +/************************************************************************* + * UuidIsNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [I] Uuid to compare + * RPC_STATUS *Status [O] retuns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidIsNil(UUID *Uuid, RPC_STATUS *Status) +{ + TRACE("(%s)\n", debugstr_guid(Uuid)); + if (!Uuid) return TRUE; + return !UuidCompare(Uuid, &uuid_nil, Status); +} + + /************************************************************************* + * UuidCreateNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [O] returns a nil UUID + * + * RETURNS + * RPC_S_OK + */ +RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid) +{ + *Uuid = uuid_nil; + return RPC_S_OK; +} + +/* Number of 100ns ticks per clock tick. To be safe, assume that the clock + resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ +#define TICKS_PER_CLOCK_TICK 1000 +#define SECSPERDAY 86400 +#define TICKSPERSEC 10000000 +/* UUID system time starts at October 15, 1582 */ +#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) +#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) + +static void RPC_UuidGetSystemTime(ULONGLONG *time) +{ + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + + *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime; + *time += TICKS_15_OCT_1582_TO_1601; +} + +/* Assume that a hardware address is at least 6 bytes long */ +#define ADDRESS_BYTES_NEEDED 6 + +static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) +{ + int i; + DWORD status = RPC_S_OK; + + ULONG buflen = sizeof(IP_ADAPTER_INFO); + PIP_ADAPTER_INFO adapter = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, buflen); + + if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { + HeapFree(GetProcessHeap(), 0, adapter); + adapter = (IP_ADAPTER_INFO *)HeapAlloc(GetProcessHeap(), 0, buflen); + } + + if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = adapter->Address[i]; + } + } + /* We can't get a hardware address, just use random numbers. + Set the multicast bit to prevent conflicts with real cards. */ + else { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = rand() & 0xff; + } + + address[0] |= 0x80; + status = RPC_S_UUID_LOCAL_ONLY; + } + + HeapFree(GetProcessHeap(), 0, adapter); + return status; +} + +/************************************************************************* + * UuidCreate [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + * FIXME: No compensation for changes across reloading + * this dll or across reboots (e.g. clock going + * backwards and swapped network cards). The RFC + * suggests using NVRAM for storing persistent + * values. + */ +RPC_STATUS WINAPI UuidCreate(UUID *Uuid) +{ + static int initialised, count; + + ULONGLONG time; + static ULONGLONG timelast; + static WORD sequence; + + static DWORD status; + static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH]; + + EnterCriticalSection(&uuid_cs); + + if (!initialised) { + RPC_UuidGetSystemTime(&timelast); + count = TICKS_PER_CLOCK_TICK; + + sequence = ((rand() & 0xff) << 8) + (rand() & 0xff); + sequence &= 0x1fff; + + status = RPC_UuidGetNodeAddress(address); + initialised = 1; + } + + /* Generate time element of the UUID. Account for going faster + than our clock as well as the clock going backwards. */ + while (1) { + RPC_UuidGetSystemTime(&time); + if (time > timelast) { + count = 0; + break; + } + if (time < timelast) { + sequence = (sequence + 1) & 0x1fff; + count = 0; + break; + } + if (count < TICKS_PER_CLOCK_TICK) { + count++; + break; + } + } + + timelast = time; + time += count; + + /* Pack the information into the UUID structure. */ + + Uuid->Data1 = (unsigned long)(time & 0xffffffff); + Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff); + Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff); + + /* This is a version 1 UUID */ + Uuid->Data3 |= (1 << 12); + + Uuid->Data4[0] = sequence & 0xff; + Uuid->Data4[1] = (sequence & 0x3f00) >> 8; + Uuid->Data4[1] |= 0x80; + + Uuid->Data4[2] = address[0]; + Uuid->Data4[3] = address[1]; + Uuid->Data4[4] = address[2]; + Uuid->Data4[5] = address[3]; + Uuid->Data4[6] = address[4]; + Uuid->Data4[7] = address[5]; + + LeaveCriticalSection(&uuid_cs); + + TRACE("%s\n", debugstr_guid(Uuid)); + + return status; +} + +/************************************************************************* + * UuidCreateSequential [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + */ +RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid) +{ + return UuidCreate(Uuid); +} + + +/************************************************************************* + * UuidHash [RPCRT4.@] + * + * Generates a hash value for a given UUID + * + * Code based on FreeDCE implementation + * + */ +unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status) +{ + BYTE *data = (BYTE*)uuid; + short c0 = 0, c1 = 0, x, y; + unsigned int i; + + if (!uuid) data = (BYTE*)(uuid = &uuid_nil); + + TRACE("(%s)\n", debugstr_guid(uuid)); + + for (i=0; iData1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + return RPC_S_OK; +} + +/************************************************************************* + * UuidToStringW [RPCRT4.@] + * + * Converts a UUID to a string. + * + * S_OK if successful. + * S_OUT_OF_MEMORY if unsucessful. + */ +RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, unsigned short** StringUuid) +{ + char buf[37]; + + if (!Uuid) Uuid = &uuid_nil; + + sprintf(buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + Uuid->Data1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + *StringUuid = RPCRT4_strdupAtoW(buf); + + if(!(*StringUuid)) + return RPC_S_OUT_OF_MEMORY; + + return RPC_S_OK; +} + +static const BYTE hex2bin[] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */ + 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */ + 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */ + 0,10,11,12,13,14,15 /* 0x60 */ +}; + +/*********************************************************************** + * UuidFromStringA (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringA(unsigned char* str, UUID *uuid) +{ + BYTE *s = (BYTE *)str; + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlen(s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + + +/*********************************************************************** + * UuidFromStringW (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringW(unsigned short* s, UUID *uuid) +{ + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlenW(s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + +/*********************************************************************** + * DllRegisterServer (RPCRT4.@) + */ + +HRESULT WINAPI RPCRT4_DllRegisterServer( void ) +{ + FIXME( "(): stub\n" ); + return S_OK; +} + +BOOL RPCRT4_StartRPCSS(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + static char cmd[6]; + BOOL rslt; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFOA)); + si.cb = sizeof(STARTUPINFOA); + + /* apparently it's not OK to use a constant string below */ + CopyMemory(cmd, "rpcss", 6); + + /* FIXME: will this do the right thing when run as a test? */ + rslt = CreateProcessA( + NULL, /* executable */ + cmd, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi /* PROCESS_INFORMATION */ + ); + + if (rslt) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return rslt; +} + +/*********************************************************************** + * RPCRT4_RPCSSOnDemandCall (internal) + * + * Attempts to send a message to the RPCSS process + * on the local machine, invoking it if necessary. + * For remote RPCSS calls, use.... your imagination. + * + * PARAMS + * msg [I] pointer to the RPCSS message + * vardata_payload [I] pointer vardata portion of the RPCSS message + * reply [O] pointer to reply structure + * + * RETURNS + * TRUE if successful + * FALSE otherwise + */ +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) +{ + HANDLE client_handle; + int i, j = 0; + + TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); + + client_handle = RPCRT4_RpcssNPConnect(); + + while (!client_handle) { + /* start the RPCSS process */ + if (!RPCRT4_StartRPCSS()) { + ERR("Unable to start RPCSS process.\n"); + return FALSE; + } + /* wait for a connection (w/ periodic polling) */ + for (i = 0; i < 60; i++) { + Sleep(200); + client_handle = RPCRT4_RpcssNPConnect(); + if (client_handle) break; + } + /* we are only willing to try twice */ + if (j++ >= 1) break; + } + + if (!client_handle) { + /* no dice! */ + ERR("Unable to connect to RPCSS process!\n"); + SetLastError(RPC_E_SERVER_DIED_DNE); + return FALSE; + } + + /* great, we're connected. now send the message */ + if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { + ERR("Something is amiss: RPC_SendReceive failed.\n"); + return FALSE; + } + + return TRUE; +} diff --git a/reactos/lib/rpcrt4/rpcss_np_client.c b/reactos/lib/rpcrt4/rpcss_np_client.c new file mode 100644 index 00000000000..62b1843e631 --- /dev/null +++ b/reactos/lib/rpcrt4/rpcss_np_client.c @@ -0,0 +1,154 @@ +/* + * RPCSS named pipe client implementation + * + * Copyright (C) 2002 Greg Turner + * + * 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "ntstatus.h" +#include "wine/rpcss_shared.h" +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HANDLE RPCRT4_RpcssNPConnect(void) +{ + HANDLE the_pipe = NULL; + DWORD dwmode, wait_result; + HANDLE master_mutex = RPCRT4_GetMasterMutex(); + + TRACE("\n"); + + while (TRUE) { + + wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT); + switch (wait_result) { + case WAIT_ABANDONED: + case WAIT_OBJECT_0: + break; + case WAIT_FAILED: + case WAIT_TIMEOUT: + default: + ERR("This should never happen: couldn't enter mutex.\n"); + return NULL; + } + + /* try to open the client side of the named pipe. */ + the_pipe = CreateFileA( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + GENERIC_READ | GENERIC_WRITE, /* r/w access */ + 0, /* no sharing */ + NULL, /* no security attributes */ + OPEN_EXISTING, /* open an existing pipe */ + 0, /* default attributes */ + NULL /* no template file */ + ); + + if (the_pipe != INVALID_HANDLE_VALUE) + break; + + if (GetLastError() != ERROR_PIPE_BUSY) { + WARN("Unable to open named pipe %s (assuming unavailable).\n", + debugstr_a(NAME_RPCSS_NAMED_PIPE)); + the_pipe = NULL; + break; + } + + WARN("Named pipe busy (will wait)\n"); + + if (!ReleaseMutex(master_mutex)) + ERR("Failed to release master mutex. Expect deadlock.\n"); + + /* wait for the named pipe. We are only + willing to wait only 5 seconds. It should be available /very/ soon. */ + if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT)) + { + ERR("Named pipe unavailable after waiting. Something is probably wrong.\n"); + return NULL; + } + + } + + if (the_pipe) { + dwmode = PIPE_READMODE_MESSAGE; + /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */ + if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) + WARN("Failed to set pipe handle state\n"); + } + + if (!ReleaseMutex(master_mutex)) + ERR("Uh oh, failed to leave the RPC Master Mutex!\n"); + + return the_pipe; +} + +BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply) +{ + DWORD count; + UINT32 payload_offset; + RPCSS_NP_MESSAGE vardata_payload_msg; + + TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n", + np, msg, vardata, reply); + + if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("write failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_MESSAGE)) { + ERR("write count mismatch.\n"); + return FALSE; + } + + /* process the vardata payload if necessary */ + vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG; + vardata_payload_msg.vardata_payload_size = 0; /* meaningless */ + for ( payload_offset = 0; payload_offset < msg->vardata_payload_size; + payload_offset += VARDATA_PAYLOAD_BYTES ) { + TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata, + payload_offset, msg->vardata_payload_size); + ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); + CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, + vardata, + min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset )); + vardata += VARDATA_PAYLOAD_BYTES; + if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("vardata write failed at %u bytes.\n", payload_offset); + return FALSE; + } + } + + if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) { + ERR("read failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_REPLY)) { + ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY)); + return FALSE; + } + + /* message execution was successful */ + return TRUE; +} diff --git a/reactos/lib/rpcrt4/rpcss_np_client.h b/reactos/lib/rpcrt4/rpcss_np_client.h new file mode 100644 index 00000000000..54793151353 --- /dev/null +++ b/reactos/lib/rpcrt4/rpcss_np_client.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2002 Greg Turner + * + * 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 + */ + +#ifndef __WINE_RPCSS_NP_CLIENT_H +#define __WINE_RPCSS_NP_CLIENT_H + +/* rpcss_np_client.c */ +HANDLE RPC_RpcssNPConnect(void); +BOOL RPCRT4_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY); + +#endif /* __RPCSS_NP_CLINET_H */