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