amstream/tests: Add some tests to retreive media streams to media stream filter.
[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 *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
630         stack_size = pProcHeader->stack_size;
631         procedure_number = pProcHeader->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->CommOffset);
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         push edi            ; Save registers
994         push esi
995         mov ebp, esp
996         mov eax, [ebp+16]   ; Get stack size
997         sub esp, eax        ; Make room in stack for arguments
998         mov edi, esp
999         mov ecx, eax
1000         mov esi, [ebp+12]
1001         shr ecx, 2
1002         cld
1003         rep movsd           ; Copy dword blocks
1004         call [ebp+8]        ; Call function
1005         lea esp, [ebp-8]    ; Restore stack
1006         pop esi             ; Restore registers
1007         pop edi
1008         pop ebp
1009         ret
1010     }
1011 }
1012 #elif defined __i386__ && defined __GNUC__
1013 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1014 __ASM_GLOBAL_FUNC(call_server_func,
1015     "pushl %ebp\n\t"
1016     __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1017     __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1018     "movl %esp,%ebp\n\t"
1019     __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1020     "pushl %edi\n\t"            /* Save registers */
1021     __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
1022     "pushl %esi\n\t"
1023     __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
1024     "movl 16(%ebp), %eax\n\t"   /* Get stack size */
1025     "subl %eax, %esp\n\t"       /* Make room in stack for arguments */
1026     "andl $~15, %esp\n\t"       /* Make sure stack has 16-byte alignment for Mac OS X */
1027     "movl %esp, %edi\n\t"
1028     "movl %eax, %ecx\n\t"
1029     "movl 12(%ebp), %esi\n\t"
1030     "shrl $2, %ecx\n\t"         /* divide by 4 */
1031     "cld\n\t"
1032     "rep; movsl\n\t"            /* Copy dword blocks */
1033     "call *8(%ebp)\n\t"         /* Call function */
1034     "leal -8(%ebp), %esp\n\t"   /* Restore stack */
1035     "popl %esi\n\t"             /* Restore registers */
1036     __ASM_CFI(".cfi_same_value %esi\n\t")
1037     "popl %edi\n\t"
1038     __ASM_CFI(".cfi_same_value %edi\n\t")
1039     "popl %ebp\n\t"
1040     __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1041     __ASM_CFI(".cfi_same_value %ebp\n\t")
1042     "ret" )
1043 #elif defined __x86_64__
1044 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1045 __ASM_GLOBAL_FUNC( call_server_func,
1046                    "pushq %rbp\n\t"
1047                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
1048                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
1049                    "movq %rsp,%rbp\n\t"
1050                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
1051                    "pushq %rsi\n\t"
1052                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
1053                    "pushq %rdi\n\t"
1054                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
1055                    "movq %rcx,%rax\n\t"   /* function to call */
1056                    "movq $32,%rcx\n\t"    /* allocate max(32,stack_size) bytes of stack space */
1057                    "cmpq %rcx,%r8\n\t"
1058                    "cmovgq %r8,%rcx\n\t"
1059                    "subq %rcx,%rsp\n\t"
1060                    "andq $~15,%rsp\n\t"
1061                    "movq %r8,%rcx\n\t"
1062                    "shrq $3,%rcx\n\t"
1063                    "movq %rsp,%rdi\n\t"
1064                    "movq %rdx,%rsi\n\t"
1065                    "rep; movsq\n\t"       /* copy arguments */
1066                    "movq 0(%rsp),%rcx\n\t"
1067                    "movq 8(%rsp),%rdx\n\t"
1068                    "movq 16(%rsp),%r8\n\t"
1069                    "movq 24(%rsp),%r9\n\t"
1070                    "movq %rcx,%xmm0\n\t"
1071                    "movq %rdx,%xmm1\n\t"
1072                    "movq %r8,%xmm2\n\t"
1073                    "movq %r9,%xmm3\n\t"
1074                    "callq *%rax\n\t"
1075                    "leaq -16(%rbp),%rsp\n\t"  /* restore stack */
1076                    "popq %rdi\n\t"
1077                    __ASM_CFI(".cfi_same_value %rdi\n\t")
1078                    "popq %rsi\n\t"
1079                    __ASM_CFI(".cfi_same_value %rsi\n\t")
1080                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
1081                    "popq %rbp\n\t"
1082                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
1083                    __ASM_CFI(".cfi_same_value %rbp\n\t")
1084                    "ret")
1085 #else
1086 #warning call_server_func not implemented for your architecture
1087 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
1088 {
1089     FIXME("Not implemented for your architecture\n");
1090     return 0;
1091 }
1092 #endif
1093
1094 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
1095                               PFORMAT_STRING pFormat, enum stubless_phase phase,
1096                               unsigned short number_of_params)
1097 {
1098     const NDR_PARAM_OIF *params = (const NDR_PARAM_OIF *)pFormat;
1099     unsigned int i;
1100     LONG_PTR *retval_ptr = NULL;
1101
1102     for (i = 0; i < number_of_params; i++)
1103     {
1104         unsigned char *pArg = pStubMsg->StackTop + params[i].stack_offset;
1105         const unsigned char *pTypeFormat = &pStubMsg->StubDesc->pFormatTypes[params[i].u.type_offset];
1106
1107         TRACE("param[%d]: %p -> %p type %02x %s\n", i,
1108               pArg, *(unsigned char **)pArg,
1109               params[i].attr.IsBasetype ? params[i].u.type_format_char : *pTypeFormat,
1110               debugstr_PROC_PF( params[i].attr ));
1111
1112         switch (phase)
1113         {
1114         case STUBLESS_MARSHAL:
1115             if (params[i].attr.IsOut || params[i].attr.IsReturn)
1116                 call_marshaller(pStubMsg, pArg, &params[i]);
1117             break;
1118         case STUBLESS_FREE:
1119             if (params[i].attr.MustFree)
1120             {
1121                 call_freer(pStubMsg, pArg, &params[i]);
1122             }
1123             else if (params[i].attr.ServerAllocSize)
1124             {
1125                 HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1126             }
1127             else if (params[i].attr.IsOut &&
1128                      !params[i].attr.IsIn &&
1129                      !params[i].attr.IsBasetype &&
1130                      !params[i].attr.IsByValue)
1131             {
1132                 if (*pTypeFormat != RPC_FC_BIND_CONTEXT) pStubMsg->pfnFree(*(void **)pArg);
1133             }
1134             break;
1135         case STUBLESS_INITOUT:
1136             if (!params[i].attr.IsIn &&
1137                 params[i].attr.IsOut &&
1138                 !params[i].attr.IsBasetype &&
1139                 !params[i].attr.ServerAllocSize &&
1140                 !params[i].attr.IsByValue)
1141             {
1142                 if (*pTypeFormat == RPC_FC_BIND_CONTEXT)
1143                 {
1144                     NDR_SCONTEXT ctxt = NdrContextHandleInitialize(pStubMsg, pTypeFormat);
1145                     *(void **)pArg = NDRSContextValue(ctxt);
1146                 }
1147                 else
1148                 {
1149                     DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1150                     if (size)
1151                     {
1152                         *(void **)pArg = NdrAllocate(pStubMsg, size);
1153                         memset(*(void **)pArg, 0, size);
1154                     }
1155                 }
1156             }
1157             break;
1158         case STUBLESS_UNMARSHAL:
1159             if (params[i].attr.ServerAllocSize)
1160                 *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1161                                            params[i].attr.ServerAllocSize * 8);
1162
1163             if (params[i].attr.IsIn)
1164                 call_unmarshaller(pStubMsg, &pArg, &params[i], 0);
1165             break;
1166         case STUBLESS_CALCSIZE:
1167             if (params[i].attr.IsOut || params[i].attr.IsReturn)
1168                 call_buffer_sizer(pStubMsg, pArg, &params[i]);
1169             break;
1170         default:
1171             RpcRaiseException(RPC_S_INTERNAL_ERROR);
1172         }
1173         TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1174
1175         /* make a note of the address of the return value parameter for later */
1176         if (params[i].attr.IsReturn) retval_ptr = (LONG_PTR *)pArg;
1177     }
1178     return retval_ptr;
1179 }
1180
1181 /***********************************************************************
1182  *            NdrStubCall2 [RPCRT4.@]
1183  *
1184  * Unmarshals [in] parameters, calls either a method in an object or a server
1185  * function, marshals any [out] parameters and frees any allocated data.
1186  *
1187  * NOTES
1188  *  Used by stubless MIDL-generated code.
1189  */
1190 LONG WINAPI NdrStubCall2(
1191     struct IRpcStubBuffer * pThis,
1192     struct IRpcChannelBuffer * pChannel,
1193     PRPC_MESSAGE pRpcMsg,
1194     DWORD * pdwStubPhase)
1195 {
1196     const MIDL_SERVER_INFO *pServerInfo;
1197     const MIDL_STUB_DESC *pStubDesc;
1198     PFORMAT_STRING pFormat;
1199     MIDL_STUB_MESSAGE stubMsg;
1200     /* pointer to start of stack to pass into stub implementation */
1201     unsigned char * args;
1202     /* size of stack */
1203     unsigned short stack_size;
1204     /* number of parameters. optional for client to give it to us */
1205     unsigned int number_of_params;
1206     /* cache of Oif_flags from v2 procedure header */
1207     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1208     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1209     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1210     /* the type of pass we are currently doing */
1211     enum stubless_phase phase;
1212     /* header for procedure string */
1213     const NDR_PROC_HEADER *pProcHeader;
1214     /* location to put retval into */
1215     LONG_PTR *retval_ptr = NULL;
1216     /* correlation cache */
1217     ULONG_PTR NdrCorrCache[256];
1218
1219     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1220
1221     if (pThis)
1222         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1223     else
1224         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1225
1226     pStubDesc = pServerInfo->pStubDesc;
1227     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1228     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1229
1230     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1231
1232     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1233     {
1234         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1235         stack_size = pProcHeader->stack_size;
1236         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1237
1238     }
1239     else
1240     {
1241         stack_size = pProcHeader->stack_size;
1242         pFormat += sizeof(NDR_PROC_HEADER);
1243     }
1244
1245     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1246
1247     /* binding */
1248     switch (pProcHeader->handle_type)
1249     {
1250     /* explicit binding: parse additional section */
1251     case RPC_FC_BIND_EXPLICIT:
1252         switch (*pFormat) /* handle_type */
1253         {
1254         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
1255             pFormat += sizeof(NDR_EHD_PRIMITIVE);
1256             break;
1257         case RPC_FC_BIND_GENERIC: /* explicit generic */
1258             pFormat += sizeof(NDR_EHD_GENERIC);
1259             break;
1260         case RPC_FC_BIND_CONTEXT: /* explicit context */
1261             pFormat += sizeof(NDR_EHD_CONTEXT);
1262             break;
1263         default:
1264             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1265             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1266         }
1267         break;
1268     case RPC_FC_BIND_GENERIC: /* implicit generic */
1269     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
1270     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
1271     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
1272         break;
1273     default:
1274         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1275         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1276     }
1277
1278     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1279         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1280     else
1281         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1282
1283     /* create the full pointer translation tables, if requested */
1284     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1285         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1286
1287     /* store the RPC flags away */
1288     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1289         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1290
1291     /* use alternate memory allocation routines */
1292     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1293 #if 0
1294           NdrRpcSsEnableAllocate(&stubMsg);
1295 #else
1296           FIXME("Set RPCSS memory allocation routines\n");
1297 #endif
1298
1299     TRACE("allocating memory for stack of size %x\n", stack_size);
1300
1301     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1302     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1303
1304     /* add the implicit This pointer as the first arg to the function if we
1305      * are calling an object method */
1306     if (pThis)
1307         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1308
1309     if (pStubDesc->Version >= 0x20000)  /* -Oicf format */
1310     {
1311         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1312
1313         Oif_flags = pOIFHeader->Oi2Flags;
1314         number_of_params = pOIFHeader->number_of_params;
1315
1316         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1317
1318         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1319
1320         if (Oif_flags.HasExtensions)
1321         {
1322             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
1323             ext_flags = pExtensions->Flags2;
1324             pFormat += pExtensions->Size;
1325         }
1326
1327         if (Oif_flags.HasPipes)
1328         {
1329             FIXME("pipes not supported yet\n");
1330             RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1331             /* init pipes package */
1332             /* NdrPipesInitialize(...) */
1333         }
1334         if (ext_flags.HasNewCorrDesc)
1335         {
1336             /* initialize extra correlation package */
1337             FIXME("new correlation description not implemented\n");
1338             stubMsg.fHasNewCorrDesc = TRUE;
1339         }
1340     }
1341     else
1342     {
1343         pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
1344                                     pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT,
1345                                     /* reuse the correlation cache, it's not needed for v1 format */
1346                                     NdrCorrCache, sizeof(NdrCorrCache), &number_of_params );
1347     }
1348
1349     /* convert strings, floating point values and endianness into our
1350      * preferred format */
1351     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1352         NdrConvert(&stubMsg, pFormat);
1353
1354     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1355     {
1356         TRACE("phase = %d\n", phase);
1357         switch (phase)
1358         {
1359         case STUBLESS_CALLSERVER:
1360             /* call the server function */
1361             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1362                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1363             else
1364             {
1365                 SERVER_ROUTINE func;
1366                 LONG_PTR retval;
1367
1368                 if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1369                 {
1370                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1371                     func = vtbl[pRpcMsg->ProcNum];
1372                 }
1373                 else
1374                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1375
1376                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1377                 retval = call_server_func(func, args, stack_size);
1378
1379                 if (retval_ptr)
1380                 {
1381                     TRACE("stub implementation returned 0x%lx\n", retval);
1382                     *retval_ptr = retval;
1383                 }
1384                 else
1385                     TRACE("void stub implementation\n");
1386             }
1387
1388             stubMsg.Buffer = NULL;
1389             stubMsg.BufferLength = 0;
1390
1391             break;
1392         case STUBLESS_GETBUFFER:
1393             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1394                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1395             else
1396             {
1397                 RPC_STATUS Status;
1398
1399                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1400                 /* allocate buffer for [out] and [ret] params */
1401                 Status = I_RpcGetBuffer(pRpcMsg); 
1402                 if (Status)
1403                     RpcRaiseException(Status);
1404                 stubMsg.Buffer = pRpcMsg->Buffer;
1405             }
1406             break;
1407         case STUBLESS_UNMARSHAL:
1408         case STUBLESS_INITOUT:
1409         case STUBLESS_CALCSIZE:
1410         case STUBLESS_MARSHAL:
1411         case STUBLESS_FREE:
1412             retval_ptr = stub_do_args(&stubMsg, pFormat, phase, number_of_params);
1413             break;
1414         default:
1415             ERR("shouldn't reach here. phase %d\n", phase);
1416             break;
1417         }
1418     }
1419
1420     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1421
1422     if (ext_flags.HasNewCorrDesc)
1423     {
1424         /* free extra correlation package */
1425         /* NdrCorrelationFree(&stubMsg); */
1426     }
1427
1428     if (Oif_flags.HasPipes)
1429     {
1430         /* NdrPipesDone(...) */
1431     }
1432
1433     /* free the full pointer translation tables */
1434     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1435         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1436
1437     /* free server function stack */
1438     HeapFree(GetProcessHeap(), 0, args);
1439
1440     return S_OK;
1441 }
1442
1443 /***********************************************************************
1444  *            NdrServerCall2 [RPCRT4.@]
1445  */
1446 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1447 {
1448     DWORD dwPhase;
1449     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1450 }
1451
1452 /***********************************************************************
1453  *            NdrStubCall [RPCRT4.@]
1454  */
1455 LONG WINAPI NdrStubCall( struct IRpcStubBuffer *This, struct IRpcChannelBuffer *channel,
1456                          PRPC_MESSAGE msg, DWORD *phase )
1457 {
1458     return NdrStubCall2( This, channel, msg, phase );
1459 }
1460
1461 /***********************************************************************
1462  *            NdrServerCall [RPCRT4.@]
1463  */
1464 void WINAPI NdrServerCall( PRPC_MESSAGE msg )
1465 {
1466     DWORD phase;
1467     NdrStubCall( NULL, NULL, msg, &phase );
1468 }
1469
1470 struct async_call_data
1471 {
1472     MIDL_STUB_MESSAGE *pStubMsg;
1473     const NDR_PROC_HEADER *pProcHeader;
1474     PFORMAT_STRING pHandleFormat;
1475     PFORMAT_STRING pParamFormat;
1476     RPC_BINDING_HANDLE hBinding;
1477     /* size of stack */
1478     unsigned short stack_size;
1479     /* number of parameters. optional for client to give it to us */
1480     unsigned int number_of_params;
1481     /* correlation cache */
1482     ULONG_PTR NdrCorrCache[256];
1483 };
1484
1485 LONG_PTR CDECL ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, void **stack_top )
1486 {
1487     /* pointer to start of stack where arguments start */
1488     PRPC_MESSAGE pRpcMsg;
1489     PMIDL_STUB_MESSAGE pStubMsg;
1490     RPC_ASYNC_STATE *pAsync;
1491     struct async_call_data *async_call_data;
1492     /* procedure number */
1493     unsigned short procedure_number;
1494     /* cache of Oif_flags from v2 procedure header */
1495     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1496     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1497     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1498     /* header for procedure string */
1499     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1500     /* -Oif or -Oicf generated format */
1501     BOOL bV2Format = FALSE;
1502     RPC_STATUS status;
1503
1504     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
1505
1506     /* Later NDR language versions probably won't be backwards compatible */
1507     if (pStubDesc->Version > 0x50002)
1508     {
1509         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1510         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1511     }
1512
1513     async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1514     if (!async_call_data) RpcRaiseException(ERROR_OUTOFMEMORY);
1515     async_call_data->pProcHeader = pProcHeader;
1516
1517     async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1518     pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
1519
1520     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1521     {
1522         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1523         async_call_data->stack_size = pProcHeader->stack_size;
1524         procedure_number = pProcHeader->proc_num;
1525         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1526     }
1527     else
1528     {
1529         async_call_data->stack_size = pProcHeader->stack_size;
1530         procedure_number = pProcHeader->proc_num;
1531         pFormat += sizeof(NDR_PROC_HEADER);
1532     }
1533     TRACE("stack size: 0x%x\n", async_call_data->stack_size);
1534     TRACE("proc num: %d\n", procedure_number);
1535
1536     /* create the full pointer translation tables, if requested */
1537     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1538         pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
1539
1540     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1541     {
1542         ERR("objects not supported\n");
1543         I_RpcFree(async_call_data);
1544         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1545     }
1546
1547     NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
1548
1549     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1550     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
1551
1552     /* needed for conformance of top-level objects */
1553     pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
1554     memcpy(pStubMsg->StackTop, stack_top, async_call_data->stack_size);
1555
1556     pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
1557     pAsync->StubInfo = async_call_data;
1558     async_call_data->pHandleFormat = pFormat;
1559
1560     pFormat = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, &async_call_data->hBinding);
1561     if (!pFormat) goto done;
1562
1563     bV2Format = (pStubDesc->Version >= 0x20000);
1564
1565     if (bV2Format)
1566     {
1567         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1568             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1569
1570         Oif_flags = pOIFHeader->Oi2Flags;
1571         async_call_data->number_of_params = pOIFHeader->number_of_params;
1572
1573         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1574
1575         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1576
1577         if (Oif_flags.HasExtensions)
1578         {
1579             const NDR_PROC_HEADER_EXTS *pExtensions =
1580                 (const NDR_PROC_HEADER_EXTS *)pFormat;
1581             ext_flags = pExtensions->Flags2;
1582             pFormat += pExtensions->Size;
1583         }
1584     }
1585     else
1586     {
1587         pFormat = convert_old_args( pStubMsg, pFormat, async_call_data->stack_size,
1588                                     pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT,
1589                                     async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache),
1590                                     &async_call_data->number_of_params );
1591     }
1592
1593     async_call_data->pParamFormat = pFormat;
1594
1595     pStubMsg->BufferLength = 0;
1596
1597     /* store the RPC flags away */
1598     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1599         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1600
1601     /* use alternate memory allocation routines */
1602     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1603         NdrRpcSmSetClientToOsf(pStubMsg);
1604
1605     if (Oif_flags.HasPipes)
1606     {
1607         FIXME("pipes not supported yet\n");
1608         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1609         /* init pipes package */
1610         /* NdrPipesInitialize(...) */
1611     }
1612     if (ext_flags.HasNewCorrDesc)
1613     {
1614         /* initialize extra correlation package */
1615         NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
1616     }
1617
1618     /* order of phases:
1619      * 1. CALCSIZE - calculate the buffer size
1620      * 2. GETBUFFER - allocate the buffer
1621      * 3. MARSHAL - marshal [in] params into the buffer
1622      * 4. SENDRECEIVE - send buffer
1623      * Then in NdrpCompleteAsyncClientCall:
1624      * 1. SENDRECEIVE - receive buffer
1625      * 2. UNMARSHAL - unmarshal [out] params from buffer
1626      */
1627
1628     /* 1. CALCSIZE */
1629     TRACE( "CALCSIZE\n" );
1630     client_do_args(pStubMsg, pFormat, STUBLESS_CALCSIZE, NULL, async_call_data->number_of_params, NULL);
1631
1632     /* 2. GETBUFFER */
1633     TRACE( "GETBUFFER\n" );
1634     if (Oif_flags.HasPipes)
1635         /* NdrGetPipeBuffer(...) */
1636         FIXME("pipes not supported yet\n");
1637     else
1638     {
1639         if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
1640 #if 0
1641             NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1642 #else
1643         FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
1644 #endif
1645         else
1646             NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1647     }
1648     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1649     status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
1650     if (status != RPC_S_OK)
1651         RpcRaiseException(status);
1652
1653     /* 3. MARSHAL */
1654     TRACE( "MARSHAL\n" );
1655     client_do_args(pStubMsg, pFormat, STUBLESS_MARSHAL, NULL, async_call_data->number_of_params, NULL);
1656
1657     /* 4. SENDRECEIVE */
1658     TRACE( "SEND\n" );
1659     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1660     /* send the [in] params only */
1661     if (Oif_flags.HasPipes)
1662         /* NdrPipesSend(...) */
1663         FIXME("pipes not supported yet\n");
1664     else
1665     {
1666         if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
1667 #if 0
1668             NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1669 #else
1670         FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
1671 #endif
1672         else
1673         {
1674             pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
1675             status = I_RpcSend(pStubMsg->RpcMsg);
1676             if (status != RPC_S_OK)
1677                 RpcRaiseException(status);
1678         }
1679     }
1680
1681 done:
1682     TRACE("returning 0\n");
1683     return 0;
1684 }
1685
1686 RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
1687 {
1688     /* pointer to start of stack where arguments start */
1689     PMIDL_STUB_MESSAGE pStubMsg;
1690     struct async_call_data *async_call_data;
1691     /* header for procedure string */
1692     const NDR_PROC_HEADER * pProcHeader;
1693     RPC_STATUS status = RPC_S_OK;
1694
1695     if (!pAsync->StubInfo)
1696         return RPC_S_INVALID_ASYNC_HANDLE;
1697
1698     async_call_data = pAsync->StubInfo;
1699     pStubMsg = async_call_data->pStubMsg;
1700     pProcHeader = async_call_data->pProcHeader;
1701
1702     /* order of phases:
1703      * 1. CALCSIZE - calculate the buffer size
1704      * 2. GETBUFFER - allocate the buffer
1705      * 3. MARSHAL - marshal [in] params into the buffer
1706      * 4. SENDRECEIVE - send buffer
1707      * Then in NdrpCompleteAsyncClientCall:
1708      * 1. SENDRECEIVE - receive buffer
1709      * 2. UNMARSHAL - unmarshal [out] params from buffer
1710      */
1711
1712     /* 1. SENDRECEIVE */
1713     TRACE( "RECEIVE\n" );
1714     pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1715     /* receive the [out] params */
1716     if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
1717 #if 0
1718         NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1719 #else
1720     FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
1721 #endif
1722     else
1723     {
1724         status = I_RpcReceive(pStubMsg->RpcMsg);
1725         if (status != RPC_S_OK)
1726             goto cleanup;
1727         pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
1728         pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
1729         pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
1730         pStubMsg->Buffer = pStubMsg->BufferStart;
1731     }
1732
1733     /* convert strings, floating point values and endianness into our
1734      * preferred format */
1735 #if 0
1736     if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1737         NdrConvert(pStubMsg, pFormat);
1738 #endif
1739
1740     /* 2. UNMARSHAL */
1741     TRACE( "UNMARSHAL\n" );
1742     client_do_args(pStubMsg, async_call_data->pParamFormat, STUBLESS_UNMARSHAL,
1743                    NULL, async_call_data->number_of_params, Reply);
1744
1745 cleanup:
1746     if (pStubMsg->fHasNewCorrDesc)
1747     {
1748         /* free extra correlation package */
1749         NdrCorrelationFree(pStubMsg);
1750     }
1751
1752     /* free the full pointer translation tables */
1753     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1754         NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
1755
1756     /* free marshalling buffer */
1757     NdrFreeBuffer(pStubMsg);
1758     client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
1759
1760     I_RpcFree(pStubMsg->StackTop);
1761     I_RpcFree(async_call_data);
1762
1763     TRACE("-- 0x%x\n", status);
1764     return status;
1765 }
1766
1767 #ifdef __x86_64__
1768
1769 __ASM_GLOBAL_FUNC( NdrAsyncClientCall,
1770                    "movq %r8,0x18(%rsp)\n\t"
1771                    "movq %r9,0x20(%rsp)\n\t"
1772                    "leaq 0x18(%rsp),%r8\n\t"
1773                    "subq $0x28,%rsp\n\t"
1774                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1775                    "call " __ASM_NAME("ndr_async_client_call") "\n\t"
1776                    "addq $0x28,%rsp\n\t"
1777                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1778                    "ret" );
1779
1780 #else  /* __x86_64__ */
1781
1782 /***********************************************************************
1783  *            NdrAsyncClientCall [RPCRT4.@]
1784  */
1785 CLIENT_CALL_RETURN WINAPIV NdrAsyncClientCall( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1786 {
1787     __ms_va_list args;
1788     LONG_PTR ret;
1789
1790     __ms_va_start( args, format );
1791     ret = ndr_async_client_call( desc, format, va_arg( args, void ** ));
1792     __ms_va_end( args );
1793     return *(CLIENT_CALL_RETURN *)&ret;
1794 }
1795
1796 #endif  /* __x86_64__ */
1797
1798 RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
1799     struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
1800     DWORD * pdwStubPhase)
1801 {
1802     FIXME("unimplemented, expect crash!\n");
1803     return 0;
1804 }