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