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