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