/*
- * NDR client stuff
+ * NDR -Oi,-Oif,-Oicf Interpreter
*
* Copyright 2001 Ove Kåven, TransGaming Technologies
+ * Copyright 2003-5 Robert Shearman (for CodeWeavers)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* TODO:
- * - Exception handling
- * - Context stuff
- * - Who knows
+ * - Pipes
+ * - Some types of binding handles
*/
+#include "config.h"
+#include "wine/port.h"
+
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
-#include "winreg.h"
+#include "objbase.h"
#include "rpc.h"
-#include "rpcndr.h"
+#include "rpcproxy.h"
+#include "wine/exception.h"
#include "wine/debug.h"
+#include "wine/rpcfc.h"
+#include "cpsf.h"
#include "ndr_misc.h"
+#include "ndr_stubless.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(rpc);
-WINE_DEFAULT_DEBUG_CHANNEL(ole);
+#define NDR_TABLE_MASK 127
-LONG_PTR /* CLIENT_CALL_RETURN */ RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, va_list args)
+static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
{
+ NDR_BUFFERSIZE m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK];
+ if (m) m(pStubMsg, pMemory, pFormat);
+ else
+ {
+ FIXME("format type 0x%x not implemented\n", pFormat[0]);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+}
- 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;
+static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
+{
+ NDR_MARSHALL m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK];
+ if (m) return m(pStubMsg, pMemory, pFormat);
+ else
+ {
+ FIXME("format type 0x%x not implemented\n", pFormat[0]);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ return NULL;
+ }
+}
+
+static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc)
+{
+ NDR_UNMARSHALL m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK];
+ if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc);
+ else
+ {
+ FIXME("format type 0x%x not implemented\n", pFormat[0]);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ return NULL;
+ }
+}
+
+static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
+{
+ NDR_FREE m = NdrFreer[pFormat[0] & NDR_TABLE_MASK];
+ if (m) m(pStubMsg, pMemory, pFormat);
+}
+
+static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat)
+{
+ NDR_MEMORYSIZE m = NdrMemorySizer[pFormat[0] & NDR_TABLE_MASK];
+ if (m)
+ {
+ unsigned char *saved_buffer = pStubMsg->Buffer;
+ unsigned long ret;
+ int saved_ignore_embedded_pointers = pStubMsg->IgnoreEmbeddedPointers;
+ pStubMsg->MemorySize = 0;
+ pStubMsg->IgnoreEmbeddedPointers = 1;
+ ret = m(pStubMsg, pFormat);
+ pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded_pointers;
+ pStubMsg->Buffer = saved_buffer;
+ return ret;
+ }
+ else
+ {
+ FIXME("format type 0x%x not implemented\n", pFormat[0]);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ return 0;
+ }
+}
+
+#define STUBLESS_UNMARSHAL 1
+#define STUBLESS_INITOUT 2
+#define STUBLESS_CALLSERVER 3
+#define STUBLESS_CALCSIZE 4
+#define STUBLESS_GETBUFFER 5
+#define STUBLESS_MARSHAL 6
+#define STUBLESS_FREE 7
+
+void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
+{
+#if 0 /* these functions are not defined yet */
+ pMessage->pfnAllocate = NdrRpcSmClientAllocate;
+ pMessage->pfnFree = NdrRpcSmClientFree;
+#endif
+}
+
+static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes)
+{
+ if (param_attributes.MustSize) TRACE(" MustSize");
+ if (param_attributes.MustFree) TRACE(" MustFree");
+ if (param_attributes.IsPipe) TRACE(" IsPipe");
+ if (param_attributes.IsIn) TRACE(" IsIn");
+ if (param_attributes.IsOut) TRACE(" IsOut");
+ if (param_attributes.IsReturn) TRACE(" IsReturn");
+ if (param_attributes.IsBasetype) TRACE(" IsBasetype");
+ if (param_attributes.IsByValue) TRACE(" IsByValue");
+ if (param_attributes.IsSimpleRef) TRACE(" IsSimpleRef");
+ if (param_attributes.IsDontCallFreeInst) TRACE(" IsDontCallFreeInst");
+ if (param_attributes.SaveForAsyncFinish) TRACE(" SaveForAsyncFinish");
+ if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
+}
+
+static void WINAPI dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
+{
+ if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize");
+ if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize");
+ if (Oi2Flags.HasReturn) TRACE(" HasReturn");
+ if (Oi2Flags.HasPipes) TRACE(" HasPipes");
+ if (Oi2Flags.Unused) TRACE(" Unused");
+ if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid");
+ if (Oi2Flags.HasExtensions) TRACE(" HasExtensions");
+ if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle");
+ TRACE("\n");
+}
+
+#define ARG_FROM_OFFSET(stubMsg, offset) ((stubMsg).StackTop + (offset))
+
+static PFORMAT_STRING client_get_handle(
+ PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
+ PFORMAT_STRING pFormat, handle_t *phBinding)
+{
+ /* binding */
+ switch (pProcHeader->handle_type)
+ {
+ /* explicit binding: parse additional section */
+ case RPC_FC_BIND_EXPLICIT:
+ switch (*pFormat) /* handle_type */
+ {
+ case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
+ {
+ const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
+
+ TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
+
+ if (pDesc->flag) /* pointer to binding */
+ *phBinding = **(handle_t **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ else
+ *phBinding = *(handle_t *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ return pFormat + sizeof(NDR_EHD_PRIMITIVE);
+ }
+ case RPC_FC_BIND_GENERIC: /* explicit generic */
+ {
+ const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
+ void *pObject = NULL;
+ void *pArg;
+ const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
+
+ TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
+
+ if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
+ pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ else
+ pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
+ pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
+ *phBinding = pGenPair->pfnBind(pObject);
+ return pFormat + sizeof(NDR_EHD_GENERIC);
+ }
+ case RPC_FC_BIND_CONTEXT: /* explicit context */
+ {
+ const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
+ NDR_CCONTEXT context_handle;
+ TRACE("Explicit bind context\n");
+ if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
+ {
+ TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
+ context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ }
+ else
+ context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ if ((pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) &&
+ !context_handle)
+ {
+ ERR("null context handle isn't allowed\n");
+ RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
+ return NULL;
+ }
+ *phBinding = NDRCContextBinding(context_handle);
+ /* FIXME: should we store this structure in stubMsg.pContext? */
+ return pFormat + sizeof(NDR_EHD_CONTEXT);
+ }
+ default:
+ ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+ break;
+ case RPC_FC_BIND_GENERIC: /* implicit generic */
+ FIXME("RPC_FC_BIND_GENERIC\n");
+ RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
+ break;
+ case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
+ TRACE("Implicit primitive handle\n");
+ *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
+ break;
+ case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
+ FIXME("RPC_FC_CALLBACK_HANDLE\n");
+ break;
+ case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
+ /* strictly speaking, it isn't necessary to set hBinding here
+ * since it isn't actually used (hence the automatic in its name),
+ * but then why does MIDL generate a valid entry in the
+ * MIDL_STUB_DESC for it? */
+ TRACE("Implicit auto handle\n");
+ *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
+ break;
+ default:
+ ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+ return pFormat;
+}
+
+static void client_free_handle(
+ PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
+ PFORMAT_STRING pFormat, handle_t hBinding)
+{
+ /* binding */
+ switch (pProcHeader->handle_type)
+ {
+ /* explicit binding: parse additional section */
+ case RPC_FC_BIND_EXPLICIT:
+ switch (*pFormat) /* handle_type */
+ {
+ case RPC_FC_BIND_GENERIC: /* explicit generic */
+ {
+ const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
+ void *pObject = NULL;
+ void *pArg;
+ const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
+
+ TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
+
+ if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
+ pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ else
+ pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
+ memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
+ pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
+ pGenPair->pfnUnbind(pObject, hBinding);
+ break;
+ }
+ case RPC_FC_BIND_CONTEXT: /* explicit context */
+ case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
+ break;
+ default:
+ ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+ break;
+ case RPC_FC_BIND_GENERIC: /* implicit generic */
+ FIXME("RPC_FC_BIND_GENERIC\n");
+ RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
+ break;
+ case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
+ case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
+ case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
+ break;
+ default:
+ ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+}
+
+static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
+ int phase, unsigned short number_of_params, unsigned char *pRetVal)
+{
+ /* current format string offset */
+ int current_offset = 0;
+ /* current stack offset */
+ unsigned short current_stack_offset = 0;
+ /* counter */
+ unsigned short i;
+
+ for (i = 0; i < number_of_params; i++)
+ {
+ const NDR_PARAM_OIF_BASETYPE *pParam =
+ (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
+ unsigned char * pArg;
+
+ current_stack_offset = pParam->stack_offset;
+ pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset);
+
+ TRACE("param[%d]: new format\n", i);
+ TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
+ TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
+ TRACE("\tmemory addr (before): %p\n", pArg);
+
+ if (pParam->param_attributes.IsBasetype)
+ {
+ const unsigned char * pTypeFormat =
+ &pParam->type_format_char;
+
+ if (pParam->param_attributes.IsSimpleRef)
+ pArg = *(unsigned char **)pArg;
+
+ TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
+
+ switch (phase)
+ {
+ case PROXY_CALCSIZE:
+ if (pParam->param_attributes.IsIn)
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ break;
+ case PROXY_MARSHAL:
+ if (pParam->param_attributes.IsIn)
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ break;
+ case PROXY_UNMARSHAL:
+ if (pParam->param_attributes.IsOut)
+ {
+ if (pParam->param_attributes.IsReturn)
+ call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
+ else
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ TRACE("pRetVal = %p\n", pRetVal);
+ }
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
+ }
+ else
+ {
+ const NDR_PARAM_OIF_OTHER *pParamOther =
+ (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
+
+ const unsigned char * pTypeFormat =
+ &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
+
+ /* if a simple ref pointer then we have to do the
+ * check for the pointer being non-NULL. */
+ if (pParam->param_attributes.IsSimpleRef)
+ {
+ if (!*(unsigned char **)pArg)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ }
+
+ TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat);
+
+ switch (phase)
+ {
+ case PROXY_CALCSIZE:
+ if (pParam->param_attributes.IsIn)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ else
+ call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ }
+ break;
+ case PROXY_MARSHAL:
+ if (pParam->param_attributes.IsIn)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ else
+ call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ }
+ break;
+ case PROXY_UNMARSHAL:
+ if (pParam->param_attributes.IsOut)
+ {
+ if (pParam->param_attributes.IsReturn)
+ call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
+ else if (pParam->param_attributes.IsByValue)
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ else
+ call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
+ }
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_offset += sizeof(NDR_PARAM_OIF_OTHER);
+ }
+ TRACE("\tmemory addr (after): %p\n", pArg);
+ }
+}
+
+static void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg,
+ PFORMAT_STRING pFormat, int phase, unsigned short stack_size,
+ unsigned char *pRetVal, BOOL object_proc)
+{
+ /* current format string offset */
+ int current_offset = 0;
+ /* current stack offset */
+ unsigned short current_stack_offset = 0;
+ /* counter */
+ unsigned short i;
+
+ /* NOTE: V1 style format does't terminate on the number_of_params
+ * condition as it doesn't have this attribute. Instead it
+ * terminates when the stack size given in the header is exceeded.
+ */
+ for (i = 0; TRUE; i++)
+ {
+ const NDR_PARAM_OI_BASETYPE *pParam =
+ (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
+ /* note: current_stack_offset starts after the This pointer
+ * if present, so adjust this */
+ unsigned short current_stack_offset_adjusted = current_stack_offset +
+ (object_proc ? sizeof(void *) : 0);
+ unsigned char * pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset_adjusted);
+
+ /* no more parameters; exit loop */
+ if (current_stack_offset_adjusted >= stack_size)
+ break;
+
+ TRACE("param[%d]: old format\n", i);
+ TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
+ TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
+ TRACE("\tmemory addr (before): %p\n", pArg);
+
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
+ pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ {
+ const unsigned char * pTypeFormat =
+ &pParam->type_format_char;
+
+ TRACE("\tbase type 0x%02x\n", *pTypeFormat);
+
+ switch (phase)
+ {
+ case PROXY_CALCSIZE:
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ break;
+ case PROXY_MARSHAL:
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ break;
+ case PROXY_UNMARSHAL:
+ if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ {
+ if (pParam->param_direction & RPC_FC_RETURN_PARAM)
+ call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
+ else
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ }
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat);
+ current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
+ }
+ else
+ {
+ const NDR_PARAM_OI_OTHER *pParamOther =
+ (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
+
+ const unsigned char *pTypeFormat =
+ &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
+
+ TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
+
+ switch (phase)
+ {
+ case PROXY_CALCSIZE:
+ if (pParam->param_direction == RPC_FC_IN_PARAM ||
+ pParam->param_direction & RPC_FC_IN_OUT_PARAM)
+ call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ break;
+ case PROXY_MARSHAL:
+ if (pParam->param_direction == RPC_FC_IN_PARAM ||
+ pParam->param_direction & RPC_FC_IN_OUT_PARAM)
+ call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ break;
+ case PROXY_UNMARSHAL:
+ if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_OUT_PARAM)
+ call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
+ else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
+ call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_stack_offset += pParamOther->stack_size * sizeof(INT);
+ current_offset += sizeof(NDR_PARAM_OI_OTHER);
+ }
+ TRACE("\tmemory addr (after): %p\n", pArg);
+ }
+}
+
+/* the return type should be CLIENT_CALL_RETURN, but this is incompatible
+ * with the way gcc returns structures. "void *" should be the largest type
+ * that MIDL should allow you to return anyway */
+LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, ...)
+{
+ /* pointer to start of stack where arguments start */
+ RPC_MESSAGE rpcMsg;
+ MIDL_STUB_MESSAGE stubMsg;
+ handle_t hBinding = NULL;
+ /* procedure number */
+ unsigned short procedure_number;
+ /* size of stack */
+ unsigned short stack_size;
+ /* number of parameters. optional for client to give it to us */
+ unsigned char number_of_params = ~0;
+ /* cache of Oif_flags from v2 procedure header */
+ INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
+ /* cache of extension flags from NDR_PROC_HEADER_EXTS */
+ INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
+ /* the type of pass we are currently doing */
+ int phase;
+ /* header for procedure string */
+ const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
+ /* -Oif or -Oicf generated format */
+ BOOL bV2Format = FALSE;
+ /* the value to return to the client from the remote procedure */
+ LONG_PTR RetVal = 0;
+ /* the pointer to the object when in OLE mode */
+ void * This = NULL;
+ PFORMAT_STRING pHandleFormat;
+ /* correlation cache */
+ unsigned long NdrCorrCache[256];
+
+ TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
+
+ /* Later NDR language versions probably won't be backwards compatible */
+ if (pStubDesc->Version > 0x50002)
+ {
+ FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
+ RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
+ }
+
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
+ {
+ const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
+ stack_size = pProcHeader->stack_size;
+ procedure_number = pProcHeader->proc_num;
+ pFormat += sizeof(NDR_PROC_HEADER_RPC);
+ }
+ else
+ {
+ stack_size = pProcHeader->stack_size;
+ procedure_number = pProcHeader->proc_num;
+ pFormat += sizeof(NDR_PROC_HEADER);
+ }
+ TRACE("stack size: 0x%x\n", stack_size);
+ TRACE("proc num: %d\n", procedure_number);
+
+ /* create the full pointer translation tables, if requested */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
+ stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
+
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ {
+ /* object is always the first argument */
+ This = **(void *const **)(&pFormat+1);
+ NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number);
+ }
+ else
+ NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number);
+
+ TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
+ TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
+
+ /* needed for conformance of top-level objects */
+#ifdef __i386__
+ stubMsg.StackTop = *(unsigned char **)(&pFormat+1);
+#else
+# warning Stack not retrieved for your CPU architecture
+#endif
+
+ pHandleFormat = pFormat;
+
+ /* we only need a handle if this isn't an object method */
+ if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT))
+ {
+ pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding);
+ if (!pFormat) return 0;
+ }
+
+ bV2Format = (pStubDesc->Version >= 0x20000);
+
+ if (bV2Format)
+ {
+ const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
+ (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
+
+ Oif_flags = pOIFHeader->Oi2Flags;
+ number_of_params = pOIFHeader->number_of_params;
+
+ pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
+ }
+
+ TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
+
+ if (Oif_flags.HasExtensions)
+ {
+ const NDR_PROC_HEADER_EXTS *pExtensions =
+ (const NDR_PROC_HEADER_EXTS *)pFormat;
+ ext_flags = pExtensions->Flags2;
+ pFormat += pExtensions->Size;
+ }
+
+ stubMsg.BufferLength = 0;
+
+ /* store the RPC flags away */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
+ rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
+
+ /* use alternate memory allocation routines */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
+ NdrRpcSmSetClientToOsf(&stubMsg);
+
+ if (Oif_flags.HasPipes)
+ {
+ FIXME("pipes not supported yet\n");
+ RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
+ /* init pipes package */
+ /* NdrPipesInitialize(...) */
+ }
+ if (ext_flags.HasNewCorrDesc)
+ {
+ /* initialize extra correlation package */
+ NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
+ }
+
+ /* order of phases:
+ * 1. PROXY_CALCSIZE - calculate the buffer size
+ * 2. PROXY_GETBUFFER - allocate the buffer
+ * 3. PROXY_MARHSAL - marshal [in] params into the buffer
+ * 4. PROXY_SENDRECEIVE - send/receive buffer
+ * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
+ */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ {
+ __TRY
+ {
+ for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
+ {
+ TRACE("phase = %d\n", phase);
+ switch (phase)
+ {
+ case PROXY_GETBUFFER:
+ /* allocate the buffer */
+ NdrProxyGetBuffer(This, &stubMsg);
+ break;
+ case PROXY_SENDRECEIVE:
+ /* send the [in] params and receive the [out] and [retval]
+ * params */
+ NdrProxySendReceive(This, &stubMsg);
+
+ /* convert strings, floating point values and endianess into our
+ * preferred format */
+ if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
+ NdrConvert(&stubMsg, pFormat);
+
+ break;
+ case PROXY_CALCSIZE:
+ case PROXY_MARSHAL:
+ case PROXY_UNMARSHAL:
+ if (bV2Format)
+ client_do_args(&stubMsg, pFormat, phase, number_of_params,
+ (unsigned char *)&RetVal);
+ else
+ client_do_args_old_format(&stubMsg, pFormat, phase, stack_size,
+ (unsigned char *)&RetVal,
+ (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
+ break;
+ default:
+ ERR("shouldn't reach here. phase %d\n", phase);
+ break;
+ }
+ }
+ }
+ __EXCEPT_ALL
+ {
+ RetVal = NdrProxyErrorHandler(GetExceptionCode());
+ }
+ __ENDTRY
+ }
+ else
+ {
+ /* order of phases:
+ * 1. PROXY_CALCSIZE - calculate the buffer size
+ * 2. PROXY_GETBUFFER - allocate the buffer
+ * 3. PROXY_MARHSAL - marshal [in] params into the buffer
+ * 4. PROXY_SENDRECEIVE - send/receive buffer
+ * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
+ */
+ for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
+ {
+ TRACE("phase = %d\n", phase);
+ switch (phase)
+ {
+ case PROXY_GETBUFFER:
+ /* allocate the buffer */
+ if (Oif_flags.HasPipes)
+ /* NdrGetPipeBuffer(...) */
+ FIXME("pipes not supported yet\n");
+ else
+ {
+ if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
+#if 0
+ NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
+#else
+ FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
+#endif
+ else
+ NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
+ }
+ break;
+ case PROXY_SENDRECEIVE:
+ /* send the [in] params and receive the [out] and [retval]
+ * params */
+ if (Oif_flags.HasPipes)
+ /* NdrPipesSendReceive(...) */
+ FIXME("pipes not supported yet\n");
+ else
+ {
+ if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
+#if 0
+ NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
+#else
+ FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
+#endif
+ else
+ NdrSendReceive(&stubMsg, stubMsg.Buffer);
+ }
+
+ /* convert strings, floating point values and endianess into our
+ * preferred format */
+ if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
+ NdrConvert(&stubMsg, pFormat);
+
+ break;
+ case PROXY_CALCSIZE:
+ case PROXY_MARSHAL:
+ case PROXY_UNMARSHAL:
+ if (bV2Format)
+ client_do_args(&stubMsg, pFormat, phase, number_of_params,
+ (unsigned char *)&RetVal);
+ else
+ client_do_args_old_format(&stubMsg, pFormat, phase, stack_size,
+ (unsigned char *)&RetVal,
+ (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
+ break;
+ default:
+ ERR("shouldn't reach here. phase %d\n", phase);
+ break;
+ }
+ }
+ }
+
+ if (ext_flags.HasNewCorrDesc)
+ {
+ /* free extra correlation package */
+ NdrCorrelationFree(&stubMsg);
+ }
+
+ if (Oif_flags.HasPipes)
+ {
+ /* NdrPipesDone(...) */
+ }
+
+ /* free the full pointer translation tables */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
+ NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
+
+ /* free marshalling buffer */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ NdrProxyFreeBuffer(This, &stubMsg);
+ else
+ {
+ NdrFreeBuffer(&stubMsg);
+ client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding);
+ }
+
+ TRACE("RetVal = 0x%lx\n", RetVal);
+
+ return RetVal;
+}
+
+/* calls a function with the specificed arguments, restoring the stack
+ * properly afterwards as we don't know the calling convention of the
+ * function */
+#if defined __i386__ && defined _MSC_VER
+__declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
+{
+ __asm
+ {
+ push ebp
+ push edi ; Save registers
+ push esi
+ mov ebp, esp
+ mov eax, [ebp+16] ; Get stack size
+ sub esp, eax ; Make room in stack for arguments
+ mov edi, esp
+ mov ecx, eax
+ mov esi, [ebp+12]
+ shr ecx, 2
+ cld
+ rep movsd ; Copy dword blocks
+ call [ebp+8] ; Call function
+ lea esp, [ebp-8] ; Restore stack
+ pop esi ; Restore registers
+ pop edi
+ pop ebp
+ ret
+ }
+}
+#elif defined __i386__ && defined __GNUC__
+LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
+__ASM_GLOBAL_FUNC(call_server_func,
+ "pushl %ebp\n\t"
+ "movl %esp, %ebp\n\t"
+ "pushl %edi\n\t" /* Save registers */
+ "pushl %esi\n\t"
+ "movl 16(%ebp), %eax\n\t" /* Get stack size */
+ "subl %eax, %esp\n\t" /* Make room in stack for arguments */
+ "andl $~15, %esp\n\t" /* Make sure stack has 16-byte alignment for Mac OS X */
+ "movl %esp, %edi\n\t"
+ "movl %eax, %ecx\n\t"
+ "movl 12(%ebp), %esi\n\t"
+ "shrl $2, %ecx\n\t" /* divide by 4 */
+ "cld\n\t"
+ "rep; movsl\n\t" /* Copy dword blocks */
+ "call *8(%ebp)\n\t" /* Call function */
+ "leal -8(%ebp), %esp\n\t" /* Restore stack */
+ "popl %esi\n\t" /* Restore registers */
+ "popl %edi\n\t"
+ "popl %ebp\n\t"
+ "ret\n" )
+#else
+#warning call_server_func not implemented for your architecture
+LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
+{
+ FIXME("Not implemented for your architecture\n");
+ return 0;
+}
+#endif
+
+static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
+{
+ DWORD size;
+ switch(*pFormat)
+ {
+ case RPC_FC_STRUCT:
+ size = *(const WORD*)(pFormat + 2);
+ break;
+ case RPC_FC_CARRAY:
+ size = *(const WORD*)(pFormat + 2);
+ ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
+ size *= pStubMsg->MaxCount;
+ break;
+ case RPC_FC_SMFARRAY:
+ size = *(const WORD*)(pFormat + 2);
+ break;
+ case RPC_FC_LGFARRAY:
+ size = *(const DWORD*)(pFormat + 2);
+ break;
+ case RPC_FC_BOGUS_ARRAY:
+ pFormat = ComputeConformance(pStubMsg, NULL, pFormat + 4, *(const WORD*)&pFormat[2]);
+ TRACE("conformance = %ld\n", pStubMsg->MaxCount);
+ pFormat = ComputeVariance(pStubMsg, NULL, pFormat, pStubMsg->MaxCount);
+ size = ComplexStructSize(pStubMsg, pFormat);
+ size *= pStubMsg->MaxCount;
+ break;
+ default:
+ FIXME("Unhandled type %02x\n", *pFormat);
+ /* fallthrough */
+ case RPC_FC_RP:
+ size = sizeof(void *);
+ break;
+ }
+ return size;
+}
+
+static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
+ PFORMAT_STRING pFormat, int phase,
+ unsigned char *args,
+ unsigned short number_of_params)
+{
+ /* counter */
+ unsigned short i;
+ /* current format string offset */
+ int current_offset = 0;
+ /* current stack offset */
+ unsigned short current_stack_offset = 0;
+ /* location to put retval into */
+ LONG_PTR *retval_ptr = NULL;
+
+ for (i = 0; i < number_of_params; i++)
+ {
+ const NDR_PARAM_OIF_BASETYPE *pParam =
+ (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
+ unsigned char *pArg;
+
+ current_stack_offset = pParam->stack_offset;
+ pArg = args + current_stack_offset;
+
+ TRACE("param[%d]: new format\n", i);
+ TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
+ TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
+ TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
+
+ if (pParam->param_attributes.IsBasetype)
+ {
+ const unsigned char *pTypeFormat =
+ &pParam->type_format_char;
+
+ TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
+
+ /* make a note of the address of the return value parameter for later */
+ if (pParam->param_attributes.IsReturn)
+ retval_ptr = (LONG_PTR *)pArg;
+
+ switch (phase)
+ {
+ case STUBLESS_MARSHAL:
+ if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
+ {
+ if (pParam->param_attributes.IsSimpleRef)
+ call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ else
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ }
+ break;
+ case STUBLESS_FREE:
+ if (pParam->param_attributes.ServerAllocSize)
+ HeapFree(GetProcessHeap(), 0, *(void **)pArg);
+ break;
+ case STUBLESS_INITOUT:
+ break;
+ case STUBLESS_UNMARSHAL:
+ if (pParam->param_attributes.ServerAllocSize)
+ *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ pParam->param_attributes.ServerAllocSize * 8);
+
+ if (pParam->param_attributes.IsIn)
+ {
+ if (pParam->param_attributes.IsSimpleRef)
+ call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
+ else
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ }
+ break;
+ case STUBLESS_CALCSIZE:
+ if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
+ {
+ if (pParam->param_attributes.IsSimpleRef)
+ call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ else
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ }
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
+ }
+ else
+ {
+ const NDR_PARAM_OIF_OTHER *pParamOther =
+ (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
+
+ const unsigned char * pTypeFormat =
+ &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
+
+ TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
+
+ switch (phase)
+ {
+ case STUBLESS_MARSHAL:
+ if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ else
+ call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ }
+ break;
+ case STUBLESS_FREE:
+ if (pParam->param_attributes.MustFree)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_freer(pStubMsg, pArg, pTypeFormat);
+ else
+ call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ }
+
+ if (pParam->param_attributes.IsOut &&
+ !pParam->param_attributes.IsIn &&
+ !pParam->param_attributes.IsByValue &&
+ !pParam->param_attributes.ServerAllocSize)
+ {
+ pStubMsg->pfnFree(*(void **)pArg);
+ }
+
+ if (pParam->param_attributes.ServerAllocSize)
+ HeapFree(GetProcessHeap(), 0, *(void **)pArg);
+ break;
+ case STUBLESS_INITOUT:
+ if (!pParam->param_attributes.IsIn &&
+ pParam->param_attributes.IsOut &&
+ !pParam->param_attributes.ServerAllocSize &&
+ !pParam->param_attributes.IsByValue)
+ {
+ DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
+
+ if(size)
+ {
+ *(void **)pArg = NdrAllocate(pStubMsg, size);
+ memset(*(void **)pArg, 0, size);
+ }
+ }
+ break;
+ case STUBLESS_UNMARSHAL:
+ if (pParam->param_attributes.ServerAllocSize)
+ *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ pParam->param_attributes.ServerAllocSize * 8);
+
+ if (pParam->param_attributes.IsIn)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ else
+ call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
+ }
+ break;
+ case STUBLESS_CALCSIZE:
+ if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
+ {
+ if (pParam->param_attributes.IsByValue)
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ else
+ call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ }
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_offset += sizeof(NDR_PARAM_OIF_OTHER);
+ }
+ TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
+ }
+
+ return retval_ptr;
+}
+
+static LONG_PTR *stub_do_old_args(MIDL_STUB_MESSAGE *pStubMsg,
+ PFORMAT_STRING pFormat, int phase,
+ unsigned char *args,
+ unsigned short stack_size, BOOL object)
+{
+ /* counter */
+ unsigned short i;
+ /* current format string offset */
+ int current_offset = 0;
+ /* current stack offset */
+ unsigned short current_stack_offset = 0;
+ /* location to put retval into */
+ LONG_PTR *retval_ptr = NULL;
+
+ for (i = 0; TRUE; i++)
+ {
+ const NDR_PARAM_OI_BASETYPE *pParam =
+ (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
+ /* note: current_stack_offset starts after the This pointer
+ * if present, so adjust this */
+ unsigned short current_stack_offset_adjusted = current_stack_offset +
+ (object ? sizeof(void *) : 0);
+ unsigned char *pArg = args + current_stack_offset_adjusted;
+
+ /* no more parameters; exit loop */
+ if (current_stack_offset_adjusted >= stack_size)
+ break;
+
+ TRACE("param[%d]: old format\n", i);
+ TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
+ TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
+
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
+ pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ {
+ const unsigned char *pTypeFormat =
+ &pParam->type_format_char;
+
+ TRACE("\tbase type 0x%02x\n", *pTypeFormat);
+
+ if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ retval_ptr = (LONG_PTR *)pArg;
+
+ switch (phase)
+ {
+ case STUBLESS_MARSHAL:
+ if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ call_marshaller(pStubMsg, pArg, pTypeFormat);
+ break;
+ case STUBLESS_FREE:
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
+ call_freer(pStubMsg, pArg, pTypeFormat);
+ break;
+ case STUBLESS_UNMARSHAL:
+ if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
+ call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
+ break;
+ case STUBLESS_CALCSIZE:
+ if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
+ call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat);
+ current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
+ }
+ else
+ {
+ const NDR_PARAM_OI_OTHER *pParamOther =
+ (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
+
+ const unsigned char * pTypeFormat =
+ &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
+
+ TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
+
+ if (pParam->param_direction == RPC_FC_RETURN_PARAM)
+ retval_ptr = (LONG_PTR *)pArg;
+
+ switch (phase)
+ {
+ case STUBLESS_MARSHAL:
+ if (pParam->param_direction == RPC_FC_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_RETURN_PARAM)
+ call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ break;
+ case STUBLESS_FREE:
+ if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_IN_PARAM)
+ call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ else if (pParam->param_direction == RPC_FC_OUT_PARAM)
+ pStubMsg->pfnFree(*(void **)pArg);
+ break;
+ case STUBLESS_INITOUT:
+ if (pParam->param_direction == RPC_FC_OUT_PARAM)
+ {
+ DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
+
+ if(size)
+ {
+ *(void **)pArg = NdrAllocate(pStubMsg, size);
+ memset(*(void **)pArg, 0, size);
+ }
+ }
+ break;
+ case STUBLESS_UNMARSHAL:
+ if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_IN_PARAM)
+ call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
+ break;
+ case STUBLESS_CALCSIZE:
+ if (pParam->param_direction == RPC_FC_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
+ pParam->param_direction == RPC_FC_RETURN_PARAM)
+ call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
+ break;
+ default:
+ RpcRaiseException(RPC_S_INTERNAL_ERROR);
+ }
+
+ current_stack_offset += pParamOther->stack_size * sizeof(INT);
+ current_offset += sizeof(NDR_PARAM_OI_OTHER);
+ }
+ }
+
+ return retval_ptr;
}
/***********************************************************************
- * NdrClientCall2 [RPCRT4.@]
+ * NdrStubCall2 [RPCRT4.@]
+ *
+ * Unmarshals [in] parameters, calls either a method in an object or a server
+ * function, marshals any [out] parameters and frees any allocated data.
+ *
+ * NOTES
+ * Used by stubless MIDL-generated code.
*/
-LONG_PTR /* CLIENT_CALL_RETURN */ WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc,
- PFORMAT_STRING pFormat, ...)
+LONG WINAPI NdrStubCall2(
+ struct IRpcStubBuffer * pThis,
+ struct IRpcChannelBuffer * pChannel,
+ PRPC_MESSAGE pRpcMsg,
+ DWORD * pdwStubPhase)
{
- LONG_PTR ret;
- va_list args;
+ const MIDL_SERVER_INFO *pServerInfo;
+ const MIDL_STUB_DESC *pStubDesc;
+ PFORMAT_STRING pFormat;
+ MIDL_STUB_MESSAGE stubMsg;
+ /* pointer to start of stack to pass into stub implementation */
+ unsigned char * args;
+ /* size of stack */
+ unsigned short stack_size;
+ /* number of parameters. optional for client to give it to us */
+ unsigned char number_of_params = ~0;
+ /* cache of Oif_flags from v2 procedure header */
+ INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
+ /* cache of extension flags from NDR_PROC_HEADER_EXTS */
+ INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
+ /* the type of pass we are currently doing */
+ int phase;
+ /* header for procedure string */
+ const NDR_PROC_HEADER *pProcHeader;
+ /* offset in format string for start of params */
+ int parameter_start_offset;
+ /* current format string offset */
+ int current_offset;
+ /* -Oif or -Oicf generated format */
+ BOOL bV2Format = FALSE;
+ /* location to put retval into */
+ LONG_PTR *retval_ptr = NULL;
+
+ TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
+
+ if (pThis)
+ pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
+ else
+ pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
+
+ pStubDesc = pServerInfo->pStubDesc;
+ pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
+ pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
+
+ /* Later NDR language versions probably won't be backwards compatible */
+ if (pStubDesc->Version > 0x50002)
+ {
+ FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
+ RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
+ }
+
+ /* create the full pointer translation tables, if requested */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
+ stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
+
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
+ {
+ const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
+ stack_size = pProcHeader->stack_size;
+ current_offset = sizeof(NDR_PROC_HEADER_RPC);
+
+ }
+ else
+ {
+ stack_size = pProcHeader->stack_size;
+ current_offset = sizeof(NDR_PROC_HEADER);
+ }
+
+ TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
+
+ /* binding */
+ switch (pProcHeader->handle_type)
+ {
+ /* explicit binding: parse additional section */
+ case RPC_FC_BIND_EXPLICIT:
+ switch (pFormat[current_offset]) /* handle_type */
+ {
+ case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
+ current_offset += sizeof(NDR_EHD_PRIMITIVE);
+ break;
+ case RPC_FC_BIND_GENERIC: /* explicit generic */
+ current_offset += sizeof(NDR_EHD_GENERIC);
+ break;
+ case RPC_FC_BIND_CONTEXT: /* explicit context */
+ current_offset += sizeof(NDR_EHD_CONTEXT);
+ break;
+ default:
+ ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+ break;
+ case RPC_FC_BIND_GENERIC: /* implicit generic */
+ case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
+ case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
+ case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
+ break;
+ default:
+ ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ }
+
+ bV2Format = (pStubDesc->Version >= 0x20000);
+
+ if (bV2Format)
+ {
+ const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
+ (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset];
+
+ Oif_flags = pOIFHeader->Oi2Flags;
+ number_of_params = pOIFHeader->number_of_params;
+
+ current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
+ }
+
+ TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
+
+ if (Oif_flags.HasExtensions)
+ {
+ const NDR_PROC_HEADER_EXTS *pExtensions =
+ (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset];
+ ext_flags = pExtensions->Flags2;
+ current_offset += pExtensions->Size;
+ }
+
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
+ else
+ NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
+
+ /* store the RPC flags away */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
+ pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
+
+ /* use alternate memory allocation routines */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
+#if 0
+ NdrRpcSsEnableAllocate(&stubMsg);
+#else
+ FIXME("Set RPCSS memory allocation routines\n");
+#endif
- TRACE("(%p,%p,...)\n", pStubDesc, pFormat);
+ if (Oif_flags.HasPipes)
+ {
+ FIXME("pipes not supported yet\n");
+ RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
+ /* init pipes package */
+ /* NdrPipesInitialize(...) */
+ }
+ if (ext_flags.HasNewCorrDesc)
+ {
+ /* initialize extra correlation package */
+ FIXME("new correlation description not implemented\n");
+ stubMsg.fHasNewCorrDesc = TRUE;
+ }
- va_start(args, pFormat);
- ret = RPCRT4_NdrClientCall2(pStubDesc, pFormat, args);
- va_end(args);
- return ret;
+ /* convert strings, floating point values and endianess into our
+ * preferred format */
+ if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
+ NdrConvert(&stubMsg, pFormat);
+
+ parameter_start_offset = current_offset;
+
+ TRACE("allocating memory for stack of size %x\n", stack_size);
+
+ args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
+ stubMsg.StackTop = args; /* used by conformance of top-level objects */
+
+ /* add the implicit This pointer as the first arg to the function if we
+ * are calling an object method */
+ if (pThis)
+ *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
+
+ /* order of phases:
+ * 1. STUBLESS_UNMARHSAL - unmarshal [in] params from buffer
+ * 2. STUBLESS_CALLSERVER - send/receive buffer
+ * 3. STUBLESS_CALCSIZE - get [out] buffer size
+ * 4. STUBLESS_GETBUFFER - allocate [out] buffer
+ * 5. STUBLESS_MARHSAL - marshal [out] params to buffer
+ */
+ for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
+ {
+ TRACE("phase = %d\n", phase);
+ switch (phase)
+ {
+ case STUBLESS_CALLSERVER:
+ /* call the server function */
+ if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
+ pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
+ else
+ {
+ SERVER_ROUTINE func;
+ LONG_PTR retval;
+
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ {
+ SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
+ func = vtbl[pRpcMsg->ProcNum];
+ }
+ else
+ func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
+
+ /* FIXME: what happens with return values that don't fit into a single register on x86? */
+ retval = call_server_func(func, args, stack_size);
+
+ if (retval_ptr)
+ {
+ TRACE("stub implementation returned 0x%lx\n", retval);
+ *retval_ptr = retval;
+ }
+ else
+ TRACE("void stub implementation\n");
+ }
+
+ stubMsg.Buffer = NULL;
+ stubMsg.BufferLength = 0;
+
+ break;
+ case STUBLESS_GETBUFFER:
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
+ NdrStubGetBuffer(pThis, pChannel, &stubMsg);
+ else
+ {
+ RPC_STATUS Status;
+
+ pRpcMsg->BufferLength = stubMsg.BufferLength;
+ /* allocate buffer for [out] and [ret] params */
+ Status = I_RpcGetBuffer(pRpcMsg);
+ if (Status)
+ RpcRaiseException(Status);
+ stubMsg.Buffer = pRpcMsg->Buffer;
+ }
+ break;
+ case STUBLESS_UNMARSHAL:
+ case STUBLESS_INITOUT:
+ case STUBLESS_CALCSIZE:
+ case STUBLESS_MARSHAL:
+ case STUBLESS_FREE:
+ if (bV2Format)
+ retval_ptr = stub_do_args(&stubMsg, &pFormat[parameter_start_offset],
+ phase, args, number_of_params);
+ else
+ retval_ptr = stub_do_old_args(&stubMsg, &pFormat[parameter_start_offset],
+ phase, args, stack_size,
+ (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
+
+ break;
+ default:
+ ERR("shouldn't reach here. phase %d\n", phase);
+ break;
+ }
+ }
+
+ pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
+
+ if (ext_flags.HasNewCorrDesc)
+ {
+ /* free extra correlation package */
+ /* NdrCorrelationFree(&stubMsg); */
+ }
+
+ if (Oif_flags.HasPipes)
+ {
+ /* NdrPipesDone(...) */
+ }
+
+ /* free the full pointer translation tables */
+ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
+ NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
+
+ /* free server function stack */
+ HeapFree(GetProcessHeap(), 0, args);
+
+ return S_OK;
+}
+
+/***********************************************************************
+ * NdrServerCall2 [RPCRT4.@]
+ */
+void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
+{
+ DWORD dwPhase;
+ NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
}