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