rpcrt4: Fix NdrFixedArrayUnmarshall to use buffer memory if applicable and to reuse...
[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 #include "ndrtypes.h"
41
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 static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat)
95 {
96     NDR_MEMORYSIZE m = NdrMemorySizer[pFormat[0] & NDR_TABLE_MASK];
97     if (m)
98     {
99         unsigned char *saved_buffer = pStubMsg->Buffer;
100         unsigned long ret;
101         int saved_ignore_embedded_pointers = pStubMsg->IgnoreEmbeddedPointers;
102         pStubMsg->MemorySize = 0;
103         pStubMsg->IgnoreEmbeddedPointers = 1;
104         ret = m(pStubMsg, pFormat);
105         pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded_pointers;
106         pStubMsg->Buffer = saved_buffer;
107         return ret;
108     }
109     else
110     {
111         FIXME("format type 0x%x not implemented\n", pFormat[0]);
112         RpcRaiseException(RPC_X_BAD_STUB_DATA);
113         return 0;
114     }
115 }
116
117 #define STUBLESS_UNMARSHAL  1
118 #define STUBLESS_CALLSERVER 2
119 #define STUBLESS_CALCSIZE   3
120 #define STUBLESS_GETBUFFER  4
121 #define STUBLESS_MARSHAL    5
122 #define STUBLESS_FREE       6
123
124 void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
125 {
126 #if 0 /* these functions are not defined yet */
127     pMessage->pfnAllocate = NdrRpcSmClientAllocate;
128     pMessage->pfnFree = NdrRpcSmClientFree;
129 #endif
130 }
131
132 static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes)
133 {
134     if (param_attributes.MustSize) TRACE(" MustSize");
135     if (param_attributes.MustFree) TRACE(" MustFree");
136     if (param_attributes.IsPipe) TRACE(" IsPipe");
137     if (param_attributes.IsIn) TRACE(" IsIn");
138     if (param_attributes.IsOut) TRACE(" IsOut");
139     if (param_attributes.IsReturn) TRACE(" IsReturn");
140     if (param_attributes.IsBasetype) TRACE(" IsBasetype");
141     if (param_attributes.IsByValue) TRACE(" IsByValue");
142     if (param_attributes.IsSimpleRef) TRACE(" IsSimpleRef");
143     if (param_attributes.IsDontCallFreeInst) TRACE(" IsDontCallFreeInst");
144     if (param_attributes.SaveForAsyncFinish) TRACE(" SaveForAsyncFinish");
145     if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
146 }
147
148 static void WINAPI dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
149 {
150     if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize");
151     if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize");
152     if (Oi2Flags.HasReturn) TRACE(" HasReturn");
153     if (Oi2Flags.HasPipes) TRACE(" HasPipes");
154     if (Oi2Flags.Unused) TRACE(" Unused");
155     if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid");
156     if (Oi2Flags.HasExtensions) TRACE(" HasExtensions");
157     if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle");
158     TRACE("\n");
159 }
160
161 #define ARG_FROM_OFFSET(stubMsg, offset) ((stubMsg).StackTop + (offset))
162
163 static PFORMAT_STRING client_get_handle(
164     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
165     PFORMAT_STRING pFormat, handle_t *phBinding)
166 {
167     /* binding */
168     switch (pProcHeader->handle_type)
169     {
170     /* explicit binding: parse additional section */
171     case RPC_FC_BIND_EXPLICIT:
172         switch (*pFormat) /* handle_type */
173         {
174         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
175             {
176                 const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
177
178                 TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
179
180                 if (pDesc->flag) /* pointer to binding */
181                     *phBinding = **(handle_t **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
182                 else
183                     *phBinding = *(handle_t *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
184                 return pFormat + sizeof(NDR_EHD_PRIMITIVE);
185             }
186         case RPC_FC_BIND_GENERIC: /* explicit generic */
187             {
188                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
189                 void *pObject = NULL;
190                 void *pArg;
191                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
192
193                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
194
195                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
196                     pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
197                 else
198                     pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
199                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
200                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
201                 *phBinding = pGenPair->pfnBind(pObject);
202                 return pFormat + sizeof(NDR_EHD_GENERIC);
203             }
204         case RPC_FC_BIND_CONTEXT: /* explicit context */
205             {
206                 const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
207                 NDR_CCONTEXT context_handle;
208                 TRACE("Explicit bind context\n");
209                 if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
210                 {
211                     TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
212                     context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
213                 }
214                 else
215                     context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
216                 if ((pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) &&
217                     !context_handle)
218                 {
219                     ERR("null context handle isn't allowed\n");
220                     RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
221                     return NULL;
222                 }
223                 *phBinding = NDRCContextBinding(context_handle);
224                 /* FIXME: should we store this structure in stubMsg.pContext? */
225                 return pFormat + sizeof(NDR_EHD_CONTEXT);
226             }
227         default:
228             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
229             RpcRaiseException(RPC_X_BAD_STUB_DATA);
230         }
231         break;
232     case RPC_FC_BIND_GENERIC: /* implicit generic */
233         FIXME("RPC_FC_BIND_GENERIC\n");
234         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
235         break;
236     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
237         TRACE("Implicit primitive handle\n");
238         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
239         break;
240     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
241         FIXME("RPC_FC_CALLBACK_HANDLE\n");
242         break;
243     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
244         /* strictly speaking, it isn't necessary to set hBinding here
245          * since it isn't actually used (hence the automatic in its name),
246          * but then why does MIDL generate a valid entry in the
247          * MIDL_STUB_DESC for it? */
248         TRACE("Implicit auto handle\n");
249         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
250         break;
251     default:
252         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
253         RpcRaiseException(RPC_X_BAD_STUB_DATA);
254     }
255     return pFormat;
256 }
257
258 static void client_free_handle(
259     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
260     PFORMAT_STRING pFormat, handle_t hBinding)
261 {
262     /* binding */
263     switch (pProcHeader->handle_type)
264     {
265     /* explicit binding: parse additional section */
266     case RPC_FC_BIND_EXPLICIT:
267         switch (*pFormat) /* handle_type */
268         {
269         case RPC_FC_BIND_GENERIC: /* explicit generic */
270             {
271                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
272                 void *pObject = NULL;
273                 void *pArg;
274                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
275
276                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
277
278                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
279                     pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
280                 else
281                     pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset);
282                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
283                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
284                 pGenPair->pfnUnbind(pObject, hBinding);
285                 break;
286             }
287         case RPC_FC_BIND_CONTEXT: /* explicit context */
288         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
289             break;
290         default:
291             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
292             RpcRaiseException(RPC_X_BAD_STUB_DATA);
293         }
294         break;
295     case RPC_FC_BIND_GENERIC: /* implicit generic */
296         FIXME("RPC_FC_BIND_GENERIC\n");
297         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
298         break;
299     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
300     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
301     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
302         break;
303     default:
304         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
305         RpcRaiseException(RPC_X_BAD_STUB_DATA);
306     }
307 }
308
309 static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
310     int phase, unsigned short number_of_params, unsigned char *pRetVal)
311 {
312     /* current format string offset */
313     int current_offset = 0;
314     /* current stack offset */
315     unsigned short current_stack_offset = 0;
316     /* counter */
317     unsigned short i;
318
319     for (i = 0; i < number_of_params; i++)
320     {
321         const NDR_PARAM_OIF_BASETYPE *pParam =
322             (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
323         unsigned char * pArg;
324
325         current_stack_offset = pParam->stack_offset;
326         pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset);
327
328         TRACE("param[%d]: new format\n", i);
329         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
330         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
331         TRACE("\tmemory addr (before): %p\n", pArg);
332
333         if (pParam->param_attributes.IsBasetype)
334         {
335             const unsigned char * pTypeFormat =
336                 &pParam->type_format_char;
337
338             if (pParam->param_attributes.IsSimpleRef)
339                 pArg = *(unsigned char **)pArg;
340
341             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
342
343             switch (phase)
344             {
345             case PROXY_CALCSIZE:
346                 if (pParam->param_attributes.IsIn)
347                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
348                 break;
349             case PROXY_MARSHAL:
350                 if (pParam->param_attributes.IsIn)
351                     call_marshaller(pStubMsg, pArg, pTypeFormat);
352                 break;
353             case PROXY_UNMARSHAL:
354                 if (pParam->param_attributes.IsOut)
355                 {
356                     if (pParam->param_attributes.IsReturn)
357                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
358                     else
359                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
360                     TRACE("pRetVal = %p\n", pRetVal);
361                 }
362                 break;
363             default:
364                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
365             }
366
367             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
368         }
369         else
370         {
371             const NDR_PARAM_OIF_OTHER *pParamOther =
372                 (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
373
374             const unsigned char * pTypeFormat =
375                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
376
377             /* if a simple ref pointer then we have to do the
378              * check for the pointer being non-NULL. */
379             if (pParam->param_attributes.IsSimpleRef)
380             {
381                 if (!*(unsigned char **)pArg)
382                     RpcRaiseException(RPC_X_NULL_REF_POINTER);
383             }
384
385             TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat);
386
387             switch (phase)
388             {
389             case PROXY_CALCSIZE:
390                 if (pParam->param_attributes.IsIn)
391                 {
392                     if (pParam->param_attributes.IsByValue)
393                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
394                     else
395                         call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
396                 }
397                 break;
398             case PROXY_MARSHAL:
399                 if (pParam->param_attributes.IsIn)
400                 {
401                     if (pParam->param_attributes.IsByValue)
402                         call_marshaller(pStubMsg, pArg, pTypeFormat);
403                     else
404                         call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
405                 }
406                 break;
407             case PROXY_UNMARSHAL:
408                 if (pParam->param_attributes.IsOut)
409                 {
410                     if (pParam->param_attributes.IsReturn)
411                         call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0);
412                     else if (pParam->param_attributes.IsByValue)
413                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
414                     else
415                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
416                 }
417                 break;
418             default:
419                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
420             }
421
422             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
423         }
424         TRACE("\tmemory addr (after): %p\n", pArg);
425     }
426 }
427
428 static void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg,
429     PFORMAT_STRING pFormat, int phase, unsigned short stack_size,
430     unsigned char *pRetVal, BOOL object_proc)
431 {
432     /* current format string offset */
433     int current_offset = 0;
434     /* current stack offset */
435     unsigned short current_stack_offset = 0;
436     /* counter */
437     unsigned short i;
438
439     /* NOTE: V1 style format does't terminate on the number_of_params
440      * condition as it doesn't have this attribute. Instead it
441      * terminates when the stack size given in the header is exceeded.
442      */
443     for (i = 0; TRUE; i++)
444     {
445         const NDR_PARAM_OI_BASETYPE *pParam =
446             (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
447         /* note: current_stack_offset starts after the This pointer
448          * if present, so adjust this */
449         unsigned short current_stack_offset_adjusted = current_stack_offset +
450             (object_proc ? sizeof(void *) : 0);
451         unsigned char * pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset_adjusted);
452
453         /* no more parameters; exit loop */
454         if (current_stack_offset_adjusted >= stack_size)
455             break;
456
457         TRACE("param[%d]: old format\n", i);
458         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
459         TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
460         TRACE("\tmemory addr (before): %p\n", pArg);
461
462         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
463             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
464         {
465             const unsigned char * pTypeFormat =
466                 &pParam->type_format_char;
467
468             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
469
470             switch (phase)
471             {
472             case PROXY_CALCSIZE:
473                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
474                     call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
475                 break;
476             case PROXY_MARSHAL:
477                 if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
478                     call_marshaller(pStubMsg, pArg, pTypeFormat);
479                 break;
480             case PROXY_UNMARSHAL:
481                 if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
482                 {
483                     if (pParam->param_direction & RPC_FC_RETURN_PARAM)
484                         call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
485                     else
486                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
487                 }
488                 break;
489             default:
490                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
491             }
492
493             current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat);
494             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
495         }
496         else
497         {
498             const NDR_PARAM_OI_OTHER *pParamOther = 
499                 (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
500
501             const unsigned char *pTypeFormat =
502                 &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
503
504             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
505
506             switch (phase)
507             {
508             case PROXY_CALCSIZE:
509                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
510                     pParam->param_direction & RPC_FC_IN_OUT_PARAM)
511                     call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
512                 break;
513             case PROXY_MARSHAL:
514                 if (pParam->param_direction == RPC_FC_IN_PARAM ||
515                     pParam->param_direction & RPC_FC_IN_OUT_PARAM)
516                     call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
517                 break;
518             case PROXY_UNMARSHAL:
519                 if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
520                     pParam->param_direction == RPC_FC_OUT_PARAM)
521                     call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
522                 else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
523                     call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0);
524                 break;
525             default:
526                 RpcRaiseException(RPC_S_INTERNAL_ERROR);
527             }
528
529             current_stack_offset += pParamOther->stack_size * sizeof(INT);
530             current_offset += sizeof(NDR_PARAM_OI_OTHER);
531         }
532         TRACE("\tmemory addr (after): %p\n", pArg);
533     }
534 }
535
536 /* the return type should be CLIENT_CALL_RETURN, but this is incompatible
537  * with the way gcc returns structures. "void *" should be the largest type
538  * that MIDL should allow you to return anyway */
539 LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, ...)
540 {
541     /* pointer to start of stack where arguments start */
542     RPC_MESSAGE rpcMsg;
543     MIDL_STUB_MESSAGE stubMsg;
544     handle_t hBinding = NULL;
545     /* procedure number */
546     unsigned short procedure_number;
547     /* size of stack */
548     unsigned short stack_size;
549     /* number of parameters. optional for client to give it to us */
550     unsigned char number_of_params = ~0;
551     /* cache of Oif_flags from v2 procedure header */
552     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
553     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
554     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
555     /* the type of pass we are currently doing */
556     int phase;
557     /* header for procedure string */
558     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
559     /* -Oif or -Oicf generated format */
560     BOOL bV2Format = FALSE;
561     /* the value to return to the client from the remote procedure */
562     LONG_PTR RetVal = 0;
563     /* the pointer to the object when in OLE mode */
564     void * This = NULL;
565     PFORMAT_STRING pHandleFormat;
566
567     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
568
569     /* Later NDR language versions probably won't be backwards compatible */
570     if (pStubDesc->Version > 0x50002)
571     {
572         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
573         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
574     }
575
576     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
577     {
578         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
579         stack_size = pProcHeader->stack_size;
580         procedure_number = pProcHeader->proc_num;
581         pFormat += sizeof(NDR_PROC_HEADER_RPC);
582     }
583     else
584     {
585         stack_size = pProcHeader->stack_size;
586         procedure_number = pProcHeader->proc_num;
587         pFormat += sizeof(NDR_PROC_HEADER);
588     }
589     TRACE("stack size: 0x%x\n", stack_size);
590     TRACE("proc num: %d\n", procedure_number);
591
592     /* create the full pointer translation tables, if requested */
593     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
594         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
595
596     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
597     {
598         /* object is always the first argument */
599         This = **(void *const **)(&pFormat+1);
600         NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number);
601     }
602     else
603         NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number);
604
605     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
606     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
607
608     /* needed for conformance of top-level objects */
609 #ifdef __i386__
610     stubMsg.StackTop = *(unsigned char **)(&pFormat+1);
611 #else
612 # warning Stack not retrieved for your CPU architecture
613 #endif
614
615     pHandleFormat = pFormat;
616
617     /* we only need a handle if this isn't an object method */
618     if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT))
619     {
620         pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding);
621         if (!pFormat) return 0;
622     }
623
624     bV2Format = (pStubDesc->Version >= 0x20000);
625
626     if (bV2Format)
627     {
628         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
629             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
630
631         Oif_flags = pOIFHeader->Oi2Flags;
632         number_of_params = pOIFHeader->number_of_params;
633
634         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
635     }
636
637     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
638
639     if (Oif_flags.HasExtensions)
640     {
641         const NDR_PROC_HEADER_EXTS *pExtensions =
642             (const NDR_PROC_HEADER_EXTS *)pFormat;
643         ext_flags = pExtensions->Flags2;
644         pFormat += pExtensions->Size;
645     }
646
647     stubMsg.BufferLength = 0;
648
649     /* store the RPC flags away */
650     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
651         rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
652
653     /* use alternate memory allocation routines */
654     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
655         NdrRpcSmSetClientToOsf(&stubMsg);
656
657     if (Oif_flags.HasPipes)
658     {
659         FIXME("pipes not supported yet\n");
660         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
661         /* init pipes package */
662         /* NdrPipesInitialize(...) */
663     }
664     if (ext_flags.HasNewCorrDesc)
665     {
666         /* initialize extra correlation package */
667         FIXME("new correlation description not implemented\n");
668         stubMsg.fHasNewCorrDesc = TRUE;
669     }
670
671     /* order of phases:
672      * 1. PROXY_CALCSIZE - calculate the buffer size
673      * 2. PROXY_GETBUFFER - allocate the buffer
674      * 3. PROXY_MARHSAL - marshal [in] params into the buffer
675      * 4. PROXY_SENDRECEIVE - send/receive buffer
676      * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer
677      */
678     for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++)
679     {
680         TRACE("phase = %d\n", phase);
681         switch (phase)
682         {
683         case PROXY_GETBUFFER:
684             /* allocate the buffer */
685             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
686                 NdrProxyGetBuffer(This, &stubMsg);
687             else if (Oif_flags.HasPipes)
688                 /* NdrGetPipeBuffer(...) */
689                 FIXME("pipes not supported yet\n");
690             else
691             {
692                 if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
693 #if 0
694                     NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
695 #else
696                     FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
697 #endif
698                 else
699                     NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
700             }
701             break;
702         case PROXY_SENDRECEIVE:
703             /* send the [in] params and receive the [out] and [retval]
704              * params */
705             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
706                 NdrProxySendReceive(This, &stubMsg);
707             else if (Oif_flags.HasPipes)
708                 /* NdrPipesSendReceive(...) */
709                 FIXME("pipes not supported yet\n");
710             else
711             {
712                 if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
713 #if 0
714                     NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
715 #else
716                     FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
717 #endif
718                 else
719                     NdrSendReceive(&stubMsg, stubMsg.Buffer);
720             }
721
722             /* convert strings, floating point values and endianess into our
723              * preferred format */
724             if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
725                 NdrConvert(&stubMsg, pFormat);
726
727             break;
728         case PROXY_CALCSIZE:
729         case PROXY_MARSHAL:
730         case PROXY_UNMARSHAL:
731             if (bV2Format)
732                 client_do_args(&stubMsg, pFormat, phase, number_of_params,
733                     (unsigned char *)&RetVal);
734             else
735                 client_do_args_old_format(&stubMsg, pFormat, phase, stack_size,
736                     (unsigned char *)&RetVal,
737                     (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
738             break;
739         default:
740             ERR("shouldn't reach here. phase %d\n", phase);
741             break;
742         }
743     }
744
745     if (ext_flags.HasNewCorrDesc)
746     {
747         /* free extra correlation package */
748         /* NdrCorrelationFree(&stubMsg); */
749     }
750
751     if (Oif_flags.HasPipes)
752     {
753         /* NdrPipesDone(...) */
754     }
755
756     /* free the full pointer translation tables */
757     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
758         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
759
760     /* free marshalling buffer */
761     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
762         NdrProxyFreeBuffer(This, &stubMsg);
763     else
764     {
765         NdrFreeBuffer(&stubMsg);
766         client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding);
767     }
768
769     TRACE("RetVal = 0x%lx\n", RetVal);
770
771     return RetVal;
772 }
773
774 /* calls a function with the specificed arguments, restoring the stack
775  * properly afterwards as we don't know the calling convention of the
776  * function */
777 #if defined __i386__ && defined _MSC_VER
778 __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
779 {
780     __asm
781     {
782         push ebp
783         push edi            ; Save registers
784         push esi
785         mov ebp, esp
786         mov eax, [ebp+16]   ; Get stack size
787         sub esp, eax        ; Make room in stack for arguments
788         mov edi, esp
789         mov ecx, eax
790         mov esi, [ebp+12]
791         shr ecx, 2
792         cld
793         rep movsd           ; Copy dword blocks
794         call [ebp+8]        ; Call function
795         lea esp, [ebp-8]    ; Restore stack
796         pop esi             ; Restore registers
797         pop edi
798         pop ebp
799         ret
800     }
801 }
802 #elif defined __i386__ && defined __GNUC__
803 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
804 __ASM_GLOBAL_FUNC(call_server_func,
805     "pushl %ebp\n\t"
806     "movl %esp, %ebp\n\t"
807     "pushl %edi\n\t"            /* Save registers */
808     "pushl %esi\n\t"
809     "movl 16(%ebp), %eax\n\t"   /* Get stack size */
810     "subl %eax, %esp\n\t"       /* Make room in stack for arguments */
811     "andl $~15, %esp\n\t"       /* Make sure stack has 16-byte alignment for Mac OS X */
812     "movl %esp, %edi\n\t"
813     "movl %eax, %ecx\n\t"
814     "movl 12(%ebp), %esi\n\t"
815     "shrl $2, %ecx\n\t"         /* divide by 4 */
816     "cld\n\t"
817     "rep; movsl\n\t"            /* Copy dword blocks */
818     "call *8(%ebp)\n\t"         /* Call function */
819     "leal -8(%ebp), %esp\n\t"   /* Restore stack */
820     "popl %esi\n\t"             /* Restore registers */
821     "popl %edi\n\t"
822     "popl %ebp\n\t"
823     "ret\n" )
824 #else
825 #warning call_server_func not implemented for your architecture
826 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
827 {
828     FIXME("Not implemented for your architecture\n");
829     return 0;
830 }
831 #endif
832
833 static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
834 {
835     DWORD size;
836     switch(*pFormat)
837     {
838     case RPC_FC_STRUCT:
839         size = *(const WORD*)(pFormat + 2);
840         break;
841     case RPC_FC_CARRAY:
842         size = *(const WORD*)(pFormat + 2);
843         ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
844         size *= pStubMsg->MaxCount;
845         break;
846     case RPC_FC_SMFARRAY:
847         size = *(const WORD*)(pFormat + 2);
848         break;
849     case RPC_FC_LGFARRAY:
850         size = *(const DWORD*)(pFormat + 2);
851         break;
852     default:
853         FIXME("Unhandled type %02x\n", *pFormat);
854         /* fallthrough */
855     case RPC_FC_RP:
856         size = sizeof(void *);
857         break;
858     }
859     return size;
860 }
861
862 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
863                               PFORMAT_STRING pFormat, int phase,
864                               unsigned char *args,
865                               unsigned short number_of_params)
866 {
867     /* counter */
868     unsigned short i;
869     /* current format string offset */
870     int current_offset = 0;
871     /* current stack offset */
872     unsigned short current_stack_offset = 0;
873     /* location to put retval into */
874     LONG_PTR *retval_ptr = NULL;
875
876     for (i = 0; i < number_of_params; i++)
877     {
878         const NDR_PARAM_OIF_BASETYPE *pParam =
879         (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
880         unsigned char *pArg;
881
882         current_stack_offset = pParam->stack_offset;
883         pArg = (unsigned char *)(args+current_stack_offset);
884
885         TRACE("param[%d]: new format\n", i);
886         TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
887         TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
888         TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
889
890         if (pParam->param_attributes.IsBasetype)
891         {
892             const unsigned char *pTypeFormat =
893             &pParam->type_format_char;
894
895             TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
896
897             switch (phase)
898             {
899                 case STUBLESS_MARSHAL:
900                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
901                     {
902                         if (pParam->param_attributes.IsSimpleRef)
903                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
904                         else
905                             call_marshaller(pStubMsg, pArg, pTypeFormat);
906                     }
907                     break;
908                 case STUBLESS_FREE:
909                     if (pParam->param_attributes.ServerAllocSize)
910                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
911                     break;
912                 case STUBLESS_UNMARSHAL:
913                     if (pParam->param_attributes.ServerAllocSize)
914                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
915                                                    pParam->param_attributes.ServerAllocSize * 8);
916
917                     if (pParam->param_attributes.IsIn)
918                     {
919                         if (pParam->param_attributes.IsSimpleRef)
920                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
921                         else
922                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
923                     }
924
925                     /* make a note of the address of the return value parameter for later */
926                     if (pParam->param_attributes.IsReturn)
927                         retval_ptr = (LONG_PTR *)pArg;
928
929                     break;
930                 case STUBLESS_CALCSIZE:
931                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
932                     {
933                         if (pParam->param_attributes.IsSimpleRef)
934                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
935                         else
936                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
937                     }
938                     break;
939                 default:
940                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
941             }
942
943             current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
944         }
945         else
946         {
947             const NDR_PARAM_OIF_OTHER *pParamOther =
948             (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
949
950             const unsigned char * pTypeFormat =
951                 &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
952
953             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
954
955             switch (phase)
956             {
957                 case STUBLESS_MARSHAL:
958                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
959                     {
960                         if (pParam->param_attributes.IsByValue)
961                             call_marshaller(pStubMsg, pArg, pTypeFormat);
962                         else
963                             call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
964                     }
965                     break;
966                 case STUBLESS_FREE:
967                     if (pParam->param_attributes.MustFree)
968                     {
969                         if (pParam->param_attributes.IsByValue)
970                             call_freer(pStubMsg, pArg, pTypeFormat);
971                         else
972                             call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
973                     }
974
975                     if (pParam->param_attributes.IsOut &&
976                         !pParam->param_attributes.IsIn &&
977                         !pParam->param_attributes.IsByValue &&
978                         !pParam->param_attributes.ServerAllocSize)
979                     {
980                         pStubMsg->pfnFree(*(void **)pArg);
981                     }
982
983                     if (pParam->param_attributes.ServerAllocSize)
984                         HeapFree(GetProcessHeap(), 0, *(void **)pArg);
985                     /* FIXME: call call_freer here for IN types with MustFree set */
986                     break;
987                 case STUBLESS_UNMARSHAL:
988                     if (pParam->param_attributes.ServerAllocSize)
989                         *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
990                                                    pParam->param_attributes.ServerAllocSize * 8);
991
992                     if (pParam->param_attributes.IsIn)
993                     {
994                         if (pParam->param_attributes.IsByValue)
995                             call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
996                         else
997                             call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
998                     }
999                     else if (pParam->param_attributes.IsOut &&
1000                              !pParam->param_attributes.ServerAllocSize &&
1001                              !pParam->param_attributes.IsByValue)
1002                     {
1003                         DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1004
1005                         if(size)
1006                         {
1007                             *(void **)pArg = NdrAllocate(pStubMsg, size);
1008                             memset(*(void **)pArg, 0, size);
1009                         }
1010                     }
1011                     break;
1012                 case STUBLESS_CALCSIZE:
1013                     if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
1014                     {
1015                         if (pParam->param_attributes.IsByValue)
1016                             call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1017                         else
1018                             call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1019                     }
1020                     break;
1021                 default:
1022                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1023             }
1024
1025             current_offset += sizeof(NDR_PARAM_OIF_OTHER);
1026         }
1027         TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1028     }
1029
1030     return retval_ptr;
1031 }
1032
1033 static LONG_PTR *stub_do_old_args(MIDL_STUB_MESSAGE *pStubMsg,
1034                                   PFORMAT_STRING pFormat, int phase,
1035                                   unsigned char *args,
1036                                   unsigned short stack_size, BOOL object)
1037 {
1038     /* counter */
1039     unsigned short i;
1040     /* current format string offset */
1041     int current_offset = 0;
1042     /* current stack offset */
1043     unsigned short current_stack_offset = 0;
1044     /* location to put retval into */
1045     LONG_PTR *retval_ptr = NULL;
1046
1047     for (i = 0; TRUE; i++)
1048     {
1049         const NDR_PARAM_OI_BASETYPE *pParam =
1050         (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
1051         /* note: current_stack_offset starts after the This pointer
1052          * if present, so adjust this */
1053         unsigned short current_stack_offset_adjusted = current_stack_offset +
1054             (object ? sizeof(void *) : 0);
1055         unsigned char *pArg = (unsigned char *)(args+current_stack_offset_adjusted);
1056
1057         /* no more parameters; exit loop */
1058         if (current_stack_offset_adjusted >= stack_size)
1059             break;
1060
1061         TRACE("param[%d]: old format\n", i);
1062         TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
1063         TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
1064
1065         if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
1066             pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1067         {
1068             const unsigned char *pTypeFormat =
1069             &pParam->type_format_char;
1070
1071             TRACE("\tbase type 0x%02x\n", *pTypeFormat);
1072
1073             switch (phase)
1074             {
1075                 case STUBLESS_MARSHAL:
1076                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1077                         call_marshaller(pStubMsg, pArg, pTypeFormat);
1078                     break;
1079                 case STUBLESS_FREE:
1080                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1081                         call_freer(pStubMsg, pArg, pTypeFormat);
1082                     break;
1083                 case STUBLESS_UNMARSHAL:
1084                     if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
1085                         call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
1086                     else if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1087                         retval_ptr = (LONG_PTR *)pArg;
1088                         break;
1089                 case STUBLESS_CALCSIZE:
1090                     if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
1091                         call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
1092                     break;
1093                 default:
1094                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1095             }
1096
1097             current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat);
1098             current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
1099         }
1100         else
1101         {
1102             const NDR_PARAM_OI_OTHER *pParamOther =
1103             (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
1104
1105             const unsigned char * pTypeFormat =
1106                 &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
1107
1108             TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
1109
1110             switch (phase)
1111             {
1112                 case STUBLESS_MARSHAL:
1113                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1114                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1115                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1116                         call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1117                     break;
1118                 case STUBLESS_FREE:
1119                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1120                         pParam->param_direction == RPC_FC_IN_PARAM)
1121                         call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1122                     else if (pParam->param_direction == RPC_FC_OUT_PARAM)
1123                         pStubMsg->pfnFree(*(void **)pArg);
1124                         break;
1125                 case STUBLESS_UNMARSHAL:
1126                     if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1127                         pParam->param_direction == RPC_FC_IN_PARAM)
1128                         call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
1129                     else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
1130                         retval_ptr = (LONG_PTR *)pArg;
1131                     else if (pParam->param_direction == RPC_FC_OUT_PARAM)
1132                     {
1133                         DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1134
1135                         if(size)
1136                         {
1137                             *(void **)pArg = NdrAllocate(pStubMsg, size);
1138                             memset(*(void **)pArg, 0, size);
1139                         }
1140                     }
1141                     break;
1142                 case STUBLESS_CALCSIZE:
1143                     if (pParam->param_direction == RPC_FC_OUT_PARAM ||
1144                         pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
1145                         pParam->param_direction == RPC_FC_RETURN_PARAM)
1146                         call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
1147                     break;
1148                 default:
1149                     RpcRaiseException(RPC_S_INTERNAL_ERROR);
1150             }
1151
1152             current_stack_offset += pParamOther->stack_size * sizeof(INT);
1153             current_offset += sizeof(NDR_PARAM_OI_OTHER);
1154         }
1155     }
1156
1157     return retval_ptr;
1158 }
1159
1160 /***********************************************************************
1161  *            NdrStubCall2 [RPCRT4.@]
1162  *
1163  * Unmarshals [in] parameters, calls either a method in an object or a server
1164  * function, marshals any [out] parameters and frees any allocated data.
1165  *
1166  * NOTES
1167  *  Used by stubless MIDL-generated code.
1168  */
1169 LONG WINAPI NdrStubCall2(
1170     struct IRpcStubBuffer * pThis,
1171     struct IRpcChannelBuffer * pChannel,
1172     PRPC_MESSAGE pRpcMsg,
1173     DWORD * pdwStubPhase)
1174 {
1175     const MIDL_SERVER_INFO *pServerInfo;
1176     const MIDL_STUB_DESC *pStubDesc;
1177     PFORMAT_STRING pFormat;
1178     MIDL_STUB_MESSAGE stubMsg;
1179     /* pointer to start of stack to pass into stub implementation */
1180     unsigned char * args;
1181     /* size of stack */
1182     unsigned short stack_size;
1183     /* number of parameters. optional for client to give it to us */
1184     unsigned char number_of_params = ~0;
1185     /* cache of Oif_flags from v2 procedure header */
1186     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1187     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1188     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1189     /* the type of pass we are currently doing */
1190     int phase;
1191     /* header for procedure string */
1192     const NDR_PROC_HEADER *pProcHeader;
1193     /* offset in format string for start of params */
1194     int parameter_start_offset;
1195     /* current format string offset */
1196     int current_offset;
1197     /* -Oif or -Oicf generated format */
1198     BOOL bV2Format = FALSE;
1199     /* location to put retval into */
1200     LONG_PTR *retval_ptr = NULL;
1201
1202     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1203
1204     if (pThis)
1205         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1206     else
1207         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1208
1209     pStubDesc = pServerInfo->pStubDesc;
1210     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1211     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1212
1213     /* Later NDR language versions probably won't be backwards compatible */
1214     if (pStubDesc->Version > 0x50002)
1215     {
1216         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1217         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1218     }
1219
1220     /* create the full pointer translation tables, if requested */
1221     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1222         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1223
1224     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1225     {
1226         const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1227         stack_size = pProcHeader->stack_size;
1228         current_offset = sizeof(NDR_PROC_HEADER_RPC);
1229
1230     }
1231     else
1232     {
1233         stack_size = pProcHeader->stack_size;
1234         current_offset = sizeof(NDR_PROC_HEADER);
1235     }
1236
1237     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1238
1239     /* binding */
1240     switch (pProcHeader->handle_type)
1241     {
1242     /* explicit binding: parse additional section */
1243     case RPC_FC_BIND_EXPLICIT:
1244         switch (pFormat[current_offset]) /* handle_type */
1245         {
1246         case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
1247             current_offset += sizeof(NDR_EHD_PRIMITIVE);
1248             break;
1249         case RPC_FC_BIND_GENERIC: /* explicit generic */
1250             current_offset += sizeof(NDR_EHD_GENERIC);
1251             break;
1252         case RPC_FC_BIND_CONTEXT: /* explicit context */
1253             current_offset += sizeof(NDR_EHD_CONTEXT);
1254             break;
1255         default:
1256             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1257             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1258         }
1259         break;
1260     case RPC_FC_BIND_GENERIC: /* implicit generic */
1261     case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */
1262     case RPC_FC_CALLBACK_HANDLE: /* implicit callback */
1263     case RPC_FC_AUTO_HANDLE: /* implicit auto handle */
1264         break;
1265     default:
1266         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1267         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1268     }
1269
1270     bV2Format = (pStubDesc->Version >= 0x20000);
1271
1272     if (bV2Format)
1273     {
1274         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1275             (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset];
1276
1277         Oif_flags = pOIFHeader->Oi2Flags;
1278         number_of_params = pOIFHeader->number_of_params;
1279
1280         current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1281     }
1282
1283     TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
1284
1285     if (Oif_flags.HasExtensions)
1286     {
1287         const NDR_PROC_HEADER_EXTS *pExtensions =
1288             (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset];
1289         ext_flags = pExtensions->Flags2;
1290         current_offset += pExtensions->Size;
1291     }
1292
1293     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1294         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1295     else
1296         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1297
1298     /* store the RPC flags away */
1299     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
1300         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1301
1302     /* use alternate memory allocation routines */
1303     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
1304 #if 0
1305           NdrRpcSsEnableAllocate(&stubMsg);
1306 #else
1307           FIXME("Set RPCSS memory allocation routines\n");
1308 #endif
1309
1310     if (Oif_flags.HasPipes)
1311     {
1312         FIXME("pipes not supported yet\n");
1313         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1314         /* init pipes package */
1315         /* NdrPipesInitialize(...) */
1316     }
1317     if (ext_flags.HasNewCorrDesc)
1318     {
1319         /* initialize extra correlation package */
1320         FIXME("new correlation description not implemented\n");
1321         stubMsg.fHasNewCorrDesc = TRUE;
1322     }
1323
1324     /* convert strings, floating point values and endianess into our
1325      * preferred format */
1326     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1327         NdrConvert(&stubMsg, pFormat);
1328
1329     parameter_start_offset = current_offset;
1330
1331     TRACE("allocating memory for stack of size %x\n", stack_size);
1332
1333     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1334     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1335
1336     /* add the implicit This pointer as the first arg to the function if we
1337      * are calling an object method */
1338     if (pThis)
1339         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1340
1341     /* order of phases:
1342      * 1. STUBLESS_UNMARHSAL - unmarshal [in] params from buffer
1343      * 2. STUBLESS_CALLSERVER - send/receive buffer
1344      * 3. STUBLESS_CALCSIZE - get [out] buffer size
1345      * 4. STUBLESS_GETBUFFER - allocate [out] buffer
1346      * 5. STUBLESS_MARHSAL - marshal [out] params to buffer
1347      */
1348     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1349     {
1350         TRACE("phase = %d\n", phase);
1351         switch (phase)
1352         {
1353         case STUBLESS_CALLSERVER:
1354             /* call the server function */
1355             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1356                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1357             else
1358             {
1359                 SERVER_ROUTINE func;
1360                 LONG_PTR retval;
1361
1362                 if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1363                 {
1364                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1365                     func = vtbl[pRpcMsg->ProcNum];
1366                 }
1367                 else
1368                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1369
1370                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1371                 retval = call_server_func(func, args, stack_size);
1372
1373                 if (retval_ptr)
1374                 {
1375                     TRACE("stub implementation returned 0x%lx\n", retval);
1376                     *retval_ptr = retval;
1377                 }
1378                 else
1379                     TRACE("void stub implementation\n");
1380             }
1381
1382             stubMsg.Buffer = NULL;
1383             stubMsg.BufferLength = 0;
1384
1385             break;
1386         case STUBLESS_GETBUFFER:
1387             if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
1388                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1389             else
1390             {
1391                 RPC_STATUS Status;
1392
1393                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1394                 /* allocate buffer for [out] and [ret] params */
1395                 Status = I_RpcGetBuffer(pRpcMsg); 
1396                 if (Status)
1397                     RpcRaiseException(Status);
1398                 stubMsg.BufferStart = pRpcMsg->Buffer;
1399                 stubMsg.BufferEnd = stubMsg.BufferStart + stubMsg.BufferLength;
1400                 stubMsg.Buffer = stubMsg.BufferStart;
1401             }
1402             break;
1403         case STUBLESS_MARSHAL:
1404         case STUBLESS_UNMARSHAL:
1405         case STUBLESS_CALCSIZE:
1406         case STUBLESS_FREE:
1407             if (bV2Format)
1408                 retval_ptr = stub_do_args(&stubMsg, &pFormat[parameter_start_offset],
1409                                           phase, args, number_of_params);
1410             else
1411                 retval_ptr = stub_do_old_args(&stubMsg, &pFormat[parameter_start_offset],
1412                                               phase, args, stack_size,
1413                                               (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
1414
1415             break;
1416         default:
1417             ERR("shouldn't reach here. phase %d\n", phase);
1418             break;
1419         }
1420     }
1421
1422     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1423
1424     if (ext_flags.HasNewCorrDesc)
1425     {
1426         /* free extra correlation package */
1427         /* NdrCorrelationFree(&stubMsg); */
1428     }
1429
1430     if (Oif_flags.HasPipes)
1431     {
1432         /* NdrPipesDone(...) */
1433     }
1434
1435     /* free the full pointer translation tables */
1436     if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
1437         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1438
1439     /* free server function stack */
1440     HeapFree(GetProcessHeap(), 0, args);
1441
1442     return S_OK;
1443 }
1444
1445 /***********************************************************************
1446  *            NdrServerCall2 [RPCRT4.@]
1447  */
1448 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1449 {
1450     DWORD dwPhase;
1451     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1452 }