dinput: SetActionMap setting the device buffer.
[wine] / dlls / rpcrt4 / ndr_stubless.c
1 /*
2  * NDR -Oi,-Oif,-Oicf Interpreter
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003-5 Robert Shearman (for CodeWeavers)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * TODO:
22  *  - Pipes
23  *  - Some types of binding handles
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36
37 #include "objbase.h"
38 #include "rpc.h"
39 #include "rpcproxy.h"
40
41 #include "wine/exception.h"
42 #include "wine/debug.h"
43 #include "wine/rpcfc.h"
44
45 #include "cpsf.h"
46 #include "ndr_misc.h"
47 #include "ndr_stubless.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
50
51 #define NDR_TABLE_MASK 127
52
53 static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
54 {
55     NDR_BUFFERSIZE m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK];
56     if (m) m(pStubMsg, pMemory, pFormat);
57     else
58     {
59         FIXME("format type 0x%x not implemented\n", pFormat[0]);
60         RpcRaiseException(RPC_X_BAD_STUB_DATA);
61     }
62 }
63
64 static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
65 {
66     NDR_MARSHALL m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK];
67     if (m) return m(pStubMsg, pMemory, pFormat);
68     else
69     {
70         FIXME("format type 0x%x not implemented\n", pFormat[0]);
71         RpcRaiseException(RPC_X_BAD_STUB_DATA);
72         return NULL;
73     }
74 }
75
76 static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc)
77 {
78     NDR_UNMARSHALL m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK];
79     if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc);
80     else
81     {
82         FIXME("format type 0x%x not implemented\n", pFormat[0]);
83         RpcRaiseException(RPC_X_BAD_STUB_DATA);
84         return NULL;
85     }
86 }
87
88 static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat)
89 {
90     NDR_FREE m = NdrFreer[pFormat[0] & NDR_TABLE_MASK];
91     if (m) m(pStubMsg, pMemory, pFormat);
92 }
93
94 #define STUBLESS_UNMARSHAL  1
95 #define STUBLESS_INITOUT    2
96 #define STUBLESS_CALLSERVER 3
97 #define STUBLESS_CALCSIZE   4
98 #define STUBLESS_GETBUFFER  5
99 #define STUBLESS_MARSHAL    6
100 #define STUBLESS_FREE       7
101
102 void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
103 {
104 #if 0 /* these functions are not defined yet */
105     pMessage->pfnAllocate = NdrRpcSmClientAllocate;
106     pMessage->pfnFree = NdrRpcSmClientFree;
107 #endif
108 }
109
110 static void dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes)
111 {
112     if (param_attributes.MustSize) TRACE(" MustSize");
113     if (param_attributes.MustFree) TRACE(" MustFree");
114     if (param_attributes.IsPipe) TRACE(" IsPipe");
115     if (param_attributes.IsIn) TRACE(" IsIn");
116     if (param_attributes.IsOut) TRACE(" IsOut");
117     if (param_attributes.IsReturn) TRACE(" IsReturn");
118     if (param_attributes.IsBasetype) TRACE(" IsBasetype");
119     if (param_attributes.IsByValue) TRACE(" IsByValue");
120     if (param_attributes.IsSimpleRef) TRACE(" IsSimpleRef");
121     if (param_attributes.IsDontCallFreeInst) TRACE(" IsDontCallFreeInst");
122     if (param_attributes.SaveForAsyncFinish) TRACE(" SaveForAsyncFinish");
123     if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
124 }
125
126 static void dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
127 {
128     if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize");
129     if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize");
130     if (Oi2Flags.HasReturn) TRACE(" HasReturn");
131     if (Oi2Flags.HasPipes) TRACE(" HasPipes");
132     if (Oi2Flags.Unused) TRACE(" Unused");
133     if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid");
134     if (Oi2Flags.HasExtensions) TRACE(" HasExtensions");
135     if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle");
136     TRACE("\n");
137 }
138
139 #define ARG_FROM_OFFSET(args, offset) ((args) + (offset))
140
141 static PFORMAT_STRING client_get_handle(
142     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
143     PFORMAT_STRING pFormat, handle_t *phBinding)
144 {
145     /* binding */
146     switch (pProcHeader->handle_type)
147     {
148     /* explicit binding: parse additional section */
149     case RPC_FC_BIND_EXPLICIT:
150         switch (*pFormat) /* handle_type */
151         {
152         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
153             {
154                 const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
155
156                 TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
157
158                 if (pDesc->flag) /* pointer to binding */
159                     *phBinding = **(handle_t **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
160                 else
161                     *phBinding = *(handle_t *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
162                 return pFormat + sizeof(NDR_EHD_PRIMITIVE);
163             }
164         case RPC_FC_BIND_GENERIC: /* explicit generic */
165             {
166                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
167                 void *pObject = NULL;
168                 void *pArg;
169                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
170
171                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
172
173                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
174                     pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
175                 else
176                     pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
177                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
178                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
179                 *phBinding = pGenPair->pfnBind(pObject);
180                 return pFormat + sizeof(NDR_EHD_GENERIC);
181             }
182         case RPC_FC_BIND_CONTEXT: /* explicit context */
183             {
184                 const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
185                 NDR_CCONTEXT context_handle;
186                 TRACE("Explicit bind context\n");
187                 if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
188                 {
189                     TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
190                     context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
191                 }
192                 else
193                     context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
194
195                 if (context_handle) *phBinding = NDRCContextBinding(context_handle);
196                 else if (pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL)
197                 {
198                     ERR("null context handle isn't allowed\n");
199                     RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
200                     return NULL;
201                 }
202                 /* FIXME: should we store this structure in stubMsg.pContext? */
203                 return pFormat + sizeof(NDR_EHD_CONTEXT);
204             }
205         default:
206             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
207             RpcRaiseException(RPC_X_BAD_STUB_DATA);
208         }
209         break;
210     case RPC_FC_BIND_GENERIC: /* implicit generic */
211         FIXME("RPC_FC_BIND_GENERIC\n");
212         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
213         break;
214     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
215         TRACE("Implicit primitive handle\n");
216         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
217         break;
218     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
219         FIXME("RPC_FC_CALLBACK_HANDLE\n");
220         break;
221     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
222         /* strictly speaking, it isn't necessary to set hBinding here
223          * since it isn't actually used (hence the automatic in its name),
224          * but then why does MIDL generate a valid entry in the
225          * MIDL_STUB_DESC for it? */
226         TRACE("Implicit auto handle\n");
227         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
228         break;
229     default:
230         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
231         RpcRaiseException(RPC_X_BAD_STUB_DATA);
232     }
233     return pFormat;
234 }
235
236 static void client_free_handle(
237     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
238     PFORMAT_STRING pFormat, handle_t hBinding)
239 {
240     /* binding */
241     switch (pProcHeader->handle_type)
242     {
243     /* explicit binding: parse additional section */
244     case RPC_FC_BIND_EXPLICIT:
245         switch (*pFormat) /* handle_type */
246         {
247         case RPC_FC_BIND_GENERIC: /* explicit generic */
248             {
249                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
250                 void *pObject = NULL;
251                 void *pArg;
252                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
253
254                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
255
256                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
257                     pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
258                 else
259                     pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
260                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
261                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
262                 pGenPair->pfnUnbind(pObject, hBinding);
263                 break;
264             }
265         case RPC_FC_BIND_CONTEXT: /* explicit context */
266         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
267             break;
268         default:
269             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
270             RpcRaiseException(RPC_X_BAD_STUB_DATA);
271         }
272         break;
273     case RPC_FC_BIND_GENERIC: /* implicit generic */
274         FIXME("RPC_FC_BIND_GENERIC\n");
275         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
276         break;
277     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
278     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
279     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
280         break;
281     default:
282         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
283         RpcRaiseException(RPC_X_BAD_STUB_DATA);
284     }
285 }
286
287 static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
288                            int phase, unsigned char *args, void **fpu_args,
289                            unsigned short number_of_params, unsigned char *pRetVal)
290 {
291     /* current format string offset */
292     int current_offset = 0;
293     /* current stack offset */
294     unsigned short current_stack_offset = 0;
295     /* counter */
296     unsigned short i;
297
298     for (i = 0; i < number_of_params; i++)
299     {
300         const NDR_PARAM_OIF_BASETYPE *pParam =
301             (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
302         unsigned char * pArg;
303
304         current_stack_offset = pParam->stack_offset;
305         pArg = ARG_FROM_OFFSET(args, current_stack_offset);
306
307         TRACE("param[%d]: new format\n", i);
308         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
309         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
310         TRACE("\tmemory addr (before): %p\n", pArg);
311
312         if (pParam->param_attributes.IsBasetype)
313         {
314             const unsigned char * pTypeFormat =
315                 &pParam->type_format_char;
316
317 #ifdef __x86_64__  /* floats are passed as doubles through varargs functions */
318             float f;
319             if (*pTypeFormat == RPC_FC_FLOAT && !pParam->param_attributes.IsSimpleRef && !fpu_args)
320             {
321                 f = *(double *)pArg;
322                 pArg = (unsigned char *)&f;
323             }
324 #endif
325             if (pParam->param_attributes.IsSimpleRef)
326             {
327                 pArg = *(unsigned char **)pArg;
328                 if (!pArg) RpcRaiseException(RPC_X_NULL_REF_POINTER);
329             }
330
331             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
332
333             switch (phase)
334             {
335             case PROXY_CALCSIZE:
336                 if (pParam->param_attributes.IsIn)
337                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
338                 break;
339             case PROXY_MARSHAL:
340                 if (pParam->param_attributes.IsIn)
341                     call_marshaller(pStubMsg, pArg, pTypeFormat);
342                 break;
343             case PROXY_UNMARSHAL:
344                 if (pParam->param_attributes.IsOut)
345                 {
346                     if (pParam->param_attributes.IsReturn) pArg = pRetVal;
347                     call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
348                 }
349                 break;
350             default:
351                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
352             }
353
354             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
355         }
356         else
357         {
358             const NDR_PARAM_OIF_OTHER *pParamOther =
359                 (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
360
361             const unsigned char * pTypeFormat =
362                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
363
364             /* if a simple ref pointer then we have to do the
365              * check for the pointer being non-NULL. */
366             if (pParam->param_attributes.IsSimpleRef)
367             {
368                 if (!*(unsigned char **)pArg)
369                     RpcRaiseException(RPC_X_NULL_REF_POINTER);
370             }
371
372             TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat);
373
374             switch (phase)
375             {
376             case PROXY_CALCSIZE:
377                 if (pParam->param_attributes.IsIn)
378                 {
379                     if (pParam->param_attributes.IsByValue)
380                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
381                     else
382                         call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
383                 }
384                 break;
385             case PROXY_MARSHAL:
386                 if (pParam->param_attributes.IsIn)
387                 {
388                     if (pParam->param_attributes.IsByValue)
389                         call_marshaller(pStubMsg, pArg, pTypeFormat);
390                     else
391                         call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
392                 }
393                 break;
394             case PROXY_UNMARSHAL:
395                 if (pParam->param_attributes.IsOut)
396                 {
397                     if (pParam->param_attributes.IsReturn) pArg = pRetVal;
398                     if (pParam->param_attributes.IsByValue)
399                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
400                     else
401                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
402                 }
403                 break;
404             default:
405                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
406             }
407
408             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
409         }
410         TRACE("\tmemory addr (after): %p\n", pArg);
411     }
412 }
413
414 static unsigned int type_stack_size(unsigned char fc)
415 {
416     switch (fc)
417     {
418     case RPC_FC_BYTE:
419     case RPC_FC_CHAR:
420     case RPC_FC_SMALL:
421     case RPC_FC_USMALL:
422     case RPC_FC_WCHAR:
423     case RPC_FC_SHORT:
424     case RPC_FC_USHORT:
425     case RPC_FC_LONG:
426     case RPC_FC_ULONG:
427     case RPC_FC_INT3264:
428     case RPC_FC_UINT3264:
429     case RPC_FC_ENUM16:
430     case RPC_FC_ENUM32:
431     case RPC_FC_FLOAT:
432     case RPC_FC_ERROR_STATUS_T:
433     case RPC_FC_IGNORE:
434         return sizeof(void *);
435     case RPC_FC_DOUBLE:
436         return sizeof(double);
437     case RPC_FC_HYPER:
438         return sizeof(ULONGLONG);
439     default:
440         ERR("invalid base type 0x%x\n", fc);
441         RpcRaiseException(RPC_S_INTERNAL_ERROR);
442     }
443 }
444
445 static BOOL is_by_value( PFORMAT_STRING format )
446 {
447     switch (*format)
448     {
449     case RPC_FC_USER_MARSHAL:
450     case RPC_FC_STRUCT:
451     case RPC_FC_PSTRUCT:
452     case RPC_FC_CSTRUCT:
453     case RPC_FC_CPSTRUCT:
454     case RPC_FC_CVSTRUCT:
455     case RPC_FC_BOGUS_STRUCT:
456         return TRUE;
457     default:
458         return FALSE;
459     }
460 }
461
462 void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg,
463     PFORMAT_STRING pFormat, int phase, unsigned char *args,
464     unsigned short stack_size,
465     unsigned char *pRetVal, BOOL object_proc, BOOL ignore_retval)
466 {
467     /* current format string offset */
468     int current_offset = 0;
469     /* current stack offset */
470     unsigned short current_stack_offset = object_proc ? sizeof(void *) : 0;
471     /* counter */
472     unsigned short i;
473
474     /* NOTE: V1 style format doesn't terminate on the number_of_params
475      * condition as it doesn't have this attribute. Instead it
476      * terminates when the stack size given in the header is exceeded.
477      */
478     for (i = 0; TRUE; i++)
479     {
480         const NDR_PARAM_OI_BASETYPE *pParam =
481             (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
482         unsigned char * pArg = ARG_FROM_OFFSET(args, current_stack_offset);
483
484         /* no more parameters; exit loop */
485         if (current_stack_offset >= stack_size)
486             break;
487
488         TRACE("param[%d]: old format\n", i);
489         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
490         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
491         TRACE("\tmemory addr (before): %p\n", pArg);
492
493         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
494             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
495         {
496             const unsigned char * pTypeFormat =
497                 &pParam->type_format_char;
498
499             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
500
501             switch (phase)
502             {
503             case PROXY_CALCSIZE:
504                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
505                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
506                 break;
507             case PROXY_MARSHAL:
508                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
509                     call_marshaller(pStubMsg, pArg, pTypeFormat);
510                 break;
511             case PROXY_UNMARSHAL:
512                 if (!ignore_retval &&
513                     pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
514                 {
515                     if (pParam->param_direction & RPC_FC_RETURN_PARAM)
516                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
517                     else
518                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
519                 }
520                 break;
521             default:
522                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
523             }
524
525             current_stack_offset += type_stack_size(*pTypeFormat);
526             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
527         }
528         else
529         {
530             const NDR_PARAM_OI_OTHER *pParamOther = (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
531             const unsigned char *pTypeFormat = &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
532             const BOOL by_value = is_by_value( pTypeFormat );
533
534             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
535
536             switch (phase)
537             {
538             case PROXY_CALCSIZE:
539                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
540                     pParam->param_direction == RPC_FC_IN_OUT_PARAM)
541                 {
542                     if (!by_value) pArg = *(unsigned char **)pArg;
543                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
544                 }
545                 break;
546             case PROXY_MARSHAL:
547                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
548                     pParam->param_direction == RPC_FC_IN_OUT_PARAM)
549                 {
550                     if (!by_value) pArg = *(unsigned char **)pArg;
551                     call_marshaller(pStubMsg, pArg, pTypeFormat);
552                 }
553                 break;
554             case PROXY_UNMARSHAL:
555                 if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
556                     pParam->param_direction == RPC_FC_OUT_PARAM)
557                 {
558                     if (by_value)
559                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
560                     else
561                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
562                 }
563                 else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
564                     call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
565                 break;
566             default:
567                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
568             }
569
570             current_stack_offset += pParamOther->stack_size * sizeof(void *);
571             current_offset += sizeof(NDR_PARAM_OI_OTHER);
572         }
573     }
574 }
575
576 LONG_PTR CDECL ndr_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
577                                 void **stack_top, void **fpu_stack )
578 {
579     /* pointer to start of stack where arguments start */
580     RPC_MESSAGE rpcMsg;
581     MIDL_STUB_MESSAGE stubMsg;
582     handle_t hBinding = NULL;
583     /* procedure number */
584     unsigned short procedure_number;
585     /* size of stack */
586     unsigned short stack_size;
587     /* number of parameters. optional for client to give it to us */
588     unsigned char number_of_params = ~0;
589     /* cache of Oif_flags from v2 procedure header */
590     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
591     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
592     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
593     /* the type of pass we are currently doing */
594     int phase;
595     /* header for procedure string */
596     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
597     /* -Oif or -Oicf generated format */
598     BOOL bV2Format = FALSE;
599     /* the value to return to the client from the remote procedure */
600     LONG_PTR RetVal = 0;
601     /* the pointer to the object when in OLE mode */
602     void * This = NULL;
603     PFORMAT_STRING pHandleFormat;
604     /* correlation cache */
605     ULONG_PTR NdrCorrCache[256];
606
607     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
608
609     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
610
611     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
612     {
613         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
614         stack_size = pProcHeader->stack_size;
615         procedure_number = pProcHeader->proc_num;
616         pFormat += sizeof(NDR_PROC_HEADER_RPC);
617     }
618     else
619     {
620         stack_size = pProcHeader->stack_size;
621         procedure_number = pProcHeader->proc_num;
622         pFormat += sizeof(NDR_PROC_HEADER);
623     }
624     TRACE("stack size: 0x%x\n", stack_size);
625     TRACE("proc num: %d\n", procedure_number);
626
627     /* create the full pointer translation tables, if requested */
628     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
629         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
630
631     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
632     {
633         /* object is always the first argument */
634         This = stack_top[0];
635         NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number);
636     }
637     else
638         NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number);
639
640     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
641     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
642
643     stubMsg.StackTop = (unsigned char *)stack_top;
644     pHandleFormat = pFormat;
645
646     /* we only need a handle if this isn't an object method */
647     if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT))
648     {
649         pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding);
650         if (!pFormat) goto done;
651     }
652
653     bV2Format = (pStubDesc->Version >= 0x20000);
654
655     if (bV2Format)
656     {
657         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
658             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
659
660         Oif_flags = pOIFHeader->Oi2Flags;
661         number_of_params = pOIFHeader->number_of_params;
662
663         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
664
665         TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
666
667         if (Oif_flags.HasExtensions)
668         {
669             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
670             ext_flags = pExtensions->Flags2;
671             pFormat += pExtensions->Size;
672 #ifdef __x86_64__
673             if (pExtensions->Size > sizeof(*pExtensions) && fpu_stack)
674             {
675                 int i;
676                 unsigned short fpu_mask = *(unsigned short *)(pExtensions + 1);
677                 for (i = 0; i < 4; i++, fpu_mask >>= 2)
678                     switch (fpu_mask & 3)
679                     {
680                     case 1: *(float *)&stack_top[i] = *(float *)&fpu_stack[i]; break;
681                     case 2: *(double *)&stack_top[i] = *(double *)&fpu_stack[i]; break;
682                     }
683             }
684 #endif
685         }
686     }
687
688     stubMsg.BufferLength = 0;
689
690     /* store the RPC flags away */
691     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
692         rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
693
694     /* use alternate memory allocation routines */
695     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
696         NdrRpcSmSetClientToOsf(&stubMsg);
697
698     if (Oif_flags.HasPipes)
699     {
700         FIXME("pipes not supported yet\n");
701         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
702         /* init pipes package */
703         /* NdrPipesInitialize(...) */
704     }
705     if (ext_flags.HasNewCorrDesc)
706     {
707         /* initialize extra correlation package */
708         NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
709     }
710
711     /* order of phases:
712      * 1. PROXY_CALCSIZE - calculate the buffer size
713      * 2. PROXY_GETBUFFER - allocate the buffer
714      * 3. PROXY_MARHSAL - marshal [in] params into the buffer
715      * 4. PROXY_SENDRECEIVE - send/receive buffer
716      * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
717      */
718     if ((pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) ||
719         (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_HAS_COMM_OR_FAULT))
720     {
721         __TRY
722         {
723             for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
724             {
725                 TRACE("phase = %d\n", phase);
726                 switch (phase)
727                 {
728                 case PROXY_GETBUFFER:
729                     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
730                     {
731                         /* allocate the buffer */
732                         NdrProxyGetBuffer(This, &stubMsg);
733                     }
734                     else
735                     {
736                         /* allocate the buffer */
737                         if (Oif_flags.HasPipes)
738                             /* NdrGetPipeBuffer(...) */
739                             FIXME("pipes not supported yet\n");
740                         else
741                         {
742                             if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
743 #if 0
744                                 NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
745 #else
746                                 FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
747 #endif
748                             else
749                                 NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
750                         }
751                     }
752                     break;
753                 case PROXY_SENDRECEIVE:
754                     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
755                     {
756                         /* send the [in] params and receive the [out] and [retval]
757                          * params */
758                         NdrProxySendReceive(This, &stubMsg);
759                     }
760                     else
761                     {
762                         /* send the [in] params and receive the [out] and [retval]
763                          * params */
764                         if (Oif_flags.HasPipes)
765                             /* NdrPipesSendReceive(...) */
766                             FIXME("pipes not supported yet\n");
767                         else
768                         {
769                             if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
770 #if 0
771                                 NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
772 #else
773                                 FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
774 #endif
775                             else
776                                 NdrSendReceive(&stubMsg, stubMsg.Buffer);
777                         }
778                     }
779
780                     /* convert strings, floating point values and endianess into our
781                      * preferred format */
782                     if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
783                         NdrConvert(&stubMsg, pFormat);
784
785                     break;
786                 case PROXY_CALCSIZE:
787                 case PROXY_MARSHAL:
788                 case PROXY_UNMARSHAL:
789                     if (bV2Format)
790                         client_do_args(&stubMsg, pFormat, phase, stubMsg.StackTop, fpu_stack,
791                             number_of_params, (unsigned char *)&RetVal);
792                     else
793                         client_do_args_old_format(&stubMsg, pFormat, phase,
794                             stubMsg.StackTop, stack_size, (unsigned char *)&RetVal,
795                             (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT), FALSE);
796                     break;
797                 default:
798                     ERR("shouldn't reach here. phase %d\n", phase);
799                     break;
800                 }
801             }
802         }
803         __EXCEPT_ALL
804         {
805             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
806                 RetVal = NdrProxyErrorHandler(GetExceptionCode());
807             else
808             {
809                 const COMM_FAULT_OFFSETS *comm_fault_offsets = &pStubDesc->CommFaultOffsets[procedure_number];
810                 ULONG *comm_status;
811                 ULONG *fault_status;
812
813                 TRACE("comm_fault_offsets = {0x%hx, 0x%hx}\n", comm_fault_offsets->CommOffset, comm_fault_offsets->FaultOffset);
814
815                 if (comm_fault_offsets->CommOffset == -1)
816                     comm_status = (ULONG *)&RetVal;
817                 else if (comm_fault_offsets->CommOffset >= 0)
818                     comm_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset);
819                 else
820                     comm_status = NULL;
821
822                 if (comm_fault_offsets->FaultOffset == -1)
823                     fault_status = (ULONG *)&RetVal;
824                 else if (comm_fault_offsets->FaultOffset >= 0)
825                     fault_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset);
826                 else
827                     fault_status = NULL;
828
829                 NdrMapCommAndFaultStatus(&stubMsg, comm_status, fault_status,
830                                          GetExceptionCode());
831             }
832         }
833         __ENDTRY
834     }
835     else
836     {
837         /* order of phases:
838          * 1. PROXY_CALCSIZE - calculate the buffer size
839          * 2. PROXY_GETBUFFER - allocate the buffer
840          * 3. PROXY_MARHSAL - marshal [in] params into the buffer
841          * 4. PROXY_SENDRECEIVE - send/receive buffer
842          * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
843          */
844         for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
845         {
846             TRACE("phase = %d\n", phase);
847             switch (phase)
848             {
849             case PROXY_GETBUFFER:
850                 /* allocate the buffer */
851                 if (Oif_flags.HasPipes)
852                     /* NdrGetPipeBuffer(...) */
853                     FIXME("pipes not supported yet\n");
854                 else
855                 {
856                     if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
857 #if 0
858                         NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
859 #else
860                         FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
861 #endif
862                     else
863                         NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
864                 }
865                 break;
866             case PROXY_SENDRECEIVE:
867                 /* send the [in] params and receive the [out] and [retval]
868                  * params */
869                 if (Oif_flags.HasPipes)
870                     /* NdrPipesSendReceive(...) */
871                     FIXME("pipes not supported yet\n");
872                 else
873                 {
874                     if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
875 #if 0
876                         NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
877 #else
878                         FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
879 #endif
880                     else
881                         NdrSendReceive(&stubMsg, stubMsg.Buffer);
882                 }
883
884                 /* convert strings, floating point values and endianess into our
885                  * preferred format */
886                 if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
887                     NdrConvert(&stubMsg, pFormat);
888
889                 break;
890             case PROXY_CALCSIZE:
891             case PROXY_MARSHAL:
892             case PROXY_UNMARSHAL:
893                 if (bV2Format)
894                     client_do_args(&stubMsg, pFormat, phase, stubMsg.StackTop, fpu_stack,
895                         number_of_params, (unsigned char *)&RetVal);
896                 else
897                     client_do_args_old_format(&stubMsg, pFormat, phase,
898                         stubMsg.StackTop, stack_size, (unsigned char *)&RetVal,
899                         (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT), FALSE);
900                 break;
901             default:
902                 ERR("shouldn't reach here. phase %d\n", phase);
903                 break;
904             }
905         }
906     }
907
908     if (ext_flags.HasNewCorrDesc)
909     {
910         /* free extra correlation package */
911         NdrCorrelationFree(&stubMsg);
912     }
913
914     if (Oif_flags.HasPipes)
915     {
916         /* NdrPipesDone(...) */
917     }
918
919     /* free the full pointer translation tables */
920     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
921         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
922
923     /* free marshalling buffer */
924     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
925         NdrProxyFreeBuffer(This, &stubMsg);
926     else
927     {
928         NdrFreeBuffer(&stubMsg);
929         client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding);
930     }
931
932 done:
933     TRACE("RetVal = 0x%lx\n", RetVal);
934     return RetVal;
935 }
936
937 #ifdef __x86_64__
938
939 __ASM_GLOBAL_FUNC( NdrClientCall2,
940                    "movq %r8,0x18(%rsp)\n\t"
941                    "movq %r9,0x20(%rsp)\n\t"
942                    "leaq 0x18(%rsp),%r8\n\t"
943                    "xorq %r9,%r9\n\t"
944                    "subq $0x28,%rsp\n\t"
945                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
946                    "call " __ASM_NAME("ndr_client_call") "\n\t"
947                    "addq $0x28,%rsp\n\t"
948                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
949                    "ret" );
950
951 #else  /* __x86_64__ */
952
953 /***********************************************************************
954  *            NdrClientCall2 [RPCRT4.@]
955  */
956 CLIENT_CALL_RETURN WINAPIV NdrClientCall2( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
957 {
958     __ms_va_list args;
959     LONG_PTR ret;
960
961     __ms_va_start( args, format );
962     ret = ndr_client_call( desc, format, va_arg( args, void ** ), NULL );
963     __ms_va_end( args );
964     return *(CLIENT_CALL_RETURN *)&ret;
965 }
966
967 #endif  /* __x86_64__ */
968
969 /* Calls a function with the specified arguments, restoring the stack
970  * properly afterwards as we don't know the calling convention of the
971  * function */
972 #if defined __i386__ && defined _MSC_VER
973 __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
974 {
975     __asm
976     {
977         push ebp
978         push edi            ; Save registers
979         push esi
980         mov ebp, esp
981         mov eax, [ebp+16]   ; Get stack size
982         sub esp, eax        ; Make room in stack for arguments
983         mov edi, esp
984         mov ecx, eax
985         mov esi, [ebp+12]
986         shr ecx, 2
987         cld
988         rep movsd           ; Copy dword blocks
989         call [ebp+8]        ; Call function
990         lea esp, [ebp-8]    ; Restore stack
991         pop esi             ; Restore registers
992         pop edi
993         pop ebp
994         ret
995     }
996 }
997 #elif defined __i386__ && defined __GNUC__
998 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
999 __ASM_GLOBAL_FUNC(call_server_func,
1000     "pushl %ebp\n\t"
1001     __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1002     __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1003     "movl %esp,%ebp\n\t"
1004     __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1005     "pushl %edi\n\t"            /* Save registers */
1006     __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
1007     "pushl %esi\n\t"
1008     __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
1009     "movl 16(%ebp), %eax\n\t"   /* Get stack size */
1010     "subl %eax, %esp\n\t"       /* Make room in stack for arguments */
1011     "andl $~15, %esp\n\t"       /* Make sure stack has 16-byte alignment for Mac OS X */
1012     "movl %esp, %edi\n\t"
1013     "movl %eax, %ecx\n\t"
1014     "movl 12(%ebp), %esi\n\t"
1015     "shrl $2, %ecx\n\t"         /* divide by 4 */
1016     "cld\n\t"
1017     "rep; movsl\n\t"            /* Copy dword blocks */
1018     "call *8(%ebp)\n\t"         /* Call function */
1019     "leal -8(%ebp), %esp\n\t"   /* Restore stack */
1020     "popl %esi\n\t"             /* Restore registers */
1021     __ASM_CFI(".cfi_same_value %esi\n\t")
1022     "popl %edi\n\t"
1023     __ASM_CFI(".cfi_same_value %edi\n\t")
1024     "popl %ebp\n\t"
1025     __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1026     __ASM_CFI(".cfi_same_value %ebp\n\t")
1027     "ret" )
1028 #elif defined __x86_64__
1029 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1030 __ASM_GLOBAL_FUNC( call_server_func,
1031                    "pushq %rbp\n\t"
1032                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
1033                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
1034                    "movq %rsp,%rbp\n\t"
1035                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
1036                    "pushq %rsi\n\t"
1037                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
1038                    "pushq %rdi\n\t"
1039                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
1040                    "movq %rcx,%rax\n\t"   /* function to call */
1041                    "movq $32,%rcx\n\t"    /* allocate max(32,stack_size) bytes of stack space */
1042                    "cmpq %rcx,%r8\n\t"
1043                    "cmovgq %r8,%rcx\n\t"
1044                    "subq %rcx,%rsp\n\t"
1045                    "andq $~15,%rsp\n\t"
1046                    "movq %r8,%rcx\n\t"
1047                    "shrq $3,%rcx\n\t"
1048                    "movq %rsp,%rdi\n\t"
1049                    "movq %rdx,%rsi\n\t"
1050                    "rep; movsq\n\t"       /* copy arguments */
1051                    "movq 0(%rsp),%rcx\n\t"
1052                    "movq 8(%rsp),%rdx\n\t"
1053                    "movq 16(%rsp),%r8\n\t"
1054                    "movq 24(%rsp),%r9\n\t"
1055                    "movq %rcx,%xmm0\n\t"
1056                    "movq %rdx,%xmm1\n\t"
1057                    "movq %r8,%xmm2\n\t"
1058                    "movq %r9,%xmm3\n\t"
1059                    "callq *%rax\n\t"
1060                    "leaq -16(%rbp),%rsp\n\t"  /* restore stack */
1061                    "popq %rdi\n\t"
1062                    __ASM_CFI(".cfi_same_value %rdi\n\t")
1063                    "popq %rsi\n\t"
1064                    __ASM_CFI(".cfi_same_value %rsi\n\t")
1065                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
1066                    "popq %rbp\n\t"
1067                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
1068                    __ASM_CFI(".cfi_same_value %rbp\n\t")
1069                    "ret")
1070 #else
1071 #warning call_server_func not implemented for your architecture
1072 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
1073 {
1074     FIXME("Not implemented for your architecture\n");
1075     return 0;
1076 }
1077 #endif
1078
1079 static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
1080 {
1081     DWORD size;
1082     switch(*pFormat)
1083     {
1084     case RPC_FC_STRUCT:
1085         size = *(const WORD*)(pFormat + 2);
1086         break;
1087     case RPC_FC_BOGUS_STRUCT:
1088         size = *(const WORD*)(pFormat + 2);
1089         if(*(const WORD*)(pFormat + 4))
1090             FIXME("Unhandled conformant description\n");
1091         break;
1092     case RPC_FC_CARRAY:
1093     case RPC_FC_CVARRAY:
1094         size = *(const WORD*)(pFormat + 2);
1095         ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
1096         size *= pStubMsg->MaxCount;
1097         break;
1098     case RPC_FC_SMFARRAY:
1099     case RPC_FC_SMVARRAY:
1100         size = *(const WORD*)(pFormat + 2);
1101         break;
1102     case RPC_FC_LGFARRAY:
1103     case RPC_FC_LGVARRAY:
1104         size = *(const DWORD*)(pFormat + 2);
1105         break;
1106     case RPC_FC_BOGUS_ARRAY:
1107         pFormat = ComputeConformance(pStubMsg, NULL, pFormat + 4, *(const WORD*)&pFormat[2]);
1108         TRACE("conformance = %ld\n", pStubMsg->MaxCount);
1109         pFormat = ComputeVariance(pStubMsg, NULL, pFormat, pStubMsg->MaxCount);
1110         size = ComplexStructSize(pStubMsg, pFormat);
1111         size *= pStubMsg->MaxCount;
1112         break;
1113     case RPC_FC_C_CSTRING:
1114     case RPC_FC_C_WSTRING:
1115         if (*pFormat == RPC_FC_C_CSTRING)
1116             size = sizeof(CHAR);
1117         else
1118             size = sizeof(WCHAR);
1119         if (pFormat[1] == RPC_FC_STRING_SIZED)
1120             ComputeConformance(pStubMsg, NULL, pFormat + 2, 0);
1121         else
1122             pStubMsg->MaxCount = 0;
1123         size *= pStubMsg->MaxCount;
1124         break;
1125     default:
1126         FIXME("Unhandled type %02x\n", *pFormat);
1127         /* fallthrough */
1128     case RPC_FC_RP:
1129         size = sizeof(void *);
1130         break;
1131     }
1132     return size;
1133 }
1134
1135 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
1136                               PFORMAT_STRING pFormat, int phase,
1137                               unsigned char *args,
1138                               unsigned short number_of_params)
1139 {
1140     /* counter */
1141     unsigned short i;
1142     /* current format string offset */
1143     int current_offset = 0;
1144     /* current stack offset */
1145     unsigned short current_stack_offset = 0;
1146     /* location to put retval into */
1147     LONG_PTR *retval_ptr = NULL;
1148
1149     for (i = 0; i < number_of_params; i++)
1150     {
1151         const NDR_PARAM_OIF_BASETYPE *pParam =
1152         (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
1153         unsigned char *pArg;
1154
1155         current_stack_offset = pParam->stack_offset;
1156         pArg = args + current_stack_offset;
1157
1158         TRACE("param[%d]: new format\n", i);
1159         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
1160         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
1161         TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
1162
1163         if (pParam->param_attributes.IsBasetype)
1164         {
1165             const unsigned char *pTypeFormat =
1166             &pParam->type_format_char;
1167
1168             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
1169
1170             switch (phase)
1171             {
1172                 case STUBLESS_MARSHAL:
1173                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1174                     {
1175                         if (pParam->param_attributes.IsSimpleRef)
1176                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1177                         else
1178                             call_marshaller(pStubMsg, pArg, pTypeFormat);
1179                     }
1180                     break;
1181                 case STUBLESS_FREE:
1182                     if (pParam->param_attributes.ServerAllocSize)
1183                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1184                     break;
1185                 case STUBLESS_INITOUT:
1186                     break;
1187                 case STUBLESS_UNMARSHAL:
1188                     if (pParam->param_attributes.ServerAllocSize)
1189                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1190                                                    pParam->param_attributes.ServerAllocSize * 8);
1191
1192                     if (pParam->param_attributes.IsIn)
1193                     {
1194                         if (pParam->param_attributes.IsSimpleRef)
1195                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1196                         else
1197                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1198                     }
1199                     break;
1200                 case STUBLESS_CALCSIZE:
1201                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1202                     {
1203                         if (pParam->param_attributes.IsSimpleRef)
1204                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1205                         else
1206                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1207                     }
1208                     break;
1209                 default:
1210                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1211             }
1212
1213             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
1214         }
1215         else
1216         {
1217             const NDR_PARAM_OIF_OTHER *pParamOther =
1218             (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
1219
1220             const unsigned char * pTypeFormat =
1221                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
1222
1223             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
1224
1225             switch (phase)
1226             {
1227                 case STUBLESS_MARSHAL:
1228                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1229                     {
1230                         if (pParam->param_attributes.IsByValue)
1231                             call_marshaller(pStubMsg, pArg, pTypeFormat);
1232                         else
1233                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1234                     }
1235                     break;
1236                 case STUBLESS_FREE:
1237                     if (pParam->param_attributes.MustFree)
1238                     {
1239                         if (pParam->param_attributes.IsByValue)
1240                             call_freer(pStubMsg, pArg, pTypeFormat);
1241                         else
1242                             call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1243                     }
1244                     else if (pParam->param_attributes.ServerAllocSize)
1245                     {
1246                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1247                     }
1248                     else if (pParam->param_attributes.IsOut &&
1249                              !pParam->param_attributes.IsIn &&
1250                              !pParam->param_attributes.IsByValue)
1251                     {
1252                         if (*pTypeFormat != RPC_FC_BIND_CONTEXT)
1253                             pStubMsg->pfnFree(*(void **)pArg);
1254                     }
1255
1256                     break;
1257                 case STUBLESS_INITOUT:
1258                     if (!pParam->param_attributes.IsIn &&
1259                              pParam->param_attributes.IsOut &&
1260                              !pParam->param_attributes.ServerAllocSize &&
1261                              !pParam->param_attributes.IsByValue)
1262                     {
1263                         if (*pTypeFormat == RPC_FC_BIND_CONTEXT)
1264                         {
1265                             NDR_SCONTEXT ctxt = NdrContextHandleInitialize(
1266                                 pStubMsg, pTypeFormat);
1267                             *(void **)pArg = NDRSContextValue(ctxt);
1268                         }
1269                         else
1270                         {
1271                             DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1272
1273                             if(size)
1274                             {
1275                                 *(void **)pArg = NdrAllocate(pStubMsg, size);
1276                                 memset(*(void **)pArg, 0, size);
1277                             }
1278                         }
1279                     }
1280                     break;
1281                 case STUBLESS_UNMARSHAL:
1282                     if (pParam->param_attributes.ServerAllocSize)
1283                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1284                                                    pParam->param_attributes.ServerAllocSize * 8);
1285
1286                     if (pParam->param_attributes.IsIn)
1287                     {
1288                         if (pParam->param_attributes.IsByValue)
1289                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1290                         else
1291                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1292                     }
1293                     break;
1294                 case STUBLESS_CALCSIZE:
1295                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1296                     {
1297                         if (pParam->param_attributes.IsByValue)
1298                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1299                         else
1300                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1301                     }
1302                     break;
1303                 default:
1304                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1305             }
1306
1307             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
1308         }
1309         TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1310
1311         /* make a note of the address of the return value parameter for later */
1312         if (pParam->param_attributes.IsReturn) retval_ptr = (LONG_PTR *)pArg;
1313     }
1314
1315     return retval_ptr;
1316 }
1317
1318 static LONG_PTR *stub_do_old_args(MIDL_STUB_MESSAGE *pStubMsg,
1319                                   PFORMAT_STRING pFormat, int phase,
1320                                   unsigned char *args,
1321                                   unsigned short stack_size, BOOL object)
1322 {
1323     /* counter */
1324     unsigned short i;
1325     /* current format string offset */
1326     int current_offset = 0;
1327     /* current stack offset */
1328     unsigned short current_stack_offset = object ? sizeof(void *) : 0;
1329     /* location to put retval into */
1330     LONG_PTR *retval_ptr = NULL;
1331
1332     for (i = 0; TRUE; i++)
1333     {
1334         const NDR_PARAM_OI_BASETYPE *pParam =
1335         (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
1336         unsigned char *pArg = args + current_stack_offset;
1337
1338         /* no more parameters; exit loop */
1339         if (current_stack_offset >= stack_size)
1340             break;
1341
1342         TRACE("param[%d]: old format\n", i);
1343         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
1344         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
1345
1346         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
1347             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1348         {
1349             const unsigned char *pTypeFormat =
1350             &pParam->type_format_char;
1351
1352             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
1353
1354             if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1355                 retval_ptr = (LONG_PTR *)pArg;
1356
1357             switch (phase)
1358             {
1359                 case STUBLESS_MARSHAL:
1360                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1361                         call_marshaller(pStubMsg, pArg, pTypeFormat);
1362                     break;
1363                 case STUBLESS_FREE:
1364                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1365                         call_freer(pStubMsg, pArg, pTypeFormat);
1366                     break;
1367                 case STUBLESS_INITOUT:
1368                     break;
1369                 case STUBLESS_UNMARSHAL:
1370                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1371                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1372                     break;
1373                 case STUBLESS_CALCSIZE:
1374                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1375                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1376                     break;
1377                 default:
1378                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1379             }
1380
1381             current_stack_offset += type_stack_size(*pTypeFormat);
1382             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
1383         }
1384         else
1385         {
1386             const NDR_PARAM_OI_OTHER *pParamOther =
1387             (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
1388
1389             const unsigned char * pTypeFormat =
1390                 &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
1391             const BOOL by_value = is_by_value( pTypeFormat );
1392
1393             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
1394
1395             if (pParam->param_direction == RPC_FC_RETURN_PARAM)
1396                 retval_ptr = (LONG_PTR *)pArg;
1397
1398             switch (phase)
1399             {
1400                 case STUBLESS_MARSHAL:
1401                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1402                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1403                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1404                     {
1405                         if (!by_value) pArg = *(unsigned char **)pArg;
1406                         call_marshaller(pStubMsg, pArg, pTypeFormat);
1407                     }
1408                     break;
1409                 case STUBLESS_FREE:
1410                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1411                         pParam->param_direction == RPC_FC_IN_PARAM)
1412                     {
1413                         if (!by_value) pArg = *(unsigned char **)pArg;
1414                         call_freer(pStubMsg, pArg, pTypeFormat);
1415                     }
1416                     else if (pParam->param_direction == RPC_FC_OUT_PARAM && !by_value)
1417                         pStubMsg->pfnFree(*(void **)pArg);
1418                     break;
1419                 case STUBLESS_INITOUT:
1420                     if (pParam->param_direction == RPC_FC_OUT_PARAM && !by_value)
1421                     {
1422                         DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1423
1424                         if(size)
1425                         {
1426                             *(void **)pArg = NdrAllocate(pStubMsg, size);
1427                             memset(*(void **)pArg, 0, size);
1428                         }
1429                     }
1430                     break;
1431                 case STUBLESS_UNMARSHAL:
1432                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1433                         pParam->param_direction == RPC_FC_IN_PARAM)
1434                     {
1435                         if (by_value)
1436                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1437                         else
1438                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1439                     }
1440                     break;
1441                 case STUBLESS_CALCSIZE:
1442                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1443                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1444                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1445                     {
1446                         if (!by_value) pArg = *(unsigned char **)pArg;
1447                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1448                     }
1449                     break;
1450                 default:
1451                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1452             }
1453
1454             current_stack_offset += pParamOther->stack_size * sizeof(void *);
1455             current_offset += sizeof(NDR_PARAM_OI_OTHER);
1456         }
1457     }
1458
1459     return retval_ptr;
1460 }
1461
1462 /***********************************************************************
1463  *            NdrStubCall2 [RPCRT4.@]
1464  *
1465  * Unmarshals [in] parameters, calls either a method in an object or a server
1466  * function, marshals any [out] parameters and frees any allocated data.
1467  *
1468  * NOTES
1469  *  Used by stubless MIDL-generated code.
1470  */
1471 LONG WINAPI NdrStubCall2(
1472     struct IRpcStubBuffer * pThis,
1473     struct IRpcChannelBuffer * pChannel,
1474     PRPC_MESSAGE pRpcMsg,
1475     DWORD * pdwStubPhase)
1476 {
1477     const MIDL_SERVER_INFO *pServerInfo;
1478     const MIDL_STUB_DESC *pStubDesc;
1479     PFORMAT_STRING pFormat;
1480     MIDL_STUB_MESSAGE stubMsg;
1481     /* pointer to start of stack to pass into stub implementation */
1482     unsigned char * args;
1483     /* size of stack */
1484     unsigned short stack_size;
1485     /* number of parameters. optional for client to give it to us */
1486     unsigned char number_of_params = ~0;
1487     /* cache of Oif_flags from v2 procedure header */
1488     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1489     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1490     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1491     /* the type of pass we are currently doing */
1492     int phase;
1493     /* header for procedure string */
1494     const NDR_PROC_HEADER *pProcHeader;
1495     /* offset in format string for start of params */
1496     int parameter_start_offset;
1497     /* current format string offset */
1498     int current_offset;
1499     /* -Oif or -Oicf generated format */
1500     BOOL bV2Format = FALSE;
1501     /* location to put retval into */
1502     LONG_PTR *retval_ptr = NULL;
1503
1504     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1505
1506     if (pThis)
1507         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1508     else
1509         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1510
1511     pStubDesc = pServerInfo->pStubDesc;
1512     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1513     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1514
1515     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1516
1517     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1518     {
1519         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1520         stack_size = pProcHeader->stack_size;
1521         current_offset = sizeof(NDR_PROC_HEADER_RPC);
1522
1523     }
1524     else
1525     {
1526         stack_size = pProcHeader->stack_size;
1527         current_offset = sizeof(NDR_PROC_HEADER);
1528     }
1529
1530     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1531
1532     /* binding */
1533     switch (pProcHeader->handle_type)
1534     {
1535     /* explicit binding: parse additional section */
1536     case RPC_FC_BIND_EXPLICIT:
1537         switch (pFormat[current_offset]) /* handle_type */
1538         {
1539         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
1540             current_offset += sizeof(NDR_EHD_PRIMITIVE);
1541             break;
1542         case RPC_FC_BIND_GENERIC: /* explicit generic */
1543             current_offset += sizeof(NDR_EHD_GENERIC);
1544             break;
1545         case RPC_FC_BIND_CONTEXT: /* explicit context */
1546             current_offset += sizeof(NDR_EHD_CONTEXT);
1547             break;
1548         default:
1549             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1550             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1551         }
1552         break;
1553     case RPC_FC_BIND_GENERIC: /* implicit generic */
1554     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
1555     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
1556     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
1557         break;
1558     default:
1559         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1560         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1561     }
1562
1563     bV2Format = (pStubDesc->Version >= 0x20000);
1564
1565     if (bV2Format)
1566     {
1567         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1568             (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset];
1569
1570         Oif_flags = pOIFHeader->Oi2Flags;
1571         number_of_params = pOIFHeader->number_of_params;
1572
1573         current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1574     }
1575
1576     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
1577
1578     if (Oif_flags.HasExtensions)
1579     {
1580         const NDR_PROC_HEADER_EXTS *pExtensions =
1581             (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset];
1582         ext_flags = pExtensions->Flags2;
1583         current_offset += pExtensions->Size;
1584     }
1585
1586     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1587         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1588     else
1589         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1590
1591     /* create the full pointer translation tables, if requested */
1592     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1593         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1594
1595     /* store the RPC flags away */
1596     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1597         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1598
1599     /* use alternate memory allocation routines */
1600     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1601 #if 0
1602           NdrRpcSsEnableAllocate(&stubMsg);
1603 #else
1604           FIXME("Set RPCSS memory allocation routines\n");
1605 #endif
1606
1607     if (Oif_flags.HasPipes)
1608     {
1609         FIXME("pipes not supported yet\n");
1610         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1611         /* init pipes package */
1612         /* NdrPipesInitialize(...) */
1613     }
1614     if (ext_flags.HasNewCorrDesc)
1615     {
1616         /* initialize extra correlation package */
1617         FIXME("new correlation description not implemented\n");
1618         stubMsg.fHasNewCorrDesc = TRUE;
1619     }
1620
1621     /* convert strings, floating point values and endianess into our
1622      * preferred format */
1623     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1624         NdrConvert(&stubMsg, pFormat);
1625
1626     parameter_start_offset = current_offset;
1627
1628     TRACE("allocating memory for stack of size %x\n", stack_size);
1629
1630     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1631     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1632
1633     /* add the implicit This pointer as the first arg to the function if we
1634      * are calling an object method */
1635     if (pThis)
1636         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1637
1638     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1639     {
1640         TRACE("phase = %d\n", phase);
1641         switch (phase)
1642         {
1643         case STUBLESS_CALLSERVER:
1644             /* call the server function */
1645             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1646                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1647             else
1648             {
1649                 SERVER_ROUTINE func;
1650                 LONG_PTR retval;
1651
1652                 if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1653                 {
1654                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1655                     func = vtbl[pRpcMsg->ProcNum];
1656                 }
1657                 else
1658                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1659
1660                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1661                 retval = call_server_func(func, args, stack_size);
1662
1663                 if (retval_ptr)
1664                 {
1665                     TRACE("stub implementation returned 0x%lx\n", retval);
1666                     *retval_ptr = retval;
1667                 }
1668                 else
1669                     TRACE("void stub implementation\n");
1670             }
1671
1672             stubMsg.Buffer = NULL;
1673             stubMsg.BufferLength = 0;
1674
1675             break;
1676         case STUBLESS_GETBUFFER:
1677             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1678                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1679             else
1680             {
1681                 RPC_STATUS Status;
1682
1683                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1684                 /* allocate buffer for [out] and [ret] params */
1685                 Status = I_RpcGetBuffer(pRpcMsg); 
1686                 if (Status)
1687                     RpcRaiseException(Status);
1688                 stubMsg.Buffer = pRpcMsg->Buffer;
1689             }
1690             break;
1691         case STUBLESS_UNMARSHAL:
1692         case STUBLESS_INITOUT:
1693         case STUBLESS_CALCSIZE:
1694         case STUBLESS_MARSHAL:
1695         case STUBLESS_FREE:
1696             if (bV2Format)
1697                 retval_ptr = stub_do_args(&stubMsg, &pFormat[parameter_start_offset],
1698                                           phase, args, number_of_params);
1699             else
1700                 retval_ptr = stub_do_old_args(&stubMsg, &pFormat[parameter_start_offset],
1701                                               phase, args, stack_size,
1702                                               (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
1703
1704             break;
1705         default:
1706             ERR("shouldn't reach here. phase %d\n", phase);
1707             break;
1708         }
1709     }
1710
1711     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1712
1713     if (ext_flags.HasNewCorrDesc)
1714     {
1715         /* free extra correlation package */
1716         /* NdrCorrelationFree(&stubMsg); */
1717     }
1718
1719     if (Oif_flags.HasPipes)
1720     {
1721         /* NdrPipesDone(...) */
1722     }
1723
1724     /* free the full pointer translation tables */
1725     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1726         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1727
1728     /* free server function stack */
1729     HeapFree(GetProcessHeap(), 0, args);
1730
1731     return S_OK;
1732 }
1733
1734 /***********************************************************************
1735  *            NdrServerCall2 [RPCRT4.@]
1736  */
1737 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1738 {
1739     DWORD dwPhase;
1740     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1741 }
1742
1743 /***********************************************************************
1744  *            NdrStubCall [RPCRT4.@]
1745  */
1746 LONG WINAPI NdrStubCall( struct IRpcStubBuffer *This, struct IRpcChannelBuffer *channel,
1747                          PRPC_MESSAGE msg, DWORD *phase )
1748 {
1749     return NdrStubCall2( This, channel, msg, phase );
1750 }
1751
1752 /***********************************************************************
1753  *            NdrServerCall [RPCRT4.@]
1754  */
1755 void WINAPI NdrServerCall( PRPC_MESSAGE msg )
1756 {
1757     DWORD phase;
1758     NdrStubCall( NULL, NULL, msg, &phase );
1759 }
1760
1761 struct async_call_data
1762 {
1763     MIDL_STUB_MESSAGE *pStubMsg;
1764     const NDR_PROC_HEADER *pProcHeader;
1765     PFORMAT_STRING pHandleFormat;
1766     PFORMAT_STRING pParamFormat;
1767     RPC_BINDING_HANDLE hBinding;
1768     /* size of stack */
1769     unsigned short stack_size;
1770     /* number of parameters. optional for client to give it to us */
1771     unsigned char number_of_params;
1772     /* correlation cache */
1773     ULONG_PTR NdrCorrCache[256];
1774 };
1775
1776 LONG_PTR CDECL ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, void **stack_top )
1777 {
1778     /* pointer to start of stack where arguments start */
1779     PRPC_MESSAGE pRpcMsg;
1780     PMIDL_STUB_MESSAGE pStubMsg;
1781     RPC_ASYNC_STATE *pAsync;
1782     struct async_call_data *async_call_data;
1783     /* procedure number */
1784     unsigned short procedure_number;
1785     /* cache of Oif_flags from v2 procedure header */
1786     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1787     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1788     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1789     /* the type of pass we are currently doing */
1790     int phase;
1791     /* header for procedure string */
1792     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1793     /* -Oif or -Oicf generated format */
1794     BOOL bV2Format = FALSE;
1795
1796     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
1797
1798     /* Later NDR language versions probably won't be backwards compatible */
1799     if (pStubDesc->Version > 0x50002)
1800     {
1801         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1802         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1803     }
1804
1805     async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1806     if (!async_call_data) RpcRaiseException(ERROR_OUTOFMEMORY);
1807     async_call_data->number_of_params = ~0;
1808     async_call_data->pProcHeader = pProcHeader;
1809
1810     async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1811     pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
1812
1813     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1814     {
1815         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1816         async_call_data->stack_size = pProcHeader->stack_size;
1817         procedure_number = pProcHeader->proc_num;
1818         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1819     }
1820     else
1821     {
1822         async_call_data->stack_size = pProcHeader->stack_size;
1823         procedure_number = pProcHeader->proc_num;
1824         pFormat += sizeof(NDR_PROC_HEADER);
1825     }
1826     TRACE("stack size: 0x%x\n", async_call_data->stack_size);
1827     TRACE("proc num: %d\n", procedure_number);
1828
1829     /* create the full pointer translation tables, if requested */
1830     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1831         pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
1832
1833     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1834     {
1835         ERR("objects not supported\n");
1836         I_RpcFree(async_call_data);
1837         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1838     }
1839
1840     NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
1841
1842     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1843     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
1844
1845     /* needed for conformance of top-level objects */
1846     pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
1847     memcpy(pStubMsg->StackTop, stack_top, async_call_data->stack_size);
1848
1849     pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
1850     pAsync->StubInfo = async_call_data;
1851     async_call_data->pHandleFormat = pFormat;
1852
1853     pFormat = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, &async_call_data->hBinding);
1854     if (!pFormat) goto done;
1855
1856     bV2Format = (pStubDesc->Version >= 0x20000);
1857
1858     if (bV2Format)
1859     {
1860         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1861             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1862
1863         Oif_flags = pOIFHeader->Oi2Flags;
1864         async_call_data->number_of_params = pOIFHeader->number_of_params;
1865
1866         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1867     }
1868
1869     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
1870
1871     if (Oif_flags.HasExtensions)
1872     {
1873         const NDR_PROC_HEADER_EXTS *pExtensions =
1874             (const NDR_PROC_HEADER_EXTS *)pFormat;
1875         ext_flags = pExtensions->Flags2;
1876         pFormat += pExtensions->Size;
1877     }
1878
1879     async_call_data->pParamFormat = pFormat;
1880
1881     pStubMsg->BufferLength = 0;
1882
1883     /* store the RPC flags away */
1884     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1885         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1886
1887     /* use alternate memory allocation routines */
1888     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1889         NdrRpcSmSetClientToOsf(pStubMsg);
1890
1891     if (Oif_flags.HasPipes)
1892     {
1893         FIXME("pipes not supported yet\n");
1894         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1895         /* init pipes package */
1896         /* NdrPipesInitialize(...) */
1897     }
1898     if (ext_flags.HasNewCorrDesc)
1899     {
1900         /* initialize extra correlation package */
1901         NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
1902     }
1903
1904     /* order of phases:
1905      * 1. PROXY_CALCSIZE - calculate the buffer size
1906      * 2. PROXY_GETBUFFER - allocate the buffer
1907      * 3. PROXY_MARHSAL - marshal [in] params into the buffer
1908      * 4. PROXY_SENDRECEIVE - send buffer
1909      * Then in NdrpCompleteAsyncClientCall:
1910      * 1. PROXY_SENDRECEIVE - receive buffer
1911      * 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer
1912      */
1913     for (phase = PROXY_CALCSIZE; phase <= PROXY_SENDRECEIVE; phase++)
1914     {
1915         RPC_STATUS status;
1916         TRACE("phase = %d\n", phase);
1917         switch (phase)
1918         {
1919         case PROXY_GETBUFFER:
1920             /* allocate the buffer */
1921             if (Oif_flags.HasPipes)
1922                 /* NdrGetPipeBuffer(...) */
1923                 FIXME("pipes not supported yet\n");
1924             else
1925             {
1926                 if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
1927 #if 0
1928                     NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1929 #else
1930                     FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
1931 #endif
1932                 else
1933                     NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1934             }
1935             pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1936             status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
1937             if (status != RPC_S_OK)
1938                 RpcRaiseException(status);
1939             break;
1940         case PROXY_SENDRECEIVE:
1941             pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1942             /* send the [in] params only */
1943             if (Oif_flags.HasPipes)
1944                 /* NdrPipesSend(...) */
1945                 FIXME("pipes not supported yet\n");
1946             else
1947             {
1948                 if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
1949 #if 0
1950                     NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1951 #else
1952                     FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
1953 #endif
1954                 else
1955                 {
1956                     pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
1957                     status = I_RpcSend(pStubMsg->RpcMsg);
1958                     if (status != RPC_S_OK)
1959                         RpcRaiseException(status);
1960                 }
1961             }
1962
1963             break;
1964         case PROXY_CALCSIZE:
1965         case PROXY_MARSHAL:
1966             if (bV2Format)
1967                 client_do_args(pStubMsg, pFormat, phase, pStubMsg->StackTop, NULL,
1968                     async_call_data->number_of_params, NULL);
1969             else
1970                 client_do_args_old_format(pStubMsg, pFormat, phase,
1971                     pStubMsg->StackTop, async_call_data->stack_size, NULL,
1972                     (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT), FALSE);
1973             break;
1974         default:
1975             ERR("shouldn't reach here. phase %d\n", phase);
1976             break;
1977         }
1978     }
1979
1980 done:
1981     TRACE("returning 0\n");
1982     return 0;
1983 }
1984
1985 RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
1986 {
1987     /* pointer to start of stack where arguments start */
1988     PMIDL_STUB_MESSAGE pStubMsg;
1989     struct async_call_data *async_call_data;
1990     /* the type of pass we are currently doing */
1991     int phase;
1992     /* header for procedure string */
1993     const NDR_PROC_HEADER * pProcHeader;
1994     /* -Oif or -Oicf generated format */
1995     BOOL bV2Format;
1996     RPC_STATUS status = RPC_S_OK;
1997
1998     if (!pAsync->StubInfo)
1999         return RPC_S_INVALID_ASYNC_HANDLE;
2000
2001     async_call_data = pAsync->StubInfo;
2002     pStubMsg = async_call_data->pStubMsg;
2003     pProcHeader = async_call_data->pProcHeader;
2004
2005     bV2Format = (pStubMsg->StubDesc->Version >= 0x20000);
2006
2007     /* order of phases:
2008      * 1. PROXY_CALCSIZE - calculate the buffer size
2009      * 2. PROXY_GETBUFFER - allocate the buffer
2010      * 3. PROXY_MARHSAL - marshal [in] params into the buffer
2011      * 4. PROXY_SENDRECEIVE - send buffer
2012      * Then in NdrpCompleteAsyncClientCall:
2013      * 1. PROXY_SENDRECEIVE - receive buffer
2014      * 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer
2015      */
2016     for (phase = PROXY_SENDRECEIVE; phase <= PROXY_UNMARSHAL; phase++)
2017     {
2018         switch (phase)
2019         {
2020         case PROXY_SENDRECEIVE:
2021             pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
2022             /* receive the [out] params */
2023             if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
2024 #if 0
2025                 NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
2026 #else
2027                 FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
2028 #endif
2029             else
2030             {
2031                 status = I_RpcReceive(pStubMsg->RpcMsg);
2032                 if (status != RPC_S_OK)
2033                     goto cleanup;
2034                 pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
2035                 pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
2036                 pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
2037                 pStubMsg->Buffer = pStubMsg->BufferStart;
2038             }
2039
2040             /* convert strings, floating point values and endianess into our
2041              * preferred format */
2042 #if 0
2043             if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
2044                 NdrConvert(pStubMsg, pFormat);
2045 #endif
2046
2047             break;
2048         case PROXY_UNMARSHAL:
2049             if (bV2Format)
2050                 client_do_args(pStubMsg, async_call_data->pParamFormat, phase, pStubMsg->StackTop,
2051                                NULL, async_call_data->number_of_params, Reply);
2052             else
2053                 client_do_args_old_format(pStubMsg, async_call_data->pParamFormat, phase,
2054                     pStubMsg->StackTop, async_call_data->stack_size, Reply, FALSE, FALSE);
2055             break;
2056         default:
2057             ERR("shouldn't reach here. phase %d\n", phase);
2058             break;
2059         }
2060     }
2061
2062 cleanup:
2063     if (pStubMsg->fHasNewCorrDesc)
2064     {
2065         /* free extra correlation package */
2066         NdrCorrelationFree(pStubMsg);
2067     }
2068
2069     /* free the full pointer translation tables */
2070     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
2071         NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
2072
2073     /* free marshalling buffer */
2074     NdrFreeBuffer(pStubMsg);
2075     client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
2076
2077     I_RpcFree(pStubMsg->StackTop);
2078     I_RpcFree(async_call_data);
2079
2080     TRACE("-- 0x%x\n", status);
2081     return status;
2082 }
2083
2084 #ifdef __x86_64__
2085
2086 __ASM_GLOBAL_FUNC( NdrAsyncClientCall,
2087                    "movq %r8,0x18(%rsp)\n\t"
2088                    "movq %r9,0x20(%rsp)\n\t"
2089                    "leaq 0x18(%rsp),%r8\n\t"
2090                    "subq $0x28,%rsp\n\t"
2091                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
2092                    "call " __ASM_NAME("ndr_async_client_call") "\n\t"
2093                    "addq $0x28,%rsp\n\t"
2094                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
2095                    "ret" );
2096
2097 #else  /* __x86_64__ */
2098
2099 /***********************************************************************
2100  *            NdrAsyncClientCall [RPCRT4.@]
2101  */
2102 CLIENT_CALL_RETURN WINAPIV NdrAsyncClientCall( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
2103 {
2104     __ms_va_list args;
2105     LONG_PTR ret;
2106
2107     __ms_va_start( args, format );
2108     ret = ndr_async_client_call( desc, format, va_arg( args, void ** ));
2109     __ms_va_end( args );
2110     return *(CLIENT_CALL_RETURN *)&ret;
2111 }
2112
2113 #endif  /* __x86_64__ */
2114
2115 RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
2116     struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
2117     DWORD * pdwStubPhase)
2118 {
2119     FIXME("unimplemented, expect crash!\n");
2120     return 0;
2121 }