xref: /reactos/dll/win32/rpcrt4/ndr_stubless.c (revision 7f26a396)
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     unsigned short BindingHandleOffset = (USHORT)-1;
1334 
1335     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1336 
1337     if (pThis)
1338         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1339     else
1340         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1341 
1342     pStubDesc = pServerInfo->pStubDesc;
1343     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1344     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1345 
1346     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1347 
1348     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1349     {
1350         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1351         stack_size = header_rpc->stack_size;
1352         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1353 
1354     }
1355     else
1356     {
1357         stack_size = pProcHeader->stack_size;
1358         pFormat += sizeof(NDR_PROC_HEADER);
1359     }
1360 
1361     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1362 
1363     /* binding */
1364     switch (pProcHeader->handle_type)
1365     {
1366     /* explicit binding: parse additional section */
1367     case 0:
1368         switch (*pFormat) /* handle_type */
1369         {
1370         case FC_BIND_PRIMITIVE: /* explicit primitive */
1371             BindingHandleOffset = ((NDR_EHD_PRIMITIVE*)pFormat)->offset;
1372             pFormat += sizeof(NDR_EHD_PRIMITIVE);
1373             break;
1374         case FC_BIND_GENERIC: /* explicit generic */
1375             BindingHandleOffset = ((NDR_EHD_GENERIC*)pFormat)->offset;
1376             pFormat += sizeof(NDR_EHD_GENERIC);
1377             break;
1378         case FC_BIND_CONTEXT: /* explicit context */
1379             BindingHandleOffset = ((NDR_EHD_CONTEXT*)pFormat)->offset;
1380             pFormat += sizeof(NDR_EHD_CONTEXT);
1381             break;
1382         default:
1383             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1384             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1385         }
1386         break;
1387     case FC_BIND_GENERIC: /* implicit generic */
1388     case FC_BIND_PRIMITIVE: /* implicit primitive */
1389     case FC_CALLBACK_HANDLE: /* implicit callback */
1390     case FC_AUTO_HANDLE: /* implicit auto handle */
1391         break;
1392     default:
1393         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1394         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1395     }
1396 
1397     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1398         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1399     else
1400         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1401 
1402     /* create the full pointer translation tables, if requested */
1403     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1404         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1405 
1406     /* store the RPC flags away */
1407     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1408         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1409 
1410     /* use alternate memory allocation routines */
1411     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1412 #if 0
1413           NdrRpcSsEnableAllocate(&stubMsg);
1414 #else
1415           FIXME("Set RPCSS memory allocation routines\n");
1416 #endif
1417 
1418     TRACE("allocating memory for stack of size %x\n", stack_size);
1419 
1420     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1421     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1422 
1423     /* add the implicit This pointer as the first arg to the function if we
1424      * are calling an object method */
1425     if (pThis)
1426         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1427 
1428     /* add the binding handle to the stack if we are using explicit binding handles */
1429     if (BindingHandleOffset != (USHORT)-1)
1430         *(RPC_BINDING_HANDLE*)&(args[BindingHandleOffset]) = pRpcMsg->Handle;
1431 
1432     if (is_oicf_stubdesc(pStubDesc))
1433     {
1434         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1435 
1436         Oif_flags = pOIFHeader->Oi2Flags;
1437         number_of_params = pOIFHeader->number_of_params;
1438 
1439         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1440 
1441         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1442 
1443         if (Oif_flags.HasExtensions)
1444         {
1445             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
1446             ext_flags = pExtensions->Flags2;
1447             pFormat += pExtensions->Size;
1448         }
1449 
1450         if (Oif_flags.HasPipes)
1451         {
1452             FIXME("pipes not supported yet\n");
1453             RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1454             /* init pipes package */
1455             /* NdrPipesInitialize(...) */
1456         }
1457         if (ext_flags.HasNewCorrDesc)
1458         {
1459             /* initialize extra correlation package */
1460             NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
1461             if (ext_flags.Unused & 0x2) /* has range on conformance */
1462                 stubMsg.CorrDespIncrement = 12;
1463         }
1464     }
1465     else
1466     {
1467         pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
1468                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1469                                     /* reuse the correlation cache, it's not needed for v1 format */
1470                                     NdrCorrCache, sizeof(NdrCorrCache), &number_of_params );
1471     }
1472 
1473     /* convert strings, floating point values and endianness into our
1474      * preferred format */
1475     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1476         NdrConvert(&stubMsg, pFormat);
1477 
1478     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1479     {
1480         TRACE("phase = %d\n", phase);
1481         switch (phase)
1482         {
1483         case STUBLESS_CALLSERVER:
1484             /* call the server function */
1485             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1486                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1487             else
1488             {
1489                 SERVER_ROUTINE func;
1490                 LONG_PTR retval;
1491 
1492                 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1493                 {
1494                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1495                     func = vtbl[pRpcMsg->ProcNum];
1496                 }
1497                 else
1498                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1499 
1500                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1501                 retval = call_server_func(func, args, stack_size);
1502 
1503                 if (retval_ptr)
1504                 {
1505                     TRACE("stub implementation returned 0x%lx\n", retval);
1506                     *retval_ptr = retval;
1507                 }
1508                 else
1509                     TRACE("void stub implementation\n");
1510             }
1511 
1512             stubMsg.Buffer = NULL;
1513             stubMsg.BufferLength = 0;
1514 
1515             break;
1516         case STUBLESS_GETBUFFER:
1517             if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1518                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1519             else
1520             {
1521                 RPC_STATUS Status;
1522 
1523                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1524                 /* allocate buffer for [out] and [ret] params */
1525                 Status = I_RpcGetBuffer(pRpcMsg);
1526                 if (Status)
1527                     RpcRaiseException(Status);
1528                 stubMsg.Buffer = pRpcMsg->Buffer;
1529             }
1530             break;
1531         case STUBLESS_UNMARSHAL:
1532         case STUBLESS_INITOUT:
1533         case STUBLESS_CALCSIZE:
1534         case STUBLESS_MARSHAL:
1535         case STUBLESS_MUSTFREE:
1536         case STUBLESS_FREE:
1537             retval_ptr = stub_do_args(&stubMsg, pFormat, phase, number_of_params);
1538             break;
1539         default:
1540             ERR("shouldn't reach here. phase %d\n", phase);
1541             break;
1542         }
1543     }
1544 
1545     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1546 
1547     if (ext_flags.HasNewCorrDesc)
1548     {
1549         /* free extra correlation package */
1550         NdrCorrelationFree(&stubMsg);
1551     }
1552 
1553     if (Oif_flags.HasPipes)
1554     {
1555         /* NdrPipesDone(...) */
1556     }
1557 
1558     /* free the full pointer translation tables */
1559     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1560         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1561 
1562     /* free server function stack */
1563     HeapFree(GetProcessHeap(), 0, args);
1564 
1565     return S_OK;
1566 }
1567 
1568 /***********************************************************************
1569  *            NdrServerCall2 [RPCRT4.@]
1570  */
1571 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1572 {
1573     DWORD dwPhase;
1574     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1575 }
1576 
1577 /***********************************************************************
1578  *            NdrStubCall [RPCRT4.@]
1579  */
1580 LONG WINAPI NdrStubCall( struct IRpcStubBuffer *This, struct IRpcChannelBuffer *channel,
1581                          PRPC_MESSAGE msg, DWORD *phase )
1582 {
1583     return NdrStubCall2( This, channel, msg, phase );
1584 }
1585 
1586 /***********************************************************************
1587  *            NdrServerCall [RPCRT4.@]
1588  */
1589 void WINAPI NdrServerCall( PRPC_MESSAGE msg )
1590 {
1591     DWORD phase;
1592     NdrStubCall( NULL, NULL, msg, &phase );
1593 }
1594 
1595 /***********************************************************************
1596  *            NdrServerCallAll [RPCRT4.@]
1597  */
1598 void WINAPI NdrServerCallAll( PRPC_MESSAGE msg )
1599 {
1600     FIXME("%p stub\n", msg);
1601 }
1602 
1603 /* Helper for ndr_async_client_call, to factor out the part that may or may not be
1604  * guarded by a try/except block. */
1605 static void do_ndr_async_client_call( const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormat, void **stack_top )
1606 {
1607     /* pointer to start of stack where arguments start */
1608     PRPC_MESSAGE pRpcMsg;
1609     PMIDL_STUB_MESSAGE pStubMsg;
1610     RPC_ASYNC_STATE *pAsync;
1611     struct async_call_data *async_call_data;
1612     /* procedure number */
1613     unsigned short procedure_number;
1614     /* cache of Oif_flags from v2 procedure header */
1615     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1616     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1617     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1618     /* header for procedure string */
1619     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1620     RPC_STATUS status;
1621 
1622     /* Later NDR language versions probably won't be backwards compatible */
1623     if (pStubDesc->Version > 0x50002)
1624     {
1625         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1626         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1627     }
1628 
1629     async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1630     if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
1631     async_call_data->pProcHeader = pProcHeader;
1632 
1633     async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1634     pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
1635 
1636     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1637     {
1638         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1639         async_call_data->stack_size = header_rpc->stack_size;
1640         procedure_number = header_rpc->proc_num;
1641         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1642     }
1643     else
1644     {
1645         async_call_data->stack_size = pProcHeader->stack_size;
1646         procedure_number = pProcHeader->proc_num;
1647         pFormat += sizeof(NDR_PROC_HEADER);
1648     }
1649     TRACE("stack size: 0x%x\n", async_call_data->stack_size);
1650     TRACE("proc num: %d\n", procedure_number);
1651 
1652     /* create the full pointer translation tables, if requested */
1653     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1654         pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
1655 
1656     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1657     {
1658         ERR("objects not supported\n");
1659         I_RpcFree(async_call_data);
1660         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1661     }
1662 
1663     NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
1664 
1665     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1666     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
1667 
1668     /* needed for conformance of top-level objects */
1669     pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
1670     memcpy(pStubMsg->StackTop, stack_top, async_call_data->stack_size);
1671 
1672     pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
1673     pAsync->StubInfo = async_call_data;
1674     async_call_data->pHandleFormat = pFormat;
1675 
1676     TRACE("pAsync %p, pAsync->StubInfo %p, NotificationType %d\n", pAsync, pAsync->StubInfo, pAsync->NotificationType);
1677 
1678     pFormat += get_handle_desc_size(pProcHeader, pFormat);
1679     async_call_data->hBinding = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat);
1680     if (!async_call_data->hBinding) return;
1681 
1682     if (is_oicf_stubdesc(pStubDesc))
1683     {
1684         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1685             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1686 
1687         Oif_flags = pOIFHeader->Oi2Flags;
1688         async_call_data->number_of_params = pOIFHeader->number_of_params;
1689 
1690         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1691 
1692         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1693 
1694         if (Oif_flags.HasExtensions)
1695         {
1696             const NDR_PROC_HEADER_EXTS *pExtensions =
1697                 (const NDR_PROC_HEADER_EXTS *)pFormat;
1698             ext_flags = pExtensions->Flags2;
1699             pFormat += pExtensions->Size;
1700         }
1701     }
1702     else
1703     {
1704         pFormat = convert_old_args( pStubMsg, pFormat, async_call_data->stack_size,
1705                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1706                                     async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache),
1707                                     &async_call_data->number_of_params );
1708     }
1709 
1710     async_call_data->pParamFormat = pFormat;
1711 
1712     pStubMsg->BufferLength = 0;
1713 
1714     /* store the RPC flags away */
1715     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1716         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1717 
1718     /* use alternate memory allocation routines */
1719     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1720         NdrRpcSmSetClientToOsf(pStubMsg);
1721 
1722     if (Oif_flags.HasPipes)
1723     {
1724         FIXME("pipes not supported yet\n");
1725         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1726         /* init pipes package */
1727         /* NdrPipesInitialize(...) */
1728     }
1729     if (ext_flags.HasNewCorrDesc)
1730     {
1731         /* initialize extra correlation package */
1732         NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
1733         if (ext_flags.Unused & 0x2) /* has range on conformance */
1734             pStubMsg->CorrDespIncrement = 12;
1735     }
1736 
1737     /* order of phases:
1738      * 1. CALCSIZE - calculate the buffer size
1739      * 2. GETBUFFER - allocate the buffer
1740      * 3. MARSHAL - marshal [in] params into the buffer
1741      * 4. SENDRECEIVE - send buffer
1742      * Then in NdrpCompleteAsyncClientCall:
1743      * 1. SENDRECEIVE - receive buffer
1744      * 2. UNMARSHAL - unmarshal [out] params from buffer
1745      */
1746 
1747     /* 1. CALCSIZE */
1748     TRACE( "CALCSIZE\n" );
1749     client_do_args(pStubMsg, pFormat, STUBLESS_CALCSIZE, NULL, async_call_data->number_of_params, NULL);
1750 
1751     /* 2. GETBUFFER */
1752     TRACE( "GETBUFFER\n" );
1753     if (Oif_flags.HasPipes)
1754         /* NdrGetPipeBuffer(...) */
1755         FIXME("pipes not supported yet\n");
1756     else
1757     {
1758         if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1759 #if 0
1760             NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1761 #else
1762         FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
1763 #endif
1764         else
1765             NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1766     }
1767     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1768     status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
1769     if (status != RPC_S_OK)
1770         RpcRaiseException(status);
1771 
1772     /* 3. MARSHAL */
1773     TRACE( "MARSHAL\n" );
1774     client_do_args(pStubMsg, pFormat, STUBLESS_MARSHAL, NULL, async_call_data->number_of_params, NULL);
1775 
1776     /* 4. SENDRECEIVE */
1777     TRACE( "SEND\n" );
1778     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1779     /* send the [in] params only */
1780     if (Oif_flags.HasPipes)
1781         /* NdrPipesSend(...) */
1782         FIXME("pipes not supported yet\n");
1783     else
1784     {
1785         if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1786 #if 0
1787             NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1788 #else
1789         FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
1790 #endif
1791         else
1792         {
1793             pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
1794             status = I_RpcSend(pStubMsg->RpcMsg);
1795             if (status != RPC_S_OK)
1796                 RpcRaiseException(status);
1797         }
1798     }
1799 }
1800 
1801 LONG_PTR CDECL DECLSPEC_HIDDEN ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
1802                                                       void **stack_top )
1803 {
1804     LONG_PTR ret = 0;
1805     const NDR_PROC_HEADER *pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1806 
1807     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
1808 
1809     if (pProcHeader->Oi_flags & Oi_HAS_COMM_OR_FAULT)
1810     {
1811         __TRY
1812         {
1813             do_ndr_async_client_call( pStubDesc, pFormat, stack_top );
1814         }
1815         __EXCEPT_ALL
1816         {
1817             FIXME("exception %x during ndr_async_client_call()\n", GetExceptionCode());
1818             ret = GetExceptionCode();
1819         }
1820         __ENDTRY
1821     }
1822     else
1823         do_ndr_async_client_call( pStubDesc, pFormat, stack_top);
1824 
1825     TRACE("returning %ld\n", ret);
1826     return ret;
1827 }
1828 
1829 RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
1830 {
1831     /* pointer to start of stack where arguments start */
1832     PMIDL_STUB_MESSAGE pStubMsg;
1833     struct async_call_data *async_call_data;
1834     /* header for procedure string */
1835     const NDR_PROC_HEADER * pProcHeader;
1836     RPC_STATUS status = RPC_S_OK;
1837 
1838     if (!pAsync->StubInfo)
1839         return RPC_S_INVALID_ASYNC_HANDLE;
1840 
1841     async_call_data = pAsync->StubInfo;
1842     pStubMsg = async_call_data->pStubMsg;
1843     pProcHeader = async_call_data->pProcHeader;
1844 
1845     /* order of phases:
1846      * 1. CALCSIZE - calculate the buffer size
1847      * 2. GETBUFFER - allocate the buffer
1848      * 3. MARSHAL - marshal [in] params into the buffer
1849      * 4. SENDRECEIVE - send buffer
1850      * Then in NdrpCompleteAsyncClientCall:
1851      * 1. SENDRECEIVE - receive buffer
1852      * 2. UNMARSHAL - unmarshal [out] params from buffer
1853      */
1854 
1855     /* 1. SENDRECEIVE */
1856     TRACE( "RECEIVE\n" );
1857     pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1858     /* receive the [out] params */
1859     if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1860 #if 0
1861         NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1862 #else
1863     FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
1864 #endif
1865     else
1866     {
1867         status = I_RpcReceive(pStubMsg->RpcMsg);
1868         if (status != RPC_S_OK)
1869             goto cleanup;
1870         pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
1871         pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
1872         pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
1873         pStubMsg->Buffer = pStubMsg->BufferStart;
1874     }
1875 
1876     /* convert strings, floating point values and endianness into our
1877      * preferred format */
1878 #if 0
1879     if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1880         NdrConvert(pStubMsg, pFormat);
1881 #endif
1882 
1883     /* 2. UNMARSHAL */
1884     TRACE( "UNMARSHAL\n" );
1885     client_do_args(pStubMsg, async_call_data->pParamFormat, STUBLESS_UNMARSHAL,
1886                    NULL, async_call_data->number_of_params, Reply);
1887 
1888 cleanup:
1889     if (pStubMsg->fHasNewCorrDesc)
1890     {
1891         /* free extra correlation package */
1892         NdrCorrelationFree(pStubMsg);
1893     }
1894 
1895     /* free the full pointer translation tables */
1896     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1897         NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
1898 
1899     /* free marshalling buffer */
1900     NdrFreeBuffer(pStubMsg);
1901     client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
1902 
1903     I_RpcFree(pStubMsg->StackTop);
1904     I_RpcFree(async_call_data);
1905 
1906     TRACE("-- 0x%x\n", status);
1907     return status;
1908 }
1909 
1910 #ifdef __x86_64__
1911 
1912 __ASM_GLOBAL_FUNC( NdrAsyncClientCall,
1913                    "subq $0x28,%rsp\n\t"
1914                    __ASM_SEH(".seh_stackalloc 0x28\n\t")
1915                    __ASM_SEH(".seh_endprologue\n\t")
1916                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1917                    "movq %r8,0x40(%rsp)\n\t"
1918                    "movq %r9,0x48(%rsp)\n\t"
1919                    "leaq 0x40(%rsp),%r8\n\t"
1920                    "call " __ASM_NAME("ndr_async_client_call") "\n\t"
1921                    "addq $0x28,%rsp\n\t"
1922                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1923                    "ret" );
1924 
1925 #else  /* __x86_64__ */
1926 
1927 /***********************************************************************
1928  *            NdrAsyncClientCall [RPCRT4.@]
1929  */
1930 CLIENT_CALL_RETURN WINAPIV NdrAsyncClientCall( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1931 {
1932     __ms_va_list args;
1933     LONG_PTR ret;
1934 
1935     __ms_va_start( args, format );
1936     ret = ndr_async_client_call( desc, format, va_arg( args, void ** ));
1937     __ms_va_end( args );
1938     return *(CLIENT_CALL_RETURN *)&ret;
1939 }
1940 
1941 #endif  /* __x86_64__ */
1942 
1943 RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
1944     struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
1945     DWORD * pdwStubPhase)
1946 {
1947     FIXME("unimplemented, expect crash!\n");
1948     return 0;
1949 }
1950 
1951 void RPC_ENTRY NdrAsyncServerCall(PRPC_MESSAGE pRpcMsg)
1952 {
1953     const MIDL_SERVER_INFO *pServerInfo;
1954     const MIDL_STUB_DESC *pStubDesc;
1955     PFORMAT_STRING pFormat;
1956     /* pointer to start of stack to pass into stub implementation */
1957     unsigned char *args;
1958     /* header for procedure string */
1959     const NDR_PROC_HEADER *pProcHeader;
1960     struct async_call_data *async_call_data;
1961     PRPC_ASYNC_STATE pAsync;
1962     RPC_STATUS status;
1963 
1964     TRACE("%p\n", pRpcMsg);
1965 
1966     pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1967 
1968     pStubDesc = pServerInfo->pStubDesc;
1969     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1970     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1971 
1972     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1973 
1974     async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1975     if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
1976     async_call_data->pProcHeader = pProcHeader;
1977 
1978     async_call_data->pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1979     *(PRPC_MESSAGE)(async_call_data->pStubMsg + 1) = *pRpcMsg;
1980 
1981     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1982     {
1983         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1984         async_call_data->stack_size = header_rpc->stack_size;
1985         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1986     }
1987     else
1988     {
1989         async_call_data->stack_size = pProcHeader->stack_size;
1990         pFormat += sizeof(NDR_PROC_HEADER);
1991     }
1992 
1993     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1994 
1995     /* binding */
1996     switch (pProcHeader->handle_type)
1997     {
1998     /* explicit binding: parse additional section */
1999     case 0:
2000         switch (*pFormat) /* handle_type */
2001         {
2002         case FC_BIND_PRIMITIVE: /* explicit primitive */
2003             pFormat += sizeof(NDR_EHD_PRIMITIVE);
2004             break;
2005         case FC_BIND_GENERIC: /* explicit generic */
2006             pFormat += sizeof(NDR_EHD_GENERIC);
2007             break;
2008         case FC_BIND_CONTEXT: /* explicit context */
2009             pFormat += sizeof(NDR_EHD_CONTEXT);
2010             break;
2011         default:
2012             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
2013             RpcRaiseException(RPC_X_BAD_STUB_DATA);
2014         }
2015         break;
2016     case FC_BIND_GENERIC: /* implicit generic */
2017     case FC_BIND_PRIMITIVE: /* implicit primitive */
2018     case FC_CALLBACK_HANDLE: /* implicit callback */
2019     case FC_AUTO_HANDLE: /* implicit auto handle */
2020         break;
2021     default:
2022         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
2023         RpcRaiseException(RPC_X_BAD_STUB_DATA);
2024     }
2025 
2026     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
2027     {
2028         ERR("objects not supported\n");
2029         I_RpcFree(async_call_data);
2030         RpcRaiseException(RPC_X_BAD_STUB_DATA);
2031     }
2032 
2033     NdrServerInitializeNew(pRpcMsg, async_call_data->pStubMsg, pStubDesc);
2034 
2035     /* create the full pointer translation tables, if requested */
2036     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
2037         async_call_data->pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0, XLAT_SERVER);
2038 
2039     /* use alternate memory allocation routines */
2040     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
2041 #if 0
2042           NdrRpcSsEnableAllocate(&stubMsg);
2043 #else
2044           FIXME("Set RPCSS memory allocation routines\n");
2045 #endif
2046 
2047     TRACE("allocating memory for stack of size %x\n", async_call_data->stack_size);
2048 
2049     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, async_call_data->stack_size);
2050     async_call_data->pStubMsg->StackTop = args; /* used by conformance of top-level objects */
2051 
2052     pAsync = I_RpcAllocate(sizeof(*pAsync));
2053     if (!pAsync) RpcRaiseException(RPC_X_NO_MEMORY);
2054 
2055     status = RpcAsyncInitializeHandle(pAsync, sizeof(*pAsync));
2056     if (status != RPC_S_OK)
2057         RpcRaiseException(status);
2058 
2059     pAsync->StubInfo = async_call_data;
2060     TRACE("pAsync %p, pAsync->StubInfo %p, pFormat %p\n", pAsync, pAsync->StubInfo, async_call_data->pHandleFormat);
2061 
2062     /* add the implicit pAsync pointer as the first arg to the function */
2063     *(void **)args = pAsync;
2064 
2065     if (is_oicf_stubdesc(pStubDesc))
2066     {
2067         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
2068         /* cache of Oif_flags from v2 procedure header */
2069         INTERPRETER_OPT_FLAGS Oif_flags;
2070         /* cache of extension flags from NDR_PROC_HEADER_EXTS */
2071         INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
2072 
2073         Oif_flags = pOIFHeader->Oi2Flags;
2074         async_call_data->number_of_params = pOIFHeader->number_of_params;
2075 
2076         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
2077 
2078         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
2079 
2080         if (Oif_flags.HasExtensions)
2081         {
2082             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
2083             ext_flags = pExtensions->Flags2;
2084             pFormat += pExtensions->Size;
2085         }
2086 
2087         if (Oif_flags.HasPipes)
2088         {
2089             FIXME("pipes not supported yet\n");
2090             RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
2091             /* init pipes package */
2092             /* NdrPipesInitialize(...) */
2093         }
2094         if (ext_flags.HasNewCorrDesc)
2095         {
2096             /* initialize extra correlation package */
2097             NdrCorrelationInitialize(async_call_data->pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
2098             if (ext_flags.Unused & 0x2) /* has range on conformance */
2099                 async_call_data->pStubMsg->CorrDespIncrement = 12;
2100         }
2101     }
2102     else
2103     {
2104         pFormat = convert_old_args( async_call_data->pStubMsg, pFormat, async_call_data->stack_size,
2105                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
2106                                     /* reuse the correlation cache, it's not needed for v1 format */
2107                                     async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), &async_call_data->number_of_params );
2108     }
2109 
2110     /* convert strings, floating point values and endianness into our
2111      * preferred format */
2112     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
2113         NdrConvert(async_call_data->pStubMsg, pFormat);
2114 
2115     async_call_data->pHandleFormat = pFormat;
2116 
2117     /* 1. UNMARSHAL */
2118     TRACE("UNMARSHAL\n");
2119     stub_do_args(async_call_data->pStubMsg, pFormat, STUBLESS_UNMARSHAL, async_call_data->number_of_params);
2120 
2121     /* 2. INITOUT */
2122     TRACE("INITOUT\n");
2123     async_call_data->retval_ptr = stub_do_args(async_call_data->pStubMsg, pFormat, STUBLESS_INITOUT, async_call_data->number_of_params);
2124 
2125     /* 3. CALLSERVER */
2126     TRACE("CALLSERVER\n");
2127     if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
2128         pServerInfo->ThunkTable[pRpcMsg->ProcNum](async_call_data->pStubMsg);
2129     else
2130         call_server_func(pServerInfo->DispatchTable[pRpcMsg->ProcNum], args, async_call_data->stack_size);
2131 }
2132 
2133 RPC_STATUS NdrpCompleteAsyncServerCall(RPC_ASYNC_STATE *pAsync, void *Reply)
2134 {
2135     /* pointer to start of stack where arguments start */
2136     PMIDL_STUB_MESSAGE pStubMsg;
2137     struct async_call_data *async_call_data;
2138     /* the type of pass we are currently doing */
2139     enum stubless_phase phase;
2140     RPC_STATUS status = RPC_S_OK;
2141 
2142     if (!pAsync->StubInfo)
2143         return RPC_S_INVALID_ASYNC_HANDLE;
2144 
2145     async_call_data = pAsync->StubInfo;
2146     pStubMsg = async_call_data->pStubMsg;
2147 
2148     TRACE("pAsync %p, pAsync->StubInfo %p, pFormat %p\n", pAsync, pAsync->StubInfo, async_call_data->pHandleFormat);
2149 
2150     if (async_call_data->retval_ptr)
2151     {
2152         TRACE("stub implementation returned 0x%lx\n", *(LONG_PTR *)Reply);
2153         *async_call_data->retval_ptr = *(LONG_PTR *)Reply;
2154     }
2155     else
2156         TRACE("void stub implementation\n");
2157 
2158     for (phase = STUBLESS_CALCSIZE; phase <= STUBLESS_FREE; phase++)
2159     {
2160         TRACE("phase = %d\n", phase);
2161         switch (phase)
2162         {
2163         case STUBLESS_GETBUFFER:
2164             if (async_call_data->pProcHeader->Oi_flags & Oi_OBJECT_PROC)
2165             {
2166                 ERR("objects not supported\n");
2167                 HeapFree(GetProcessHeap(), 0, async_call_data->pStubMsg->StackTop);
2168                 I_RpcFree(async_call_data);
2169                 I_RpcFree(pAsync);
2170                 RpcRaiseException(RPC_X_BAD_STUB_DATA);
2171             }
2172             else
2173             {
2174                 pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength;
2175                 /* allocate buffer for [out] and [ret] params */
2176                 status = I_RpcGetBuffer(pStubMsg->RpcMsg);
2177                 if (status)
2178                     RpcRaiseException(status);
2179                 pStubMsg->Buffer = pStubMsg->RpcMsg->Buffer;
2180             }
2181             break;
2182 
2183         case STUBLESS_CALCSIZE:
2184         case STUBLESS_MARSHAL:
2185         case STUBLESS_MUSTFREE:
2186         case STUBLESS_FREE:
2187             stub_do_args(pStubMsg, async_call_data->pHandleFormat, phase, async_call_data->number_of_params);
2188             break;
2189         default:
2190             ERR("shouldn't reach here. phase %d\n", phase);
2191             break;
2192         }
2193     }
2194 
2195 #if 0 /* FIXME */
2196     if (ext_flags.HasNewCorrDesc)
2197     {
2198         /* free extra correlation package */
2199         NdrCorrelationFree(pStubMsg);
2200     }
2201 
2202     if (Oif_flags.HasPipes)
2203     {
2204         /* NdrPipesDone(...) */
2205     }
2206 
2207     /* free the full pointer translation tables */
2208     if (async_call_data->pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
2209         NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
2210 #endif
2211 
2212     /* free server function stack */
2213     HeapFree(GetProcessHeap(), 0, async_call_data->pStubMsg->StackTop);
2214     I_RpcFree(async_call_data);
2215     I_RpcFree(pAsync);
2216 
2217     return S_OK;
2218 }
2219