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