[RPCRT4]
[reactos.git] / reactos / dll / win32 / rpcrt4 / ndr_marshall.c
index e18f59c..839a4ca 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * TODO:
- *  - Non-conformant strings
  *  - String structs
  *  - Byte count pointers
  *  - transmit_as/represent as
  *  - Multi-dimensional arrays
  *  - Conversion functions (NdrConvert)
- *  - Checks for integer addition overflow in base type and user marshall functions
+ *  - Checks for integer addition overflow in user marshall functions
  */
 
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <limits.h>
 
+#define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 
 #include "ndr_misc.h"
 #include "rpcndr.h"
+#include "ndrtypes.h"
 
 #include "wine/unicode.h"
 #include "wine/rpcfc.h"
@@ -60,8 +60,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
     (*(pchar)     = LOBYTE(LOWORD(uint32)), \
      *((pchar)+1) = HIBYTE(LOWORD(uint32)), \
      *((pchar)+2) = LOBYTE(HIWORD(uint32)), \
-     *((pchar)+3) = HIBYTE(HIWORD(uint32)), \
-     (uint32)) /* allow as r-value */
+     *((pchar)+3) = HIBYTE(HIWORD(uint32)))
 
 # define LITTLE_ENDIAN_UINT32_READ(pchar) \
     (MAKELONG( \
@@ -73,8 +72,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
   (*((pchar)+3) = LOBYTE(LOWORD(uint32)), \
    *((pchar)+2) = HIBYTE(LOWORD(uint32)), \
    *((pchar)+1) = LOBYTE(HIWORD(uint32)), \
-   *(pchar)     = HIBYTE(HIWORD(uint32)), \
-   (uint32)) /* allow as r-value */
+   *(pchar)     = HIBYTE(HIWORD(uint32)))
 
 #define BIG_ENDIAN_UINT32_READ(pchar) \
   (MAKELONG( \
@@ -106,14 +104,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
     } while(0)
 
 #define STD_OVERFLOW_CHECK(_Msg) do { \
-    TRACE("buffer=%d/%d\n", _Msg->Buffer - (unsigned char *)_Msg->RpcMsg->Buffer, _Msg->BufferLength); \
+    TRACE("buffer=%d/%d\n", (ULONG)(_Msg->Buffer - (unsigned char *)_Msg->RpcMsg->Buffer), _Msg->BufferLength); \
     if (_Msg->Buffer > (unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength) \
-        ERR("buffer overflow %d bytes\n", _Msg->Buffer - ((unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength)); \
+        ERR("buffer overflow %d bytes\n", (ULONG)(_Msg->Buffer - ((unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength))); \
   } while (0)
 
+#define NDR_POINTER_ID_BASE 0x20000
+#define NDR_POINTER_ID(pStubMsg) (NDR_POINTER_ID_BASE + ((pStubMsg)->UniquePtrCount++) * 4)
 #define NDR_TABLE_SIZE 128
 #define NDR_TABLE_MASK 127
 
+#define NDRSContextFromValue(user_context) (NDR_SCONTEXT)((char *)(user_context) - (char *)NDRSContextValue((NDR_SCONTEXT)NULL))
+
 static unsigned char *WINAPI NdrBaseTypeMarshall(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING);
 static unsigned char *WINAPI NdrBaseTypeUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char);
 static void WINAPI NdrBaseTypeBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING);
@@ -124,6 +126,13 @@ static unsigned char *WINAPI NdrContextHandleMarshall(PMIDL_STUB_MESSAGE, unsign
 static void WINAPI NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING);
 static unsigned char *WINAPI NdrContextHandleUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char);
 
+static unsigned char *WINAPI NdrRangeMarshall(PMIDL_STUB_MESSAGE,unsigned char *, PFORMAT_STRING);
+static void WINAPI NdrRangeBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING);
+static ULONG WINAPI NdrRangeMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING);
+static void WINAPI NdrRangeFree(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING);
+
+static ULONG WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING);
+
 const NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = {
   0,
   NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall,
@@ -361,10 +370,10 @@ typedef struct _NDR_MEMORY_LIST
  *  If the function is unable to allocate memory an ERROR_OUTOFMEMORY
  *  exception is raised.
  */
-void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len)
+void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, SIZE_T len)
 {
-    size_t aligned_len;
-    size_t adjusted_len;
+    SIZE_T aligned_len;
+    SIZE_T adjusted_len;
     void *p;
     NDR_MEMORY_LIST *mem_list;
 
@@ -373,7 +382,7 @@ void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len)
     /* check for overflow */
     if (adjusted_len < len)
     {
-        ERR("overflow of adjusted_len %d, len %d\n", adjusted_len, len);
+        ERR("overflow of adjusted_len %ld, len %ld\n", adjusted_len, len);
         RpcRaiseException(RPC_X_BAD_STUB_DATA);
     }
 
@@ -391,7 +400,7 @@ void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len)
     return p;
 }
 
-static void WINAPI NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer)
+static void NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer)
 {
     TRACE("(%p, %p)\n", pStubMsg, Pointer);
 
@@ -542,7 +551,8 @@ PFORMAT_STRING ComputeConformanceOrVariance(
     }
     break;
   default:
-    FIXME("unknown conformance type %x\n", pFormat[0] & 0xf0);
+    FIXME("unknown conformance type %x, expect crash.\n", pFormat[0] & 0xf0);
+    goto finish_conf;
   }
 
   switch (pFormat[1]) {
@@ -625,6 +635,19 @@ finish_conf:
     return pFormat+4;
 }
 
+static inline PFORMAT_STRING SkipConformance(PMIDL_STUB_MESSAGE pStubMsg,
+                                             PFORMAT_STRING pFormat)
+{
+  if (IsConformanceOrVariancePresent(pFormat))
+  {
+    if (pStubMsg->fHasNewCorrDesc)
+      pFormat += 6;
+    else
+      pFormat += 4;
+  }
+  return pFormat;
+}
+
 /* multiply two numbers together, raising an RPC_S_INVALID_BOUND exception if
  * the result overflows 32-bits */
 static inline ULONG safe_multiply(ULONG a, ULONG b)
@@ -689,1436 +712,1875 @@ static inline void safe_copy_to_buffer(MIDL_STUB_MESSAGE *pStubMsg, const void *
     pStubMsg->Buffer += size;
 }
 
-/*
- * 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)
-{ 
-  ULONG esize, size;
-
-  TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat);
-  
-  if (*pFormat == RPC_FC_C_CSTRING) {
-    TRACE("string=%s\n", debugstr_a((char*)pszMessage));
-    pStubMsg->ActualCount = strlen((char*)pszMessage)+1;
-    esize = 1;
-  }
-  else if (*pFormat == RPC_FC_C_WSTRING) {
-    TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage));
-    pStubMsg->ActualCount = 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_STRING_SIZED)
-    pFormat = ComputeConformance(pStubMsg, pszMessage, pFormat + 2, 0);
-  else
-    pStubMsg->MaxCount = pStubMsg->ActualCount;
-  pStubMsg->Offset = 0;
-  WriteConformance(pStubMsg);
-  WriteVariance(pStubMsg);
-
-  size = safe_multiply(esize, pStubMsg->ActualCount);
-  safe_copy_to_buffer(pStubMsg, pszMessage, size); /* the string itself */
-
-  /* success */
-  return NULL; /* is this always right? */
-}
-
-/***********************************************************************
- *           NdrConformantStringBufferSize [RPCRT4.@]
- */
-void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-  unsigned char* pMemory, PFORMAT_STRING pFormat)
-{
-  ULONG esize;
-
-  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
-
-  SizeConformance(pStubMsg);
-  SizeVariance(pStubMsg);
-
-  if (*pFormat == RPC_FC_C_CSTRING) {
-    TRACE("string=%s\n", debugstr_a((char*)pMemory));
-    pStubMsg->ActualCount = strlen((char*)pMemory)+1;
-    esize = 1;
-  }
-  else if (*pFormat == RPC_FC_C_WSTRING) {
-    TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory));
-    pStubMsg->ActualCount = strlenW((LPWSTR)pMemory)+1;
-    esize = 2;
-  }
-  else {
-    ERR("Unhandled string type: %#x\n", *pFormat); 
-    /* FIXME: raise an exception */
-    return;
-  }
-
-  if (pFormat[1] == RPC_FC_STRING_SIZED)
-    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 2, 0);
-  else
-    pStubMsg->MaxCount = pStubMsg->ActualCount;
-
-  safe_buffer_length_increment(pStubMsg, safe_multiply(esize, pStubMsg->ActualCount));
-}
-
-/************************************************************************
- *            NdrConformantStringMemorySize [RPCRT4.@]
- */
-ULONG WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg,
-  PFORMAT_STRING pFormat )
+/* verify that string data sitting in the buffer is valid and safe to
+ * unmarshall */
+static void validate_string_data(MIDL_STUB_MESSAGE *pStubMsg, ULONG bufsize, ULONG esize)
 {
-  ULONG bufsize, memsize, esize, i;
-
-  TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat);
-
-  ReadConformance(pStubMsg, NULL);
-  ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount);
-
-  if (pFormat[1] != RPC_FC_STRING_SIZED && (pStubMsg->MaxCount != pStubMsg->ActualCount))
-  {
-    ERR("buffer size %d must equal memory size %ld for non-sized conformant strings\n",
-        pStubMsg->ActualCount, pStubMsg->MaxCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-  }
-  if (pStubMsg->Offset)
-  {
-    ERR("conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-  }
-
-  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;
-  }
-
-  memsize = safe_multiply(esize, pStubMsg->MaxCount);
-  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-
-  /* strings must always have null terminating bytes */
-  if (bufsize < esize)
-  {
-    ERR("invalid string length of %d\n", pStubMsg->ActualCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-  }
+    ULONG i;
 
-  /* verify the buffer is safe to access */
-  if ((pStubMsg->Buffer + bufsize < pStubMsg->Buffer) ||
-      (pStubMsg->Buffer + bufsize > pStubMsg->BufferEnd))
-  {
-    ERR("bufsize 0x%x exceeded buffer end %p of buffer %p\n", bufsize,
-        pStubMsg->BufferEnd, pStubMsg->Buffer);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-  }
+    /* verify the buffer is safe to access */
+    if ((pStubMsg->Buffer + bufsize < pStubMsg->Buffer) ||
+        (pStubMsg->Buffer + bufsize > pStubMsg->BufferEnd))
+    {
+        ERR("bufsize 0x%x exceeded buffer end %p of buffer %p\n", bufsize,
+            pStubMsg->BufferEnd, pStubMsg->Buffer);
+        RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    }
 
-  for (i = bufsize - esize; i < bufsize; i++)
-    if (pStubMsg->Buffer[i] != 0)
+    /* strings must always have null terminating bytes */
+    if (bufsize < esize)
     {
-      ERR("string not null-terminated at byte position %d, data is 0x%x\n",
-        i, pStubMsg->Buffer[i]);
-      RpcRaiseException(RPC_S_INVALID_BOUND);
+        ERR("invalid string length of %d\n", bufsize / esize);
+        RpcRaiseException(RPC_S_INVALID_BOUND);
     }
 
-  safe_buffer_increment(pStubMsg, bufsize);
-  pStubMsg->MemorySize += memsize;
+    for (i = bufsize - esize; i < bufsize; i++)
+        if (pStubMsg->Buffer[i] != 0)
+        {
+            ERR("string not null-terminated at byte position %d, data is 0x%x\n",
+                i, pStubMsg->Buffer[i]);
+            RpcRaiseException(RPC_S_INVALID_BOUND);
+        }
+}
 
-  return pStubMsg->MemorySize;
+static inline void dump_pointer_attr(unsigned char attr)
+{
+    if (attr & RPC_FC_P_ALLOCALLNODES)
+        TRACE(" RPC_FC_P_ALLOCALLNODES");
+    if (attr & RPC_FC_P_DONTFREE)
+        TRACE(" RPC_FC_P_DONTFREE");
+    if (attr & RPC_FC_P_ONSTACK)
+        TRACE(" RPC_FC_P_ONSTACK");
+    if (attr & RPC_FC_P_SIMPLEPOINTER)
+        TRACE(" RPC_FC_P_SIMPLEPOINTER");
+    if (attr & RPC_FC_P_DEREF)
+        TRACE(" RPC_FC_P_DEREF");
+    TRACE("\n");
 }
 
-/************************************************************************
- *           NdrConformantStringUnmarshall [RPCRT4.@]
+/***********************************************************************
+ *           PointerMarshall [internal]
  */
-unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg,
-  unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc )
+static void PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                            unsigned char *Buffer,
+                            unsigned char *Pointer,
+                            PFORMAT_STRING pFormat)
 {
-  ULONG bufsize, memsize, esize, i;
-
-  TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n",
-    pStubMsg, *ppMemory, pFormat, fMustAlloc);
-
-  assert(pFormat && ppMemory && pStubMsg);
-
-  ReadConformance(pStubMsg, NULL);
-  ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount);
-
-  if (pFormat[1] != RPC_FC_STRING_SIZED && (pStubMsg->MaxCount != pStubMsg->ActualCount))
-  {
-    ERR("buffer size %d must equal memory size %ld for non-sized conformant strings\n",
-        pStubMsg->ActualCount, pStubMsg->MaxCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-    return NULL;
-  }
-  if (pStubMsg->Offset)
-  {
-    ERR("conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-    return NULL;
-  }
-
-  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;
-  }
-
-  memsize = safe_multiply(esize, pStubMsg->MaxCount);
-  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-
-  /* strings must always have null terminating bytes */
-  if (bufsize < esize)
-  {
-    ERR("invalid string length of %d\n", pStubMsg->ActualCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-    return NULL;
-  }
+  unsigned type = pFormat[0], attr = pFormat[1];
+  PFORMAT_STRING desc;
+  NDR_MARSHALL m;
+  ULONG pointer_id;
+  int pointer_needs_marshaling;
 
-  /* verify the buffer is safe to access */
-  if ((pStubMsg->Buffer + bufsize < pStubMsg->Buffer) ||
-      (pStubMsg->Buffer + bufsize > pStubMsg->BufferEnd))
-  {
-    ERR("bufsize 0x%x exceeded buffer end %p of buffer %p\n", bufsize,
-        pStubMsg->BufferEnd, pStubMsg->Buffer);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return NULL;
-  }
+  TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat);
+  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  pFormat += 2;
+  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
+  else desc = pFormat + *(const SHORT*)pFormat;
 
-  for (i = bufsize - esize; i < bufsize; i++)
-    if (pStubMsg->Buffer[i] != 0)
+  switch (type) {
+  case RPC_FC_RP: /* ref pointer (always non-null) */
+    if (!Pointer)
     {
-      ERR("string not null-terminated at byte position %d, data is 0x%x\n",
-        i, pStubMsg->Buffer[i]);
-      RpcRaiseException(RPC_S_INVALID_BOUND);
-      return NULL;
+      ERR("NULL ref pointer is not allowed\n");
+      RpcRaiseException(RPC_X_NULL_REF_POINTER);
     }
-
-  if (fMustAlloc)
-    *ppMemory = NdrAllocate(pStubMsg, memsize);
-  else
-  {
-    if (!pStubMsg->IsClient && !*ppMemory && (pStubMsg->MaxCount == pStubMsg->ActualCount))
-      /* if the data in the RPC buffer is big enough, we just point straight
-       * into it */
-      *ppMemory = pStubMsg->Buffer;
-    else if (!*ppMemory)
-      *ppMemory = NdrAllocate(pStubMsg, memsize);
+    pointer_needs_marshaling = 1;
+    break;
+  case RPC_FC_UP: /* unique pointer */
+  case RPC_FC_OP: /* object pointer - same as unique here */
+    if (Pointer)
+      pointer_needs_marshaling = 1;
+    else
+      pointer_needs_marshaling = 0;
+    pointer_id = Pointer ? NDR_POINTER_ID(pStubMsg) : 0;
+    TRACE("writing 0x%08x to buffer\n", pointer_id);
+    NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id);
+    break;
+  case RPC_FC_FP:
+    pointer_needs_marshaling = !NdrFullPointerQueryPointer(
+      pStubMsg->FullPtrXlatTables, Pointer, 1, &pointer_id);
+    TRACE("writing 0x%08x to buffer\n", pointer_id);
+    NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id);
+    break;
+  default:
+    FIXME("unhandled ptr type=%02x\n", type);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    return;
   }
 
-  if (*ppMemory == pStubMsg->Buffer)
-    safe_buffer_increment(pStubMsg, bufsize);
-  else
-    safe_copy_from_buffer(pStubMsg, *ppMemory, bufsize);
+  TRACE("calling marshaller for type 0x%x\n", (int)*desc);
 
-  if (*pFormat == RPC_FC_C_CSTRING) {
-    TRACE("string=%s\n", debugstr_a((char*)*ppMemory));
-  }
-  else if (*pFormat == RPC_FC_C_WSTRING) {
-    TRACE("string=%s\n", debugstr_w((LPWSTR)*ppMemory));
+  if (pointer_needs_marshaling) {
+    if (attr & RPC_FC_P_DEREF) {
+      Pointer = *(unsigned char**)Pointer;
+      TRACE("deref => %p\n", Pointer);
+    }
+    m = NdrMarshaller[*desc & NDR_TABLE_MASK];
+    if (m) m(pStubMsg, Pointer, desc);
+    else FIXME("no marshaller for data type=%02x\n", *desc);
   }
 
-  return NULL; /* FIXME: is this always right? */
+  STD_OVERFLOW_CHECK(pStubMsg);
 }
 
 /***********************************************************************
- *           NdrNonConformantStringMarshall [RPCRT4.@]
+ *           PointerUnmarshall [internal]
  */
-unsigned char *  WINAPI NdrNonConformantStringMarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                unsigned char *pMemory,
-                                PFORMAT_STRING pFormat)
+static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                              unsigned char *Buffer,
+                              unsigned char **pPointer,
+                              unsigned char *pSrcPointer,
+                              PFORMAT_STRING pFormat,
+                              unsigned char fMustAlloc)
 {
-  ULONG esize, size, maxsize;
-
-  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
+  unsigned type = pFormat[0], attr = pFormat[1];
+  PFORMAT_STRING desc;
+  NDR_UNMARSHALL m;
+  DWORD pointer_id = 0;
+  int pointer_needs_unmarshaling;
 
-  maxsize = *(USHORT *)&pFormat[2];
+  TRACE("(%p,%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pSrcPointer, pFormat, fMustAlloc);
+  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  pFormat += 2;
+  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
+  else desc = pFormat + *(const SHORT*)pFormat;
 
-  if (*pFormat == RPC_FC_CSTRING)
-  {
-    ULONG i;
-    const char *str = (const char *)pMemory;
-    for (i = 0; i < maxsize && *str; i++, str++)
-        ;
-    TRACE("string=%s\n", debugstr_an(str, i));
-    pStubMsg->ActualCount = i + 1;
-    esize = 1;
-  }
-  else if (*pFormat == RPC_FC_WSTRING)
-  {
-    ULONG i;
-    const WCHAR *str = (const WCHAR *)pMemory;
-    for (i = 0; i < maxsize && *str; i++, str++)
-        ;
-    TRACE("string=%s\n", debugstr_wn(str, i));
-    pStubMsg->ActualCount = i + 1;
-    esize = 2;
-  }
-  else
-  {
-    ERR("Unhandled string type: %#x\n", *pFormat);
+  switch (type) {
+  case RPC_FC_RP: /* ref pointer (always non-null) */
+    pointer_needs_unmarshaling = 1;
+    break;
+  case RPC_FC_UP: /* unique pointer */
+    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
+    TRACE("pointer_id is 0x%08x\n", pointer_id);
+    if (pointer_id)
+      pointer_needs_unmarshaling = 1;
+    else {
+      *pPointer = NULL;
+      pointer_needs_unmarshaling = 0;
+    }
+    break;
+  case RPC_FC_OP: /* object pointer - we must free data before overwriting it */
+    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
+    TRACE("pointer_id is 0x%08x\n", pointer_id);
+    if (!fMustAlloc && pSrcPointer)
+    {
+        FIXME("free object pointer %p\n", pSrcPointer);
+        fMustAlloc = TRUE;
+    }
+    if (pointer_id)
+      pointer_needs_unmarshaling = 1;
+    else
+    {
+      *pPointer = NULL;    
+      pointer_needs_unmarshaling = 0;
+    }
+    break;
+  case RPC_FC_FP:
+    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
+    TRACE("pointer_id is 0x%08x\n", pointer_id);
+    pointer_needs_unmarshaling = !NdrFullPointerQueryRefId(
+      pStubMsg->FullPtrXlatTables, pointer_id, 1, (void **)pPointer);
+    break;
+  default:
+    FIXME("unhandled ptr type=%02x\n", type);
     RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    return;
   }
 
-  pStubMsg->Offset = 0;
-  WriteVariance(pStubMsg);
+  if (pointer_needs_unmarshaling) {
+    unsigned char *base_ptr_val = *pPointer;
+    unsigned char **current_ptr = pPointer;
+    if (pStubMsg->IsClient) {
+      TRACE("client\n");
+      /* if we aren't forcing allocation of memory then try to use the existing
+       * (source) pointer to unmarshall the data into so that [in,out]
+       * parameters behave correctly. it doesn't matter if the parameter is
+       * [out] only since in that case the pointer will be NULL. we force
+       * allocation when the source pointer is NULL here instead of in the type
+       * unmarshalling routine for the benefit of the deref code below */
+      if (!fMustAlloc) {
+        if (pSrcPointer) {
+          TRACE("setting *pPointer to %p\n", pSrcPointer);
+          *pPointer = base_ptr_val = pSrcPointer;
+        } else
+          fMustAlloc = TRUE;
+      }
+    } else {
+      TRACE("server\n");
+      /* the memory in a stub is never initialised, so we have to work out here
+       * whether we have to initialise it so we can use the optimisation of
+       * setting the pointer to the buffer, if possible, or set fMustAlloc to
+       * TRUE. */
+      if (attr & RPC_FC_P_DEREF) {
+        fMustAlloc = TRUE;
+      } else {
+        base_ptr_val = NULL;
+        *current_ptr = NULL;
+      }
+    }
 
-  size = safe_multiply(esize, pStubMsg->ActualCount);
-  safe_copy_to_buffer(pStubMsg, pMemory, size); /* the string itself */
+    if (attr & RPC_FC_P_ALLOCALLNODES)
+        FIXME("RPC_FC_P_ALLOCALLNODES not implemented\n");
 
-  return NULL;
+    if (attr & RPC_FC_P_DEREF) {
+      if (fMustAlloc) {
+        base_ptr_val = NdrAllocate(pStubMsg, sizeof(void *));
+        *pPointer = base_ptr_val;
+        current_ptr = (unsigned char **)base_ptr_val;
+      } else
+        current_ptr = *(unsigned char***)current_ptr;
+      TRACE("deref => %p\n", current_ptr);
+      if (!fMustAlloc && !*current_ptr) fMustAlloc = TRUE;
+    }
+    m = NdrUnmarshaller[*desc & NDR_TABLE_MASK];
+    if (m) m(pStubMsg, current_ptr, desc, fMustAlloc);
+    else FIXME("no unmarshaller for data type=%02x\n", *desc);
+
+    if (type == RPC_FC_FP)
+      NdrFullPointerInsertRefId(pStubMsg->FullPtrXlatTables, pointer_id,
+                                *pPointer);
+  }
+
+  TRACE("pointer=%p\n", *pPointer);
 }
 
 /***********************************************************************
- *           NdrNonConformantStringUnmarshall [RPCRT4.@]
+ *           PointerBufferSize [internal]
  */
-unsigned char *  WINAPI NdrNonConformantStringUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                unsigned char **ppMemory,
-                                PFORMAT_STRING pFormat,
-                                unsigned char fMustAlloc)
+static void PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
+                              unsigned char *Pointer,
+                              PFORMAT_STRING pFormat)
 {
-  ULONG bufsize, memsize, esize, i, maxsize;
-
-  TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n",
-    pStubMsg, *ppMemory, pFormat, fMustAlloc);
+  unsigned type = pFormat[0], attr = pFormat[1];
+  PFORMAT_STRING desc;
+  NDR_BUFFERSIZE m;
+  int pointer_needs_sizing;
+  ULONG pointer_id;
 
-  maxsize = *(USHORT *)&pFormat[2];
+  TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat);
+  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  pFormat += 2;
+  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
+  else desc = pFormat + *(const SHORT*)pFormat;
 
-  ReadVariance(pStubMsg, NULL, maxsize);
-  if (pStubMsg->Offset)
-  {
-    ERR("non-conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
+  switch (type) {
+  case RPC_FC_RP: /* ref pointer (always non-null) */
+    if (!Pointer)
+    {
+      ERR("NULL ref pointer is not allowed\n");
+      RpcRaiseException(RPC_X_NULL_REF_POINTER);
+    }
+    break;
+  case RPC_FC_OP:
+  case RPC_FC_UP:
+    /* NULL pointer has no further representation */
+    if (!Pointer)
+        return;
+    break;
+  case RPC_FC_FP:
+    pointer_needs_sizing = !NdrFullPointerQueryPointer(
+      pStubMsg->FullPtrXlatTables, Pointer, 0, &pointer_id);
+    if (!pointer_needs_sizing)
+      return;
+    break;
+  default:
+    FIXME("unhandled ptr type=%02x\n", type);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    return;
   }
 
-  if (*pFormat == RPC_FC_CSTRING) esize = 1;
-  else if (*pFormat == RPC_FC_WSTRING) esize = 2;
-  else
-  {
-    ERR("Unhandled string type: %#x\n", *pFormat);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  if (attr & RPC_FC_P_DEREF) {
+    Pointer = *(unsigned char**)Pointer;
+    TRACE("deref => %p\n", Pointer);
   }
 
-  memsize = esize * maxsize;
-  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+  m = NdrBufferSizer[*desc & NDR_TABLE_MASK];
+  if (m) m(pStubMsg, Pointer, desc);
+  else FIXME("no buffersizer for data type=%02x\n", *desc);
+}
 
-  if (bufsize < esize)
-  {
-    ERR("invalid string length of %d\n", pStubMsg->ActualCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
-    return NULL;
-  }
+/***********************************************************************
+ *           PointerMemorySize [internal]
+ */
+static ULONG PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                               unsigned char *Buffer, PFORMAT_STRING pFormat)
+{
+  unsigned type = pFormat[0], attr = pFormat[1];
+  PFORMAT_STRING desc;
+  NDR_MEMORYSIZE m;
+  DWORD pointer_id = 0;
+  int pointer_needs_sizing;
+
+  TRACE("(%p,%p,%p)\n", pStubMsg, Buffer, pFormat);
+  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  pFormat += 2;
+  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
+  else desc = pFormat + *(const SHORT*)pFormat;
 
-  /* verify the buffer is safe to access */
-  if ((pStubMsg->Buffer + bufsize < pStubMsg->Buffer) ||
-      (pStubMsg->Buffer + bufsize > pStubMsg->BufferEnd))
+  switch (type) {
+  case RPC_FC_RP: /* ref pointer (always non-null) */
+    pointer_needs_sizing = 1;
+    break;
+  case RPC_FC_UP: /* unique pointer */
+  case RPC_FC_OP: /* object pointer - we must free data before overwriting it */
+    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
+    TRACE("pointer_id is 0x%08x\n", pointer_id);
+    if (pointer_id)
+      pointer_needs_sizing = 1;
+    else
+      pointer_needs_sizing = 0;
+    break;
+  case RPC_FC_FP:
   {
-    ERR("bufsize 0x%x exceeded buffer end %p of buffer %p\n", bufsize,
-        pStubMsg->BufferEnd, pStubMsg->Buffer);
+    void *pointer;
+    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
+    TRACE("pointer_id is 0x%08x\n", pointer_id);
+    pointer_needs_sizing = !NdrFullPointerQueryRefId(
+      pStubMsg->FullPtrXlatTables, pointer_id, 1, &pointer);
+    break;
+  }
+  default:
+    FIXME("unhandled ptr type=%02x\n", type);
     RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return NULL;
+    return 0;
   }
 
-  /* strings must always have null terminating bytes */
-  for (i = bufsize - esize; i < bufsize; i++)
-    if (pStubMsg->Buffer[i] != 0)
-    {
-      ERR("string not null-terminated at byte position %d, data is 0x%x\n",
-        i, pStubMsg->Buffer[i]);
-      RpcRaiseException(RPC_S_INVALID_BOUND);
-    }
-
-  if (fMustAlloc || !*ppMemory)
-    *ppMemory = NdrAllocate(pStubMsg, memsize);
-
-  safe_copy_from_buffer(pStubMsg, *ppMemory, bufsize);
-
-  if (*pFormat == RPC_FC_CSTRING) {
-    TRACE("string=%s\n", debugstr_an((char*)*ppMemory, pStubMsg->ActualCount));
+  if (attr & RPC_FC_P_DEREF) {
+    ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(void*));
+    pStubMsg->MemorySize += sizeof(void*);
+    TRACE("deref\n");
   }
-  else if (*pFormat == RPC_FC_WSTRING) {
-    TRACE("string=%s\n", debugstr_wn((LPWSTR)*ppMemory, pStubMsg->ActualCount));
+
+  if (pointer_needs_sizing) {
+    m = NdrMemorySizer[*desc & NDR_TABLE_MASK];
+    if (m) m(pStubMsg, desc);
+    else FIXME("no memorysizer for data type=%02x\n", *desc);
   }
 
-  return NULL;
+  return pStubMsg->MemorySize;
 }
 
 /***********************************************************************
- *           NdrNonConformantStringBufferSize [RPCRT4.@]
+ *           PointerFree [internal]
  */
-void WINAPI NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-                                unsigned char *pMemory,
-                                PFORMAT_STRING pFormat)
+static void PointerFree(PMIDL_STUB_MESSAGE pStubMsg,
+                        unsigned char *Pointer,
+                        PFORMAT_STRING pFormat)
 {
-  ULONG esize, maxsize;
-
-  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
+  unsigned type = pFormat[0], attr = pFormat[1];
+  PFORMAT_STRING desc;
+  NDR_FREE m;
+  unsigned char *current_pointer = Pointer;
 
-  maxsize = *(USHORT *)&pFormat[2];
+  TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat);
+  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  if (attr & RPC_FC_P_DONTFREE) return;
+  pFormat += 2;
+  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
+  else desc = pFormat + *(const SHORT*)pFormat;
 
-  SizeVariance(pStubMsg);
+  if (!Pointer) return;
 
-  if (*pFormat == RPC_FC_CSTRING)
-  {
-    ULONG i;
-    const char *str = (const char *)pMemory;
-    for (i = 0; i < maxsize && *str; i++, str++)
-        ;
-    TRACE("string=%s\n", debugstr_an(str, i));
-    pStubMsg->ActualCount = i + 1;
-    esize = 1;
-  }
-  else if (*pFormat == RPC_FC_WSTRING)
-  {
-    ULONG i;
-    const WCHAR *str = (const WCHAR *)pMemory;
-    for (i = 0; i < maxsize && *str; i++, str++)
-        ;
-    TRACE("string=%s\n", debugstr_wn(str, i));
-    pStubMsg->ActualCount = i + 1;
-    esize = 2;
+  if (type == RPC_FC_FP) {
+    int pointer_needs_freeing = NdrFullPointerFree(
+      pStubMsg->FullPtrXlatTables, Pointer);
+    if (!pointer_needs_freeing)
+      return;
   }
-  else
-  {
-    ERR("Unhandled string type: %#x\n", *pFormat);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+
+  if (attr & RPC_FC_P_DEREF) {
+    current_pointer = *(unsigned char**)Pointer;
+    TRACE("deref => %p\n", current_pointer);
   }
 
-  safe_buffer_length_increment(pStubMsg, safe_multiply(esize, pStubMsg->ActualCount));
+  m = NdrFreer[*desc & NDR_TABLE_MASK];
+  if (m) m(pStubMsg, current_pointer, desc);
+
+  /* this check stops us from trying to free buffer memory. we don't have to
+   * worry about clients, since they won't call this function.
+   * we don't have to check for the buffer being reallocated because
+   * BufferStart and BufferEnd won't be reset when allocating memory for
+   * sending the response. we don't have to check for the new buffer here as
+   * it won't be used a type memory, only for buffer memory */
+  if (Pointer >= pStubMsg->BufferStart && Pointer < pStubMsg->BufferEnd)
+      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);
 }
 
 /***********************************************************************
- *           NdrNonConformantStringMemorySize [RPCRT4.@]
+ *           EmbeddedPointerMarshall
  */
-ULONG WINAPI NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                PFORMAT_STRING pFormat)
+static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                               unsigned char *pMemory,
+                                               PFORMAT_STRING pFormat)
 {
-  ULONG bufsize, memsize, esize, i, maxsize;
-
-  TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat);
+  unsigned char *Mark = pStubMsg->BufferMark;
+  unsigned rep, count, stride;
+  unsigned i;
+  unsigned char *saved_buffer = NULL;
 
-  maxsize = *(USHORT *)&pFormat[2];
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
-  ReadVariance(pStubMsg, NULL, maxsize);
+  if (*pFormat != RPC_FC_PP) return NULL;
+  pFormat += 2;
 
-  if (pStubMsg->Offset)
+  if (pStubMsg->PointerBufferMark)
   {
-    ERR("non-conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
+    saved_buffer = pStubMsg->Buffer;
+    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
+    pStubMsg->PointerBufferMark = NULL;
   }
 
-  if (*pFormat == RPC_FC_CSTRING) esize = 1;
-  else if (*pFormat == RPC_FC_WSTRING) esize = 2;
-  else
-  {
-    ERR("Unhandled string type: %#x\n", *pFormat);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-  }
+  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;
+      count = 1;
+      pFormat += 2;
+      break;
+    case RPC_FC_FIXED_REPEAT:
+      rep = *(const WORD*)&pFormat[2];
+      stride = *(const WORD*)&pFormat[4];
+      count = *(const WORD*)&pFormat[8];
+      pFormat += 10;
+      break;
+    case RPC_FC_VARIABLE_REPEAT:
+      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
+      stride = *(const WORD*)&pFormat[2];
+      count = *(const WORD*)&pFormat[6];
+      pFormat += 8;
+      break;
+    }
+    for (i = 0; i < rep; i++) {
+      PFORMAT_STRING info = pFormat;
+      unsigned char *membase = pMemory + (i * stride);
+      unsigned char *bufbase = Mark + (i * stride);
+      unsigned u;
 
-  memsize = esize * maxsize;
-  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+      for (u=0; u<count; u++,info+=8) {
+        unsigned char *memptr = membase + *(const SHORT*)&info[0];
+        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
+        unsigned char *saved_memory = pStubMsg->Memory;
+
+        pStubMsg->Memory = pMemory;
+        PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4);
+        pStubMsg->Memory = saved_memory;
+      }
+    }
+    pFormat += 8 * count;
+  }
 
-  /* strings must always have null terminating bytes */
-  if (bufsize < esize)
+  if (saved_buffer)
   {
-    ERR("invalid string length of %d\n", pStubMsg->ActualCount);
-    RpcRaiseException(RPC_S_INVALID_BOUND);
+    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
+    pStubMsg->Buffer = saved_buffer;
   }
 
-  /* verify the buffer is safe to access */
-  if ((pStubMsg->Buffer + bufsize < pStubMsg->Buffer) ||
-      (pStubMsg->Buffer + bufsize > pStubMsg->BufferEnd))
+  STD_OVERFLOW_CHECK(pStubMsg);
+
+  return NULL;
+}
+
+/***********************************************************************
+ *           EmbeddedPointerUnmarshall
+ */
+static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                                 unsigned char *pDstBuffer,
+                                                 unsigned char *pSrcMemoryPtrs,
+                                                 PFORMAT_STRING pFormat,
+                                                 unsigned char fMustAlloc)
+{
+  unsigned char *Mark = pStubMsg->BufferMark;
+  unsigned rep, count, stride;
+  unsigned i;
+  unsigned char *saved_buffer = NULL;
+
+  TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, pDstBuffer, pSrcMemoryPtrs, pFormat, fMustAlloc);
+
+  if (*pFormat != RPC_FC_PP) return NULL;
+  pFormat += 2;
+
+  if (pStubMsg->PointerBufferMark)
   {
-    ERR("bufsize 0x%x exceeded buffer end %p of buffer %p\n", bufsize,
-        pStubMsg->BufferEnd, pStubMsg->Buffer);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    saved_buffer = pStubMsg->Buffer;
+    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
+    pStubMsg->PointerBufferMark = NULL;
   }
 
-  for (i = bufsize - esize; i < bufsize; i++)
-    if (pStubMsg->Buffer[i] != 0)
-    {
-      ERR("string not null-terminated at byte position %d, data is 0x%x\n",
-        i, pStubMsg->Buffer[i]);
-      RpcRaiseException(RPC_S_INVALID_BOUND);
+  while (pFormat[0] != RPC_FC_END) {
+    TRACE("pFormat[0] = 0x%x\n", pFormat[0]);
+    switch (pFormat[0]) {
+    default:
+      FIXME("unknown repeat type %d\n", pFormat[0]);
+    case RPC_FC_NO_REPEAT:
+      rep = 1;
+      stride = 0;
+      count = 1;
+      pFormat += 2;
+      break;
+    case RPC_FC_FIXED_REPEAT:
+      rep = *(const WORD*)&pFormat[2];
+      stride = *(const WORD*)&pFormat[4];
+      count = *(const WORD*)&pFormat[8];
+      pFormat += 10;
+      break;
+    case RPC_FC_VARIABLE_REPEAT:
+      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
+      stride = *(const WORD*)&pFormat[2];
+      count = *(const WORD*)&pFormat[6];
+      pFormat += 8;
+      break;
     }
+    for (i = 0; i < rep; i++) {
+      PFORMAT_STRING info = pFormat;
+      unsigned char *bufdstbase = pDstBuffer + (i * stride);
+      unsigned char *memsrcbase = pSrcMemoryPtrs + (i * stride);
+      unsigned char *bufbase = Mark + (i * stride);
+      unsigned u;
 
-  safe_buffer_increment(pStubMsg, bufsize);
-  pStubMsg->MemorySize += memsize;
+      for (u=0; u<count; u++,info+=8) {
+        unsigned char **bufdstptr = (unsigned char **)(bufdstbase + *(const SHORT*)&info[2]);
+        unsigned char **memsrcptr = (unsigned char **)(memsrcbase + *(const SHORT*)&info[0]);
+        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
+        PointerUnmarshall(pStubMsg, bufptr, bufdstptr, *memsrcptr, info+4, fMustAlloc);
+      }
+    }
+    pFormat += 8 * count;
+  }
 
-  return pStubMsg->MemorySize;
-}
+  if (saved_buffer)
+  {
+    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
+    pStubMsg->Buffer = saved_buffer;
+  }
 
-static inline void dump_pointer_attr(unsigned char attr)
-{
-    if (attr & RPC_FC_P_ALLOCALLNODES)
-        TRACE(" RPC_FC_P_ALLOCALLNODES");
-    if (attr & RPC_FC_P_DONTFREE)
-        TRACE(" RPC_FC_P_DONTFREE");
-    if (attr & RPC_FC_P_ONSTACK)
-        TRACE(" RPC_FC_P_ONSTACK");
-    if (attr & RPC_FC_P_SIMPLEPOINTER)
-        TRACE(" RPC_FC_P_SIMPLEPOINTER");
-    if (attr & RPC_FC_P_DEREF)
-        TRACE(" RPC_FC_P_DEREF");
-    TRACE("\n");
+  return NULL;
 }
 
 /***********************************************************************
- *           PointerMarshall [internal]
+ *           EmbeddedPointerBufferSize
  */
-static void PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                            unsigned char *Buffer,
-                            unsigned char *Pointer,
-                            PFORMAT_STRING pFormat)
+static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
+                                      unsigned char *pMemory,
+                                      PFORMAT_STRING pFormat)
 {
-  unsigned type = pFormat[0], attr = pFormat[1];
-  PFORMAT_STRING desc;
-  NDR_MARSHALL m;
-  ULONG pointer_id;
-  int pointer_needs_marshaling;
+  unsigned rep, count, stride;
+  unsigned i;
+  ULONG saved_buffer_length = 0;
 
-  TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat);
-  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+
+  if (pStubMsg->IgnoreEmbeddedPointers) return;
+
+  if (*pFormat != RPC_FC_PP) return;
   pFormat += 2;
-  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
-  else desc = pFormat + *(const SHORT*)pFormat;
 
-  switch (type) {
-  case RPC_FC_RP: /* ref pointer (always non-null) */
-    if (!Pointer)
-    {
-      ERR("NULL ref pointer is not allowed\n");
-      RpcRaiseException(RPC_X_NULL_REF_POINTER);
+  if (pStubMsg->PointerLength)
+  {
+    saved_buffer_length = pStubMsg->BufferLength;
+    pStubMsg->BufferLength = pStubMsg->PointerLength;
+    pStubMsg->PointerLength = 0;
+  }
+
+  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;
+      count = 1;
+      pFormat += 2;
+      break;
+    case RPC_FC_FIXED_REPEAT:
+      rep = *(const WORD*)&pFormat[2];
+      stride = *(const WORD*)&pFormat[4];
+      count = *(const WORD*)&pFormat[8];
+      pFormat += 10;
+      break;
+    case RPC_FC_VARIABLE_REPEAT:
+      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
+      stride = *(const WORD*)&pFormat[2];
+      count = *(const WORD*)&pFormat[6];
+      pFormat += 8;
+      break;
     }
-    pointer_needs_marshaling = 1;
-    break;
-  case RPC_FC_UP: /* unique pointer */
-  case RPC_FC_OP: /* object pointer - same as unique here */
-    if (Pointer)
-      pointer_needs_marshaling = 1;
-    else
-      pointer_needs_marshaling = 0;
-    pointer_id = (ULONG)Pointer;
-    TRACE("writing 0x%08x to buffer\n", pointer_id);
-    NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id);
-    break;
-  case RPC_FC_FP:
-    pointer_needs_marshaling = !NdrFullPointerQueryPointer(
-      pStubMsg->FullPtrXlatTables, Pointer, 1, &pointer_id);
-    TRACE("writing 0x%08x to buffer\n", pointer_id);
-    NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id);
-    break;
-  default:
-    FIXME("unhandled ptr type=%02x\n", type);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return;
+    for (i = 0; i < rep; i++) {
+      PFORMAT_STRING info = pFormat;
+      unsigned char *membase = pMemory + (i * stride);
+      unsigned u;
+
+      for (u=0; u<count; u++,info+=8) {
+        unsigned char *memptr = membase + *(const SHORT*)&info[0];
+        unsigned char *saved_memory = pStubMsg->Memory;
+
+        pStubMsg->Memory = pMemory;
+        PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4);
+        pStubMsg->Memory = saved_memory;
+      }
+    }
+    pFormat += 8 * count;
   }
 
-  TRACE("calling marshaller for type 0x%x\n", (int)*desc);
+  if (saved_buffer_length)
+  {
+    pStubMsg->PointerLength = pStubMsg->BufferLength;
+    pStubMsg->BufferLength = saved_buffer_length;
+  }
+}
 
-  if (pointer_needs_marshaling) {
-    if (attr & RPC_FC_P_DEREF) {
-      Pointer = *(unsigned char**)Pointer;
-      TRACE("deref => %p\n", Pointer);
+/***********************************************************************
+ *           EmbeddedPointerMemorySize [internal]
+ */
+static ULONG EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                       PFORMAT_STRING pFormat)
+{
+  unsigned char *Mark = pStubMsg->BufferMark;
+  unsigned rep, count, stride;
+  unsigned i;
+  unsigned char *saved_buffer = NULL;
+
+  TRACE("(%p,%p)\n", pStubMsg, pFormat);
+
+  if (pStubMsg->IgnoreEmbeddedPointers) return 0;
+
+  if (pStubMsg->PointerBufferMark)
+  {
+    saved_buffer = pStubMsg->Buffer;
+    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
+    pStubMsg->PointerBufferMark = NULL;
+  }
+
+  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;
+      count = 1;
+      pFormat += 2;
+      break;
+    case RPC_FC_FIXED_REPEAT:
+      rep = *(const WORD*)&pFormat[2];
+      stride = *(const WORD*)&pFormat[4];
+      count = *(const WORD*)&pFormat[8];
+      pFormat += 10;
+      break;
+    case RPC_FC_VARIABLE_REPEAT:
+      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
+      stride = *(const WORD*)&pFormat[2];
+      count = *(const WORD*)&pFormat[6];
+      pFormat += 8;
+      break;
     }
-    m = NdrMarshaller[*desc & NDR_TABLE_MASK];
-    if (m) m(pStubMsg, Pointer, desc);
-    else FIXME("no marshaller for data type=%02x\n", *desc);
+    for (i = 0; i < rep; i++) {
+      PFORMAT_STRING info = pFormat;
+      unsigned char *bufbase = Mark + (i * stride);
+      unsigned u;
+      for (u=0; u<count; u++,info+=8) {
+        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
+        PointerMemorySize(pStubMsg, bufptr, info+4);
+      }
+    }
+    pFormat += 8 * count;
   }
 
-  STD_OVERFLOW_CHECK(pStubMsg);
+  if (saved_buffer)
+  {
+    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
+    pStubMsg->Buffer = saved_buffer;
+  }
+
+  return 0;
 }
 
 /***********************************************************************
- *           PointerUnmarshall [internal]
+ *           EmbeddedPointerFree [internal]
  */
-static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                              unsigned char *Buffer,
-                              unsigned char **pPointer,
-                              unsigned char *pSrcPointer,
-                              PFORMAT_STRING pFormat,
-                              unsigned char fMustAlloc)
+static void EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg,
+                                unsigned char *pMemory,
+                                PFORMAT_STRING pFormat)
 {
-  unsigned type = pFormat[0], attr = pFormat[1];
-  PFORMAT_STRING desc;
-  NDR_UNMARSHALL m;
-  DWORD pointer_id = 0;
-  int pointer_needs_unmarshaling;
+  unsigned rep, count, stride;
+  unsigned i;
 
-  TRACE("(%p,%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pSrcPointer, pFormat, fMustAlloc);
-  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+  if (*pFormat != RPC_FC_PP) return;
   pFormat += 2;
-  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
-  else desc = pFormat + *(const SHORT*)pFormat;
 
-  switch (type) {
-  case RPC_FC_RP: /* ref pointer (always non-null) */
-    pointer_needs_unmarshaling = 1;
-    break;
-  case RPC_FC_UP: /* unique pointer */
-    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
-    TRACE("pointer_id is 0x%08x\n", pointer_id);
-    if (pointer_id)
-      pointer_needs_unmarshaling = 1;
-    else {
-      *pPointer = NULL;
-      pointer_needs_unmarshaling = 0;
+  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;
+      count = 1;
+      pFormat += 2;
+      break;
+    case RPC_FC_FIXED_REPEAT:
+      rep = *(const WORD*)&pFormat[2];
+      stride = *(const WORD*)&pFormat[4];
+      count = *(const WORD*)&pFormat[8];
+      pFormat += 10;
+      break;
+    case RPC_FC_VARIABLE_REPEAT:
+      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
+      stride = *(const WORD*)&pFormat[2];
+      count = *(const WORD*)&pFormat[6];
+      pFormat += 8;
+      break;
     }
-    break;
-  case RPC_FC_OP: /* object pointer - we must free data before overwriting it */
-    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
-    TRACE("pointer_id is 0x%08x\n", pointer_id);
-    if (!fMustAlloc && pSrcPointer)
+    for (i = 0; i < rep; i++) {
+      PFORMAT_STRING info = pFormat;
+      unsigned char *membase = pMemory + (i * stride);
+      unsigned u;
+
+      for (u=0; u<count; u++,info+=8) {
+        unsigned char *memptr = membase + *(const SHORT*)&info[0];
+        unsigned char *saved_memory = pStubMsg->Memory;
+
+        pStubMsg->Memory = pMemory;
+        PointerFree(pStubMsg, *(unsigned char**)memptr, info+4);
+        pStubMsg->Memory = saved_memory;
+      }
+    }
+    pFormat += 8 * count;
+  }
+}
+
+/***********************************************************************
+ *           NdrPointerMarshall [RPCRT4.@]
+ */
+unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                          unsigned char *pMemory,
+                                          PFORMAT_STRING pFormat)
+{
+  unsigned char *Buffer;
+
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+
+  /* Increment the buffer here instead of in PointerMarshall,
+   * as that is used by embedded pointers which already handle the incrementing
+   * the buffer, and shouldn't write any additional pointer data to the wire */
+  if (*pFormat != RPC_FC_RP)
+  {
+    ALIGN_POINTER_CLEAR(pStubMsg->Buffer, 4);
+    Buffer = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, 4);
+  }
+  else
+    Buffer = pStubMsg->Buffer;
+
+  PointerMarshall(pStubMsg, Buffer, pMemory, pFormat);
+
+  return NULL;
+}
+
+/***********************************************************************
+ *           NdrPointerUnmarshall [RPCRT4.@]
+ */
+unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                            unsigned char **ppMemory,
+                                            PFORMAT_STRING pFormat,
+                                            unsigned char fMustAlloc)
+{
+  unsigned char *Buffer;
+
+  TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
+
+  if (*pFormat == RPC_FC_RP)
+  {
+    Buffer = pStubMsg->Buffer;
+    /* Do the NULL ref pointer check here because embedded pointers can be
+     * NULL if the type the pointer is embedded in was allocated rather than
+     * being passed in by the client */
+    if (pStubMsg->IsClient && !*ppMemory)
     {
-        FIXME("free object pointer %p\n", pSrcPointer);
-        fMustAlloc = TRUE;
+      ERR("NULL ref pointer is not allowed\n");
+      RpcRaiseException(RPC_X_NULL_REF_POINTER);
     }
-    if (pointer_id)
-      pointer_needs_unmarshaling = 1;
-    else
-      pointer_needs_unmarshaling = 0;
-    break;
-  case RPC_FC_FP:
-    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
-    TRACE("pointer_id is 0x%08x\n", pointer_id);
-    pointer_needs_unmarshaling = !NdrFullPointerQueryRefId(
-      pStubMsg->FullPtrXlatTables, pointer_id, 1, (void **)pPointer);
-    break;
-  default:
-    FIXME("unhandled ptr type=%02x\n", type);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return;
+  }
+  else
+  {
+    /* Increment the buffer here instead of in PointerUnmarshall,
+     * as that is used by embedded pointers which already handle the incrementing
+     * the buffer, and shouldn't read any additional pointer data from the
+     * buffer */
+    ALIGN_POINTER(pStubMsg->Buffer, 4);
+    Buffer = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, 4);
   }
 
-  if (pointer_needs_unmarshaling) {
-    unsigned char *base_ptr_val = *pPointer;
-    unsigned char **current_ptr = pPointer;
-    if (pStubMsg->IsClient) {
-      TRACE("client\n");
-      /* if we aren't forcing allocation of memory then try to use the existing
-       * (source) pointer to unmarshall the data into so that [in,out]
-       * parameters behave correctly. it doesn't matter if the parameter is
-       * [out] only since in that case the pointer will be NULL. we force
-       * allocation when the source pointer is NULL here instead of in the type
-       * unmarshalling routine for the benefit of the deref code below */
-      if (!fMustAlloc) {
-        if (pSrcPointer) {
-          TRACE("setting *pPointer to %p\n", pSrcPointer);
-          *pPointer = base_ptr_val = pSrcPointer;
-        } else
-          fMustAlloc = TRUE;
-      }
-    } else {
-      TRACE("server\n");
-      /* the memory in a stub is never initialised, so we have to work out here
-       * whether we have to initialise it so we can use the optimisation of
-       * setting the pointer to the buffer, if possible, or set fMustAlloc to
-       * TRUE. */
-      if (attr & RPC_FC_P_DEREF) {
-        fMustAlloc = TRUE;
-      } else {
-        base_ptr_val = NULL;
-        *current_ptr = NULL;
-      }
+  PointerUnmarshall(pStubMsg, Buffer, ppMemory, *ppMemory, pFormat, fMustAlloc);
+
+  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);
+
+  /* Increment the buffer length here instead of in PointerBufferSize,
+   * as that is used by embedded pointers which already handle the buffer
+   * length, and shouldn't write anything more to the wire */
+  if (*pFormat != RPC_FC_RP)
+  {
+    ALIGN_LENGTH(pStubMsg->BufferLength, 4);
+    safe_buffer_length_increment(pStubMsg, 4);
+  }
+
+  PointerBufferSize(pStubMsg, pMemory, pFormat);
+}
+
+/***********************************************************************
+ *           NdrPointerMemorySize [RPCRT4.@]
+ */
+ULONG WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                  PFORMAT_STRING pFormat)
+{
+    unsigned char *Buffer = pStubMsg->Buffer;
+    if (*pFormat != RPC_FC_RP)
+    {
+        ALIGN_POINTER(pStubMsg->Buffer, 4);
+        safe_buffer_increment(pStubMsg, 4);
     }
+    ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(void *));
+    return PointerMemorySize(pStubMsg, Buffer, pFormat);
+}
 
-    if (attr & RPC_FC_P_ALLOCALLNODES)
-        FIXME("RPC_FC_P_ALLOCALLNODES not implemented\n");
+/***********************************************************************
+ *           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);
+}
 
-    if (attr & RPC_FC_P_DEREF) {
-      if (fMustAlloc) {
-        base_ptr_val = NdrAllocate(pStubMsg, sizeof(void *));
-        *pPointer = base_ptr_val;
-        current_ptr = (unsigned char **)base_ptr_val;
-      } else
-        current_ptr = *(unsigned char***)current_ptr;
-      TRACE("deref => %p\n", current_ptr);
-      if (!fMustAlloc && !*current_ptr) fMustAlloc = TRUE;
+/***********************************************************************
+ *           NdrSimpleTypeMarshall [RPCRT4.@]
+ */
+void WINAPI NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory,
+                                   unsigned char FormatChar )
+{
+    NdrBaseTypeMarshall(pStubMsg, pMemory, &FormatChar);
+}
+
+/***********************************************************************
+ *           NdrSimpleTypeUnmarshall [RPCRT4.@]
+ *
+ * Unmarshall a base type.
+ *
+ * NOTES
+ *  Doesn't check that the buffer is long enough before copying, so the caller
+ * should do this.
+ */
+void WINAPI NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory,
+                                     unsigned char FormatChar )
+{
+#define BASE_TYPE_UNMARSHALL(type) \
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \
+       TRACE("pMemory: %p\n", pMemory); \
+       *(type *)pMemory = *(type *)pStubMsg->Buffer; \
+        pStubMsg->Buffer += sizeof(type);
+
+    switch(FormatChar)
+    {
+    case RPC_FC_BYTE:
+    case RPC_FC_CHAR:
+    case RPC_FC_SMALL:
+    case RPC_FC_USMALL:
+        BASE_TYPE_UNMARSHALL(UCHAR);
+        TRACE("value: 0x%02x\n", *pMemory);
+        break;
+    case RPC_FC_WCHAR:
+    case RPC_FC_SHORT:
+    case RPC_FC_USHORT:
+        BASE_TYPE_UNMARSHALL(USHORT);
+        TRACE("value: 0x%04x\n", *(USHORT *)pMemory);
+        break;
+    case RPC_FC_LONG:
+    case RPC_FC_ULONG:
+    case RPC_FC_ERROR_STATUS_T:
+    case RPC_FC_ENUM32:
+        BASE_TYPE_UNMARSHALL(ULONG);
+        TRACE("value: 0x%08x\n", *(ULONG *)pMemory);
+        break;
+   case RPC_FC_FLOAT:
+        BASE_TYPE_UNMARSHALL(float);
+        TRACE("value: %f\n", *(float *)pMemory);
+        break;
+    case RPC_FC_DOUBLE:
+        BASE_TYPE_UNMARSHALL(double);
+        TRACE("value: %f\n", *(double *)pMemory);
+        break;
+    case RPC_FC_HYPER:
+        BASE_TYPE_UNMARSHALL(ULONGLONG);
+        TRACE("value: %s\n", wine_dbgstr_longlong(*(ULONGLONG *)pMemory));
+        break;
+    case RPC_FC_ENUM16:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT));
+        TRACE("pMemory: %p\n", pMemory);
+        /* 16-bits on the wire, but int in memory */
+        *(UINT *)pMemory = *(USHORT *)pStubMsg->Buffer;
+        pStubMsg->Buffer += sizeof(USHORT);
+        TRACE("value: 0x%08x\n", *(UINT *)pMemory);
+        break;
+    case RPC_FC_IGNORE:
+        break;
+    default:
+        FIXME("Unhandled base type: 0x%02x\n", FormatChar);
     }
-    m = NdrUnmarshaller[*desc & NDR_TABLE_MASK];
-    if (m) m(pStubMsg, current_ptr, desc, fMustAlloc);
-    else FIXME("no unmarshaller for data type=%02x\n", *desc);
-
-    if (type == RPC_FC_FP)
-      NdrFullPointerInsertRefId(pStubMsg->FullPtrXlatTables, pointer_id,
-                                base_ptr_val);
-  }
-
-  TRACE("pointer=%p\n", *pPointer);
+#undef BASE_TYPE_UNMARSHALL
 }
 
 /***********************************************************************
- *           PointerBufferSize [internal]
+ *           NdrSimpleStructMarshall [RPCRT4.@]
  */
-static void PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-                              unsigned char *Pointer,
-                              PFORMAT_STRING pFormat)
+unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                               unsigned char *pMemory,
+                                               PFORMAT_STRING pFormat)
 {
-  unsigned type = pFormat[0], attr = pFormat[1];
-  PFORMAT_STRING desc;
-  NDR_BUFFERSIZE m;
-  int pointer_needs_sizing;
-  ULONG pointer_id;
+  unsigned size = *(const WORD*)(pFormat+2);
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
-  TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat);
-  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
-  pFormat += 2;
-  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
-  else desc = pFormat + *(const SHORT*)pFormat;
+  ALIGN_POINTER_CLEAR(pStubMsg->Buffer, pFormat[1] + 1);
 
-  switch (type) {
-  case RPC_FC_RP: /* ref pointer (always non-null) */
-    if (!Pointer)
-    {
-      ERR("NULL ref pointer is not allowed\n");
-      RpcRaiseException(RPC_X_NULL_REF_POINTER);
-    }
-    break;
-  case RPC_FC_OP:
-  case RPC_FC_UP:
-    /* NULL pointer has no further representation */
-    if (!Pointer)
-        return;
-    break;
-  case RPC_FC_FP:
-    pointer_needs_sizing = !NdrFullPointerQueryPointer(
-      pStubMsg->FullPtrXlatTables, Pointer, 0, &pointer_id);
-    if (!pointer_needs_sizing)
-      return;
-    break;
-  default:
-    FIXME("unhandled ptr type=%02x\n", type);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return;
-  }
+  pStubMsg->BufferMark = pStubMsg->Buffer;
+  safe_copy_to_buffer(pStubMsg, pMemory, size);
 
-  if (attr & RPC_FC_P_DEREF) {
-    Pointer = *(unsigned char**)Pointer;
-    TRACE("deref => %p\n", Pointer);
-  }
+  if (pFormat[0] != RPC_FC_STRUCT)
+    EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4);
 
-  m = NdrBufferSizer[*desc & NDR_TABLE_MASK];
-  if (m) m(pStubMsg, Pointer, desc);
-  else FIXME("no buffersizer for data type=%02x\n", *desc);
+  return NULL;
 }
 
 /***********************************************************************
- *           PointerMemorySize [internal]
+ *           NdrSimpleStructUnmarshall [RPCRT4.@]
  */
-static unsigned long PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                       unsigned char *Buffer,
-                                       PFORMAT_STRING pFormat)
+unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                                 unsigned char **ppMemory,
+                                                 PFORMAT_STRING pFormat,
+                                                 unsigned char fMustAlloc)
 {
-  unsigned type = pFormat[0], attr = pFormat[1];
-  PFORMAT_STRING desc;
-  NDR_MEMORYSIZE m;
-  DWORD pointer_id = 0;
-  int pointer_needs_sizing;
+  unsigned size = *(const WORD*)(pFormat+2);
+  unsigned char *saved_buffer;
+  TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
 
-  TRACE("(%p,%p,%p)\n", pStubMsg, Buffer, pFormat);
-  TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr);
-  pFormat += 2;
-  if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat;
-  else desc = pFormat + *(const SHORT*)pFormat;
+  ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
 
-  switch (type) {
-  case RPC_FC_RP: /* ref pointer (always non-null) */
-    pointer_needs_sizing = 1;
-    break;
-  case RPC_FC_UP: /* unique pointer */
-  case RPC_FC_OP: /* object pointer - we must free data before overwriting it */
-    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
-    TRACE("pointer_id is 0x%08x\n", pointer_id);
-    if (pointer_id)
-      pointer_needs_sizing = 1;
-    else
-      pointer_needs_sizing = 0;
-    break;
-  case RPC_FC_FP:
+  if (fMustAlloc)
+    *ppMemory = NdrAllocate(pStubMsg, size);
+  else
   {
-    void *pointer;
-    pointer_id = NDR_LOCAL_UINT32_READ(Buffer);
-    TRACE("pointer_id is 0x%08x\n", pointer_id);
-    pointer_needs_sizing = !NdrFullPointerQueryRefId(
-      pStubMsg->FullPtrXlatTables, pointer_id, 1, &pointer);
-    break;
-  }
-  default:
-    FIXME("unhandled ptr type=%02x\n", type);
-    RpcRaiseException(RPC_X_BAD_STUB_DATA);
-    return 0;
+    if (!pStubMsg->IsClient && !*ppMemory)
+      /* for servers, we just point straight into the RPC buffer */
+      *ppMemory = pStubMsg->Buffer;
   }
 
-  if (attr & RPC_FC_P_DEREF) {
-    TRACE("deref\n");
-  }
+  saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
+  safe_buffer_increment(pStubMsg, size);
+  if (pFormat[0] == RPC_FC_PSTRUCT)
+      EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat+4, fMustAlloc);
 
-  if (pointer_needs_sizing) {
-    m = NdrMemorySizer[*desc & NDR_TABLE_MASK];
-    if (m) m(pStubMsg, desc);
-    else FIXME("no memorysizer for data type=%02x\n", *desc);
-  }
+  TRACE("copying %p to %p\n", saved_buffer, *ppMemory);
+  if (*ppMemory != saved_buffer)
+      memcpy(*ppMemory, saved_buffer, size);
 
-  return pStubMsg->MemorySize;
+  return NULL;
 }
 
 /***********************************************************************
- *           PointerFree [internal]
+ *           NdrSimpleStructBufferSize [RPCRT4.@]
  */
-static void PointerFree(PMIDL_STUB_MESSAGE pStubMsg,
-                        unsigned char *Pointer,
-                        PFORMAT_STRING pFormat)
+void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
+                                      unsigned char *pMemory,
+                                      PFORMAT_STRING pFormat)
 {
-  unsigned type = pFormat[0], attr = pFormat[1];
-  PFORMAT_STRING desc;
-  NDR_FREE m;
-  unsigned char *current_pointer = Pointer;
-
-  TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat);
-  TRACE("type=0x%x, attr=", type); dump_pointer_attr(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 (!Pointer) return;
-
-  if (type == RPC_FC_FP) {
-    int pointer_needs_freeing = NdrFullPointerFree(
-      pStubMsg->FullPtrXlatTables, Pointer);
-    if (!pointer_needs_freeing)
-      return;
-  }
-
-  if (attr & RPC_FC_P_DEREF) {
-    current_pointer = *(unsigned char**)Pointer;
-    TRACE("deref => %p\n", current_pointer);
-  }
-
-  m = NdrFreer[*desc & NDR_TABLE_MASK];
-  if (m) m(pStubMsg, current_pointer, desc);
+  unsigned size = *(const WORD*)(pFormat+2);
+  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
-  /* this check stops us from trying to free buffer memory. we don't have to
-   * worry about clients, since they won't call this function.
-   * we don't have to check for the buffer being reallocated because
-   * BufferStart and BufferEnd won't be reset when allocating memory for
-   * sending the response. we don't have to check for the new buffer here as
-   * it won't be used a type memory, only for buffer memory */
-  if (Pointer >= (unsigned char *)pStubMsg->BufferStart &&
-      Pointer < (unsigned char *)pStubMsg->BufferEnd)
-      goto notfree;
+  ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1);
 
-  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);
+  safe_buffer_length_increment(pStubMsg, size);
+  if (pFormat[0] != RPC_FC_STRUCT)
+    EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4);
 }
 
 /***********************************************************************
- *           EmbeddedPointerMarshall
+ *           NdrSimpleStructMemorySize [RPCRT4.@]
  */
-static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                               unsigned char *pMemory,
-                                               PFORMAT_STRING pFormat)
+ULONG WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                       PFORMAT_STRING pFormat)
 {
-  unsigned char *Mark = pStubMsg->BufferMark;
-  unsigned rep, count, stride;
-  unsigned i;
-  unsigned char *saved_buffer = NULL;
+  unsigned short size = *(const WORD *)(pFormat+2);
 
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+  TRACE("(%p,%p)\n", pStubMsg, pFormat);
 
-  if (*pFormat != RPC_FC_PP) return NULL;
-  pFormat += 2;
+  ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
+  pStubMsg->MemorySize += size;
+  safe_buffer_increment(pStubMsg, size);
 
-  if (pStubMsg->PointerBufferMark)
-  {
-    saved_buffer = pStubMsg->Buffer;
-    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
-    pStubMsg->PointerBufferMark = NULL;
-  }
+  if (pFormat[0] != RPC_FC_STRUCT)
+    EmbeddedPointerMemorySize(pStubMsg, pFormat+4);
+  return pStubMsg->MemorySize;
+}
 
-  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;
-      count = 1;
-      pFormat += 2;
-      break;
-    case RPC_FC_FIXED_REPEAT:
-      rep = *(const WORD*)&pFormat[2];
-      stride = *(const WORD*)&pFormat[4];
-      count = *(const WORD*)&pFormat[8];
-      pFormat += 10;
-      break;
-    case RPC_FC_VARIABLE_REPEAT:
-      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
-      stride = *(const WORD*)&pFormat[2];
-      count = *(const WORD*)&pFormat[6];
-      pFormat += 8;
-      break;
-    }
-    for (i = 0; i < rep; i++) {
-      PFORMAT_STRING info = pFormat;
-      unsigned char *membase = pMemory + (i * stride);
-      unsigned char *bufbase = Mark + (i * stride);
-      unsigned u;
+/***********************************************************************
+ *           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);
+}
 
-      for (u=0; u<count; u++,info+=8) {
-        unsigned char *memptr = membase + *(const SHORT*)&info[0];
-        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
-        unsigned char *saved_memory = pStubMsg->Memory;
+/* Array helpers */
 
-        pStubMsg->Memory = pMemory;
-        PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4);
-        pStubMsg->Memory = saved_memory;
-      }
+static inline void array_compute_and_size_conformance(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
+    PFORMAT_STRING pFormat)
+{
+  switch (fc)
+  {
+  case RPC_FC_CARRAY:
+    ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
+    SizeConformance(pStubMsg);
+    break;
+  case RPC_FC_CVARRAY:
+    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 4, 0);
+    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
+    SizeConformance(pStubMsg);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+    {
+      TRACE("string=%s\n", debugstr_a((const char *)pMemory));
+      pStubMsg->ActualCount = strlen((const char *)pMemory)+1;
     }
-    pFormat += 8 * count;
+    else
+    {
+      TRACE("string=%s\n", debugstr_w((LPCWSTR)pMemory));
+      pStubMsg->ActualCount = strlenW((LPCWSTR)pMemory)+1;
+    }
+
+    if (pFormat[1] == RPC_FC_STRING_SIZED)
+      pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 2, 0);
+    else
+      pStubMsg->MaxCount = pStubMsg->ActualCount;
+
+    SizeConformance(pStubMsg);
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
+}
 
-  if (saved_buffer)
+static inline void array_buffer_size(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
+    PFORMAT_STRING pFormat, unsigned char fHasPointers)
+{
+  DWORD size;
+  DWORD esize;
+  unsigned char alignment;
+
+  switch (fc)
   {
-    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-    pStubMsg->Buffer = saved_buffer;
-  }
+  case RPC_FC_CARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  STD_OVERFLOW_CHECK(pStubMsg);
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
 
-  return NULL;
-}
+    ALIGN_LENGTH(pStubMsg->BufferLength, alignment);
 
-/***********************************************************************
- *           EmbeddedPointerUnmarshall
- */
-static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                                 unsigned char *pDstMemoryPtrs,
-                                                 unsigned char *pSrcMemoryPtrs,
-                                                 PFORMAT_STRING pFormat,
-                                                 unsigned char fMustAlloc)
-{
-  unsigned char *Mark = pStubMsg->BufferMark;
-  unsigned rep, count, stride;
-  unsigned i;
-  unsigned char *saved_buffer = NULL;
+    size = safe_multiply(esize, pStubMsg->MaxCount);
+    /* conformance value plus array */
+    safe_buffer_length_increment(pStubMsg, size);
 
-  TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, pDstMemoryPtrs, pSrcMemoryPtrs, pFormat, fMustAlloc);
+    if (fHasPointers)
+      EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_CVARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  if (*pFormat != RPC_FC_PP) return NULL;
-  pFormat += 2;
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
+    pFormat = SkipConformance(pStubMsg, pFormat);
 
-  if (pStubMsg->PointerBufferMark)
-  {
-    saved_buffer = pStubMsg->Buffer;
-    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
-    pStubMsg->PointerBufferMark = NULL;
-  }
+    SizeVariance(pStubMsg);
 
-  while (pFormat[0] != RPC_FC_END) {
-    TRACE("pFormat[0] = 0x%x\n", pFormat[0]);
-    switch (pFormat[0]) {
-    default:
-      FIXME("unknown repeat type %d\n", pFormat[0]);
-    case RPC_FC_NO_REPEAT:
-      rep = 1;
-      stride = 0;
-      count = 1;
-      pFormat += 2;
-      break;
-    case RPC_FC_FIXED_REPEAT:
-      rep = *(const WORD*)&pFormat[2];
-      stride = *(const WORD*)&pFormat[4];
-      count = *(const WORD*)&pFormat[8];
-      pFormat += 10;
-      break;
-    case RPC_FC_VARIABLE_REPEAT:
-      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
-      stride = *(const WORD*)&pFormat[2];
-      count = *(const WORD*)&pFormat[6];
-      pFormat += 8;
-      break;
-    }
-    for (i = 0; i < rep; i++) {
-      PFORMAT_STRING info = pFormat;
-      unsigned char *memdstbase = pDstMemoryPtrs + (i * stride);
-      unsigned char *memsrcbase = pSrcMemoryPtrs + (i * stride);
-      unsigned char *bufbase = Mark + (i * stride);
-      unsigned u;
+    ALIGN_LENGTH(pStubMsg->BufferLength, alignment);
 
-      for (u=0; u<count; u++,info+=8) {
-        unsigned char **memdstptr = (unsigned char **)(memdstbase + *(const SHORT*)&info[0]);
-        unsigned char **memsrcptr = (unsigned char **)(memsrcbase + *(const SHORT*)&info[0]);
-        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
-        PointerUnmarshall(pStubMsg, bufptr, memdstptr, *memsrcptr, info+4, fMustAlloc);
-      }
-    }
-    pFormat += 8 * count;
+    size = safe_multiply(esize, pStubMsg->ActualCount);
+    safe_buffer_length_increment(pStubMsg, size);
+
+    if (fHasPointers)
+      EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+      esize = 1;
+    else
+      esize = 2;
+
+    SizeVariance(pStubMsg);
+
+    size = safe_multiply(esize, pStubMsg->ActualCount);
+    safe_buffer_length_increment(pStubMsg, size);
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
+}
 
-  if (saved_buffer)
+static inline void array_compute_and_write_conformance(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
+    PFORMAT_STRING pFormat)
+{
+  switch (fc)
   {
-    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-    pStubMsg->Buffer = saved_buffer;
+  case RPC_FC_CARRAY:
+    ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
+    WriteConformance(pStubMsg);
+    break;
+  case RPC_FC_CVARRAY:
+    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 4, 0);
+    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
+    WriteConformance(pStubMsg);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+    {
+      TRACE("string=%s\n", debugstr_a((const char *)pMemory));
+      pStubMsg->ActualCount = strlen((const char *)pMemory)+1;
+    }
+    else
+    {
+      TRACE("string=%s\n", debugstr_w((LPCWSTR)pMemory));
+      pStubMsg->ActualCount = strlenW((LPCWSTR)pMemory)+1;
+    }
+    if (pFormat[1] == RPC_FC_STRING_SIZED)
+      pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 2, 0);
+    else
+      pStubMsg->MaxCount = pStubMsg->ActualCount;
+    pStubMsg->Offset = 0;
+    WriteConformance(pStubMsg);
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
-
-  return NULL;
 }
 
-/***********************************************************************
- *           EmbeddedPointerBufferSize
- */
-static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-                                      unsigned char *pMemory,
-                                      PFORMAT_STRING pFormat)
+static inline void array_write_variance_and_marshall(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
+    PFORMAT_STRING pFormat, unsigned char fHasPointers)
 {
-  unsigned rep, count, stride;
-  unsigned i;
-  ULONG saved_buffer_length = 0;
+  DWORD size;
+  DWORD esize;
+  unsigned char alignment;
 
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+  switch (fc)
+  {
+  case RPC_FC_CARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  if (pStubMsg->IgnoreEmbeddedPointers) return;
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
 
-  if (*pFormat != RPC_FC_PP) return;
-  pFormat += 2;
+    ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment);
 
-  if (pStubMsg->PointerLength)
-  {
-    saved_buffer_length = pStubMsg->BufferLength;
-    pStubMsg->BufferLength = pStubMsg->PointerLength;
-    pStubMsg->PointerLength = 0;
-  }
+    size = safe_multiply(esize, pStubMsg->MaxCount);
+    if (fHasPointers)
+      pStubMsg->BufferMark = pStubMsg->Buffer;
+    safe_copy_to_buffer(pStubMsg, pMemory, size);
 
-  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;
-      count = 1;
-      pFormat += 2;
-      break;
-    case RPC_FC_FIXED_REPEAT:
-      rep = *(const WORD*)&pFormat[2];
-      stride = *(const WORD*)&pFormat[4];
-      count = *(const WORD*)&pFormat[8];
-      pFormat += 10;
-      break;
-    case RPC_FC_VARIABLE_REPEAT:
-      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
-      stride = *(const WORD*)&pFormat[2];
-      count = *(const WORD*)&pFormat[6];
-      pFormat += 8;
-      break;
-    }
-    for (i = 0; i < rep; i++) {
-      PFORMAT_STRING info = pFormat;
-      unsigned char *membase = pMemory + (i * stride);
-      unsigned u;
+    if (fHasPointers)
+      EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_CVARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-      for (u=0; u<count; u++,info+=8) {
-        unsigned char *memptr = membase + *(const SHORT*)&info[0];
-        unsigned char *saved_memory = pStubMsg->Memory;
+    /* conformance */
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
+    /* variance */
+    pFormat = SkipConformance(pStubMsg, pFormat);
 
-        pStubMsg->Memory = pMemory;
-        PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4);
-        pStubMsg->Memory = saved_memory;
-      }
-    }
-    pFormat += 8 * count;
+    WriteVariance(pStubMsg);
+
+    ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment);
+
+    size = safe_multiply(esize, pStubMsg->ActualCount);
+
+    if (fHasPointers)
+      pStubMsg->BufferMark = pStubMsg->Buffer;
+    safe_copy_to_buffer(pStubMsg, pMemory + pStubMsg->Offset, size);
+
+    if (fHasPointers)
+      EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+      esize = 1;
+    else
+      esize = 2;
+
+    WriteVariance(pStubMsg);
+
+    size = safe_multiply(esize, pStubMsg->ActualCount);
+    safe_copy_to_buffer(pStubMsg, pMemory, size); /* the string itself */
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
+}
 
-  if (saved_buffer_length)
+static inline ULONG array_read_conformance(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat)
+{
+  DWORD esize;
+
+  switch (fc)
   {
-    pStubMsg->PointerLength = pStubMsg->BufferLength;
-    pStubMsg->BufferLength = saved_buffer_length;
+  case RPC_FC_CARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    pFormat = ReadConformance(pStubMsg, pFormat+4);
+    return safe_multiply(esize, pStubMsg->MaxCount);
+  case RPC_FC_CVARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    pFormat = ReadConformance(pStubMsg, pFormat+4);
+    return safe_multiply(esize, pStubMsg->MaxCount);
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+      esize = 1;
+    else
+      esize = 2;
+
+    if (pFormat[1] == RPC_FC_STRING_SIZED)
+      ReadConformance(pStubMsg, pFormat + 2);
+    else
+      ReadConformance(pStubMsg, NULL);
+    return safe_multiply(esize, pStubMsg->MaxCount);
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
 }
 
-/***********************************************************************
- *           EmbeddedPointerMemorySize [internal]
- */
-static unsigned long EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                               PFORMAT_STRING pFormat)
+static inline ULONG array_read_variance_and_unmarshall(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory,
+    PFORMAT_STRING pFormat, unsigned char fMustAlloc,
+    unsigned char fUseBufferMemoryServer, unsigned char fUnmarshall)
 {
-  unsigned char *Mark = pStubMsg->BufferMark;
-  unsigned rep, count, stride;
-  unsigned i;
-  unsigned char *saved_buffer = NULL;
+  ULONG bufsize, memsize;
+  WORD esize;
+  unsigned char alignment;
+  unsigned char *saved_buffer;
+  ULONG offset;
+
+  switch (fc)
+  {
+  case RPC_FC_CARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
+
+    bufsize = memsize = safe_multiply(esize, pStubMsg->MaxCount);
+
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
+
+    ALIGN_POINTER(pStubMsg->Buffer, alignment);
+
+    if (fUnmarshall)
+    {
+      if (fMustAlloc)
+        *ppMemory = NdrAllocate(pStubMsg, memsize);
+      else
+      {
+        if (fUseBufferMemoryServer && !pStubMsg->IsClient && !*ppMemory)
+          /* for servers, we just point straight into the RPC buffer */
+          *ppMemory = pStubMsg->Buffer;
+      }
+
+      saved_buffer = pStubMsg->Buffer;
+      safe_buffer_increment(pStubMsg, bufsize);
+
+      pStubMsg->BufferMark = saved_buffer;
+      EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc);
+
+      TRACE("copying %p to %p\n", saved_buffer, *ppMemory);
+      if (*ppMemory != saved_buffer)
+        memcpy(*ppMemory, saved_buffer, bufsize);
+    }
+    return bufsize;
+  case RPC_FC_CVARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  TRACE("(%p,%p)\n", pStubMsg, pFormat);
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
 
-  if (pStubMsg->IgnoreEmbeddedPointers) return 0;
+    pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount);
 
-  if (pStubMsg->PointerBufferMark)
-  {
-    saved_buffer = pStubMsg->Buffer;
-    pStubMsg->Buffer = pStubMsg->PointerBufferMark;
-    pStubMsg->PointerBufferMark = NULL;
-  }
+    ALIGN_POINTER(pStubMsg->Buffer, alignment);
 
-  if (*pFormat != RPC_FC_PP) return 0;
-  pFormat += 2;
+    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+    memsize = safe_multiply(esize, pStubMsg->MaxCount);
 
-  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;
-      count = 1;
-      pFormat += 2;
-      break;
-    case RPC_FC_FIXED_REPEAT:
-      rep = *(const WORD*)&pFormat[2];
-      stride = *(const WORD*)&pFormat[4];
-      count = *(const WORD*)&pFormat[8];
-      pFormat += 10;
-      break;
-    case RPC_FC_VARIABLE_REPEAT:
-      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
-      stride = *(const WORD*)&pFormat[2];
-      count = *(const WORD*)&pFormat[6];
-      pFormat += 8;
-      break;
-    }
-    for (i = 0; i < rep; i++) {
-      PFORMAT_STRING info = pFormat;
-      unsigned char *bufbase = Mark + (i * stride);
-      unsigned u;
-      for (u=0; u<count; u++,info+=8) {
-        unsigned char *bufptr = bufbase + *(const SHORT*)&info[2];
-        PointerMemorySize(pStubMsg, bufptr, info+4);
-      }
-    }
-    pFormat += 8 * count;
-  }
+    if (fUnmarshall)
+    {
+      offset = pStubMsg->Offset;
 
-  if (saved_buffer)
-  {
-    pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-    pStubMsg->Buffer = saved_buffer;
-  }
+      if (!fMustAlloc && !*ppMemory)
+        fMustAlloc = TRUE;
+      if (fMustAlloc)
+        *ppMemory = NdrAllocate(pStubMsg, memsize);
+      saved_buffer = pStubMsg->Buffer;
+      safe_buffer_increment(pStubMsg, bufsize);
 
-  return 0;
-}
+      pStubMsg->BufferMark = saved_buffer;
+      EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat,
+                                fMustAlloc);
 
-/***********************************************************************
- *           EmbeddedPointerFree [internal]
- */
-static void EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg,
-                                unsigned char *pMemory,
-                                PFORMAT_STRING pFormat)
-{
-  unsigned rep, count, stride;
-  unsigned i;
+      memcpy(*ppMemory + offset, saved_buffer, bufsize);
+    }
+    return bufsize;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+      esize = 1;
+    else
+      esize = 2;
 
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
-  if (*pFormat != RPC_FC_PP) return;
-  pFormat += 2;
+    ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount);
 
-  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;
-      count = 1;
-      pFormat += 2;
-      break;
-    case RPC_FC_FIXED_REPEAT:
-      rep = *(const WORD*)&pFormat[2];
-      stride = *(const WORD*)&pFormat[4];
-      count = *(const WORD*)&pFormat[8];
-      pFormat += 10;
-      break;
-    case RPC_FC_VARIABLE_REPEAT:
-      rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount;
-      stride = *(const WORD*)&pFormat[2];
-      count = *(const WORD*)&pFormat[6];
-      pFormat += 8;
-      break;
+    if (pFormat[1] != RPC_FC_STRING_SIZED && (pStubMsg->MaxCount != pStubMsg->ActualCount))
+    {
+      ERR("buffer size %d must equal memory size %ld for non-sized conformant strings\n",
+          pStubMsg->ActualCount, pStubMsg->MaxCount);
+      RpcRaiseException(RPC_S_INVALID_BOUND);
+    }
+    if (pStubMsg->Offset)
+    {
+      ERR("conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
+      RpcRaiseException(RPC_S_INVALID_BOUND);
     }
-    for (i = 0; i < rep; i++) {
-      PFORMAT_STRING info = pFormat;
-      unsigned char *membase = pMemory + (i * stride);
-      unsigned u;
 
-      for (u=0; u<count; u++,info+=8) {
-        unsigned char *memptr = membase + *(const SHORT*)&info[0];
-        unsigned char *saved_memory = pStubMsg->Memory;
+    memsize = safe_multiply(esize, pStubMsg->MaxCount);
+    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
 
-        pStubMsg->Memory = pMemory;
-        PointerFree(pStubMsg, *(unsigned char**)memptr, info+4);
-        pStubMsg->Memory = saved_memory;
+    validate_string_data(pStubMsg, bufsize, esize);
+
+    if (fUnmarshall)
+    {
+      if (fMustAlloc)
+        *ppMemory = NdrAllocate(pStubMsg, memsize);
+      else
+      {
+        if (fUseBufferMemoryServer && !pStubMsg->IsClient &&
+            !*ppMemory && (pStubMsg->MaxCount == pStubMsg->ActualCount))
+          /* if the data in the RPC buffer is big enough, we just point
+           * straight into it */
+          *ppMemory = pStubMsg->Buffer;
+        else if (!*ppMemory)
+          *ppMemory = NdrAllocate(pStubMsg, memsize);
       }
+
+      if (*ppMemory == pStubMsg->Buffer)
+        safe_buffer_increment(pStubMsg, bufsize);
+      else
+        safe_copy_from_buffer(pStubMsg, *ppMemory, bufsize);
+
+      if (*pFormat == RPC_FC_C_CSTRING)
+        TRACE("string=%s\n", debugstr_a((char*)*ppMemory));
+      else
+        TRACE("string=%s\n", debugstr_w((LPWSTR)*ppMemory));
     }
-    pFormat += 8 * count;
+    return bufsize;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
 }
 
-/***********************************************************************
- *           NdrPointerMarshall [RPCRT4.@]
- */
-unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                          unsigned char *pMemory,
-                                          PFORMAT_STRING pFormat)
+static inline void array_memory_size(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
+    unsigned char fHasPointers)
 {
-  unsigned char *Buffer;
-
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+  ULONG bufsize, memsize;
+  DWORD esize;
+  unsigned char alignment;
 
-  /* incremement the buffer here instead of in PointerMarshall,
-   * as that is used by embedded pointers which already handle the incrementing
-   * the buffer, and shouldn't write any additional pointer data to the wire */
-  if (*pFormat != RPC_FC_RP)
+  switch (fc)
   {
-    ALIGN_POINTER_CLEAR(pStubMsg->Buffer, 4);
-    Buffer = pStubMsg->Buffer;
-    safe_buffer_increment(pStubMsg, 4);
-  }
-  else
-    Buffer = pStubMsg->Buffer;
+  case RPC_FC_CARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  PointerMarshall(pStubMsg, Buffer, pMemory, pFormat);
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
 
-  return NULL;
-}
+    bufsize = memsize = safe_multiply(esize, pStubMsg->MaxCount);
+    pStubMsg->MemorySize += memsize;
 
-/***********************************************************************
- *           NdrPointerUnmarshall [RPCRT4.@]
- */
-unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                            unsigned char **ppMemory,
-                                            PFORMAT_STRING pFormat,
-                                            unsigned char fMustAlloc)
-{
-  unsigned char *Buffer;
+    ALIGN_POINTER(pStubMsg->Buffer, alignment);
+    if (fHasPointers)
+      pStubMsg->BufferMark = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, bufsize);
 
-  TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
+    if (fHasPointers)
+      EmbeddedPointerMemorySize(pStubMsg, pFormat);
+    break;
+  case RPC_FC_CVARRAY:
+    esize = *(const WORD*)(pFormat+2);
+    alignment = pFormat[1] + 1;
 
-  /* incremement the buffer here instead of in PointerUnmarshall,
-   * as that is used by embedded pointers which already handle the incrementing
-   * the buffer, and shouldn't read any additional pointer data from the
-   * buffer */
-  if (*pFormat != RPC_FC_RP)
-  {
-    ALIGN_POINTER(pStubMsg->Buffer, 4);
-    Buffer = pStubMsg->Buffer;
-    safe_buffer_increment(pStubMsg, 4);
-  }
-  else
-    Buffer = pStubMsg->Buffer;
+    pFormat = SkipConformance(pStubMsg, pFormat + 4);
 
-  PointerUnmarshall(pStubMsg, Buffer, ppMemory, *ppMemory, pFormat, fMustAlloc);
+    pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount);
 
-  return NULL;
+    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+    memsize = safe_multiply(esize, pStubMsg->MaxCount);
+    pStubMsg->MemorySize += memsize;
+
+    ALIGN_POINTER(pStubMsg->Buffer, alignment);
+    if (fHasPointers)
+      pStubMsg->BufferMark = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, bufsize);
+
+    if (fHasPointers)
+      EmbeddedPointerMemorySize(pStubMsg, pFormat);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    if (fc == RPC_FC_C_CSTRING)
+      esize = 1;
+    else
+      esize = 2;
+
+    ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount);
+
+    if (pFormat[1] != RPC_FC_STRING_SIZED && (pStubMsg->MaxCount != pStubMsg->ActualCount))
+    {
+      ERR("buffer size %d must equal memory size %ld for non-sized conformant strings\n",
+          pStubMsg->ActualCount, pStubMsg->MaxCount);
+      RpcRaiseException(RPC_S_INVALID_BOUND);
+    }
+    if (pStubMsg->Offset)
+    {
+      ERR("conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
+      RpcRaiseException(RPC_S_INVALID_BOUND);
+    }
+
+    memsize = safe_multiply(esize, pStubMsg->MaxCount);
+    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+
+    validate_string_data(pStubMsg, bufsize, esize);
+
+    safe_buffer_increment(pStubMsg, bufsize);
+    pStubMsg->MemorySize += memsize;
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 }
 
-/***********************************************************************
- *           NdrPointerBufferSize [RPCRT4.@]
- */
-void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-                                      unsigned char *pMemory,
-                                      PFORMAT_STRING pFormat)
+static inline void array_free(
+    unsigned char fc, PMIDL_STUB_MESSAGE pStubMsg,
+    unsigned char *pMemory, PFORMAT_STRING pFormat, unsigned char fHasPointers)
 {
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
-
-  /* incremement the buffer length here instead of in PointerBufferSize,
-   * as that is used by embedded pointers which already handle the buffer
-   * length, and shouldn't write anything more to the wire */
-  if (*pFormat != RPC_FC_RP)
+  switch (fc)
   {
-    ALIGN_LENGTH(pStubMsg->BufferLength, 4);
-    safe_buffer_length_increment(pStubMsg, 4);
+  case RPC_FC_CARRAY:
+    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
+    if (fHasPointers)
+      EmbeddedPointerFree(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_CVARRAY:
+    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
+    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
+    if (fHasPointers)
+      EmbeddedPointerFree(pStubMsg, pMemory, pFormat);
+    break;
+  case RPC_FC_C_CSTRING:
+  case RPC_FC_C_WSTRING:
+    /* No embedded pointers so nothing to do */
+    break;
+  default:
+    ERR("unknown array format 0x%x\n", fc);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
-
-  PointerBufferSize(pStubMsg, pMemory, pFormat);
 }
 
-/***********************************************************************
- *           NdrPointerMemorySize [RPCRT4.@]
+/*
+ * 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)
+ *
  */
-ULONG 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.@]
+ *            NdrConformantStringMarshall [RPCRT4.@]
  */
-void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg,
-                           unsigned char *pMemory,
-                           PFORMAT_STRING pFormat)
+unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg,
+  unsigned char *pszMessage, PFORMAT_STRING pFormat)
 {
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
-  PointerFree(pStubMsg, pMemory, pFormat);
+  TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat);
+
+  if (pFormat[0] != RPC_FC_C_CSTRING && pFormat[0] != RPC_FC_C_WSTRING) {
+    ERR("Unhandled string type: %#x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  /* allow compiler to optimise inline function by passing constant into
+   * these functions */
+  if (pFormat[0] == RPC_FC_C_CSTRING) {
+    array_compute_and_write_conformance(RPC_FC_C_CSTRING, pStubMsg, pszMessage,
+                                        pFormat);
+    array_write_variance_and_marshall(RPC_FC_C_CSTRING, pStubMsg, pszMessage,
+                                      pFormat, TRUE /* fHasPointers */);
+  } else {
+    array_compute_and_write_conformance(RPC_FC_C_WSTRING, pStubMsg, pszMessage,
+                                        pFormat);
+    array_write_variance_and_marshall(RPC_FC_C_WSTRING, pStubMsg, pszMessage,
+                                      pFormat, TRUE /* fHasPointers */);
+  }
+
+  return NULL;
 }
 
 /***********************************************************************
- *           NdrSimpleTypeMarshall [RPCRT4.@]
+ *           NdrConformantStringBufferSize [RPCRT4.@]
  */
-void WINAPI NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory,
-                                   unsigned char FormatChar )
+void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
+  unsigned char* pMemory, PFORMAT_STRING pFormat)
 {
-    NdrBaseTypeMarshall(pStubMsg, pMemory, &FormatChar);
+  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
+
+  if (pFormat[0] != RPC_FC_C_CSTRING && pFormat[0] != RPC_FC_C_WSTRING) {
+    ERR("Unhandled string type: %#x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  /* allow compiler to optimise inline function by passing constant into
+   * these functions */
+  if (pFormat[0] == RPC_FC_C_CSTRING) {
+    array_compute_and_size_conformance(RPC_FC_C_CSTRING, pStubMsg, pMemory,
+                                       pFormat);
+    array_buffer_size(RPC_FC_C_CSTRING, pStubMsg, pMemory, pFormat,
+                      TRUE /* fHasPointers */);
+  } else {
+    array_compute_and_size_conformance(RPC_FC_C_WSTRING, pStubMsg, pMemory,
+                                       pFormat);
+    array_buffer_size(RPC_FC_C_WSTRING, pStubMsg, pMemory, pFormat,
+                      TRUE /* fHasPointers */);
+  }
 }
 
-/***********************************************************************
- *           NdrSimpleTypeUnmarshall [RPCRT4.@]
+/************************************************************************
+ *            NdrConformantStringMemorySize [RPCRT4.@]
  */
-void WINAPI NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory,
-                                     unsigned char FormatChar )
+ULONG WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg,
+  PFORMAT_STRING pFormat )
 {
-    NdrBaseTypeUnmarshall(pStubMsg, &pMemory, &FormatChar, 0);
+  TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat);
+
+  if (pFormat[0] != RPC_FC_C_CSTRING && pFormat[0] != RPC_FC_C_WSTRING) {
+    ERR("Unhandled string type: %#x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  /* allow compiler to optimise inline function by passing constant into
+   * these functions */
+  if (pFormat[0] == RPC_FC_C_CSTRING) {
+    array_read_conformance(RPC_FC_C_CSTRING, pStubMsg, pFormat);
+    array_memory_size(RPC_FC_C_CSTRING, pStubMsg, pFormat,
+                      TRUE /* fHasPointers */);
+  } else {
+    array_read_conformance(RPC_FC_C_WSTRING, pStubMsg, pFormat);
+    array_memory_size(RPC_FC_C_WSTRING, pStubMsg, pFormat,
+                      TRUE /* fHasPointers */);
+  }
+
+  return pStubMsg->MemorySize;
 }
 
-/***********************************************************************
- *           NdrSimpleStructMarshall [RPCRT4.@]
+/************************************************************************
+ *           NdrConformantStringUnmarshall [RPCRT4.@]
  */
-unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                               unsigned char *pMemory,
-                                               PFORMAT_STRING pFormat)
+unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg,
+  unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc )
 {
-  unsigned size = *(const WORD*)(pFormat+2);
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
-
-  ALIGN_POINTER_CLEAR(pStubMsg->Buffer, pFormat[1] + 1);
+  TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n",
+    pStubMsg, *ppMemory, pFormat, fMustAlloc);
 
-  pStubMsg->BufferMark = pStubMsg->Buffer;
-  safe_copy_to_buffer(pStubMsg, pMemory, size);
+  if (pFormat[0] != RPC_FC_C_CSTRING && pFormat[0] != RPC_FC_C_WSTRING) {
+    ERR("Unhandled string type: %#x\n", *pFormat);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 
-  if (pFormat[0] != RPC_FC_STRUCT)
-    EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4);
+  /* allow compiler to optimise inline function by passing constant into
+   * these functions */
+  if (pFormat[0] == RPC_FC_C_CSTRING) {
+    array_read_conformance(RPC_FC_C_CSTRING, pStubMsg, pFormat);
+    array_read_variance_and_unmarshall(RPC_FC_C_CSTRING, pStubMsg, ppMemory,
+                                       pFormat, fMustAlloc,
+                                       TRUE /* fUseBufferMemoryServer */,
+                                       TRUE /* fUnmarshall */);
+  } else {
+    array_read_conformance(RPC_FC_C_WSTRING, pStubMsg, pFormat);
+    array_read_variance_and_unmarshall(RPC_FC_C_WSTRING, pStubMsg, ppMemory,
+                                       pFormat, fMustAlloc,
+                                       TRUE /* fUseBufferMemoryServer */,
+                                       TRUE /* fUnmarshall */);
+  }
 
   return NULL;
 }
 
 /***********************************************************************
- *           NdrSimpleStructUnmarshall [RPCRT4.@]
+ *           NdrNonConformantStringMarshall [RPCRT4.@]
  */
-unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
-                                                 unsigned char **ppMemory,
-                                                 PFORMAT_STRING pFormat,
-                                                 unsigned char fMustAlloc)
+unsigned char *  WINAPI NdrNonConformantStringMarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                unsigned char *pMemory,
+                                PFORMAT_STRING pFormat)
 {
-  unsigned size = *(const WORD*)(pFormat+2);
-  unsigned char *saved_buffer;
-  TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
+  ULONG esize, size, maxsize;
 
-  ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
+  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
 
-  if (fMustAlloc)
-    *ppMemory = NdrAllocate(pStubMsg, size);
+  maxsize = *(USHORT *)&pFormat[2];
+
+  if (*pFormat == RPC_FC_CSTRING)
+  {
+    ULONG i;
+    const char *str = (const char *)pMemory;
+    for (i = 0; i < maxsize && *str; i++, str++)
+        ;
+    TRACE("string=%s\n", debugstr_an(str, i));
+    pStubMsg->ActualCount = i + 1;
+    esize = 1;
+  }
+  else if (*pFormat == RPC_FC_WSTRING)
+  {
+    ULONG i;
+    const WCHAR *str = (const WCHAR *)pMemory;
+    for (i = 0; i < maxsize && *str; i++, str++)
+        ;
+    TRACE("string=%s\n", debugstr_wn(str, i));
+    pStubMsg->ActualCount = i + 1;
+    esize = 2;
+  }
   else
   {
-    if (!pStubMsg->IsClient && !*ppMemory)
-      /* for servers, we just point straight into the RPC buffer */
-      *ppMemory = pStubMsg->Buffer;
+    ERR("Unhandled string type: %#x\n", *pFormat);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
 
-  saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
-  safe_buffer_increment(pStubMsg, size);
-  if (pFormat[0] == RPC_FC_PSTRUCT)
-      EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat+4, fMustAlloc);
+  pStubMsg->Offset = 0;
+  WriteVariance(pStubMsg);
 
-  TRACE("copying %p to %p\n", saved_buffer, *ppMemory);
-  if (*ppMemory != saved_buffer)
-      memcpy(*ppMemory, saved_buffer, size);
+  size = safe_multiply(esize, pStubMsg->ActualCount);
+  safe_copy_to_buffer(pStubMsg, pMemory, size); /* the string itself */
 
   return NULL;
 }
 
 /***********************************************************************
- *           NdrSimpleStructBufferSize [RPCRT4.@]
+ *           NdrNonConformantStringUnmarshall [RPCRT4.@]
  */
-void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
-                                      unsigned char *pMemory,
-                                      PFORMAT_STRING pFormat)
+unsigned char *  WINAPI NdrNonConformantStringUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
+                                unsigned char **ppMemory,
+                                PFORMAT_STRING pFormat,
+                                unsigned char fMustAlloc)
 {
-  unsigned size = *(const WORD*)(pFormat+2);
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
+  ULONG bufsize, memsize, esize, maxsize;
 
-  ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1);
+  TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n",
+    pStubMsg, *ppMemory, pFormat, fMustAlloc);
 
-  safe_buffer_length_increment(pStubMsg, size);
-  if (pFormat[0] != RPC_FC_STRUCT)
-    EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4);
+  maxsize = *(USHORT *)&pFormat[2];
+
+  ReadVariance(pStubMsg, NULL, maxsize);
+  if (pStubMsg->Offset)
+  {
+    ERR("non-conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
+    RpcRaiseException(RPC_S_INVALID_BOUND);
+  }
+
+  if (*pFormat == RPC_FC_CSTRING) esize = 1;
+  else if (*pFormat == RPC_FC_WSTRING) esize = 2;
+  else
+  {
+    ERR("Unhandled string type: %#x\n", *pFormat);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  memsize = esize * maxsize;
+  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+
+  validate_string_data(pStubMsg, bufsize, esize);
+
+  if (!fMustAlloc && !*ppMemory)
+    fMustAlloc = TRUE;
+  if (fMustAlloc)
+    *ppMemory = NdrAllocate(pStubMsg, memsize);
+
+  safe_copy_from_buffer(pStubMsg, *ppMemory, bufsize);
+
+  if (*pFormat == RPC_FC_CSTRING) {
+    TRACE("string=%s\n", debugstr_an((char*)*ppMemory, pStubMsg->ActualCount));
+  }
+  else if (*pFormat == RPC_FC_WSTRING) {
+    TRACE("string=%s\n", debugstr_wn((LPWSTR)*ppMemory, pStubMsg->ActualCount));
+  }
+
+  return NULL;
 }
 
 /***********************************************************************
- *           NdrSimpleStructMemorySize [RPCRT4.@]
+ *           NdrNonConformantStringBufferSize [RPCRT4.@]
  */
-ULONG WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                       PFORMAT_STRING pFormat)
+void WINAPI NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
+                                unsigned char *pMemory,
+                                PFORMAT_STRING pFormat)
 {
-  unsigned short size = *(const WORD *)(pFormat+2);
+  ULONG esize, maxsize;
 
-  TRACE("(%p,%p)\n", pStubMsg, pFormat);
+  TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat);
 
-  ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
-  pStubMsg->MemorySize += size;
-  safe_buffer_increment(pStubMsg, size);
+  maxsize = *(USHORT *)&pFormat[2];
 
-  if (pFormat[0] != RPC_FC_STRUCT)
-    EmbeddedPointerMemorySize(pStubMsg, pFormat+4);
-  return pStubMsg->MemorySize;
+  SizeVariance(pStubMsg);
+
+  if (*pFormat == RPC_FC_CSTRING)
+  {
+    ULONG i;
+    const char *str = (const char *)pMemory;
+    for (i = 0; i < maxsize && *str; i++, str++)
+        ;
+    TRACE("string=%s\n", debugstr_an(str, i));
+    pStubMsg->ActualCount = i + 1;
+    esize = 1;
+  }
+  else if (*pFormat == RPC_FC_WSTRING)
+  {
+    ULONG i;
+    const WCHAR *str = (const WCHAR *)pMemory;
+    for (i = 0; i < maxsize && *str; i++, str++)
+        ;
+    TRACE("string=%s\n", debugstr_wn(str, i));
+    pStubMsg->ActualCount = i + 1;
+    esize = 2;
+  }
+  else
+  {
+    ERR("Unhandled string type: %#x\n", *pFormat);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  safe_buffer_length_increment(pStubMsg, safe_multiply(esize, pStubMsg->ActualCount));
 }
 
 /***********************************************************************
- *           NdrSimpleStructFree [RPCRT4.@]
+ *           NdrNonConformantStringMemorySize [RPCRT4.@]
  */
-void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg,
-                                unsigned char *pMemory,
+ULONG WINAPI NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
                                 PFORMAT_STRING pFormat)
 {
-  TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
-  if (pFormat[0] != RPC_FC_STRUCT)
-    EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4);
+  ULONG bufsize, memsize, esize, maxsize;
+
+  TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat);
+
+  maxsize = *(USHORT *)&pFormat[2];
+
+  ReadVariance(pStubMsg, NULL, maxsize);
+
+  if (pStubMsg->Offset)
+  {
+    ERR("non-conformant strings can't have Offset (%d)\n", pStubMsg->Offset);
+    RpcRaiseException(RPC_S_INVALID_BOUND);
+  }
+
+  if (*pFormat == RPC_FC_CSTRING) esize = 1;
+  else if (*pFormat == RPC_FC_WSTRING) esize = 2;
+  else
+  {
+    ERR("Unhandled string type: %#x\n", *pFormat);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
+
+  memsize = esize * maxsize;
+  bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+
+  validate_string_data(pStubMsg, bufsize, esize);
+
+  safe_buffer_increment(pStubMsg, bufsize);
+  pStubMsg->MemorySize += memsize;
+
+  return pStubMsg->MemorySize;
 }
 
+/* Complex types */
+
+#include "pshpack1.h"
+typedef struct
+{
+    unsigned char type;
+    unsigned char flags_type; /* flags in upper nibble, type in lower nibble */
+    ULONG low_value;
+    ULONG high_value;
+} NDR_RANGE;
+#include "poppack.h"
 
-static unsigned long EmbeddedComplexSize(const MIDL_STUB_MESSAGE *pStubMsg,
-                                         PFORMAT_STRING pFormat)
+static ULONG EmbeddedComplexSize(MIDL_STUB_MESSAGE *pStubMsg,
+                                 PFORMAT_STRING pFormat)
 {
   switch (*pFormat) {
   case RPC_FC_STRUCT:
@@ -2131,6 +2593,34 @@ static unsigned long EmbeddedComplexSize(const MIDL_STUB_MESSAGE *pStubMsg,
     return *(const WORD*)&pFormat[2];
   case RPC_FC_USER_MARSHAL:
     return *(const WORD*)&pFormat[4];
+  case RPC_FC_RANGE: {
+    switch (((const NDR_RANGE *)pFormat)->flags_type & 0xf) {
+    case RPC_FC_BYTE:
+    case RPC_FC_CHAR:
+    case RPC_FC_SMALL:
+    case RPC_FC_USMALL:
+        return sizeof(UCHAR);
+    case RPC_FC_WCHAR:
+    case RPC_FC_SHORT:
+    case RPC_FC_USHORT:
+        return sizeof(USHORT);
+    case RPC_FC_LONG:
+    case RPC_FC_ULONG:
+    case RPC_FC_ENUM32:
+        return sizeof(ULONG);
+    case RPC_FC_FLOAT:
+        return sizeof(float);
+    case RPC_FC_DOUBLE:
+        return sizeof(double);
+    case RPC_FC_HYPER:
+        return sizeof(ULONGLONG);
+    case RPC_FC_ENUM16:
+        return sizeof(UINT);
+    default:
+        ERR("unknown type 0x%x\n", ((const NDR_RANGE *)pFormat)->flags_type & 0xf);
+        RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    }
+  }
   case RPC_FC_NON_ENCAPSULATED_UNION:
     pFormat += 2;
     if (pStubMsg->fHasNewCorrDesc)
@@ -2151,8 +2641,8 @@ static unsigned long EmbeddedComplexSize(const MIDL_STUB_MESSAGE *pStubMsg,
 }
 
 
-static unsigned long EmbeddedComplexMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                               PFORMAT_STRING pFormat)
+static ULONG EmbeddedComplexMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                       PFORMAT_STRING pFormat)
 {
   NDR_MEMORYSIZE m = NdrMemorySizer[*pFormat & NDR_TABLE_MASK];
 
@@ -2173,7 +2663,7 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
 {
   PFORMAT_STRING desc;
   NDR_MARSHALL m;
-  unsigned long size;
+  ULONG size;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2192,6 +2682,13 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
       safe_copy_to_buffer(pStubMsg, pMemory, 2);
       pMemory += 2;
       break;
+    case RPC_FC_ENUM16:
+      TRACE("enum16=%d <= %p\n", *(DWORD*)pMemory, pMemory);
+      if (32767 < *(DWORD*)pMemory)
+        RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE);
+      safe_copy_to_buffer(pStubMsg, pMemory, 2);
+      pMemory += 4;
+      break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
     case RPC_FC_ENUM32:
@@ -2199,17 +2696,35 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
       safe_copy_to_buffer(pStubMsg, pMemory, 4);
       pMemory += 4;
       break;
+    case RPC_FC_FLOAT:
+      TRACE("float=%f <= %p\n", *(float*)pMemory, pMemory);
+      safe_copy_to_buffer(pStubMsg, pMemory, sizeof(float));
+      pMemory += sizeof(float);
+      break;
     case RPC_FC_HYPER:
       TRACE("longlong=%s <= %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory);
       safe_copy_to_buffer(pStubMsg, pMemory, 8);
       pMemory += 8;
       break;
+    case RPC_FC_DOUBLE:
+      TRACE("double=%f <= %p\n", *(double*)pMemory, pMemory);
+      safe_copy_to_buffer(pStubMsg, pMemory, sizeof(double));
+      pMemory += sizeof(double);
+      break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
     {
       unsigned char *saved_buffer;
       int pointer_buffer_mark_set = 0;
       TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory);
-      ALIGN_POINTER_CLEAR(pStubMsg->Buffer, 4);
+      TRACE("pStubMsg->Buffer before %p\n", pStubMsg->Buffer);
+      if (*pFormat != RPC_FC_POINTER)
+        pPointer = pFormat;
+      if (*pPointer != RPC_FC_RP)
+        ALIGN_POINTER_CLEAR(pStubMsg->Buffer, 4);
       saved_buffer = pStubMsg->Buffer;
       if (pStubMsg->PointerBufferMark)
       {
@@ -2217,25 +2732,28 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
         pStubMsg->PointerBufferMark = NULL;
         pointer_buffer_mark_set = 1;
       }
-      else
+      else if (*pPointer != RPC_FC_RP)
         safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
       PointerMarshall(pStubMsg, saved_buffer, *(unsigned char**)pMemory, pPointer);
       if (pointer_buffer_mark_set)
       {
         STD_OVERFLOW_CHECK(pStubMsg);
         pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-        if (saved_buffer + 4 > (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength)
-        {
-            ERR("buffer overflow - saved_buffer = %p, BufferEnd = %p\n",
-                saved_buffer, (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength);
-            RpcRaiseException(RPC_X_BAD_STUB_DATA);
-        }
-        pStubMsg->Buffer = saved_buffer + 4;
+        pStubMsg->Buffer = saved_buffer;
+        if (*pPointer != RPC_FC_RP)
+          safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
       }
-      pPointer += 4;
-      pMemory += 4;
+      TRACE("pStubMsg->Buffer after %p\n", pStubMsg->Buffer);
+      if (*pFormat == RPC_FC_POINTER)
+        pPointer += 4;
+      else
+        pFormat += 4;
+      pMemory += sizeof(void *);
       break;
     }
+    case RPC_FC_ALIGNM2:
+      ALIGN_POINTER(pMemory, 2);
+      break;
     case RPC_FC_ALIGNM4:
       ALIGN_POINTER(pMemory, 4);
       break;
@@ -2256,7 +2774,7 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
       pFormat += 2;
       desc = pFormat + *(const SHORT*)pFormat;
       size = EmbeddedComplexSize(pStubMsg, desc);
-      TRACE("embedded complex (size=%ld) <= %p\n", size, pMemory);
+      TRACE("embedded complex (size=%d) <= %p\n", size, pMemory);
       m = NdrMarshaller[*desc & NDR_TABLE_MASK];
       if (m)
       {
@@ -2287,11 +2805,12 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg,
 static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                          unsigned char *pMemory,
                                          PFORMAT_STRING pFormat,
-                                         PFORMAT_STRING pPointer)
+                                         PFORMAT_STRING pPointer,
+                                         unsigned char fMustAlloc)
 {
   PFORMAT_STRING desc;
   NDR_UNMARSHALL m;
-  unsigned long size;
+  ULONG size;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2310,6 +2829,14 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
       TRACE("short=%d => %p\n", *(WORD*)pMemory, pMemory);
       pMemory += 2;
       break;
+    case RPC_FC_ENUM16:
+      safe_copy_from_buffer(pStubMsg, pMemory, 2);
+      *(DWORD*)pMemory &= 0xffff;
+      TRACE("enum16=%d => %p\n", *(DWORD*)pMemory, pMemory);
+      if (32767 < *(DWORD*)pMemory)
+        RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE);
+      pMemory += 4;
+      break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
     case RPC_FC_ENUM32:
@@ -2317,17 +2844,34 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
       TRACE("long=%d => %p\n", *(DWORD*)pMemory, pMemory);
       pMemory += 4;
       break;
+    case RPC_FC_FLOAT:
+      safe_copy_from_buffer(pStubMsg, pMemory, sizeof(float));
+      TRACE("float=%f => %p\n", *(float*)pMemory, pMemory);
+      pMemory += sizeof(float);
+      break;
     case RPC_FC_HYPER:
       safe_copy_from_buffer(pStubMsg, pMemory, 8);
       TRACE("longlong=%s => %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory);
       pMemory += 8;
       break;
+    case RPC_FC_DOUBLE:
+      safe_copy_from_buffer(pStubMsg, pMemory, sizeof(double));
+      TRACE("double=%f => %p\n", *(double*)pMemory, pMemory);
+      pMemory += sizeof(double);
+      break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
     {
       unsigned char *saved_buffer;
       int pointer_buffer_mark_set = 0;
       TRACE("pointer => %p\n", pMemory);
-      ALIGN_POINTER(pStubMsg->Buffer, 4);
+      if (*pFormat != RPC_FC_POINTER)
+        pPointer = pFormat;
+      if (*pPointer != RPC_FC_RP)
+        ALIGN_POINTER(pStubMsg->Buffer, 4);
       saved_buffer = pStubMsg->Buffer;
       if (pStubMsg->PointerBufferMark)
       {
@@ -2335,26 +2879,28 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
         pStubMsg->PointerBufferMark = NULL;
         pointer_buffer_mark_set = 1;
       }
-      else
+      else if (*pPointer != RPC_FC_RP)
         safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
 
-      PointerUnmarshall(pStubMsg, saved_buffer, (unsigned char**)pMemory, *(unsigned char**)pMemory, pPointer, TRUE);
+      PointerUnmarshall(pStubMsg, saved_buffer, (unsigned char**)pMemory, *(unsigned char**)pMemory, pPointer, fMustAlloc);
       if (pointer_buffer_mark_set)
       {
         STD_OVERFLOW_CHECK(pStubMsg);
         pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-        if (saved_buffer + 4 > (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength)
-        {
-            ERR("buffer overflow - saved_buffer = %p, BufferEnd = %p\n",
-                saved_buffer, (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength);
-            RpcRaiseException(RPC_X_BAD_STUB_DATA);
-        }
-        pStubMsg->Buffer = saved_buffer + 4;
+        pStubMsg->Buffer = saved_buffer;
+        if (*pPointer != RPC_FC_RP)
+          safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
       }
-      pPointer += 4;
-      pMemory += 4;
+      if (*pFormat == RPC_FC_POINTER)
+        pPointer += 4;
+      else
+        pFormat += 4;
+      pMemory += sizeof(void *);
       break;
     }
+    case RPC_FC_ALIGNM2:
+      ALIGN_POINTER_CLEAR(pMemory, 2);
+      break;
     case RPC_FC_ALIGNM4:
       ALIGN_POINTER_CLEAR(pMemory, 4);
       break;
@@ -2376,9 +2922,15 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
       pFormat += 2;
       desc = pFormat + *(const SHORT*)pFormat;
       size = EmbeddedComplexSize(pStubMsg, desc);
-      TRACE("embedded complex (size=%ld) => %p\n", size, pMemory);
+      TRACE("embedded complex (size=%d) => %p\n", size, pMemory);
+      if (fMustAlloc)
+        /* we can't pass fMustAlloc=TRUE into the marshaller for this type
+         * since the type is part of the memory block that is encompassed by
+         * the whole complex type. Memory is forced to allocate when pointers
+         * are set to NULL, so we emulate that part of fMustAlloc=TRUE by
+         * clearing the memory we pass in to the unmarshaller */
+        memset(pMemory, 0, size);
       m = NdrUnmarshaller[*desc & NDR_TABLE_MASK];
-      memset(pMemory, 0, size); /* just in case */
       if (m)
       {
         /* for some reason interface pointers aren't generated as
@@ -2412,7 +2964,7 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
 {
   PFORMAT_STRING desc;
   NDR_BUFFERSIZE m;
-  unsigned long size;
+  ULONG size;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2429,17 +2981,29 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
       safe_buffer_length_increment(pStubMsg, 2);
       pMemory += 2;
       break;
+    case RPC_FC_ENUM16:
+      safe_buffer_length_increment(pStubMsg, 2);
+      pMemory += 4;
+      break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
     case RPC_FC_ENUM32:
+    case RPC_FC_FLOAT:
       safe_buffer_length_increment(pStubMsg, 4);
       pMemory += 4;
       break;
     case RPC_FC_HYPER:
+    case RPC_FC_DOUBLE:
       safe_buffer_length_increment(pStubMsg, 8);
       pMemory += 8;
       break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
+      if (*pFormat != RPC_FC_POINTER)
+        pPointer = pFormat;
       if (!pStubMsg->IgnoreEmbeddedPointers)
       {
         int saved_buffer_length = pStubMsg->BufferLength;
@@ -2451,9 +3015,19 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
         pStubMsg->PointerLength = pStubMsg->BufferLength;
         pStubMsg->BufferLength = saved_buffer_length;
       }
-      safe_buffer_length_increment(pStubMsg, 4);
-      pPointer += 4;
-      pMemory += 4;
+      if (*pPointer != RPC_FC_RP)
+      {
+        ALIGN_LENGTH(pStubMsg->BufferLength, 4);
+        safe_buffer_length_increment(pStubMsg, 4);
+      }
+      if (*pFormat == RPC_FC_POINTER)
+        pPointer += 4;
+      else
+        pFormat += 4;
+      pMemory += sizeof(void*);
+      break;
+    case RPC_FC_ALIGNM2:
+      ALIGN_POINTER(pMemory, 2);
       break;
     case RPC_FC_ALIGNM4:
       ALIGN_POINTER(pMemory, 4);
@@ -2509,7 +3083,7 @@ static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg,
 {
   PFORMAT_STRING desc;
   NDR_FREE m;
-  unsigned long size;
+  ULONG size;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2526,16 +3100,31 @@ static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg,
       break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
+    case RPC_FC_ENUM16:
     case RPC_FC_ENUM32:
+    case RPC_FC_FLOAT:
       pMemory += 4;
       break;
     case RPC_FC_HYPER:
+    case RPC_FC_DOUBLE:
       pMemory += 8;
       break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
+      if (*pFormat != RPC_FC_POINTER)
+        pPointer = pFormat;
       NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer);
-      pPointer += 4;
-      pMemory += 4;
+      if (*pFormat == RPC_FC_POINTER)
+        pPointer += 4;
+      else
+        pFormat += 4;
+      pMemory += sizeof(void *);
+      break;
+    case RPC_FC_ALIGNM2:
+      ALIGN_POINTER(pMemory, 2);
       break;
     case RPC_FC_ALIGNM4:
       ALIGN_POINTER(pMemory, 4);
@@ -2583,11 +3172,12 @@ static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg,
   return pMemory;
 }
 
-static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                       PFORMAT_STRING pFormat)
+static ULONG ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                     PFORMAT_STRING pFormat,
+                                     PFORMAT_STRING pPointer)
 {
   PFORMAT_STRING desc;
-  unsigned long size = 0;
+  ULONG size = 0;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2604,29 +3194,69 @@ static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
       size += 2;
       safe_buffer_increment(pStubMsg, 2);
       break;
+    case RPC_FC_ENUM16:
+      size += 4;
+      safe_buffer_increment(pStubMsg, 2);
+      break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
     case RPC_FC_ENUM32:
+    case RPC_FC_FLOAT:
       size += 4;
       safe_buffer_increment(pStubMsg, 4);
       break;
     case RPC_FC_HYPER:
+    case RPC_FC_DOUBLE:
       size += 8;
       safe_buffer_increment(pStubMsg, 8);
       break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
-      size += 4;
-      safe_buffer_increment(pStubMsg, 4);
+    {
+      unsigned char *saved_buffer;
+      int pointer_buffer_mark_set = 0;
+      if (*pFormat != RPC_FC_POINTER)
+        pPointer = pFormat;
+      if (*pPointer != RPC_FC_RP)
+        ALIGN_POINTER(pStubMsg->Buffer, 4);
+      saved_buffer = pStubMsg->Buffer;
+      if (pStubMsg->PointerBufferMark)
+      {
+        pStubMsg->Buffer = pStubMsg->PointerBufferMark;
+        pStubMsg->PointerBufferMark = NULL;
+        pointer_buffer_mark_set = 1;
+      }
+      else if (*pPointer != RPC_FC_RP)
+        safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
+
       if (!pStubMsg->IgnoreEmbeddedPointers)
-        FIXME("embedded pointers\n");
+        PointerMemorySize(pStubMsg, saved_buffer, pPointer);
+      if (pointer_buffer_mark_set)
+      {
+        STD_OVERFLOW_CHECK(pStubMsg);
+        pStubMsg->PointerBufferMark = pStubMsg->Buffer;
+        pStubMsg->Buffer = saved_buffer;
+        if (*pPointer != RPC_FC_RP)
+          safe_buffer_increment(pStubMsg, 4); /* for pointer ID */
+      }
+      if (*pFormat == RPC_FC_POINTER)
+        pPointer += 4;
+      else
+        pFormat += 4;
+      size += sizeof(void *);
+      break;
+    }
+    case RPC_FC_ALIGNM2:
+      ALIGN_LENGTH(size, 2);
       break;
     case RPC_FC_ALIGNM4:
       ALIGN_LENGTH(size, 4);
-      ALIGN_POINTER(pStubMsg->Buffer, 4);
       break;
     case RPC_FC_ALIGNM8:
       ALIGN_LENGTH(size, 8);
-      ALIGN_POINTER(pStubMsg->Buffer, 8);
       break;
     case RPC_FC_STRUCTPAD1:
     case RPC_FC_STRUCTPAD2:
@@ -2655,11 +3285,10 @@ static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
   return size;
 }
 
-unsigned long ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg,
-                                PFORMAT_STRING pFormat)
+ULONG ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat)
 {
   PFORMAT_STRING desc;
-  unsigned long size = 0;
+  ULONG size = 0;
 
   while (*pFormat != RPC_FC_END) {
     switch (*pFormat) {
@@ -2676,14 +3305,26 @@ unsigned long ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg,
       break;
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
+    case RPC_FC_ENUM16:
     case RPC_FC_ENUM32:
+    case RPC_FC_FLOAT:
       size += 4;
       break;
     case RPC_FC_HYPER:
+    case RPC_FC_DOUBLE:
       size += 8;
       break;
+    case RPC_FC_RP:
+    case RPC_FC_UP:
+    case RPC_FC_OP:
+    case RPC_FC_FP:
     case RPC_FC_POINTER:
       size += sizeof(void *);
+      if (*pFormat != RPC_FC_POINTER)
+        pFormat += 4;
+      break;
+    case RPC_FC_ALIGNM2:
+      ALIGN_LENGTH(size, 2);
       break;
     case RPC_FC_ALIGNM4:
       ALIGN_LENGTH(size, 4);
@@ -2729,6 +3370,9 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg,
   PFORMAT_STRING pointer_desc = NULL;
   unsigned char *OldMemory = pStubMsg->Memory;
   int pointer_buffer_mark_set = 0;
+  ULONG count = 0;
+  ULONG max_count = 0;
+  ULONG offset = 0;
 
   TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
@@ -2736,18 +3380,18 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg,
   {
     int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers;
     /* save buffer length */
-    unsigned long saved_buffer_length = pStubMsg->BufferLength;
+    ULONG saved_buffer_length = pStubMsg->BufferLength;
 
     /* get the buffer pointer after complex array data, but before
      * pointer data */
-    pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart;
+    pStubMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
     pStubMsg->IgnoreEmbeddedPointers = 1;
     NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat);
     pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded;
 
     /* save it for use by embedded pointer code later */
-    pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength;
-    TRACE("difference = 0x%x\n", pStubMsg->PointerBufferMark - pStubMsg->Buffer);
+    pStubMsg->PointerBufferMark = (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength;
+    TRACE("difference = 0x%x\n", (ULONG)(pStubMsg->PointerBufferMark - pStubMsg->Buffer));
     pointer_buffer_mark_set = 1;
 
     /* restore the original buffer length */
@@ -2757,17 +3401,34 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg,
   ALIGN_POINTER_CLEAR(pStubMsg->Buffer, pFormat[1] + 1);
 
   pFormat += 4;
-  if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat;
+  if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)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)
+  {
+    ULONG struct_size = ComplexStructSize(pStubMsg, pFormat);
+    array_compute_and_write_conformance(conf_array[0], pStubMsg,
+                                        pMemory + struct_size, conf_array);
+    /* these could be changed in ComplexMarshall so save them for later */
+    max_count = pStubMsg->MaxCount;
+    count = pStubMsg->ActualCount;
+    offset = pStubMsg->Offset;
+  }
+
+  pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc);
 
   if (conf_array)
-    NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array);
+  {
+    pStubMsg->MaxCount = max_count;
+    pStubMsg->ActualCount = count;
+    pStubMsg->Offset = offset;
+    array_write_variance_and_marshall(conf_array[0], pStubMsg, pMemory,
+                                      conf_array, TRUE /* fHasPointers */);
+  }
 
   pStubMsg->Memory = OldMemory;
 
@@ -2795,6 +3456,10 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
   PFORMAT_STRING pointer_desc = NULL;
   unsigned char *pMemory;
   int pointer_buffer_mark_set = 0;
+  ULONG count = 0;
+  ULONG max_count = 0;
+  ULONG offset = 0;
+  ULONG array_size = 0;
 
   TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
 
@@ -2812,7 +3477,7 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
 
     /* save it for use by embedded pointer code later */
     pStubMsg->PointerBufferMark = pStubMsg->Buffer;
-    TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->PointerBufferMark - saved_buffer));
+    TRACE("difference = 0x%x\n", (ULONG)(pStubMsg->PointerBufferMark - saved_buffer));
     pointer_buffer_mark_set = 1;
 
     /* restore the original buffer */
@@ -2821,22 +3486,42 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
 
   ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
 
-  if (fMustAlloc || !*ppMemory)
-  {
-    *ppMemory = NdrAllocate(pStubMsg, size);
-    memset(*ppMemory, 0, size);
-  }
-
   pFormat += 4;
-  if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat;
+  if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)pFormat;
   pFormat += 2;
   if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat;
   pFormat += 2;
 
-  pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc);
+  if (conf_array)
+  {
+    array_size = array_read_conformance(conf_array[0], pStubMsg, conf_array);
+    size += array_size;
+
+    /* these could be changed in ComplexMarshall so save them for later */
+    max_count = pStubMsg->MaxCount;
+    count = pStubMsg->ActualCount;
+    offset = pStubMsg->Offset;
+  }
+
+  if (!fMustAlloc && !*ppMemory)
+    fMustAlloc = TRUE;
+  if (fMustAlloc)
+    *ppMemory = NdrAllocate(pStubMsg, size);
+
+  pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc);
 
   if (conf_array)
-    NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc);
+  {
+    pStubMsg->MaxCount = max_count;
+    pStubMsg->ActualCount = count;
+    pStubMsg->Offset = offset;
+    if (fMustAlloc)
+      memset(pMemory, 0, array_size);
+    array_read_variance_and_unmarshall(conf_array[0], pStubMsg, &pMemory,
+                                       conf_array, FALSE,
+                                       FALSE /* fUseBufferMemoryServer */,
+                                       TRUE /* fUnmarshall */);
+  }
 
   if (pointer_buffer_mark_set)
   {
@@ -2858,6 +3543,9 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
   PFORMAT_STRING pointer_desc = NULL;
   unsigned char *OldMemory = pStubMsg->Memory;
   int pointer_length_set = 0;
+  ULONG count = 0;
+  ULONG max_count = 0;
+  ULONG offset = 0;
 
   TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
@@ -2866,7 +3554,7 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
   if(!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength)
   {
     int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers;
-    unsigned long saved_buffer_length = pStubMsg->BufferLength;
+    ULONG saved_buffer_length = pStubMsg->BufferLength;
 
     /* get the buffer length after complex struct data, but before
      * pointer data */
@@ -2877,24 +3565,42 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
     /* save it for use by embedded pointer code later */
     pStubMsg->PointerLength = pStubMsg->BufferLength;
     pointer_length_set = 1;
-    TRACE("difference = 0x%lx\n", pStubMsg->PointerLength - saved_buffer_length);
+    TRACE("difference = 0x%x\n", pStubMsg->PointerLength - saved_buffer_length);
 
     /* restore the original buffer length */
     pStubMsg->BufferLength = saved_buffer_length;
   }
 
   pFormat += 4;
-  if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat;
+  if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)pFormat;
   pFormat += 2;
   if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat;
   pFormat += 2;
 
   pStubMsg->Memory = pMemory;
 
+  if (conf_array)
+  {
+    ULONG struct_size = ComplexStructSize(pStubMsg, pFormat);
+    array_compute_and_size_conformance(conf_array[0], pStubMsg, pMemory + struct_size,
+                                       conf_array);
+
+    /* these could be changed in ComplexMarshall so save them for later */
+    max_count = pStubMsg->MaxCount;
+    count = pStubMsg->ActualCount;
+    offset = pStubMsg->Offset;
+  }
+
   pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc);
 
   if (conf_array)
-    NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array);
+  {
+    pStubMsg->MaxCount = max_count;
+    pStubMsg->ActualCount = count;
+    pStubMsg->Offset = offset;
+    array_buffer_size(conf_array[0], pStubMsg, pMemory, conf_array,
+                      TRUE /* fHasPointers */);
+  }
 
   pStubMsg->Memory = OldMemory;
 
@@ -2915,21 +3621,41 @@ ULONG WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
   unsigned size = *(const WORD*)(pFormat+2);
   PFORMAT_STRING conf_array = NULL;
   PFORMAT_STRING pointer_desc = NULL;
+  ULONG count = 0;
+  ULONG max_count = 0;
+  ULONG offset = 0;
 
   TRACE("(%p,%p)\n", pStubMsg, pFormat);
 
   ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1);
 
   pFormat += 4;
-  if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat;
+  if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)pFormat;
   pFormat += 2;
   if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat;
   pFormat += 2;
 
-  ComplexStructMemorySize(pStubMsg, pFormat);
+  if (conf_array)
+  {
+    array_read_conformance(conf_array[0], pStubMsg, conf_array);
+
+    /* these could be changed in ComplexStructMemorySize so save them for
+     * later */
+    max_count = pStubMsg->MaxCount;
+    count = pStubMsg->ActualCount;
+    offset = pStubMsg->Offset;
+  }
+
+  ComplexStructMemorySize(pStubMsg, pFormat, pointer_desc);
 
   if (conf_array)
-    NdrConformantArrayMemorySize(pStubMsg, conf_array);
+  {
+    pStubMsg->MaxCount = max_count;
+    pStubMsg->ActualCount = count;
+    pStubMsg->Offset = offset;
+    array_memory_size(conf_array[0], pStubMsg, conf_array,
+                      TRUE /* fHasPointers */);
+  }
 
   return size;
 }
@@ -2948,7 +3674,7 @@ void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg,
   TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
 
   pFormat += 4;
-  if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat;
+  if (*(const SHORT*)pFormat) conf_array = pFormat + *(const SHORT*)pFormat;
   pFormat += 2;
   if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat;
   pFormat += 2;
@@ -2958,7 +3684,8 @@ void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg,
   pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc);
 
   if (conf_array)
-    NdrConformantArrayFree(pStubMsg, pMemory, conf_array);
+    array_free(conf_array[0], pStubMsg, pMemory, conf_array,
+               TRUE /* fHasPointers */);
 
   pStubMsg->Memory = OldMemory;
 }
@@ -2970,23 +3697,17 @@ unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                                   unsigned char *pMemory,
                                                   PFORMAT_STRING pFormat)
 {
-  DWORD size = 0, esize = *(const WORD*)(pFormat+2);
-  unsigned char alignment = pFormat[1] + 1;
-
   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);
-
-  WriteConformance(pStubMsg);
-
-  ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment);
-
-  size = safe_multiply(esize, pStubMsg->MaxCount);
-  pStubMsg->BufferMark = pStubMsg->Buffer;
-  safe_copy_to_buffer(pStubMsg, pMemory, size);
+  if (pFormat[0] != RPC_FC_CARRAY)
+  {
+    ERR("invalid format = 0x%x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 
-  EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat);
+  array_compute_and_write_conformance(RPC_FC_CARRAY, pStubMsg, pMemory,
+                                      pFormat);
+  array_write_variance_and_marshall(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat,
+                                    TRUE /* fHasPointers */);
 
   return NULL;
 }
@@ -2999,34 +3720,18 @@ unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                                     PFORMAT_STRING pFormat,
                                                     unsigned char fMustAlloc)
 {
-  DWORD size, esize = *(const WORD*)(pFormat+2);
-  unsigned char alignment = pFormat[1] + 1;
-  unsigned char *saved_buffer;
-
   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 = safe_multiply(esize, pStubMsg->MaxCount);
-  ALIGN_POINTER(pStubMsg->Buffer, alignment);
-
-  if (fMustAlloc)
-    *ppMemory = NdrAllocate(pStubMsg, size);
-  else
+  if (pFormat[0] != RPC_FC_CARRAY)
   {
-    if (!pStubMsg->IsClient && !*ppMemory)
-      /* for servers, we just point straight into the RPC buffer */
-      *ppMemory = pStubMsg->Buffer;
+    ERR("invalid format = 0x%x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
   }
 
-  saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
-  safe_buffer_increment(pStubMsg, size);
-  EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc);
-
-  TRACE("copying %p to %p\n", saved_buffer, *ppMemory);
-  if (*ppMemory != saved_buffer)
-      memcpy(*ppMemory, saved_buffer, size);
+  array_read_conformance(RPC_FC_CARRAY, pStubMsg, pFormat);
+  array_read_variance_and_unmarshall(RPC_FC_CARRAY, pStubMsg, ppMemory, pFormat,
+                                     fMustAlloc,
+                                     TRUE /* fUseBufferMemoryServer */,
+                                     TRUE /* fUnmarshall */);
 
   return NULL;
 }
@@ -3038,23 +3743,16 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
                                          unsigned char *pMemory,
                                          PFORMAT_STRING pFormat)
 {
-  DWORD size, esize = *(const WORD*)(pFormat+2);
-  unsigned char alignment = pFormat[1] + 1;
-
   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);
-
-  SizeConformance(pStubMsg);
-
-  ALIGN_LENGTH(pStubMsg->BufferLength, alignment);
-
-  size = safe_multiply(esize, pStubMsg->MaxCount);
-  /* conformance value plus array */
-  safe_buffer_length_increment(pStubMsg, size);
+  if (pFormat[0] != RPC_FC_CARRAY)
+  {
+    ERR("invalid format = 0x%x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 
-  EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat);
+  array_compute_and_size_conformance(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat);
+  array_buffer_size(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat,
+                    TRUE /* fHasPointers */);
 }
 
 /***********************************************************************
@@ -3063,21 +3761,15 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
 ULONG WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
                                           PFORMAT_STRING pFormat)
 {
-  DWORD size = 0, esize = *(const WORD*)(pFormat+2);
-  unsigned char alignment = pFormat[1] + 1;
-
   TRACE("(%p,%p)\n", pStubMsg, pFormat);
-  if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]);
-
-  pFormat = ReadConformance(pStubMsg, pFormat+4);
-  size = safe_multiply(esize, pStubMsg->MaxCount);
-  pStubMsg->MemorySize += size;
-
-  ALIGN_POINTER(pStubMsg->Buffer, alignment);
-  pStubMsg->BufferMark = pStubMsg->Buffer;
-  safe_buffer_increment(pStubMsg, size);
+  if (pFormat[0] != RPC_FC_CARRAY)
+  {
+    ERR("invalid format = 0x%x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 
-  EmbeddedPointerMemorySize(pStubMsg, pFormat);
+  array_read_conformance(RPC_FC_CARRAY, pStubMsg, pFormat);
+  array_memory_size(RPC_FC_CARRAY, pStubMsg, pFormat, TRUE /* fHasPointers */);
 
   return pStubMsg->MemorySize;
 }
@@ -3090,11 +3782,14 @@ void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg,
                                    PFORMAT_STRING pFormat)
 {
   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);
+  if (pFormat[0] != RPC_FC_CARRAY)
+  {
+    ERR("invalid format = 0x%x\n", pFormat[0]);
+    RpcRaiseException(RPC_X_BAD_STUB_DATA);
+  }
 
-  EmbeddedPointerFree(pStubMsg, pMemory, pFormat);
+  array_free(RPC_FC_CARRAY, pStubMsg, pMemory, pFormat,
+             TRUE /* fHasPointers */);
 }
 
 
@@ -3105,10 +3800,6 @@ unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStu
                                                          unsigned char* pMemory,
                                                          PFORMAT_STRING pFormat )
 {
-    ULONG bufsize;
-    unsigned char alignment = pFormat[1] + 1;
-    DWORD esize = *(const WORD*)(pFormat+2);
-
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
     if (pFormat[0] != RPC_FC_CVARRAY)
@@ -3118,20 +3809,10 @@ unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStu
         return NULL;
     }
 
-    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
-    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
-
-    WriteConformance(pStubMsg);
-    WriteVariance(pStubMsg);
-
-    ALIGN_POINTER_CLEAR(pStubMsg->Buffer, alignment);
-
-    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-
-    pStubMsg->BufferMark = pStubMsg->Buffer;
-    safe_copy_to_buffer(pStubMsg, pMemory + pStubMsg->Offset, bufsize);
-
-    EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat);
+    array_compute_and_write_conformance(RPC_FC_CVARRAY, pStubMsg, pMemory,
+                                        pFormat);
+    array_write_variance_and_marshall(RPC_FC_CVARRAY, pStubMsg, pMemory,
+                                      pFormat, TRUE /* fHasPointers */);
 
     return NULL;
 }
@@ -3145,38 +3826,20 @@ unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pS
                                                            PFORMAT_STRING pFormat,
                                                            unsigned char fMustAlloc )
 {
-    ULONG bufsize, memsize;
-    unsigned char alignment = pFormat[1] + 1;
-    DWORD esize = *(const WORD*)(pFormat+2);
-    unsigned char *saved_buffer;
-    ULONG offset;
-
     TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
 
-    if (pFormat[0] != RPC_FC_CVARRAY)
-    {
-        ERR("invalid format type %x\n", pFormat[0]);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return NULL;
-    }
-
-    pFormat = ReadConformance(pStubMsg, pFormat+4);
-    pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount);
-
-    ALIGN_POINTER(pStubMsg->Buffer, alignment);
-
-    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-    memsize = safe_multiply(esize, pStubMsg->MaxCount);
-    offset = pStubMsg->Offset;
-
-    if (!*ppMemory || fMustAlloc)
-        *ppMemory = NdrAllocate(pStubMsg, memsize);
-    saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
-    safe_buffer_increment(pStubMsg, bufsize);
-
-    EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc);
+    if (pFormat[0] != RPC_FC_CVARRAY)
+    {
+        ERR("invalid format type %x\n", pFormat[0]);
+        RpcRaiseException(RPC_S_INTERNAL_ERROR);
+        return NULL;
+    }
 
-    memcpy(*ppMemory + offset, saved_buffer, bufsize);
+    array_read_conformance(RPC_FC_CVARRAY, pStubMsg, pFormat);
+    array_read_variance_and_unmarshall(RPC_FC_CVARRAY, pStubMsg, ppMemory,
+                                       pFormat, fMustAlloc,
+                                       TRUE /* fUseBufferMemoryServer */,
+                                       TRUE /* fUnmarshall */);
 
     return NULL;
 }
@@ -3198,10 +3861,8 @@ void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg,
         return;
     }
 
-    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
-    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
-
-    EmbeddedPointerFree(pStubMsg, pMemory, pFormat);
+    array_free(RPC_FC_CVARRAY, pStubMsg, pMemory, pFormat,
+               TRUE /* fHasPointers */);
 }
 
 
@@ -3211,9 +3872,6 @@ void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg,
 void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg,
                                                  unsigned char* pMemory, PFORMAT_STRING pFormat )
 {
-    unsigned char alignment = pFormat[1] + 1;
-    DWORD esize = *(const WORD*)(pFormat+2);
-
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
     if (pFormat[0] != RPC_FC_CVARRAY)
@@ -3223,19 +3881,10 @@ void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg,
         return;
     }
 
-    /* compute size */
-    pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0);
-    /* compute length */
-    pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0);
-
-    SizeConformance(pStubMsg);
-    SizeVariance(pStubMsg);
-
-    ALIGN_LENGTH(pStubMsg->BufferLength, alignment);
-
-    safe_buffer_length_increment(pStubMsg, safe_multiply(esize, pStubMsg->ActualCount));
-
-    EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat);
+    array_compute_and_size_conformance(RPC_FC_CVARRAY, pStubMsg, pMemory,
+                                       pFormat);
+    array_buffer_size(RPC_FC_CVARRAY, pStubMsg, pMemory, pFormat,
+                      TRUE /* fHasPointers */);
 }
 
 
@@ -3245,10 +3894,6 @@ void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg,
 ULONG WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg,
                                                   PFORMAT_STRING pFormat )
 {
-    ULONG bufsize, memsize;
-    unsigned char alignment = pFormat[1] + 1;
-    DWORD esize = *(const WORD*)(pFormat+2);
-
     TRACE("(%p, %p)\n", pStubMsg, pFormat);
 
     if (pFormat[0] != RPC_FC_CVARRAY)
@@ -3258,18 +3903,9 @@ ULONG WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg,
         return pStubMsg->MemorySize;
     }
 
-    pFormat = ReadConformance(pStubMsg, pFormat+4);
-    pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount);
-
-    ALIGN_POINTER(pStubMsg->Buffer, alignment);
-
-    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-    memsize = safe_multiply(esize, pStubMsg->MaxCount);
-
-    safe_buffer_increment(pStubMsg, bufsize);
-    pStubMsg->MemorySize += memsize;
-
-    EmbeddedPointerMemorySize(pStubMsg, pFormat);
+    array_read_conformance(RPC_FC_CVARRAY, pStubMsg, pFormat);
+    array_memory_size(RPC_FC_CVARRAY, pStubMsg, pFormat,
+                      TRUE /* fHasPointers */);
 
     return pStubMsg->MemorySize;
 }
@@ -3303,21 +3939,21 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg,
     /* save buffer fields that may be changed by buffer sizer functions
      * and that may be needed later on */
     int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers;
-    unsigned long saved_buffer_length = pStubMsg->BufferLength;
-    unsigned long saved_max_count = pStubMsg->MaxCount;
-    unsigned long saved_offset = pStubMsg->Offset;
-    unsigned long saved_actual_count = pStubMsg->ActualCount;
+    ULONG saved_buffer_length = pStubMsg->BufferLength;
+    ULONG_PTR saved_max_count = pStubMsg->MaxCount;
+    ULONG saved_offset = pStubMsg->Offset;
+    ULONG saved_actual_count = pStubMsg->ActualCount;
 
     /* get the buffer pointer after complex array data, but before
      * pointer data */
-    pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart;
+    pStubMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
     pStubMsg->IgnoreEmbeddedPointers = 1;
     NdrComplexArrayBufferSize(pStubMsg, pMemory, pFormat);
     pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded;
 
     /* save it for use by embedded pointer code later */
-    pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength;
-    TRACE("difference = 0x%x\n", pStubMsg->Buffer - pStubMsg->BufferStart);
+    pStubMsg->PointerBufferMark = (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength;
+    TRACE("difference = 0x%x\n", (ULONG)(pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer));
     pointer_buffer_mark_set = 1;
 
     /* restore fields */
@@ -3395,7 +4031,7 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
   size = pStubMsg->MemorySize;
   pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded;
 
-  TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->Buffer - saved_buffer));
+  TRACE("difference = 0x%x\n", (ULONG)(pStubMsg->Buffer - saved_buffer));
   if (!pStubMsg->PointerBufferMark)
   {
     /* save it for use by embedded pointer code later */
@@ -3410,18 +4046,17 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
   pFormat = ReadConformance(pStubMsg, pFormat);
   pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount);
 
-  if (fMustAlloc || !*ppMemory)
-  {
+  if (!fMustAlloc && !*ppMemory)
+    fMustAlloc = TRUE;
+  if (fMustAlloc)
     *ppMemory = NdrAllocate(pStubMsg, size);
-    memset(*ppMemory, 0, size);
-  }
 
   ALIGN_POINTER(pStubMsg->Buffer, alignment);
 
   pMemory = *ppMemory;
   count = pStubMsg->ActualCount;
   for (i = 0; i < count; i++)
-    pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL);
+    pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL, fMustAlloc);
 
   if (pointer_buffer_mark_set)
   {
@@ -3460,10 +4095,10 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
     /* save buffer fields that may be changed by buffer sizer functions
      * and that may be needed later on */
     int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers;
-    unsigned long saved_buffer_length = pStubMsg->BufferLength;
-    unsigned long saved_max_count = pStubMsg->MaxCount;
-    unsigned long saved_offset = pStubMsg->Offset;
-    unsigned long saved_actual_count = pStubMsg->ActualCount;
+    ULONG saved_buffer_length = pStubMsg->BufferLength;
+    ULONG_PTR saved_max_count = pStubMsg->MaxCount;
+    ULONG saved_offset = pStubMsg->Offset;
+    ULONG saved_actual_count = pStubMsg->ActualCount;
 
     /* get the buffer pointer after complex array data, but before
      * pointer data */
@@ -3538,11 +4173,12 @@ ULONG WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
   SavedMemorySize = pStubMsg->MemorySize;
 
   esize = ComplexStructSize(pStubMsg, pFormat);
+
   MemorySize = safe_multiply(pStubMsg->MaxCount, esize);
 
   count = pStubMsg->ActualCount;
   for (i = 0; i < count; i++)
-    ComplexStructMemorySize(pStubMsg, pFormat);
+    ComplexStructMemorySize(pStubMsg, pFormat, NULL);
 
   pStubMsg->MemorySize = SavedMemorySize;
 
@@ -3684,8 +4320,13 @@ unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
   else
     ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1);
 
-  if (fMustAlloc || !*ppMemory)
+  if (!fMustAlloc && !*ppMemory)
+    fMustAlloc = TRUE;
+  if (fMustAlloc)
+  {
     *ppMemory = NdrAllocate(pStubMsg, memsize);
+    memset(*ppMemory, 0, memsize);
+  }
 
   pStubMsg->Buffer =
     pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall(
@@ -3712,7 +4353,7 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
   unsigned index = *(const WORD*)&pFormat[2];
   DWORD bufsize = *(const WORD*)&pFormat[6];
   USER_MARSHAL_CB umcb;
-  unsigned long saved_buffer_length = 0;
+  ULONG saved_buffer_length = 0;
 
   TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat);
   TRACE("index=%d\n", index);
@@ -3810,6 +4451,56 @@ void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg,
     &umcb.Flags, pMemory);
 }
 
+/***********************************************************************
+ *           NdrGetUserMarshalInfo [RPCRT4.@]
+ */
+RPC_STATUS RPC_ENTRY NdrGetUserMarshalInfo(ULONG *flags, ULONG level, NDR_USER_MARSHAL_INFO *umi)
+{
+    USER_MARSHAL_CB *umcb = CONTAINING_RECORD(flags, USER_MARSHAL_CB, Flags);
+
+    TRACE("(%p,%u,%p)\n", flags, level, umi);
+
+    if (level != 1)
+        return RPC_S_INVALID_ARG;
+
+    memset(&umi->u1.Level1, 0, sizeof(umi->u1.Level1));
+    umi->InformationLevel = level;
+
+    if (umcb->Signature != USER_MARSHAL_CB_SIGNATURE)
+        return RPC_S_INVALID_ARG;
+
+    umi->u1.Level1.pfnAllocate = umcb->pStubMsg->pfnAllocate;
+    umi->u1.Level1.pfnFree = umcb->pStubMsg->pfnFree;
+    umi->u1.Level1.pRpcChannelBuffer = umcb->pStubMsg->pRpcChannelBuffer;
+
+    switch (umcb->CBType)
+    {
+    case USER_MARSHAL_CB_MARSHALL:
+    case USER_MARSHAL_CB_UNMARSHALL:
+    {
+        RPC_MESSAGE *msg = umcb->pStubMsg->RpcMsg;
+        unsigned char *buffer_start = msg->Buffer;
+        unsigned char *buffer_end =
+            (unsigned char *)msg->Buffer + msg->BufferLength;
+
+        if (umcb->pStubMsg->Buffer < buffer_start ||
+            umcb->pStubMsg->Buffer > buffer_end)
+            return ERROR_INVALID_USER_BUFFER;
+
+        umi->u1.Level1.Buffer = umcb->pStubMsg->Buffer;
+        umi->u1.Level1.BufferSize = buffer_end - umcb->pStubMsg->Buffer;
+        break;
+    }
+    case USER_MARSHAL_CB_BUFFER_SIZE:
+    case USER_MARSHAL_CB_FREE:
+        break;
+    default:
+        WARN("unrecognised CBType %d\n", umcb->CBType);
+    }
+
+    return RPC_S_OK;
+}
+
 /***********************************************************************
  *           NdrClearOutParameters [RPCRT4.@]
  */
@@ -4041,7 +4732,6 @@ void WINAPI NdrConformantStructFree(PMIDL_STUB_MESSAGE pStubMsg,
 {
     const NDR_CSTRUCT_FORMAT *pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCArrayFormat;
-    ULONG esize;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4061,7 +4751,6 @@ void WINAPI NdrConformantStructFree(PMIDL_STUB_MESSAGE pStubMsg,
         RpcRaiseException(RPC_S_INTERNAL_ERROR);
         return;
     }
-    esize = *(const WORD*)(pCArrayFormat+2);
 
     ComputeConformance(pStubMsg, pMemory + pCStructFormat->memory_size,
                        pCArrayFormat + 4, 0);
@@ -4084,7 +4773,6 @@ unsigned char *  WINAPI NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE pS
 {
     const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCVArrayFormat;
-    ULONG esize, bufsize;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4098,43 +4786,10 @@ unsigned char *  WINAPI NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE pS
 
     pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description +
         pCVStructFormat->offset_to_array_description;
-    switch (*pCVArrayFormat)
-    {
-    case RPC_FC_CVARRAY:
-        esize = *(const WORD*)(pCVArrayFormat+2);
-
-        pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                            pCVArrayFormat + 4, 0);
-        pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                         pCVArrayFormat, 0);
-        break;
-    case RPC_FC_C_CSTRING:
-        TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(char);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    case RPC_FC_C_WSTRING:
-        TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(WCHAR);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    default:
-        ERR("invalid array format type %x\n", *pCVArrayFormat);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return NULL;
-    }
 
-    WriteConformance(pStubMsg);
+    array_compute_and_write_conformance(*pCVArrayFormat, pStubMsg,
+                                        pMemory + pCVStructFormat->memory_size,
+                                        pCVArrayFormat);
 
     ALIGN_POINTER_CLEAR(pStubMsg->Buffer, pCVStructFormat->alignment + 1);
 
@@ -4144,12 +4799,9 @@ unsigned char *  WINAPI NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE pS
     pStubMsg->BufferMark = pStubMsg->Buffer;
     safe_copy_to_buffer(pStubMsg, pMemory, pCVStructFormat->memory_size);
 
-    WriteVariance(pStubMsg);
-
-    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
-
-    /* write array part */
-    safe_copy_to_buffer(pStubMsg, pMemory + pCVStructFormat->memory_size, bufsize);
+    array_write_variance_and_marshall(*pCVArrayFormat, pStubMsg,
+                                      pMemory + pCVStructFormat->memory_size,
+                                      pCVArrayFormat, FALSE /* fHasPointers */);
 
     EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat);
 
@@ -4166,8 +4818,10 @@ unsigned char *  WINAPI NdrConformantVaryingStructUnmarshall(PMIDL_STUB_MESSAGE
 {
     const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCVArrayFormat;
-    ULONG esize, bufsize;
-    unsigned char cvarray_type;
+    ULONG memsize, bufsize;
+    unsigned char *saved_buffer, *saved_array_buffer;
+    ULONG offset;
+    unsigned char *array_memory;
 
     TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
 
@@ -4181,83 +4835,55 @@ unsigned char *  WINAPI NdrConformantVaryingStructUnmarshall(PMIDL_STUB_MESSAGE
 
     pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description +
         pCVStructFormat->offset_to_array_description;
-    cvarray_type = *pCVArrayFormat;
-    switch (cvarray_type)
-    {
-    case RPC_FC_CVARRAY:
-        esize = *(const WORD*)(pCVArrayFormat+2);
-        pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4);
-        break;
-    case RPC_FC_C_CSTRING:
-        esize = sizeof(char);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2);
-        else
-            pCVArrayFormat = ReadConformance(pStubMsg, NULL);
-        break;
-    case RPC_FC_C_WSTRING:
-        esize = sizeof(WCHAR);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2);
-        else
-            pCVArrayFormat = ReadConformance(pStubMsg, NULL);
-        break;
-    default:
-        ERR("invalid array format type %x\n", *pCVArrayFormat);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return NULL;
-    }
+
+    memsize = array_read_conformance(*pCVArrayFormat, pStubMsg,
+                                     pCVArrayFormat);
 
     ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1);
 
     TRACE("memory_size = %d\n", pCVStructFormat->memory_size);
 
     /* work out how much memory to allocate if we need to do so */
-    if (!*ppMemory || fMustAlloc)
+    if (!fMustAlloc && !*ppMemory)
+        fMustAlloc = TRUE;
+    if (fMustAlloc)
     {
-        SIZE_T size = pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount);
+        SIZE_T size = pCVStructFormat->memory_size + memsize;
         *ppMemory = NdrAllocate(pStubMsg, size);
     }
 
-    /* copy the constant data */
-    pStubMsg->BufferMark = pStubMsg->Buffer;
-    safe_copy_from_buffer(pStubMsg, *ppMemory, pCVStructFormat->memory_size);
+    /* mark the start of the constant data */
+    saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, pCVStructFormat->memory_size);
 
-    pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount);
+    array_memory = *ppMemory + pCVStructFormat->memory_size;
+    bufsize = array_read_variance_and_unmarshall(*pCVArrayFormat, pStubMsg,
+                                                 &array_memory, pCVArrayFormat,
+                                                 FALSE /* fMustAlloc */,
+                                                 FALSE /* fUseServerBufferMemory */,
+                                                 FALSE /* fUnmarshall */);
 
-    bufsize = safe_multiply(esize, pStubMsg->ActualCount);
+    /* save offset in case unmarshalling pointers changes it */
+    offset = pStubMsg->Offset;
 
-    if ((cvarray_type == RPC_FC_C_CSTRING) ||
-        (cvarray_type == RPC_FC_C_WSTRING))
-    {
-        ULONG i;
-        /* strings must always have null terminating bytes */
-        if (bufsize < esize)
-        {
-            ERR("invalid string length of %d\n", pStubMsg->ActualCount);
-            RpcRaiseException(RPC_S_INVALID_BOUND);
-            return NULL;
-        }
-        for (i = bufsize - esize; i < bufsize; i++)
-            if (pStubMsg->Buffer[i] != 0)
-            {
-                ERR("string not null-terminated at byte position %d, data is 0x%x\n",
-                    i, pStubMsg->Buffer[i]);
-                RpcRaiseException(RPC_S_INVALID_BOUND);
-                return NULL;
-            }
-    }
+    /* mark the start of the array data */
+    saved_array_buffer = pStubMsg->Buffer;
+    safe_buffer_increment(pStubMsg, bufsize);
+
+    EmbeddedPointerUnmarshall(pStubMsg, saved_buffer, *ppMemory, pFormat, fMustAlloc);
 
+    /* copy the constant data */
+    memcpy(*ppMemory, saved_buffer, pCVStructFormat->memory_size);
     /* copy the array data */
-    safe_copy_from_buffer(pStubMsg, *ppMemory + pCVStructFormat->memory_size, bufsize);
+    TRACE("copying %p to %p\n", saved_array_buffer, *ppMemory + pCVStructFormat->memory_size);
+    memcpy(*ppMemory + pCVStructFormat->memory_size + offset,
+           saved_array_buffer, bufsize);
 
-    if (cvarray_type == RPC_FC_C_CSTRING)
+    if (*pCVArrayFormat == RPC_FC_C_CSTRING)
         TRACE("string=%s\n", debugstr_a((char *)(*ppMemory + pCVStructFormat->memory_size)));
-    else if (cvarray_type == RPC_FC_C_WSTRING)
+    else if (*pCVArrayFormat == RPC_FC_C_WSTRING)
         TRACE("string=%s\n", debugstr_w((WCHAR *)(*ppMemory + pCVStructFormat->memory_size)));
 
-    EmbeddedPointerUnmarshall(pStubMsg, *ppMemory, *ppMemory, pFormat, TRUE /* FIXME */);
-
     return NULL;
 }
 
@@ -4270,7 +4896,6 @@ void WINAPI NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
 {
     const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCVArrayFormat;
-    ULONG esize;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4284,51 +4909,19 @@ void WINAPI NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
 
     pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description +
         pCVStructFormat->offset_to_array_description;
-    switch (*pCVArrayFormat)
-    {
-    case RPC_FC_CVARRAY:
-        esize = *(const WORD*)(pCVArrayFormat+2);
-
-        pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                            pCVArrayFormat + 4, 0);
-        pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                         pCVArrayFormat, 0);
-        break;
-    case RPC_FC_C_CSTRING:
-        TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(char);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    case RPC_FC_C_WSTRING:
-        TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(WCHAR);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    default:
-        ERR("invalid array format type %x\n", *pCVArrayFormat);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return;
-    }
-
-    SizeConformance(pStubMsg);
+    array_compute_and_size_conformance(*pCVArrayFormat, pStubMsg,
+                                       pMemory + pCVStructFormat->memory_size,
+                                       pCVArrayFormat);
 
     ALIGN_LENGTH(pStubMsg->BufferLength, pCVStructFormat->alignment + 1);
 
     TRACE("memory_size = %d\n", pCVStructFormat->memory_size);
 
     safe_buffer_length_increment(pStubMsg, pCVStructFormat->memory_size);
-    SizeVariance(pStubMsg);
-    safe_buffer_length_increment(pStubMsg, safe_multiply(pStubMsg->MaxCount, esize));
+
+    array_buffer_size(*pCVArrayFormat, pStubMsg,
+                      pMemory + pCVStructFormat->memory_size, pCVArrayFormat,
+                      FALSE /* fHasPointers */);
 
     EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat);
 }
@@ -4341,8 +4934,6 @@ ULONG WINAPI NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
 {
     const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCVArrayFormat;
-    ULONG esize;
-    unsigned char cvarray_type;
 
     TRACE("(%p, %p)\n", pStubMsg, pFormat);
 
@@ -4356,46 +4947,21 @@ ULONG WINAPI NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
 
     pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description +
         pCVStructFormat->offset_to_array_description;
-    cvarray_type = *pCVArrayFormat;
-    switch (cvarray_type)
-    {
-    case RPC_FC_CVARRAY:
-        esize = *(const WORD*)(pCVArrayFormat+2);
-        pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4);
-        break;
-    case RPC_FC_C_CSTRING:
-        esize = sizeof(char);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2);
-        else
-            pCVArrayFormat = ReadConformance(pStubMsg, NULL);
-        break;
-    case RPC_FC_C_WSTRING:
-        esize = sizeof(WCHAR);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2);
-        else
-            pCVArrayFormat = ReadConformance(pStubMsg, NULL);
-        break;
-    default:
-        ERR("invalid array format type %x\n", *pCVArrayFormat);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return 0;
-    }
+    array_read_conformance(*pCVArrayFormat, pStubMsg, pCVArrayFormat);
 
     ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1);
 
     TRACE("memory_size = %d\n", pCVStructFormat->memory_size);
 
     safe_buffer_increment(pStubMsg, pCVStructFormat->memory_size);
-    pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount);
-    safe_buffer_increment(pStubMsg, safe_multiply(esize, pStubMsg->ActualCount));
+    array_memory_size(*pCVArrayFormat, pStubMsg, pCVArrayFormat,
+                      FALSE /* fHasPointers */);
 
-    pStubMsg->MemorySize += pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount);
+    pStubMsg->MemorySize += pCVStructFormat->memory_size;
 
     EmbeddedPointerMemorySize(pStubMsg, pFormat);
 
-    return pCVStructFormat->memory_size + pStubMsg->MaxCount * esize;
+    return pStubMsg->MemorySize;
 }
 
 /***********************************************************************
@@ -4407,7 +4973,6 @@ void WINAPI NdrConformantVaryingStructFree(PMIDL_STUB_MESSAGE pStubMsg,
 {
     const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat;
     PFORMAT_STRING pCVArrayFormat;
-    ULONG esize;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4421,41 +4986,9 @@ void WINAPI NdrConformantVaryingStructFree(PMIDL_STUB_MESSAGE pStubMsg,
 
     pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description +
         pCVStructFormat->offset_to_array_description;
-    switch (*pCVArrayFormat)
-    {
-    case RPC_FC_CVARRAY:
-        esize = *(const WORD*)(pCVArrayFormat+2);
-
-        pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                            pCVArrayFormat + 4, 0);
-        pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                         pCVArrayFormat, 0);
-        break;
-    case RPC_FC_C_CSTRING:
-        TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(char);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    case RPC_FC_C_WSTRING:
-        TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size));
-        pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1;
-        esize = sizeof(WCHAR);
-        if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED)
-            pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size,
-                                                pCVArrayFormat + 2, 0);
-        else
-            pStubMsg->MaxCount = pStubMsg->ActualCount;
-        break;
-    default:
-        ERR("invalid array format type %x\n", *pCVArrayFormat);
-        RpcRaiseException(RPC_S_INTERNAL_ERROR);
-        return;
-    }
+    array_free(*pCVArrayFormat, pStubMsg,
+               pMemory + pCVStructFormat->memory_size, pCVArrayFormat,
+               FALSE /* fHasPointers */);
 
     TRACE("memory_size = %d\n", pCVStructFormat->memory_size);
 
@@ -4474,7 +5007,7 @@ typedef struct
 {
     unsigned char type;
     unsigned char alignment;
-    unsigned long total_size;
+    ULONG total_size;
 } NDR_LGFARRAY_FORMAT;
 #include "poppack.h"
 
@@ -4486,7 +5019,7 @@ unsigned char *  WINAPI NdrFixedArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                 PFORMAT_STRING pFormat)
 {
     const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat;
-    unsigned long total_size;
+    ULONG total_size;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4529,7 +5062,7 @@ unsigned char *  WINAPI NdrFixedArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                 unsigned char fMustAlloc)
 {
     const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat;
-    unsigned long total_size;
+    ULONG total_size;
     unsigned char *saved_buffer;
 
     TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
@@ -4584,7 +5117,7 @@ void WINAPI NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
                                 PFORMAT_STRING pFormat)
 {
     const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat;
-    unsigned long total_size;
+    ULONG total_size;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
 
@@ -4800,7 +5333,9 @@ unsigned char *  WINAPI NdrVaryingArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
     bufsize = safe_multiply(esize, pStubMsg->ActualCount);
     offset = pStubMsg->Offset;
 
-    if (!*ppMemory || fMustAlloc)
+    if (!fMustAlloc && !*ppMemory)
+        fMustAlloc = TRUE;
+    if (fMustAlloc)
         *ppMemory = NdrAllocate(pStubMsg, size);
     saved_buffer = pStubMsg->BufferMark = pStubMsg->Buffer;
     safe_buffer_increment(pStubMsg, bufsize);
@@ -4929,7 +5464,6 @@ void WINAPI NdrVaryingArrayFree(PMIDL_STUB_MESSAGE pStubMsg,
                                 unsigned char *pMemory,
                                 PFORMAT_STRING pFormat)
 {
-    unsigned char alignment;
     DWORD elements;
 
     TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
@@ -4942,8 +5476,6 @@ void WINAPI NdrVaryingArrayFree(PMIDL_STUB_MESSAGE pStubMsg,
         return;
     }
 
-    alignment = pFormat[1] + 1;
-
     if (pFormat[0] == RPC_FC_SMVARRAY)
     {
         pFormat += 2;
@@ -4980,7 +5512,7 @@ static ULONG get_discriminant(unsigned char fc, const unsigned char *pMemory)
     case RPC_FC_CHAR:
     case RPC_FC_SMALL:
     case RPC_FC_USMALL:
-        return *(const UCHAR *)pMemory;
+        return *pMemory;
     case RPC_FC_WCHAR:
     case RPC_FC_SHORT:
     case RPC_FC_USHORT:
@@ -4997,7 +5529,7 @@ static ULONG get_discriminant(unsigned char fc, const unsigned char *pMemory)
 }
 
 static PFORMAT_STRING get_arm_offset_from_union_arm_selector(PMIDL_STUB_MESSAGE pStubMsg,
-                                                             unsigned long discriminant,
+                                                             ULONG discriminant,
                                                              PFORMAT_STRING pFormat)
 {
     unsigned short num_arms, arm, type;
@@ -5020,13 +5552,13 @@ static PFORMAT_STRING get_arm_offset_from_union_arm_selector(PMIDL_STUB_MESSAGE
     {
         if(type == 0xffff)
         {
-            ERR("no arm for 0x%lx and no default case\n", discriminant);
+            ERR("no arm for 0x%x and no default case\n", discriminant);
             RpcRaiseException(RPC_S_INVALID_TAG);
             return NULL;
         }
         if(type == 0)
         {
-            TRACE("falling back to empty default case for 0x%lx\n", discriminant);
+            TRACE("falling back to empty default case for 0x%x\n", discriminant);
             return NULL;
         }
     }
@@ -5131,7 +5663,6 @@ static unsigned char *union_arm_unmarshall(PMIDL_STUB_MESSAGE pStubMsg,
             case RPC_FC_UP:
             case RPC_FC_OP:
             case RPC_FC_FP:
-                **(void***)ppMemory = NULL;
                 ALIGN_POINTER(pStubMsg->Buffer, 4);
                 saved_buffer = pStubMsg->Buffer;
                 if (pStubMsg->PointerBufferMark)
@@ -5255,8 +5786,8 @@ static ULONG union_arm_memory_size(PMIDL_STUB_MESSAGE pStubMsg,
                 ALIGN_POINTER(pStubMsg->Buffer, 4);
                 saved_buffer = pStubMsg->Buffer;
                 safe_buffer_increment(pStubMsg, 4);
-                ALIGN_LENGTH(pStubMsg->MemorySize, 4);
-                pStubMsg->MemorySize += 4;
+                ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(void *));
+                pStubMsg->MemorySize += sizeof(void *);
                 if (!pStubMsg->IgnoreEmbeddedPointers)
                     PointerMemorySize(pStubMsg, saved_buffer, pFormat);
                 break;
@@ -5361,13 +5892,23 @@ unsigned char *  WINAPI NdrEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pStubM
     TRACE("got switch value 0x%x\n", switch_value);
 
     size = *(const unsigned short*)pFormat + increment;
-    if(!*ppMemory || fMustAlloc)
+    if (!fMustAlloc && !*ppMemory)
+        fMustAlloc = TRUE;
+    if (fMustAlloc)
         *ppMemory = NdrAllocate(pStubMsg, size);
 
+    /* we can't pass fMustAlloc=TRUE into the marshaller for the arm
+     * since the arm is part of the memory block that is encompassed by
+     * the whole union. Memory is forced to allocate when pointers
+     * are set to NULL, so we emulate that part of fMustAlloc=TRUE by
+     * clearing the memory we pass in to the unmarshaller */
+    if (fMustAlloc)
+        memset(*ppMemory, 0, size);
+
     NdrBaseTypeUnmarshall(pStubMsg, ppMemory, &switch_type, FALSE);
     pMemoryArm = *ppMemory + increment;
 
-    return union_arm_unmarshall(pStubMsg, &pMemoryArm, switch_value, pFormat, fMustAlloc);
+    return union_arm_unmarshall(pStubMsg, &pMemoryArm, switch_value, pFormat, FALSE);
 }
 
 /***********************************************************************
@@ -5445,7 +5986,7 @@ void WINAPI NdrEncapsulatedUnionFree(PMIDL_STUB_MESSAGE pStubMsg,
 
     pMemory += increment;
 
-    return union_arm_free(pStubMsg, pMemory, switch_value, pFormat);
+    union_arm_free(pStubMsg, pMemory, switch_value, pFormat);
 }
 
 /***********************************************************************
@@ -5471,10 +6012,10 @@ unsigned char *  WINAPI NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStub
     return union_arm_marshall(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat);
 }
 
-static long unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg,
+static LONG unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg,
                                     PFORMAT_STRING *ppFormat)
 {
-    long discriminant = 0;
+    LONG discriminant = 0;
 
     switch(**ppFormat)
     {
@@ -5491,6 +6032,7 @@ static long unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg,
     case RPC_FC_WCHAR:
     case RPC_FC_SHORT:
     case RPC_FC_USHORT:
+    case RPC_FC_ENUM16:
     {
         USHORT d;
         ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT));
@@ -5527,7 +6069,7 @@ unsigned char *  WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pSt
                                 PFORMAT_STRING pFormat,
                                 unsigned char fMustAlloc)
 {
-    long discriminant;
+    LONG discriminant;
     unsigned short size;
 
     TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
@@ -5535,16 +6077,26 @@ unsigned char *  WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pSt
 
     /* Unmarshall discriminant */
     discriminant = unmarshall_discriminant(pStubMsg, &pFormat);
-    TRACE("unmarshalled discriminant %lx\n", discriminant);
+    TRACE("unmarshalled discriminant %x\n", discriminant);
 
     pFormat += *(const SHORT*)pFormat;
 
     size = *(const unsigned short*)pFormat;
 
-    if(!*ppMemory || fMustAlloc)
+    if (!fMustAlloc && !*ppMemory)
+        fMustAlloc = TRUE;
+    if (fMustAlloc)
         *ppMemory = NdrAllocate(pStubMsg, size);
 
-    return union_arm_unmarshall(pStubMsg, ppMemory, discriminant, pFormat, fMustAlloc);
+    /* we can't pass fMustAlloc=TRUE into the marshaller for the arm
+     * since the arm is part of the memory block that is encompassed by
+     * the whole union. Memory is forced to allocate when pointers
+     * are set to NULL, so we emulate that part of fMustAlloc=TRUE by
+     * clearing the memory we pass in to the unmarshaller */
+    if (fMustAlloc)
+        memset(*ppMemory, 0, size);
+
+    return union_arm_unmarshall(pStubMsg, ppMemory, discriminant, pFormat, FALSE);
 }
 
 /***********************************************************************
@@ -5600,7 +6152,7 @@ void WINAPI NdrNonEncapsulatedUnionFree(PMIDL_STUB_MESSAGE pStubMsg,
     pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0);
     TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount);
 
-    return union_arm_free(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat);
+    union_arm_free(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat);
 }
 
 /***********************************************************************
@@ -5637,10 +6189,10 @@ void WINAPI NdrByteCountPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
 }
 
 /***********************************************************************
- *           NdrByteCountPointerMemorySize [RPCRT4.@]
+ *           NdrByteCountPointerMemorySize [internal]
  */
-ULONG WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
-                                PFORMAT_STRING pFormat)
+static ULONG WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg,
+                                                  PFORMAT_STRING pFormat)
 {
     FIXME("stub\n");
     return 0;
@@ -5709,20 +6261,10 @@ void WINAPI NdrXmitOrRepAsFree(PMIDL_STUB_MESSAGE pStubMsg,
     FIXME("stub\n");
 }
 
-#include "pshpack1.h"
-typedef struct
-{
-    unsigned char type;
-    unsigned char flags_type; /* flags in upper nibble, type in lower nibble */
-    ULONG low_value;
-    ULONG high_value;
-} NDR_RANGE;
-#include "poppack.h"
-
 /***********************************************************************
  *           NdrRangeMarshall [internal]
  */
-unsigned char *WINAPI NdrRangeMarshall(
+static unsigned char *WINAPI NdrRangeMarshall(
     PMIDL_STUB_MESSAGE pStubMsg,
     unsigned char *pMemory,
     PFORMAT_STRING pFormat)
@@ -5745,7 +6287,7 @@ unsigned char *WINAPI NdrRangeMarshall(
 }
 
 /***********************************************************************
- *           NdrRangeUnmarshall
+ *           NdrRangeUnmarshall [RPCRT4.@]
  */
 unsigned char *WINAPI NdrRangeUnmarshall(
     PMIDL_STUB_MESSAGE pStubMsg,
@@ -5769,66 +6311,68 @@ unsigned char *WINAPI NdrRangeUnmarshall(
     TRACE("base_type = 0x%02x, low_value = %d, high_value = %d\n",
         base_type, pRange->low_value, pRange->high_value);
 
-#define RANGE_UNMARSHALL(type, format_spec) \
+#define RANGE_UNMARSHALL(mem_type, wire_type, format_spec) \
     do \
     { \
-        ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \
-        if (fMustAlloc || !*ppMemory) \
-            *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \
-        if (pStubMsg->Buffer + sizeof(type) > pStubMsg->BufferEnd) \
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(wire_type)); \
+        if (!fMustAlloc && !*ppMemory) \
+            fMustAlloc = TRUE; \
+        if (fMustAlloc) \
+            *ppMemory = NdrAllocate(pStubMsg, sizeof(mem_type)); \
+        if (pStubMsg->Buffer + sizeof(wire_type) > pStubMsg->BufferEnd) \
         { \
             ERR("buffer overflow - Buffer = %p, BufferEnd = %p\n", \
                 pStubMsg->Buffer, (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength); \
             RpcRaiseException(RPC_X_BAD_STUB_DATA); \
         } \
-        if ((*(type *)pStubMsg->Buffer < (type)pRange->low_value) || \
-            (*(type *)pStubMsg->Buffer > (type)pRange->high_value)) \
+        if ((*(wire_type *)pStubMsg->Buffer < (mem_type)pRange->low_value) || \
+            (*(wire_type *)pStubMsg->Buffer > (mem_type)pRange->high_value)) \
         { \
             ERR("value exceeded bounds: " format_spec ", low: " format_spec ", high: " format_spec "\n", \
-                *(type *)pStubMsg->Buffer, (type)pRange->low_value, \
-                (type)pRange->high_value); \
+                *(wire_type *)pStubMsg->Buffer, (mem_type)pRange->low_value, \
+                (mem_type)pRange->high_value); \
             RpcRaiseException(RPC_S_INVALID_BOUND); \
             return NULL; \
         } \
         TRACE("*ppMemory: %p\n", *ppMemory); \
-        **(type **)ppMemory = *(type *)pStubMsg->Buffer; \
-        pStubMsg->Buffer += sizeof(type); \
+        **(mem_type **)ppMemory = *(wire_type *)pStubMsg->Buffer; \
+        pStubMsg->Buffer += sizeof(wire_type); \
     } while (0)
 
     switch(base_type)
     {
     case RPC_FC_CHAR:
     case RPC_FC_SMALL:
-        RANGE_UNMARSHALL(UCHAR, "%d");
-        TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory);
+        RANGE_UNMARSHALL(UCHAR, UCHAR, "%d");
+        TRACE("value: 0x%02x\n", **ppMemory);
         break;
     case RPC_FC_BYTE:
     case RPC_FC_USMALL:
-        RANGE_UNMARSHALL(CHAR, "%u");
-        TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory);
+        RANGE_UNMARSHALL(CHAR, CHAR, "%u");
+        TRACE("value: 0x%02x\n", **ppMemory);
         break;
     case RPC_FC_WCHAR: /* FIXME: valid? */
     case RPC_FC_USHORT:
-        RANGE_UNMARSHALL(USHORT, "%u");
+        RANGE_UNMARSHALL(USHORT, USHORT, "%u");
         TRACE("value: 0x%04x\n", **(USHORT **)ppMemory);
         break;
     case RPC_FC_SHORT:
-        RANGE_UNMARSHALL(SHORT, "%d");
+        RANGE_UNMARSHALL(SHORT, SHORT, "%d");
         TRACE("value: 0x%04x\n", **(USHORT **)ppMemory);
         break;
     case RPC_FC_LONG:
-        RANGE_UNMARSHALL(LONG, "%d");
+    case RPC_FC_ENUM32:
+        RANGE_UNMARSHALL(LONG, LONG, "%d");
         TRACE("value: 0x%08x\n", **(ULONG **)ppMemory);
         break;
     case RPC_FC_ULONG:
-        RANGE_UNMARSHALL(ULONG, "%u");
+        RANGE_UNMARSHALL(ULONG, ULONG, "%u");
         TRACE("value: 0x%08x\n", **(ULONG **)ppMemory);
         break;
     case RPC_FC_ENUM16:
-    case RPC_FC_ENUM32:
-        FIXME("Unhandled enum type\n");
+        RANGE_UNMARSHALL(UINT, USHORT, "%u");
+        TRACE("value: 0x%08x\n", **(UINT **)ppMemory);
         break;
-    case RPC_FC_ERROR_STATUS_T: /* FIXME: valid? */
     case RPC_FC_FLOAT:
     case RPC_FC_DOUBLE:
     case RPC_FC_HYPER:
@@ -5843,7 +6387,7 @@ unsigned char *WINAPI NdrRangeUnmarshall(
 /***********************************************************************
  *           NdrRangeBufferSize [internal]
  */
-void WINAPI NdrRangeBufferSize(
+static void WINAPI NdrRangeBufferSize(
     PMIDL_STUB_MESSAGE pStubMsg,
     unsigned char *pMemory,
     PFORMAT_STRING pFormat)
@@ -5866,7 +6410,7 @@ void WINAPI NdrRangeBufferSize(
 /***********************************************************************
  *           NdrRangeMemorySize [internal]
  */
-ULONG WINAPI NdrRangeMemorySize(
+static ULONG WINAPI NdrRangeMemorySize(
     PMIDL_STUB_MESSAGE pStubMsg,
     PFORMAT_STRING pFormat)
 {
@@ -5887,7 +6431,7 @@ ULONG WINAPI NdrRangeMemorySize(
 /***********************************************************************
  *           NdrRangeFree [internal]
  */
-void WINAPI NdrRangeFree(PMIDL_STUB_MESSAGE pStubMsg,
+static void WINAPI NdrRangeFree(PMIDL_STUB_MESSAGE pStubMsg,
                                 unsigned char *pMemory,
                                 PFORMAT_STRING pFormat)
 {
@@ -5913,7 +6457,7 @@ static unsigned char *WINAPI NdrBaseTypeMarshall(
     case RPC_FC_SMALL:
     case RPC_FC_USMALL:
         safe_copy_to_buffer(pStubMsg, pMemory, sizeof(UCHAR));
-        TRACE("value: 0x%02x\n", *(UCHAR *)pMemory);
+        TRACE("value: 0x%02x\n", *pMemory);
         break;
     case RPC_FC_WCHAR:
     case RPC_FC_SHORT:
@@ -5981,15 +6525,15 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall(
         { \
             *ppMemory = pStubMsg->Buffer; \
             TRACE("*ppMemory: %p\n", *ppMemory); \
+            safe_buffer_increment(pStubMsg, sizeof(type)); \
         } \
         else \
         {  \
             if (fMustAlloc) \
                 *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \
             TRACE("*ppMemory: %p\n", *ppMemory); \
-            **(type **)ppMemory = *(type *)pStubMsg->Buffer; \
-        } \
-        pStubMsg->Buffer += sizeof(type);
+            safe_copy_from_buffer(pStubMsg, *ppMemory, sizeof(type)); \
+        }
 
     switch(*pFormat)
     {
@@ -5998,7 +6542,7 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall(
     case RPC_FC_SMALL:
     case RPC_FC_USMALL:
         BASE_TYPE_UNMARSHALL(UCHAR);
-        TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory);
+        TRACE("value: 0x%02x\n", **ppMemory);
         break;
     case RPC_FC_WCHAR:
     case RPC_FC_SHORT:
@@ -6027,7 +6571,9 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall(
         break;
     case RPC_FC_ENUM16:
         ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT));
-        if (fMustAlloc || !*ppMemory)
+        if (!fMustAlloc && !*ppMemory)
+            fMustAlloc = TRUE;
+        if (fMustAlloc)
             *ppMemory = NdrAllocate(pStubMsg, sizeof(UINT));
         if (pStubMsg->Buffer + sizeof(USHORT) > pStubMsg->BufferEnd)
             RpcRaiseException(RPC_X_BAD_STUB_DATA);
@@ -6124,36 +6670,51 @@ static ULONG WINAPI NdrBaseTypeMemorySize(
     case RPC_FC_WCHAR:
     case RPC_FC_SHORT:
     case RPC_FC_USHORT:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT));
         safe_buffer_increment(pStubMsg, sizeof(USHORT));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(USHORT));
         pStubMsg->MemorySize += sizeof(USHORT);
         return sizeof(USHORT);
     case RPC_FC_LONG:
     case RPC_FC_ULONG:
     case RPC_FC_ENUM32:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG));
         safe_buffer_increment(pStubMsg, sizeof(ULONG));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(ULONG));
         pStubMsg->MemorySize += sizeof(ULONG);
         return sizeof(ULONG);
     case RPC_FC_FLOAT:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(float));
         safe_buffer_increment(pStubMsg, sizeof(float));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(float));
         pStubMsg->MemorySize += sizeof(float);
         return sizeof(float);
     case RPC_FC_DOUBLE:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(double));
         safe_buffer_increment(pStubMsg, sizeof(double));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(double));
         pStubMsg->MemorySize += sizeof(double);
         return sizeof(double);
     case RPC_FC_HYPER:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONGLONG));
         safe_buffer_increment(pStubMsg, sizeof(ULONGLONG));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(ULONGLONG));
         pStubMsg->MemorySize += sizeof(ULONGLONG);
         return sizeof(ULONGLONG);
     case RPC_FC_ERROR_STATUS_T:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(error_status_t));
         safe_buffer_increment(pStubMsg, sizeof(error_status_t));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(error_status_t));
         pStubMsg->MemorySize += sizeof(error_status_t);
         return sizeof(error_status_t);
     case RPC_FC_ENUM16:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT));
         safe_buffer_increment(pStubMsg, sizeof(USHORT));
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(UINT));
         pStubMsg->MemorySize += sizeof(UINT);
         return sizeof(UINT);
     case RPC_FC_IGNORE:
+        ALIGN_LENGTH(pStubMsg->MemorySize, sizeof(void *));
         pStubMsg->MemorySize += sizeof(void *);
         return sizeof(void *);
     default:
@@ -6208,11 +6769,21 @@ static unsigned char *WINAPI NdrContextHandleMarshall(
         ERR("invalid format type %x\n", *pFormat);
         RpcRaiseException(RPC_S_INTERNAL_ERROR);
     }
+    TRACE("flags: 0x%02x\n", pFormat[1]);
 
-    if (pFormat[1] & 0x80)
-        NdrClientContextMarshall(pStubMsg, *(NDR_CCONTEXT **)pMemory, FALSE);
+    if (pStubMsg->IsClient)
+    {
+        if (pFormat[1] & HANDLE_PARAM_IS_VIA_PTR)
+            NdrClientContextMarshall(pStubMsg, *(NDR_CCONTEXT **)pMemory, FALSE);
+        else
+            NdrClientContextMarshall(pStubMsg, pMemory, FALSE);
+    }
     else
-        NdrClientContextMarshall(pStubMsg, (NDR_CCONTEXT *)pMemory, FALSE);
+    {
+        NDR_SCONTEXT ctxt = NDRSContextFromValue(pMemory);
+        NDR_RUNDOWN rundown = pStubMsg->StubDesc->apfnNdrRundownRoutines[pFormat[2]];
+        NdrServerContextNewMarshall(pStubMsg, ctxt, rundown, pFormat);
+    }
 
     return NULL;
 }
@@ -6226,16 +6797,34 @@ static unsigned char *WINAPI NdrContextHandleUnmarshall(
     PFORMAT_STRING pFormat,
     unsigned char fMustAlloc)
 {
+    TRACE("pStubMsg %p, ppMemory %p, pFormat %p, fMustAlloc %s\n", pStubMsg,
+        ppMemory, pFormat, fMustAlloc ? "TRUE": "FALSE");
+
     if (*pFormat != RPC_FC_BIND_CONTEXT)
     {
         ERR("invalid format type %x\n", *pFormat);
         RpcRaiseException(RPC_S_INTERNAL_ERROR);
     }
+    TRACE("flags: 0x%02x\n", pFormat[1]);
 
-  **(NDR_CCONTEXT **)ppMemory = NULL;
-  NdrClientContextUnmarshall(pStubMsg, *(NDR_CCONTEXT **)ppMemory, pStubMsg->RpcMsg->Handle);
+    if (pStubMsg->IsClient)
+    {
+        /* [out]-only or [ret] param */
+        if ((pFormat[1] & (HANDLE_PARAM_IS_IN|HANDLE_PARAM_IS_OUT)) == HANDLE_PARAM_IS_OUT)
+            **(NDR_CCONTEXT **)ppMemory = NULL;
+        NdrClientContextUnmarshall(pStubMsg, *(NDR_CCONTEXT **)ppMemory, pStubMsg->RpcMsg->Handle);
+    }
+    else
+    {
+        NDR_SCONTEXT ctxt;
+        ctxt = NdrServerContextNewUnmarshall(pStubMsg, pFormat);
+        if (pFormat[1] & HANDLE_PARAM_IS_VIA_PTR)
+            *(void **)ppMemory = NDRSContextValue(ctxt);
+        else
+            *(void **)ppMemory = *NDRSContextValue(ctxt);
+    }
 
-  return NULL;
+    return NULL;
 }
 
 /***********************************************************************
@@ -6301,7 +6890,8 @@ void WINAPI NdrServerContextMarshall(PMIDL_STUB_MESSAGE pStubMsg,
     }
 
     NDRSContextMarshall2(pStubMsg->RpcMsg->Handle, ContextHandle,
-                         pStubMsg->Buffer, RundownRoutine, NULL, 0);
+                         pStubMsg->Buffer, RundownRoutine, NULL,
+                         RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
     pStubMsg->Buffer += cbNDRContext;
 }
 
@@ -6323,7 +6913,7 @@ NDR_SCONTEXT WINAPI NdrServerContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg)
     ContextHandle = NDRSContextUnmarshall2(pStubMsg->RpcMsg->Handle,
                                            pStubMsg->Buffer,
                                            pStubMsg->RpcMsg->DataRepresentation,
-                                           NULL, 0);
+                                           NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
     pStubMsg->Buffer += cbNDRContext;
 
     return ContextHandle;
@@ -6339,9 +6929,24 @@ void WINAPI NdrContextHandleSize(PMIDL_STUB_MESSAGE pStubMsg,
 NDR_SCONTEXT WINAPI NdrContextHandleInitialize(PMIDL_STUB_MESSAGE pStubMsg,
                                                PFORMAT_STRING pFormat)
 {
+    RPC_SYNTAX_IDENTIFIER *if_id = NULL;
+    ULONG flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS;
+
     TRACE("(%p, %p)\n", pStubMsg, pFormat);
+
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_SERIALIZE;
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_DONT_SERIALIZE;
+    if (pFormat[1] & NDR_STRICT_CONTEXT_HANDLE)
+    {
+        RPC_SERVER_INTERFACE *sif = pStubMsg->StubDesc->RpcInterfaceInformation;
+        if_id = &sif->InterfaceId;
+    }
+
     return NDRSContextUnmarshall2(pStubMsg->RpcMsg->Handle, NULL,
-                                  pStubMsg->RpcMsg->DataRepresentation, NULL, 0);
+                                  pStubMsg->RpcMsg->DataRepresentation, if_id,
+                                  flags);
 }
 
 void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg,
@@ -6349,6 +6954,9 @@ void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                         NDR_RUNDOWN RundownRoutine,
                                         PFORMAT_STRING pFormat)
 {
+    RPC_SYNTAX_IDENTIFIER *if_id = NULL;
+    ULONG flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS;
+
     TRACE("(%p, %p, %p, %p)\n", pStubMsg, ContextHandle, RundownRoutine, pFormat);
 
     ALIGN_POINTER(pStubMsg->Buffer, 4);
@@ -6360,9 +6968,18 @@ void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg,
         RpcRaiseException(RPC_X_BAD_STUB_DATA);
     }
 
-    /* FIXME: do something with pFormat */
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_SERIALIZE;
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_DONT_SERIALIZE;
+    if (pFormat[1] & NDR_STRICT_CONTEXT_HANDLE)
+    {
+        RPC_SERVER_INTERFACE *sif = pStubMsg->StubDesc->RpcInterfaceInformation;
+        if_id = &sif->InterfaceId;
+    }
+
     NDRSContextMarshall2(pStubMsg->RpcMsg->Handle, ContextHandle,
-                          pStubMsg->Buffer, RundownRoutine, NULL, 0);
+                          pStubMsg->Buffer, RundownRoutine, if_id, flags);
     pStubMsg->Buffer += cbNDRContext;
 }
 
@@ -6370,6 +6987,8 @@ NDR_SCONTEXT WINAPI NdrServerContextNewUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                                   PFORMAT_STRING pFormat)
 {
     NDR_SCONTEXT ContextHandle;
+    RPC_SYNTAX_IDENTIFIER *if_id = NULL;
+    ULONG flags = RPC_CONTEXT_HANDLE_DEFAULT_FLAGS;
 
     TRACE("(%p, %p)\n", pStubMsg, pFormat);
 
@@ -6382,12 +7001,74 @@ NDR_SCONTEXT WINAPI NdrServerContextNewUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
         RpcRaiseException(RPC_X_BAD_STUB_DATA);
     }
 
-    /* FIXME: do something with pFormat */
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_SERIALIZE;
+    if (pFormat[1] & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
+        flags |= RPC_CONTEXT_HANDLE_DONT_SERIALIZE;
+    if (pFormat[1] & NDR_STRICT_CONTEXT_HANDLE)
+    {
+        RPC_SERVER_INTERFACE *sif = pStubMsg->StubDesc->RpcInterfaceInformation;
+        if_id = &sif->InterfaceId;
+    }
+
     ContextHandle = NDRSContextUnmarshall2(pStubMsg->RpcMsg->Handle,
                                            pStubMsg->Buffer,
                                            pStubMsg->RpcMsg->DataRepresentation,
-                                           NULL, 0);
+                                           if_id, flags);
     pStubMsg->Buffer += cbNDRContext;
 
     return ContextHandle;
 }
+
+/***********************************************************************
+ *           NdrCorrelationInitialize [RPCRT4.@]
+ *
+ * Initializes correlation validity checking.
+ *
+ * PARAMS
+ *  pStubMsg    [I] MIDL_STUB_MESSAGE used during unmarshalling.
+ *  pMemory     [I] Pointer to memory to use as a cache.
+ *  CacheSize   [I] Size of the memory pointed to by pMemory.
+ *  Flags       [I] Reserved. Set to zero.
+ *
+ * RETURNS
+ *  Nothing.
+ */
+void WINAPI NdrCorrelationInitialize(PMIDL_STUB_MESSAGE pStubMsg, void *pMemory, ULONG CacheSize, ULONG Flags)
+{
+    FIXME("(%p, %p, %d, 0x%x): stub\n", pStubMsg, pMemory, CacheSize, Flags);
+    pStubMsg->fHasNewCorrDesc = TRUE;
+}
+
+/***********************************************************************
+ *           NdrCorrelationPass [RPCRT4.@]
+ *
+ * Performs correlation validity checking.
+ *
+ * PARAMS
+ *  pStubMsg    [I] MIDL_STUB_MESSAGE used during unmarshalling.
+ *
+ * RETURNS
+ *  Nothing.
+ */
+void WINAPI NdrCorrelationPass(PMIDL_STUB_MESSAGE pStubMsg)
+{
+    FIXME("(%p): stub\n", pStubMsg);
+}
+
+/***********************************************************************
+ *           NdrCorrelationFree [RPCRT4.@]
+ *
+ * Frees any resources used while unmarshalling parameters that need
+ * correlation validity checking.
+ *
+ * PARAMS
+ *  pStubMsg    [I] MIDL_STUB_MESSAGE used during unmarshalling.
+ *
+ * RETURNS
+ *  Nothing.
+ */
+void WINAPI NdrCorrelationFree(PMIDL_STUB_MESSAGE pStubMsg)
+{
+    FIXME("(%p): stub\n", pStubMsg);
+}