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