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