netapi32: Fix tests when the machine is on DOMAIN.
[wine] / dlls / rpcrt4 / ndr_stubless.c
1 /*
2  * NDR -Oi,-Oif,-Oicf Interpreter
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003-5 Robert Shearman (for CodeWeavers)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * TODO:
22  *  - Pipes
23  *  - Some types of binding handles
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36
37 #include "objbase.h"
38 #include "rpc.h"
39 #include "rpcproxy.h"
40
41 #include "wine/exception.h"
42 #include "wine/debug.h"
43 #include "wine/rpcfc.h"
44
45 #include "cpsf.h"
46 #include "ndr_misc.h"
47 #include "ndr_stubless.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
50
51 #define NDR_TABLE_MASK 127
52
53 static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
54 {
55     NDR_BUFFERSIZE m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK];
56     if (m) m(pStubMsg, pMemory, pFormat);
57     else
58     {
59         FIXME("format type 0x%x not implemented\n", pFormat[0]);
60         RpcRaiseException(RPC_X_BAD_STUB_DATA);
61     }
62 }
63
64 static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
65 {
66     NDR_MARSHALL m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK];
67     if (m) return m(pStubMsg, pMemory, pFormat);
68     else
69     {
70         FIXME("format type 0x%x not implemented\n", pFormat[0]);
71         RpcRaiseException(RPC_X_BAD_STUB_DATA);
72         return NULL;
73     }
74 }
75
76 static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc)
77 {
78     NDR_UNMARSHALL m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK];
79     if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc);
80     else
81     {
82         FIXME("format type 0x%x not implemented\n", pFormat[0]);
83         RpcRaiseException(RPC_X_BAD_STUB_DATA);
84         return NULL;
85     }
86 }
87
88 static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
89 {
90     NDR_FREE m = NdrFreer[pFormat[0] & NDR_TABLE_MASK];
91     if (m) m(pStubMsg, pMemory, pFormat);
92 }
93
94 #define STUBLESS_UNMARSHAL  1
95 #define STUBLESS_INITOUT    2
96 #define STUBLESS_CALLSERVER 3
97 #define STUBLESS_CALCSIZE   4
98 #define STUBLESS_GETBUFFER  5
99 #define STUBLESS_MARSHAL    6
100 #define STUBLESS_FREE       7
101
102 void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
103 {
104 #if 0 /* these functions are not defined yet */
105     pMessage->pfnAllocate = NdrRpcSmClientAllocate;
106     pMessage->pfnFree = NdrRpcSmClientFree;
107 #endif
108 }
109
110 static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes)
111 {
112     if (param_attributes.MustSize) TRACE(" MustSize");
113     if (param_attributes.MustFree) TRACE(" MustFree");
114     if (param_attributes.IsPipe) TRACE(" IsPipe");
115     if (param_attributes.IsIn) TRACE(" IsIn");
116     if (param_attributes.IsOut) TRACE(" IsOut");
117     if (param_attributes.IsReturn) TRACE(" IsReturn");
118     if (param_attributes.IsBasetype) TRACE(" IsBasetype");
119     if (param_attributes.IsByValue) TRACE(" IsByValue");
120     if (param_attributes.IsSimpleRef) TRACE(" IsSimpleRef");
121     if (param_attributes.IsDontCallFreeInst) TRACE(" IsDontCallFreeInst");
122     if (param_attributes.SaveForAsyncFinish) TRACE(" SaveForAsyncFinish");
123     if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
124 }
125
126 static void WINAPI dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
127 {
128     if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize");
129     if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize");
130     if (Oi2Flags.HasReturn) TRACE(" HasReturn");
131     if (Oi2Flags.HasPipes) TRACE(" HasPipes");
132     if (Oi2Flags.Unused) TRACE(" Unused");
133     if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid");
134     if (Oi2Flags.HasExtensions) TRACE(" HasExtensions");
135     if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle");
136     TRACE("\n");
137 }
138
139 #define ARG_FROM_OFFSET(stubMsg, offset) ((stubMsg).StackTop + (offset))
140
141 static PFORMAT_STRING client_get_handle(
142     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
143     PFORMAT_STRING pFormat, handle_t *phBinding)
144 {
145     /* binding */
146     switch (pProcHeader->handle_type)
147     {
148     /* explicit binding: parse additional section */
149     case RPC_FC_BIND_EXPLICIT:
150         switch (*pFormat) /* handle_type */
151         {
152         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
153             {
154                 const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
155
156                 TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
157
158                 if (pDesc->flag) /* pointer to binding */
159                     *phBinding = **(handle_t **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
160                 else
161                     *phBinding = *(handle_t *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
162                 return pFormat + sizeof(NDR_EHD_PRIMITIVE);
163             }
164         case RPC_FC_BIND_GENERIC: /* explicit generic */
165             {
166                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
167                 void *pObject = NULL;
168                 void *pArg;
169                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
170
171                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
172
173                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
174                     pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
175                 else
176                     pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
177                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
178                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
179                 *phBinding = pGenPair->pfnBind(pObject);
180                 return pFormat + sizeof(NDR_EHD_GENERIC);
181             }
182         case RPC_FC_BIND_CONTEXT: /* explicit context */
183             {
184                 const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
185                 NDR_CCONTEXT context_handle;
186                 TRACE("Explicit bind context\n");
187                 if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
188                 {
189                     TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
190                     context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
191                 }
192                 else
193                     context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
194                 if ((pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) &&
195                     !context_handle)
196                 {
197                     ERR("null context handle isn't allowed\n");
198                     RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
199                     return NULL;
200                 }
201                 *phBinding = NDRCContextBinding(context_handle);
202                 /* FIXME: should we store this structure in stubMsg.pContext? */
203                 return pFormat + sizeof(NDR_EHD_CONTEXT);
204             }
205         default:
206             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
207             RpcRaiseException(RPC_X_BAD_STUB_DATA);
208         }
209         break;
210     case RPC_FC_BIND_GENERIC: /* implicit generic */
211         FIXME("RPC_FC_BIND_GENERIC\n");
212         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
213         break;
214     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
215         TRACE("Implicit primitive handle\n");
216         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
217         break;
218     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
219         FIXME("RPC_FC_CALLBACK_HANDLE\n");
220         break;
221     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
222         /* strictly speaking, it isn't necessary to set hBinding here
223          * since it isn't actually used (hence the automatic in its name),
224          * but then why does MIDL generate a valid entry in the
225          * MIDL_STUB_DESC for it? */
226         TRACE("Implicit auto handle\n");
227         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
228         break;
229     default:
230         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
231         RpcRaiseException(RPC_X_BAD_STUB_DATA);
232     }
233     return pFormat;
234 }
235
236 static void client_free_handle(
237     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
238     PFORMAT_STRING pFormat, handle_t hBinding)
239 {
240     /* binding */
241     switch (pProcHeader->handle_type)
242     {
243     /* explicit binding: parse additional section */
244     case RPC_FC_BIND_EXPLICIT:
245         switch (*pFormat) /* handle_type */
246         {
247         case RPC_FC_BIND_GENERIC: /* explicit generic */
248             {
249                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
250                 void *pObject = NULL;
251                 void *pArg;
252                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
253
254                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
255
256                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
257                     pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
258                 else
259                     pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
260                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
261                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
262                 pGenPair->pfnUnbind(pObject, hBinding);
263                 break;
264             }
265         case RPC_FC_BIND_CONTEXT: /* explicit context */
266         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
267             break;
268         default:
269             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
270             RpcRaiseException(RPC_X_BAD_STUB_DATA);
271         }
272         break;
273     case RPC_FC_BIND_GENERIC: /* implicit generic */
274         FIXME("RPC_FC_BIND_GENERIC\n");
275         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
276         break;
277     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
278     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
279     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
280         break;
281     default:
282         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
283         RpcRaiseException(RPC_X_BAD_STUB_DATA);
284     }
285 }
286
287 static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
288     int phase, unsigned short number_of_params, unsigned char *pRetVal)
289 {
290     /* current format string offset */
291     int current_offset = 0;
292     /* current stack offset */
293     unsigned short current_stack_offset = 0;
294     /* counter */
295     unsigned short i;
296
297     for (i = 0; i < number_of_params; i++)
298     {
299         const NDR_PARAM_OIF_BASETYPE *pParam =
300             (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
301         unsigned char * pArg;
302
303         current_stack_offset = pParam->stack_offset;
304         pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset);
305
306         TRACE("param[%d]: new format\n", i);
307         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
308         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
309         TRACE("\tmemory addr (before): %p\n", pArg);
310
311         if (pParam->param_attributes.IsBasetype)
312         {
313             const unsigned char * pTypeFormat =
314                 &pParam->type_format_char;
315
316             if (pParam->param_attributes.IsSimpleRef)
317                 pArg = *(unsigned char **)pArg;
318
319             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
320
321             switch (phase)
322             {
323             case PROXY_CALCSIZE:
324                 if (pParam->param_attributes.IsIn)
325                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
326                 break;
327             case PROXY_MARSHAL:
328                 if (pParam->param_attributes.IsIn)
329                     call_marshaller(pStubMsg, pArg, pTypeFormat);
330                 break;
331             case PROXY_UNMARSHAL:
332                 if (pParam->param_attributes.IsOut)
333                 {
334                     if (pParam->param_attributes.IsReturn)
335                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
336                     else
337                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
338                     TRACE("pRetVal = %p\n", pRetVal);
339                 }
340                 break;
341             default:
342                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
343             }
344
345             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
346         }
347         else
348         {
349             const NDR_PARAM_OIF_OTHER *pParamOther =
350                 (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
351
352             const unsigned char * pTypeFormat =
353                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
354
355             /* if a simple ref pointer then we have to do the
356              * check for the pointer being non-NULL. */
357             if (pParam->param_attributes.IsSimpleRef)
358             {
359                 if (!*(unsigned char **)pArg)
360                     RpcRaiseException(RPC_X_NULL_REF_POINTER);
361             }
362
363             TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat);
364
365             switch (phase)
366             {
367             case PROXY_CALCSIZE:
368                 if (pParam->param_attributes.IsIn)
369                 {
370                     if (pParam->param_attributes.IsByValue)
371                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
372                     else
373                         call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
374                 }
375                 break;
376             case PROXY_MARSHAL:
377                 if (pParam->param_attributes.IsIn)
378                 {
379                     if (pParam->param_attributes.IsByValue)
380                         call_marshaller(pStubMsg, pArg, pTypeFormat);
381                     else
382                         call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
383                 }
384                 break;
385             case PROXY_UNMARSHAL:
386                 if (pParam->param_attributes.IsOut)
387                 {
388                     if (pParam->param_attributes.IsReturn)
389                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
390                     else if (pParam->param_attributes.IsByValue)
391                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
392                     else
393                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
394                 }
395                 break;
396             default:
397                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
398             }
399
400             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
401         }
402         TRACE("\tmemory addr (after): %p\n", pArg);
403     }
404 }
405
406 static unsigned int type_stack_size(unsigned char fc)
407 {
408     switch (fc)
409     {
410     case RPC_FC_BYTE:
411     case RPC_FC_CHAR:
412     case RPC_FC_SMALL:
413     case RPC_FC_USMALL:
414         return sizeof(char);
415     case RPC_FC_WCHAR:
416     case RPC_FC_SHORT:
417     case RPC_FC_USHORT:
418         return sizeof(short);
419     case RPC_FC_LONG:
420     case RPC_FC_ULONG:
421     case RPC_FC_ENUM16:
422     case RPC_FC_ENUM32:
423         return sizeof(int);
424     case RPC_FC_FLOAT:
425         return sizeof(float);
426     case RPC_FC_DOUBLE:
427         return sizeof(double);
428     case RPC_FC_HYPER:
429         return sizeof(ULONGLONG);
430     case RPC_FC_ERROR_STATUS_T:
431         return sizeof(error_status_t);
432     case RPC_FC_IGNORE:
433         return sizeof(void *);
434     default:
435         ERR("invalid base type 0x%x\n", fc);
436         RpcRaiseException(RPC_S_INTERNAL_ERROR);
437     }
438 }
439
440 static void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg,
441     PFORMAT_STRING pFormat, int phase, unsigned short stack_size,
442     unsigned char *pRetVal, BOOL object_proc)
443 {
444     /* current format string offset */
445     int current_offset = 0;
446     /* current stack offset */
447     unsigned short current_stack_offset = 0;
448     /* counter */
449     unsigned short i;
450
451     /* NOTE: V1 style format doesn't terminate on the number_of_params
452      * condition as it doesn't have this attribute. Instead it
453      * terminates when the stack size given in the header is exceeded.
454      */
455     for (i = 0; TRUE; i++)
456     {
457         const NDR_PARAM_OI_BASETYPE *pParam =
458             (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
459         /* note: current_stack_offset starts after the This pointer
460          * if present, so adjust this */
461         unsigned short current_stack_offset_adjusted = current_stack_offset +
462             (object_proc ? sizeof(void *) : 0);
463         unsigned char * pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset_adjusted);
464
465         /* no more parameters; exit loop */
466         if (current_stack_offset_adjusted >= stack_size)
467             break;
468
469         TRACE("param[%d]: old format\n", i);
470         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
471         TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
472         TRACE("\tmemory addr (before): %p\n", pArg);
473
474         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
475             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
476         {
477             const unsigned char * pTypeFormat =
478                 &pParam->type_format_char;
479
480             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
481
482             switch (phase)
483             {
484             case PROXY_CALCSIZE:
485                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
486                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
487                 break;
488             case PROXY_MARSHAL:
489                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
490                     call_marshaller(pStubMsg, pArg, pTypeFormat);
491                 break;
492             case PROXY_UNMARSHAL:
493                 if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
494                 {
495                     if (pParam->param_direction & RPC_FC_RETURN_PARAM)
496                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
497                     else
498                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
499                 }
500                 break;
501             default:
502                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
503             }
504
505             current_stack_offset += type_stack_size(*pTypeFormat);
506             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
507         }
508         else
509         {
510             const NDR_PARAM_OI_OTHER *pParamOther = 
511                 (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
512
513             const unsigned char *pTypeFormat =
514                 &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
515
516             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
517
518             switch (phase)
519             {
520             case PROXY_CALCSIZE:
521                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
522                     pParam->param_direction & RPC_FC_IN_OUT_PARAM)
523                     call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
524                 break;
525             case PROXY_MARSHAL:
526                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
527                     pParam->param_direction & RPC_FC_IN_OUT_PARAM)
528                     call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
529                 break;
530             case PROXY_UNMARSHAL:
531                 if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
532                     pParam->param_direction == RPC_FC_OUT_PARAM)
533                     call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
534                 else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
535                     call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
536                 break;
537             default:
538                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
539             }
540
541             current_stack_offset += pParamOther->stack_size * sizeof(INT);
542             current_offset += sizeof(NDR_PARAM_OI_OTHER);
543         }
544         TRACE("\tmemory addr (after): %p\n", pArg);
545     }
546 }
547
548 /* the return type should be CLIENT_CALL_RETURN, but this is incompatible
549  * with the way gcc returns structures. "void *" should be the largest type
550  * that MIDL should allow you to return anyway */
551 LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, ...)
552 {
553     /* pointer to start of stack where arguments start */
554     RPC_MESSAGE rpcMsg;
555     MIDL_STUB_MESSAGE stubMsg;
556     handle_t hBinding = NULL;
557     /* procedure number */
558     unsigned short procedure_number;
559     /* size of stack */
560     unsigned short stack_size;
561     /* number of parameters. optional for client to give it to us */
562     unsigned char number_of_params = ~0;
563     /* cache of Oif_flags from v2 procedure header */
564     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
565     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
566     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
567     /* the type of pass we are currently doing */
568     int phase;
569     /* header for procedure string */
570     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
571     /* -Oif or -Oicf generated format */
572     BOOL bV2Format = FALSE;
573     /* the value to return to the client from the remote procedure */
574     LONG_PTR RetVal = 0;
575     /* the pointer to the object when in OLE mode */
576     void * This = NULL;
577     PFORMAT_STRING pHandleFormat;
578     /* correlation cache */
579     unsigned long NdrCorrCache[256];
580
581     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
582
583     /* Later NDR language versions probably won't be backwards compatible */
584     if (pStubDesc->Version > 0x50002)
585     {
586         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
587         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
588     }
589
590     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
591     {
592         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
593         stack_size = pProcHeader->stack_size;
594         procedure_number = pProcHeader->proc_num;
595         pFormat += sizeof(NDR_PROC_HEADER_RPC);
596     }
597     else
598     {
599         stack_size = pProcHeader->stack_size;
600         procedure_number = pProcHeader->proc_num;
601         pFormat += sizeof(NDR_PROC_HEADER);
602     }
603     TRACE("stack size: 0x%x\n", stack_size);
604     TRACE("proc num: %d\n", procedure_number);
605
606     /* create the full pointer translation tables, if requested */
607     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
608         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
609
610     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
611     {
612         /* object is always the first argument */
613         This = **(void *const **)(&pFormat+1);
614         NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number);
615     }
616     else
617         NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number);
618
619     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
620     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
621
622     /* needed for conformance of top-level objects */
623 #ifdef __i386__
624     stubMsg.StackTop = *(unsigned char **)(&pFormat+1);
625 #else
626 # warning Stack not retrieved for your CPU architecture
627 #endif
628
629     pHandleFormat = pFormat;
630
631     /* we only need a handle if this isn't an object method */
632     if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT))
633     {
634         pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding);
635         if (!pFormat) return 0;
636     }
637
638     bV2Format = (pStubDesc->Version >= 0x20000);
639
640     if (bV2Format)
641     {
642         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
643             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
644
645         Oif_flags = pOIFHeader->Oi2Flags;
646         number_of_params = pOIFHeader->number_of_params;
647
648         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
649     }
650
651     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
652
653     if (Oif_flags.HasExtensions)
654     {
655         const NDR_PROC_HEADER_EXTS *pExtensions =
656             (const NDR_PROC_HEADER_EXTS *)pFormat;
657         ext_flags = pExtensions->Flags2;
658         pFormat += pExtensions->Size;
659     }
660
661     stubMsg.BufferLength = 0;
662
663     /* store the RPC flags away */
664     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
665         rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
666
667     /* use alternate memory allocation routines */
668     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
669         NdrRpcSmSetClientToOsf(&stubMsg);
670
671     if (Oif_flags.HasPipes)
672     {
673         FIXME("pipes not supported yet\n");
674         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
675         /* init pipes package */
676         /* NdrPipesInitialize(...) */
677     }
678     if (ext_flags.HasNewCorrDesc)
679     {
680         /* initialize extra correlation package */
681         NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
682     }
683
684     /* order of phases:
685      * 1. PROXY_CALCSIZE - calculate the buffer size
686      * 2. PROXY_GETBUFFER - allocate the buffer
687      * 3. PROXY_MARHSAL - marshal [in] params into the buffer
688      * 4. PROXY_SENDRECEIVE - send/receive buffer
689      * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
690      */
691     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
692     {
693         __TRY
694         {
695             for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
696             {
697                 TRACE("phase = %d\n", phase);
698                 switch (phase)
699                 {
700                 case PROXY_GETBUFFER:
701                     /* allocate the buffer */
702                     NdrProxyGetBuffer(This, &stubMsg);
703                     break;
704                 case PROXY_SENDRECEIVE:
705                     /* send the [in] params and receive the [out] and [retval]
706                      * params */
707                     NdrProxySendReceive(This, &stubMsg);
708
709                     /* convert strings, floating point values and endianess into our
710                      * preferred format */
711                     if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
712                         NdrConvert(&stubMsg, pFormat);
713
714                     break;
715                 case PROXY_CALCSIZE:
716                 case PROXY_MARSHAL:
717                 case PROXY_UNMARSHAL:
718                     if (bV2Format)
719                         client_do_args(&stubMsg, pFormat, phase, number_of_params,
720                             (unsigned char *)&RetVal);
721                     else
722                         client_do_args_old_format(&stubMsg, pFormat, phase, stack_size,
723                             (unsigned char *)&RetVal,
724                             (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
725                     break;
726                 default:
727                     ERR("shouldn't reach here. phase %d\n", phase);
728                     break;
729                 }
730             }
731         }
732         __EXCEPT_ALL
733         {
734             RetVal = NdrProxyErrorHandler(GetExceptionCode());
735         }
736         __ENDTRY
737     }
738     else
739     {
740         /* order of phases:
741          * 1. PROXY_CALCSIZE - calculate the buffer size
742          * 2. PROXY_GETBUFFER - allocate the buffer
743          * 3. PROXY_MARHSAL - marshal [in] params into the buffer
744          * 4. PROXY_SENDRECEIVE - send/receive buffer
745          * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
746          */
747         for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
748         {
749             TRACE("phase = %d\n", phase);
750             switch (phase)
751             {
752             case PROXY_GETBUFFER:
753                 /* allocate the buffer */
754                 if (Oif_flags.HasPipes)
755                     /* NdrGetPipeBuffer(...) */
756                     FIXME("pipes not supported yet\n");
757                 else
758                 {
759                     if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
760 #if 0
761                         NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
762 #else
763                         FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
764 #endif
765                     else
766                         NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
767                 }
768                 break;
769             case PROXY_SENDRECEIVE:
770                 /* send the [in] params and receive the [out] and [retval]
771                  * params */
772                 if (Oif_flags.HasPipes)
773                     /* NdrPipesSendReceive(...) */
774                     FIXME("pipes not supported yet\n");
775                 else
776                 {
777                     if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
778 #if 0
779                         NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
780 #else
781                         FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
782 #endif
783                     else
784                         NdrSendReceive(&stubMsg, stubMsg.Buffer);
785                 }
786
787                 /* convert strings, floating point values and endianess into our
788                  * preferred format */
789                 if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
790                     NdrConvert(&stubMsg, pFormat);
791
792                 break;
793             case PROXY_CALCSIZE:
794             case PROXY_MARSHAL:
795             case PROXY_UNMARSHAL:
796                 if (bV2Format)
797                     client_do_args(&stubMsg, pFormat, phase, number_of_params,
798                         (unsigned char *)&RetVal);
799                 else
800                     client_do_args_old_format(&stubMsg, pFormat, phase, stack_size,
801                         (unsigned char *)&RetVal,
802                         (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
803                 break;
804             default:
805                 ERR("shouldn't reach here. phase %d\n", phase);
806                 break;
807             }
808         }
809     }
810
811     if (ext_flags.HasNewCorrDesc)
812     {
813         /* free extra correlation package */
814         NdrCorrelationFree(&stubMsg);
815     }
816
817     if (Oif_flags.HasPipes)
818     {
819         /* NdrPipesDone(...) */
820     }
821
822     /* free the full pointer translation tables */
823     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
824         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
825
826     /* free marshalling buffer */
827     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
828         NdrProxyFreeBuffer(This, &stubMsg);
829     else
830     {
831         NdrFreeBuffer(&stubMsg);
832         client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding);
833     }
834
835     TRACE("RetVal = 0x%lx\n", RetVal);
836
837     return RetVal;
838 }
839
840 /* Calls a function with the specified arguments, restoring the stack
841  * properly afterwards as we don't know the calling convention of the
842  * function */
843 #if defined __i386__ && defined _MSC_VER
844 __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
845 {
846     __asm
847     {
848         push ebp
849         push edi            ; Save registers
850         push esi
851         mov ebp, esp
852         mov eax, [ebp+16]   ; Get stack size
853         sub esp, eax        ; Make room in stack for arguments
854         mov edi, esp
855         mov ecx, eax
856         mov esi, [ebp+12]
857         shr ecx, 2
858         cld
859         rep movsd           ; Copy dword blocks
860         call [ebp+8]        ; Call function
861         lea esp, [ebp-8]    ; Restore stack
862         pop esi             ; Restore registers
863         pop edi
864         pop ebp
865         ret
866     }
867 }
868 #elif defined __i386__ && defined __GNUC__
869 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
870 __ASM_GLOBAL_FUNC(call_server_func,
871     "pushl %ebp\n\t"
872     "movl %esp, %ebp\n\t"
873     "pushl %edi\n\t"            /* Save registers */
874     "pushl %esi\n\t"
875     "movl 16(%ebp), %eax\n\t"   /* Get stack size */
876     "subl %eax, %esp\n\t"       /* Make room in stack for arguments */
877     "andl $~15, %esp\n\t"       /* Make sure stack has 16-byte alignment for Mac OS X */
878     "movl %esp, %edi\n\t"
879     "movl %eax, %ecx\n\t"
880     "movl 12(%ebp), %esi\n\t"
881     "shrl $2, %ecx\n\t"         /* divide by 4 */
882     "cld\n\t"
883     "rep; movsl\n\t"            /* Copy dword blocks */
884     "call *8(%ebp)\n\t"         /* Call function */
885     "leal -8(%ebp), %esp\n\t"   /* Restore stack */
886     "popl %esi\n\t"             /* Restore registers */
887     "popl %edi\n\t"
888     "popl %ebp\n\t"
889     "ret\n" )
890 #else
891 #warning call_server_func not implemented for your architecture
892 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
893 {
894     FIXME("Not implemented for your architecture\n");
895     return 0;
896 }
897 #endif
898
899 static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
900 {
901     DWORD size;
902     switch(*pFormat)
903     {
904     case RPC_FC_STRUCT:
905         size = *(const WORD*)(pFormat + 2);
906         break;
907     case RPC_FC_CARRAY:
908         size = *(const WORD*)(pFormat + 2);
909         ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
910         size *= pStubMsg->MaxCount;
911         break;
912     case RPC_FC_SMFARRAY:
913         size = *(const WORD*)(pFormat + 2);
914         break;
915     case RPC_FC_LGFARRAY:
916         size = *(const DWORD*)(pFormat + 2);
917         break;
918     case RPC_FC_BOGUS_ARRAY:
919         pFormat = ComputeConformance(pStubMsg, NULL, pFormat + 4, *(const WORD*)&pFormat[2]);
920         TRACE("conformance = %ld\n", pStubMsg->MaxCount);
921         pFormat = ComputeVariance(pStubMsg, NULL, pFormat, pStubMsg->MaxCount);
922         size = ComplexStructSize(pStubMsg, pFormat);
923         size *= pStubMsg->MaxCount;
924         break;
925     default:
926         FIXME("Unhandled type %02x\n", *pFormat);
927         /* fallthrough */
928     case RPC_FC_RP:
929         size = sizeof(void *);
930         break;
931     }
932     return size;
933 }
934
935 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
936                               PFORMAT_STRING pFormat, int phase,
937                               unsigned char *args,
938                               unsigned short number_of_params)
939 {
940     /* counter */
941     unsigned short i;
942     /* current format string offset */
943     int current_offset = 0;
944     /* current stack offset */
945     unsigned short current_stack_offset = 0;
946     /* location to put retval into */
947     LONG_PTR *retval_ptr = NULL;
948
949     for (i = 0; i < number_of_params; i++)
950     {
951         const NDR_PARAM_OIF_BASETYPE *pParam =
952         (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
953         unsigned char *pArg;
954
955         current_stack_offset = pParam->stack_offset;
956         pArg = args + current_stack_offset;
957
958         TRACE("param[%d]: new format\n", i);
959         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
960         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
961         TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
962
963         if (pParam->param_attributes.IsBasetype)
964         {
965             const unsigned char *pTypeFormat =
966             &pParam->type_format_char;
967
968             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
969
970             /* make a note of the address of the return value parameter for later */
971             if (pParam->param_attributes.IsReturn)
972                 retval_ptr = (LONG_PTR *)pArg;
973
974             switch (phase)
975             {
976                 case STUBLESS_MARSHAL:
977                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
978                     {
979                         if (pParam->param_attributes.IsSimpleRef)
980                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
981                         else
982                             call_marshaller(pStubMsg, pArg, pTypeFormat);
983                     }
984                     break;
985                 case STUBLESS_FREE:
986                     if (pParam->param_attributes.ServerAllocSize)
987                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
988                     break;
989                 case STUBLESS_INITOUT:
990                     break;
991                 case STUBLESS_UNMARSHAL:
992                     if (pParam->param_attributes.ServerAllocSize)
993                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
994                                                    pParam->param_attributes.ServerAllocSize * 8);
995
996                     if (pParam->param_attributes.IsIn)
997                     {
998                         if (pParam->param_attributes.IsSimpleRef)
999                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1000                         else
1001                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1002                     }
1003                     break;
1004                 case STUBLESS_CALCSIZE:
1005                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1006                     {
1007                         if (pParam->param_attributes.IsSimpleRef)
1008                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1009                         else
1010                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1011                     }
1012                     break;
1013                 default:
1014                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1015             }
1016
1017             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
1018         }
1019         else
1020         {
1021             const NDR_PARAM_OIF_OTHER *pParamOther =
1022             (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
1023
1024             const unsigned char * pTypeFormat =
1025                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
1026
1027             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
1028
1029             switch (phase)
1030             {
1031                 case STUBLESS_MARSHAL:
1032                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1033                     {
1034                         if (pParam->param_attributes.IsByValue)
1035                             call_marshaller(pStubMsg, pArg, pTypeFormat);
1036                         else
1037                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1038                     }
1039                     break;
1040                 case STUBLESS_FREE:
1041                     if (pParam->param_attributes.MustFree)
1042                     {
1043                         if (pParam->param_attributes.IsByValue)
1044                             call_freer(pStubMsg, pArg, pTypeFormat);
1045                         else
1046                             call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1047                     }
1048
1049                     if (pParam->param_attributes.IsOut &&
1050                         !pParam->param_attributes.IsIn &&
1051                         !pParam->param_attributes.IsByValue &&
1052                         !pParam->param_attributes.ServerAllocSize)
1053                     {
1054                         pStubMsg->pfnFree(*(void **)pArg);
1055                     }
1056
1057                     if (pParam->param_attributes.ServerAllocSize)
1058                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1059                     break;
1060                 case STUBLESS_INITOUT:
1061                     if (!pParam->param_attributes.IsIn &&
1062                              pParam->param_attributes.IsOut &&
1063                              !pParam->param_attributes.ServerAllocSize &&
1064                              !pParam->param_attributes.IsByValue)
1065                     {
1066                         DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1067
1068                         if(size)
1069                         {
1070                             *(void **)pArg = NdrAllocate(pStubMsg, size);
1071                             memset(*(void **)pArg, 0, size);
1072                         }
1073                     }
1074                     break;
1075                 case STUBLESS_UNMARSHAL:
1076                     if (pParam->param_attributes.ServerAllocSize)
1077                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1078                                                    pParam->param_attributes.ServerAllocSize * 8);
1079
1080                     if (pParam->param_attributes.IsIn)
1081                     {
1082                         if (pParam->param_attributes.IsByValue)
1083                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1084                         else
1085                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1086                     }
1087                     break;
1088                 case STUBLESS_CALCSIZE:
1089                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1090                     {
1091                         if (pParam->param_attributes.IsByValue)
1092                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1093                         else
1094                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1095                     }
1096                     break;
1097                 default:
1098                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1099             }
1100
1101             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
1102         }
1103         TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1104     }
1105
1106     return retval_ptr;
1107 }
1108
1109 static LONG_PTR *stub_do_old_args(MIDL_STUB_MESSAGE *pStubMsg,
1110                                   PFORMAT_STRING pFormat, int phase,
1111                                   unsigned char *args,
1112                                   unsigned short stack_size, BOOL object)
1113 {
1114     /* counter */
1115     unsigned short i;
1116     /* current format string offset */
1117     int current_offset = 0;
1118     /* current stack offset */
1119     unsigned short current_stack_offset = 0;
1120     /* location to put retval into */
1121     LONG_PTR *retval_ptr = NULL;
1122
1123     for (i = 0; TRUE; i++)
1124     {
1125         const NDR_PARAM_OI_BASETYPE *pParam =
1126         (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
1127         /* note: current_stack_offset starts after the This pointer
1128          * if present, so adjust this */
1129         unsigned short current_stack_offset_adjusted = current_stack_offset +
1130             (object ? sizeof(void *) : 0);
1131         unsigned char *pArg = args + current_stack_offset_adjusted;
1132
1133         /* no more parameters; exit loop */
1134         if (current_stack_offset_adjusted >= stack_size)
1135             break;
1136
1137         TRACE("param[%d]: old format\n", i);
1138         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
1139         TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
1140
1141         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
1142             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1143         {
1144             const unsigned char *pTypeFormat =
1145             &pParam->type_format_char;
1146
1147             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
1148
1149             if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1150                 retval_ptr = (LONG_PTR *)pArg;
1151
1152             switch (phase)
1153             {
1154                 case STUBLESS_MARSHAL:
1155                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1156                         call_marshaller(pStubMsg, pArg, pTypeFormat);
1157                     break;
1158                 case STUBLESS_FREE:
1159                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1160                         call_freer(pStubMsg, pArg, pTypeFormat);
1161                     break;
1162                 case STUBLESS_UNMARSHAL:
1163                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1164                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1165                     break;
1166                 case STUBLESS_CALCSIZE:
1167                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1168                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1169                     break;
1170                 default:
1171                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1172             }
1173
1174             current_stack_offset += type_stack_size(*pTypeFormat);
1175             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
1176         }
1177         else
1178         {
1179             const NDR_PARAM_OI_OTHER *pParamOther =
1180             (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
1181
1182             const unsigned char * pTypeFormat =
1183                 &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
1184
1185             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
1186
1187             if (pParam->param_direction == RPC_FC_RETURN_PARAM)
1188                 retval_ptr = (LONG_PTR *)pArg;
1189
1190             switch (phase)
1191             {
1192                 case STUBLESS_MARSHAL:
1193                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1194                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1195                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1196                         call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1197                     break;
1198                 case STUBLESS_FREE:
1199                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1200                         pParam->param_direction == RPC_FC_IN_PARAM)
1201                         call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1202                     else if (pParam->param_direction == RPC_FC_OUT_PARAM)
1203                         pStubMsg->pfnFree(*(void **)pArg);
1204                     break;
1205                 case STUBLESS_INITOUT:
1206                     if (pParam->param_direction == RPC_FC_OUT_PARAM)
1207                     {
1208                         DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1209
1210                         if(size)
1211                         {
1212                             *(void **)pArg = NdrAllocate(pStubMsg, size);
1213                             memset(*(void **)pArg, 0, size);
1214                         }
1215                     }
1216                     break;
1217                 case STUBLESS_UNMARSHAL:
1218                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1219                         pParam->param_direction == RPC_FC_IN_PARAM)
1220                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1221                     break;
1222                 case STUBLESS_CALCSIZE:
1223                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1224                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1225                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1226                         call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1227                     break;
1228                 default:
1229                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1230             }
1231
1232             current_stack_offset += pParamOther->stack_size * sizeof(INT);
1233             current_offset += sizeof(NDR_PARAM_OI_OTHER);
1234         }
1235     }
1236
1237     return retval_ptr;
1238 }
1239
1240 /***********************************************************************
1241  *            NdrStubCall2 [RPCRT4.@]
1242  *
1243  * Unmarshals [in] parameters, calls either a method in an object or a server
1244  * function, marshals any [out] parameters and frees any allocated data.
1245  *
1246  * NOTES
1247  *  Used by stubless MIDL-generated code.
1248  */
1249 LONG WINAPI NdrStubCall2(
1250     struct IRpcStubBuffer * pThis,
1251     struct IRpcChannelBuffer * pChannel,
1252     PRPC_MESSAGE pRpcMsg,
1253     DWORD * pdwStubPhase)
1254 {
1255     const MIDL_SERVER_INFO *pServerInfo;
1256     const MIDL_STUB_DESC *pStubDesc;
1257     PFORMAT_STRING pFormat;
1258     MIDL_STUB_MESSAGE stubMsg;
1259     /* pointer to start of stack to pass into stub implementation */
1260     unsigned char * args;
1261     /* size of stack */
1262     unsigned short stack_size;
1263     /* number of parameters. optional for client to give it to us */
1264     unsigned char number_of_params = ~0;
1265     /* cache of Oif_flags from v2 procedure header */
1266     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1267     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1268     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1269     /* the type of pass we are currently doing */
1270     int phase;
1271     /* header for procedure string */
1272     const NDR_PROC_HEADER *pProcHeader;
1273     /* offset in format string for start of params */
1274     int parameter_start_offset;
1275     /* current format string offset */
1276     int current_offset;
1277     /* -Oif or -Oicf generated format */
1278     BOOL bV2Format = FALSE;
1279     /* location to put retval into */
1280     LONG_PTR *retval_ptr = NULL;
1281
1282     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1283
1284     if (pThis)
1285         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1286     else
1287         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1288
1289     pStubDesc = pServerInfo->pStubDesc;
1290     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1291     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1292
1293     /* Later NDR language versions probably won't be backwards compatible */
1294     if (pStubDesc->Version > 0x50002)
1295     {
1296         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1297         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1298     }
1299
1300     /* create the full pointer translation tables, if requested */
1301     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1302         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1303
1304     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1305     {
1306         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1307         stack_size = pProcHeader->stack_size;
1308         current_offset = sizeof(NDR_PROC_HEADER_RPC);
1309
1310     }
1311     else
1312     {
1313         stack_size = pProcHeader->stack_size;
1314         current_offset = sizeof(NDR_PROC_HEADER);
1315     }
1316
1317     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1318
1319     /* binding */
1320     switch (pProcHeader->handle_type)
1321     {
1322     /* explicit binding: parse additional section */
1323     case RPC_FC_BIND_EXPLICIT:
1324         switch (pFormat[current_offset]) /* handle_type */
1325         {
1326         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
1327             current_offset += sizeof(NDR_EHD_PRIMITIVE);
1328             break;
1329         case RPC_FC_BIND_GENERIC: /* explicit generic */
1330             current_offset += sizeof(NDR_EHD_GENERIC);
1331             break;
1332         case RPC_FC_BIND_CONTEXT: /* explicit context */
1333             current_offset += sizeof(NDR_EHD_CONTEXT);
1334             break;
1335         default:
1336             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1337             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1338         }
1339         break;
1340     case RPC_FC_BIND_GENERIC: /* implicit generic */
1341     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
1342     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
1343     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
1344         break;
1345     default:
1346         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1347         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1348     }
1349
1350     bV2Format = (pStubDesc->Version >= 0x20000);
1351
1352     if (bV2Format)
1353     {
1354         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1355             (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset];
1356
1357         Oif_flags = pOIFHeader->Oi2Flags;
1358         number_of_params = pOIFHeader->number_of_params;
1359
1360         current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1361     }
1362
1363     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
1364
1365     if (Oif_flags.HasExtensions)
1366     {
1367         const NDR_PROC_HEADER_EXTS *pExtensions =
1368             (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset];
1369         ext_flags = pExtensions->Flags2;
1370         current_offset += pExtensions->Size;
1371     }
1372
1373     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1374         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1375     else
1376         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1377
1378     /* store the RPC flags away */
1379     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1380         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1381
1382     /* use alternate memory allocation routines */
1383     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1384 #if 0
1385           NdrRpcSsEnableAllocate(&stubMsg);
1386 #else
1387           FIXME("Set RPCSS memory allocation routines\n");
1388 #endif
1389
1390     if (Oif_flags.HasPipes)
1391     {
1392         FIXME("pipes not supported yet\n");
1393         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1394         /* init pipes package */
1395         /* NdrPipesInitialize(...) */
1396     }
1397     if (ext_flags.HasNewCorrDesc)
1398     {
1399         /* initialize extra correlation package */
1400         FIXME("new correlation description not implemented\n");
1401         stubMsg.fHasNewCorrDesc = TRUE;
1402     }
1403
1404     /* convert strings, floating point values and endianess into our
1405      * preferred format */
1406     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1407         NdrConvert(&stubMsg, pFormat);
1408
1409     parameter_start_offset = current_offset;
1410
1411     TRACE("allocating memory for stack of size %x\n", stack_size);
1412
1413     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1414     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1415
1416     /* add the implicit This pointer as the first arg to the function if we
1417      * are calling an object method */
1418     if (pThis)
1419         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1420
1421     /* order of phases:
1422      * 1. STUBLESS_UNMARHSAL - unmarshal [in] params from buffer
1423      * 2. STUBLESS_CALLSERVER - send/receive buffer
1424      * 3. STUBLESS_CALCSIZE - get [out] buffer size
1425      * 4. STUBLESS_GETBUFFER - allocate [out] buffer
1426      * 5. STUBLESS_MARHSAL - marshal [out] params to buffer
1427      */
1428     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1429     {
1430         TRACE("phase = %d\n", phase);
1431         switch (phase)
1432         {
1433         case STUBLESS_CALLSERVER:
1434             /* call the server function */
1435             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1436                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1437             else
1438             {
1439                 SERVER_ROUTINE func;
1440                 LONG_PTR retval;
1441
1442                 if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1443                 {
1444                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1445                     func = vtbl[pRpcMsg->ProcNum];
1446                 }
1447                 else
1448                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1449
1450                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1451                 retval = call_server_func(func, args, stack_size);
1452
1453                 if (retval_ptr)
1454                 {
1455                     TRACE("stub implementation returned 0x%lx\n", retval);
1456                     *retval_ptr = retval;
1457                 }
1458                 else
1459                     TRACE("void stub implementation\n");
1460             }
1461
1462             stubMsg.Buffer = NULL;
1463             stubMsg.BufferLength = 0;
1464
1465             break;
1466         case STUBLESS_GETBUFFER:
1467             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1468                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1469             else
1470             {
1471                 RPC_STATUS Status;
1472
1473                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1474                 /* allocate buffer for [out] and [ret] params */
1475                 Status = I_RpcGetBuffer(pRpcMsg); 
1476                 if (Status)
1477                     RpcRaiseException(Status);
1478                 stubMsg.Buffer = pRpcMsg->Buffer;
1479             }
1480             break;
1481         case STUBLESS_UNMARSHAL:
1482         case STUBLESS_INITOUT:
1483         case STUBLESS_CALCSIZE:
1484         case STUBLESS_MARSHAL:
1485         case STUBLESS_FREE:
1486             if (bV2Format)
1487                 retval_ptr = stub_do_args(&stubMsg, &pFormat[parameter_start_offset],
1488                                           phase, args, number_of_params);
1489             else
1490                 retval_ptr = stub_do_old_args(&stubMsg, &pFormat[parameter_start_offset],
1491                                               phase, args, stack_size,
1492                                               (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
1493
1494             break;
1495         default:
1496             ERR("shouldn't reach here. phase %d\n", phase);
1497             break;
1498         }
1499     }
1500
1501     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1502
1503     if (ext_flags.HasNewCorrDesc)
1504     {
1505         /* free extra correlation package */
1506         /* NdrCorrelationFree(&stubMsg); */
1507     }
1508
1509     if (Oif_flags.HasPipes)
1510     {
1511         /* NdrPipesDone(...) */
1512     }
1513
1514     /* free the full pointer translation tables */
1515     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1516         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1517
1518     /* free server function stack */
1519     HeapFree(GetProcessHeap(), 0, args);
1520
1521     return S_OK;
1522 }
1523
1524 /***********************************************************************
1525  *            NdrServerCall2 [RPCRT4.@]
1526  */
1527 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1528 {
1529     DWORD dwPhase;
1530     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1531 }