wined3d: Use wined3d_resource_gl_legacy_map_flags() in wined3d_buffer_gl_map().
[wine.git] / dlls / rpcrt4 / ndr_stubless.c
blobbceecdc8277fc3305a9761452ccd61832920b4bf
1 /*
2 * NDR -Oi,-Oif,-Oicf Interpreter
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003-5 Robert Shearman (for CodeWeavers)
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.
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.
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
21 * TODO:
22 * - Pipes
23 * - Some types of binding handles
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
34 #include "objbase.h"
35 #include "rpc.h"
36 #include "rpcproxy.h"
38 #include "wine/exception.h"
39 #include "wine/asm.h"
40 #include "wine/debug.h"
42 #include "cpsf.h"
43 #include "ndr_misc.h"
44 #include "ndr_stubless.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
48 #define NDR_TABLE_MASK 127
50 static inline BOOL is_oicf_stubdesc(const PMIDL_STUB_DESC pStubDesc)
52 return pStubDesc->Version >= 0x20000;
55 static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
56 const NDR_PARAM_OIF *param)
58 PFORMAT_STRING pFormat;
59 NDR_BUFFERSIZE m;
61 if (param->attr.IsBasetype)
63 pFormat = &param->u.type_format_char;
64 if (param->attr.IsSimpleRef) pMemory = *(unsigned char **)pMemory;
66 else
68 pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
69 if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
72 m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK];
73 if (m) m(pStubMsg, pMemory, pFormat);
74 else
76 FIXME("format type 0x%x not implemented\n", pFormat[0]);
77 RpcRaiseException(RPC_X_BAD_STUB_DATA);
81 static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
82 const NDR_PARAM_OIF *param)
84 PFORMAT_STRING pFormat;
85 NDR_MARSHALL m;
87 if (param->attr.IsBasetype)
89 pFormat = &param->u.type_format_char;
90 if (param->attr.IsSimpleRef) pMemory = *(unsigned char **)pMemory;
92 else
94 pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
95 if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
98 m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK];
99 if (m) return m(pStubMsg, pMemory, pFormat);
100 else
102 FIXME("format type 0x%x not implemented\n", pFormat[0]);
103 RpcRaiseException(RPC_X_BAD_STUB_DATA);
104 return NULL;
108 static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory,
109 const NDR_PARAM_OIF *param, unsigned char fMustAlloc)
111 PFORMAT_STRING pFormat;
112 NDR_UNMARSHALL m;
114 if (param->attr.IsBasetype)
116 pFormat = &param->u.type_format_char;
117 if (param->attr.IsSimpleRef) ppMemory = (unsigned char **)*ppMemory;
119 else
121 pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
122 if (!param->attr.IsByValue) ppMemory = (unsigned char **)*ppMemory;
125 m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK];
126 if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc);
127 else
129 FIXME("format type 0x%x not implemented\n", pFormat[0]);
130 RpcRaiseException(RPC_X_BAD_STUB_DATA);
131 return NULL;
135 static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
136 const NDR_PARAM_OIF *param)
138 PFORMAT_STRING pFormat;
139 NDR_FREE m;
141 if (param->attr.IsBasetype) return; /* nothing to do */
142 pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
143 if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
145 m = NdrFreer[pFormat[0] & NDR_TABLE_MASK];
146 if (m) m(pStubMsg, pMemory, pFormat);
149 static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
151 DWORD size;
152 switch(*pFormat)
154 case FC_RP:
155 if (pFormat[1] & FC_SIMPLE_POINTER)
157 size = 0;
158 break;
160 size = calc_arg_size(pStubMsg, &pFormat[2] + *(const SHORT*)&pFormat[2]);
161 break;
162 case FC_STRUCT:
163 case FC_PSTRUCT:
164 size = *(const WORD*)(pFormat + 2);
165 break;
166 case FC_BOGUS_STRUCT:
167 size = *(const WORD*)(pFormat + 2);
168 if(*(const WORD*)(pFormat + 4))
169 FIXME("Unhandled conformant description\n");
170 break;
171 case FC_CARRAY:
172 case FC_CVARRAY:
173 size = *(const WORD*)(pFormat + 2);
174 ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
175 size *= pStubMsg->MaxCount;
176 break;
177 case FC_SMFARRAY:
178 case FC_SMVARRAY:
179 size = *(const WORD*)(pFormat + 2);
180 break;
181 case FC_LGFARRAY:
182 case FC_LGVARRAY:
183 size = *(const DWORD*)(pFormat + 2);
184 break;
185 case FC_BOGUS_ARRAY:
186 pFormat = ComputeConformance(pStubMsg, NULL, pFormat + 4, *(const WORD*)&pFormat[2]);
187 TRACE("conformance = %ld\n", pStubMsg->MaxCount);
188 pFormat = ComputeVariance(pStubMsg, NULL, pFormat, pStubMsg->MaxCount);
189 size = ComplexStructSize(pStubMsg, pFormat);
190 size *= pStubMsg->MaxCount;
191 break;
192 case FC_USER_MARSHAL:
193 size = *(const WORD*)(pFormat + 4);
194 break;
195 case FC_CSTRING:
196 size = *(const WORD*)(pFormat + 2);
197 break;
198 case FC_WSTRING:
199 size = *(const WORD*)(pFormat + 2) * sizeof(WCHAR);
200 break;
201 case FC_C_CSTRING:
202 case FC_C_WSTRING:
203 if (*pFormat == FC_C_CSTRING)
204 size = sizeof(CHAR);
205 else
206 size = sizeof(WCHAR);
207 if (pFormat[1] == FC_STRING_SIZED)
208 ComputeConformance(pStubMsg, NULL, pFormat + 2, 0);
209 else
210 pStubMsg->MaxCount = 0;
211 size *= pStubMsg->MaxCount;
212 break;
213 default:
214 FIXME("Unhandled type %02x\n", *pFormat);
215 /* fallthrough */
216 case FC_UP:
217 case FC_OP:
218 case FC_FP:
219 case FC_IP:
220 size = sizeof(void *);
221 break;
223 return size;
226 void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
228 #if 0 /* these functions are not defined yet */
229 pMessage->pfnAllocate = NdrRpcSmClientAllocate;
230 pMessage->pfnFree = NdrRpcSmClientFree;
231 #endif
234 static const char *debugstr_PROC_PF(PARAM_ATTRIBUTES param_attributes)
236 char buffer[160];
238 buffer[0] = 0;
239 if (param_attributes.MustSize) strcat(buffer, " MustSize");
240 if (param_attributes.MustFree) strcat(buffer, " MustFree");
241 if (param_attributes.IsPipe) strcat(buffer, " IsPipe");
242 if (param_attributes.IsIn) strcat(buffer, " IsIn");
243 if (param_attributes.IsOut) strcat(buffer, " IsOut");
244 if (param_attributes.IsReturn) strcat(buffer, " IsReturn");
245 if (param_attributes.IsBasetype) strcat(buffer, " IsBasetype");
246 if (param_attributes.IsByValue) strcat(buffer, " IsByValue");
247 if (param_attributes.IsSimpleRef) strcat(buffer, " IsSimpleRef");
248 if (param_attributes.IsDontCallFreeInst) strcat(buffer, " IsDontCallFreeInst");
249 if (param_attributes.SaveForAsyncFinish) strcat(buffer, " SaveForAsyncFinish");
250 if (param_attributes.ServerAllocSize)
251 sprintf( buffer + strlen(buffer), " ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
252 return buffer[0] ? wine_dbg_sprintf( "%s", buffer + 1 ) : "";
255 static const char *debugstr_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
257 char buffer[160];
259 buffer[0] = 0;
260 if (Oi2Flags.ServerMustSize) strcat(buffer, " ServerMustSize");
261 if (Oi2Flags.ClientMustSize) strcat(buffer, " ClientMustSize");
262 if (Oi2Flags.HasReturn) strcat(buffer, " HasReturn");
263 if (Oi2Flags.HasPipes) strcat(buffer, " HasPipes");
264 if (Oi2Flags.Unused) strcat(buffer, " Unused");
265 if (Oi2Flags.HasAsyncUuid) strcat(buffer, " HasAsyncUuid");
266 if (Oi2Flags.HasExtensions) strcat(buffer, " HasExtensions");
267 if (Oi2Flags.HasAsyncHandle) strcat(buffer, " HasAsyncHandle");
268 return buffer[0] ? wine_dbg_sprintf( "%s", buffer + 1 ) : "";
271 #define ARG_FROM_OFFSET(args, offset) ((args) + (offset))
273 static size_t get_handle_desc_size(const NDR_PROC_HEADER *proc_header, PFORMAT_STRING format)
275 if (!proc_header->handle_type)
277 if (*format == FC_BIND_PRIMITIVE)
278 return sizeof(NDR_EHD_PRIMITIVE);
279 else if (*format == FC_BIND_GENERIC)
280 return sizeof(NDR_EHD_GENERIC);
281 else if (*format == FC_BIND_CONTEXT)
282 return sizeof(NDR_EHD_CONTEXT);
284 return 0;
287 static handle_t client_get_handle(const MIDL_STUB_MESSAGE *pStubMsg,
288 const NDR_PROC_HEADER *pProcHeader, const PFORMAT_STRING pFormat)
290 /* binding */
291 switch (pProcHeader->handle_type)
293 /* explicit binding: parse additional section */
294 case 0:
295 switch (*pFormat) /* handle_type */
297 case FC_BIND_PRIMITIVE: /* explicit primitive */
299 const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
301 TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
303 if (pDesc->flag) /* pointer to binding */
304 return **(handle_t **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
305 else
306 return *(handle_t *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
308 case FC_BIND_GENERIC: /* explicit generic */
310 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
311 void *pObject = NULL;
312 void *pArg;
313 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
315 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
317 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
318 pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
319 else
320 pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
321 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
322 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
323 return pGenPair->pfnBind(pObject);
325 case FC_BIND_CONTEXT: /* explicit context */
327 const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
328 NDR_CCONTEXT context_handle;
329 TRACE("Explicit bind context\n");
330 if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
332 TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
333 context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
335 else
336 context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
338 if (context_handle) return NDRCContextBinding(context_handle);
339 else if (pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL)
341 ERR("null context handle isn't allowed\n");
342 RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
343 return NULL;
345 /* FIXME: should we store this structure in stubMsg.pContext? */
347 default:
348 ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
349 RpcRaiseException(RPC_X_BAD_STUB_DATA);
351 break;
352 case FC_BIND_GENERIC: /* implicit generic */
353 FIXME("FC_BIND_GENERIC\n");
354 RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
355 break;
356 case FC_BIND_PRIMITIVE: /* implicit primitive */
357 TRACE("Implicit primitive handle\n");
358 return *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
359 case FC_CALLBACK_HANDLE: /* implicit callback */
360 TRACE("FC_CALLBACK_HANDLE\n");
361 /* server calls callback procedures only in response to remote call, and most recent
362 binding handle is used. Calling back to a client can potentially result in another
363 callback with different current handle. */
364 return I_RpcGetCurrentCallHandle();
365 case FC_AUTO_HANDLE: /* implicit auto handle */
366 /* strictly speaking, it isn't necessary to set hBinding here
367 * since it isn't actually used (hence the automatic in its name),
368 * but then why does MIDL generate a valid entry in the
369 * MIDL_STUB_DESC for it? */
370 TRACE("Implicit auto handle\n");
371 return *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
372 default:
373 ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
374 RpcRaiseException(RPC_X_BAD_STUB_DATA);
376 return NULL;
379 static void client_free_handle(
380 PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
381 PFORMAT_STRING pFormat, handle_t hBinding)
383 /* binding */
384 switch (pProcHeader->handle_type)
386 /* explicit binding: parse additional section */
387 case 0:
388 switch (*pFormat) /* handle_type */
390 case FC_BIND_GENERIC: /* explicit generic */
392 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
393 void *pObject = NULL;
394 void *pArg;
395 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
397 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
399 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
400 pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
401 else
402 pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
403 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
404 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
405 pGenPair->pfnUnbind(pObject, hBinding);
406 break;
408 case FC_BIND_CONTEXT: /* explicit context */
409 case FC_BIND_PRIMITIVE: /* explicit primitive */
410 break;
411 default:
412 ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
413 RpcRaiseException(RPC_X_BAD_STUB_DATA);
415 break;
416 case FC_BIND_GENERIC: /* implicit generic */
417 FIXME("FC_BIND_GENERIC\n");
418 RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
419 break;
420 case FC_CALLBACK_HANDLE: /* implicit callback */
421 case FC_BIND_PRIMITIVE: /* implicit primitive */
422 case FC_AUTO_HANDLE: /* implicit auto handle */
423 break;
424 default:
425 ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
426 RpcRaiseException(RPC_X_BAD_STUB_DATA);
430 static inline BOOL param_needs_alloc( PARAM_ATTRIBUTES attr )
432 return attr.IsOut && !attr.IsIn && !attr.IsBasetype && !attr.IsByValue;
435 static inline BOOL param_is_out_basetype( PARAM_ATTRIBUTES attr )
437 return attr.IsOut && !attr.IsIn && attr.IsBasetype && attr.IsSimpleRef;
440 static size_t basetype_arg_size( unsigned char fc )
442 switch (fc)
444 case FC_BYTE:
445 case FC_CHAR:
446 case FC_SMALL:
447 case FC_USMALL:
448 return sizeof(char);
449 case FC_WCHAR:
450 case FC_SHORT:
451 case FC_USHORT:
452 return sizeof(short);
453 case FC_LONG:
454 case FC_ULONG:
455 case FC_ENUM16:
456 case FC_ENUM32:
457 case FC_ERROR_STATUS_T:
458 return sizeof(int);
459 case FC_FLOAT:
460 return sizeof(float);
461 case FC_HYPER:
462 return sizeof(LONGLONG);
463 case FC_DOUBLE:
464 return sizeof(double);
465 case FC_INT3264:
466 case FC_UINT3264:
467 return sizeof(INT_PTR);
468 default:
469 FIXME("Unhandled basetype %#x.\n", fc);
470 return 0;
474 void client_do_args( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, enum stubless_phase phase,
475 void **fpu_args, unsigned short number_of_params, unsigned char *pRetVal )
477 const NDR_PARAM_OIF *params = (const NDR_PARAM_OIF *)pFormat;
478 unsigned int i;
480 for (i = 0; i < number_of_params; i++)
482 unsigned char *pArg = pStubMsg->StackTop + params[i].stack_offset;
483 PFORMAT_STRING pTypeFormat = (PFORMAT_STRING)&pStubMsg->StubDesc->pFormatTypes[params[i].u.type_offset];
485 #ifdef __x86_64__ /* floats are passed as doubles through varargs functions */
486 float f;
488 if (params[i].attr.IsBasetype &&
489 params[i].u.type_format_char == FC_FLOAT &&
490 !params[i].attr.IsSimpleRef &&
491 !fpu_args)
493 f = *(double *)pArg;
494 pArg = (unsigned char *)&f;
496 #endif
498 TRACE("param[%d]: %p type %02x %s\n", i, pArg,
499 params[i].attr.IsBasetype ? params[i].u.type_format_char : *pTypeFormat,
500 debugstr_PROC_PF( params[i].attr ));
502 switch (phase)
504 case STUBLESS_INITOUT:
505 if (*(unsigned char **)pArg)
507 if (param_needs_alloc(params[i].attr))
508 memset( *(unsigned char **)pArg, 0, calc_arg_size( pStubMsg, pTypeFormat ));
509 else if (param_is_out_basetype(params[i].attr))
510 memset( *(unsigned char **)pArg, 0, basetype_arg_size( params[i].u.type_format_char ));
512 break;
513 case STUBLESS_CALCSIZE:
514 if (params[i].attr.IsSimpleRef && !*(unsigned char **)pArg)
515 RpcRaiseException(RPC_X_NULL_REF_POINTER);
516 if (params[i].attr.IsIn) call_buffer_sizer(pStubMsg, pArg, &params[i]);
517 break;
518 case STUBLESS_MARSHAL:
519 if (params[i].attr.IsIn) call_marshaller(pStubMsg, pArg, &params[i]);
520 break;
521 case STUBLESS_UNMARSHAL:
522 if (params[i].attr.IsOut)
524 if (params[i].attr.IsReturn && pRetVal) pArg = pRetVal;
525 call_unmarshaller(pStubMsg, &pArg, &params[i], 0);
527 break;
528 case STUBLESS_FREE:
529 if (!params[i].attr.IsBasetype && params[i].attr.IsOut && !params[i].attr.IsByValue)
530 NdrClearOutParameters( pStubMsg, pTypeFormat, *(unsigned char **)pArg );
531 break;
532 default:
533 RpcRaiseException(RPC_S_INTERNAL_ERROR);
538 static unsigned int type_stack_size(unsigned char fc)
540 switch (fc)
542 case FC_BYTE:
543 case FC_CHAR:
544 case FC_SMALL:
545 case FC_USMALL:
546 case FC_WCHAR:
547 case FC_SHORT:
548 case FC_USHORT:
549 case FC_LONG:
550 case FC_ULONG:
551 case FC_INT3264:
552 case FC_UINT3264:
553 case FC_ENUM16:
554 case FC_ENUM32:
555 case FC_FLOAT:
556 case FC_ERROR_STATUS_T:
557 case FC_IGNORE:
558 return sizeof(void *);
559 case FC_DOUBLE:
560 return sizeof(double);
561 case FC_HYPER:
562 return sizeof(ULONGLONG);
563 default:
564 ERR("invalid base type 0x%x\n", fc);
565 RpcRaiseException(RPC_S_INTERNAL_ERROR);
569 static BOOL is_by_value( PFORMAT_STRING format )
571 switch (*format)
573 case FC_USER_MARSHAL:
574 case FC_STRUCT:
575 case FC_PSTRUCT:
576 case FC_CSTRUCT:
577 case FC_CPSTRUCT:
578 case FC_CVSTRUCT:
579 case FC_BOGUS_STRUCT:
580 return TRUE;
581 default:
582 return FALSE;
586 PFORMAT_STRING convert_old_args( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
587 unsigned int stack_size, BOOL object_proc,
588 void *buffer, unsigned int size, unsigned int *count )
590 NDR_PARAM_OIF *args = buffer;
591 unsigned int i, stack_offset = object_proc ? sizeof(void *) : 0;
593 for (i = 0; stack_offset < stack_size; i++)
595 const NDR_PARAM_OI_BASETYPE *param = (const NDR_PARAM_OI_BASETYPE *)pFormat;
596 const NDR_PARAM_OI_OTHER *other = (const NDR_PARAM_OI_OTHER *)pFormat;
598 if (i + 1 > size / sizeof(*args))
600 FIXME( "%u args not supported\n", i );
601 RpcRaiseException( RPC_S_INTERNAL_ERROR );
604 args[i].stack_offset = stack_offset;
605 memset( &args[i].attr, 0, sizeof(args[i].attr) );
607 switch (param->param_direction)
609 case FC_IN_PARAM_BASETYPE:
610 args[i].attr.IsIn = 1;
611 args[i].attr.IsBasetype = 1;
612 break;
613 case FC_RETURN_PARAM_BASETYPE:
614 args[i].attr.IsOut = 1;
615 args[i].attr.IsReturn = 1;
616 args[i].attr.IsBasetype = 1;
617 break;
618 case FC_IN_PARAM:
619 args[i].attr.IsIn = 1;
620 args[i].attr.MustFree = 1;
621 break;
622 case FC_IN_PARAM_NO_FREE_INST:
623 args[i].attr.IsIn = 1;
624 args[i].attr.IsDontCallFreeInst = 1;
625 break;
626 case FC_IN_OUT_PARAM:
627 args[i].attr.IsIn = 1;
628 args[i].attr.IsOut = 1;
629 args[i].attr.MustFree = 1;
630 break;
631 case FC_OUT_PARAM:
632 args[i].attr.IsOut = 1;
633 break;
634 case FC_RETURN_PARAM:
635 args[i].attr.IsOut = 1;
636 args[i].attr.IsReturn = 1;
637 break;
639 if (args[i].attr.IsBasetype)
641 args[i].u.type_format_char = param->type_format_char;
642 stack_offset += type_stack_size( param->type_format_char );
643 pFormat += sizeof(NDR_PARAM_OI_BASETYPE);
645 else
647 args[i].u.type_offset = other->type_offset;
648 args[i].attr.IsByValue = is_by_value( &pStubMsg->StubDesc->pFormatTypes[other->type_offset] );
649 stack_offset += other->stack_size * sizeof(void *);
650 pFormat += sizeof(NDR_PARAM_OI_OTHER);
653 *count = i;
654 return (PFORMAT_STRING)args;
657 struct ndr_client_call_ctx
659 MIDL_STUB_MESSAGE *stub_msg;
660 INTERPRETER_OPT_FLAGS Oif_flags;
661 INTERPRETER_OPT_FLAGS2 ext_flags;
662 const NDR_PROC_HEADER *proc_header;
663 void *This;
664 PFORMAT_STRING handle_format;
665 handle_t hbinding;
668 static void CALLBACK ndr_client_call_finally(BOOL normal, void *arg)
670 struct ndr_client_call_ctx *ctx = arg;
672 if (ctx->ext_flags.HasNewCorrDesc)
674 /* free extra correlation package */
675 NdrCorrelationFree(ctx->stub_msg);
678 if (ctx->Oif_flags.HasPipes)
680 /* NdrPipesDone(...) */
683 /* free the full pointer translation tables */
684 if (ctx->proc_header->Oi_flags & Oi_FULL_PTR_USED)
685 NdrFullPointerXlatFree(ctx->stub_msg->FullPtrXlatTables);
687 /* free marshalling buffer */
688 if (ctx->proc_header->Oi_flags & Oi_OBJECT_PROC)
689 NdrProxyFreeBuffer(ctx->This, ctx->stub_msg);
690 else
692 NdrFreeBuffer(ctx->stub_msg);
693 client_free_handle(ctx->stub_msg, ctx->proc_header, ctx->handle_format, ctx->hbinding);
697 /* Helper for ndr_client_call, to factor out the part that may or may not be
698 * guarded by a try/except block. */
699 static LONG_PTR do_ndr_client_call( const MIDL_STUB_DESC *stub_desc, const PFORMAT_STRING format,
700 const PFORMAT_STRING handle_format, void **stack_top, void **fpu_stack, MIDL_STUB_MESSAGE *stub_msg,
701 unsigned short procedure_number, unsigned short stack_size, unsigned int number_of_params,
702 INTERPRETER_OPT_FLAGS Oif_flags, INTERPRETER_OPT_FLAGS2 ext_flags, const NDR_PROC_HEADER *proc_header )
704 struct ndr_client_call_ctx finally_ctx;
705 RPC_MESSAGE rpc_msg;
706 handle_t hbinding = NULL;
707 /* the value to return to the client from the remote procedure */
708 LONG_PTR retval = 0;
709 /* the pointer to the object when in OLE mode */
710 void *This = NULL;
711 /* correlation cache */
712 ULONG_PTR NdrCorrCache[256];
714 /* create the full pointer translation tables, if requested */
715 if (proc_header->Oi_flags & Oi_FULL_PTR_USED)
716 stub_msg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
718 if (proc_header->Oi_flags & Oi_OBJECT_PROC)
720 /* object is always the first argument */
721 This = stack_top[0];
722 NdrProxyInitialize(This, &rpc_msg, stub_msg, stub_desc, procedure_number);
725 finally_ctx.stub_msg = stub_msg;
726 finally_ctx.Oif_flags = Oif_flags;
727 finally_ctx.ext_flags = ext_flags;
728 finally_ctx.proc_header = proc_header;
729 finally_ctx.This = This;
730 finally_ctx.handle_format = handle_format;
731 finally_ctx.hbinding = hbinding;
733 __TRY
735 if (!(proc_header->Oi_flags & Oi_OBJECT_PROC))
736 NdrClientInitializeNew(&rpc_msg, stub_msg, stub_desc, procedure_number);
738 stub_msg->StackTop = (unsigned char *)stack_top;
740 /* we only need a handle if this isn't an object method */
741 if (!(proc_header->Oi_flags & Oi_OBJECT_PROC))
743 hbinding = client_get_handle(stub_msg, proc_header, handle_format);
744 if (!hbinding) return 0;
747 stub_msg->BufferLength = 0;
749 /* store the RPC flags away */
750 if (proc_header->Oi_flags & Oi_HAS_RPCFLAGS)
751 rpc_msg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)proc_header)->rpc_flags;
753 /* use alternate memory allocation routines */
754 if (proc_header->Oi_flags & Oi_RPCSS_ALLOC_USED)
755 NdrRpcSmSetClientToOsf(stub_msg);
757 if (Oif_flags.HasPipes)
759 FIXME("pipes not supported yet\n");
760 RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
761 /* init pipes package */
762 /* NdrPipesInitialize(...) */
764 if (ext_flags.HasNewCorrDesc)
766 /* initialize extra correlation package */
767 NdrCorrelationInitialize(stub_msg, NdrCorrCache, sizeof(NdrCorrCache), 0);
768 if (ext_flags.Unused & 0x2) /* has range on conformance */
769 stub_msg->CorrDespIncrement = 12;
772 /* order of phases:
773 * 1. INITOUT - zero [out] parameters (proxies only)
774 * 2. CALCSIZE - calculate the buffer size
775 * 3. GETBUFFER - allocate the buffer
776 * 4. MARSHAL - marshal [in] params into the buffer
777 * 5. SENDRECEIVE - send/receive buffer
778 * 6. UNMARSHAL - unmarshal [out] params from buffer
779 * 7. FREE - clear [out] parameters (for proxies, and only on error)
782 /* 1. INITOUT */
783 if (proc_header->Oi_flags & Oi_OBJECT_PROC)
785 TRACE( "INITOUT\n" );
786 client_do_args(stub_msg, format, STUBLESS_INITOUT, fpu_stack,
787 number_of_params, (unsigned char *)&retval);
790 /* 2. CALCSIZE */
791 TRACE( "CALCSIZE\n" );
792 client_do_args(stub_msg, format, STUBLESS_CALCSIZE, fpu_stack,
793 number_of_params, (unsigned char *)&retval);
795 /* 3. GETBUFFER */
796 TRACE( "GETBUFFER\n" );
797 if (proc_header->Oi_flags & Oi_OBJECT_PROC)
798 NdrProxyGetBuffer(This, stub_msg);
799 else if (Oif_flags.HasPipes)
800 FIXME("pipes not supported yet\n");
801 else if (proc_header->handle_type == FC_AUTO_HANDLE)
802 #if 0
803 NdrNsGetBuffer(stub_msg, stub_msg->BufferLength, hBinding);
804 #else
805 FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
806 #endif
807 else
808 NdrGetBuffer(stub_msg, stub_msg->BufferLength, hbinding);
810 /* 4. MARSHAL */
811 TRACE( "MARSHAL\n" );
812 client_do_args(stub_msg, format, STUBLESS_MARSHAL, fpu_stack,
813 number_of_params, (unsigned char *)&retval);
815 /* 5. SENDRECEIVE */
816 TRACE( "SENDRECEIVE\n" );
817 if (proc_header->Oi_flags & Oi_OBJECT_PROC)
818 NdrProxySendReceive(This, stub_msg);
819 else if (Oif_flags.HasPipes)
820 /* NdrPipesSendReceive(...) */
821 FIXME("pipes not supported yet\n");
822 else if (proc_header->handle_type == FC_AUTO_HANDLE)
823 #if 0
824 NdrNsSendReceive(stub_msg, stub_msg->Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
825 #else
826 FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
827 #endif
828 else
829 NdrSendReceive(stub_msg, stub_msg->Buffer);
831 /* convert strings, floating point values and endianness into our
832 * preferred format */
833 if ((rpc_msg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
834 NdrConvert(stub_msg, format);
836 /* 6. UNMARSHAL */
837 TRACE( "UNMARSHAL\n" );
838 client_do_args(stub_msg, format, STUBLESS_UNMARSHAL, fpu_stack,
839 number_of_params, (unsigned char *)&retval);
841 __FINALLY_CTX(ndr_client_call_finally, &finally_ctx)
843 return retval;
846 LONG_PTR CDECL DECLSPEC_HIDDEN ndr_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
847 void **stack_top, void **fpu_stack )
849 /* pointer to start of stack where arguments start */
850 MIDL_STUB_MESSAGE stubMsg;
851 /* procedure number */
852 unsigned short procedure_number;
853 /* size of stack */
854 unsigned short stack_size;
855 /* number of parameters. optional for client to give it to us */
856 unsigned int number_of_params;
857 /* cache of Oif_flags from v2 procedure header */
858 INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
859 /* cache of extension flags from NDR_PROC_HEADER_EXTS */
860 INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
861 /* header for procedure string */
862 const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
863 /* the value to return to the client from the remote procedure */
864 LONG_PTR RetVal = 0;
865 PFORMAT_STRING pHandleFormat;
866 NDR_PARAM_OIF old_args[256];
868 TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
870 TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
872 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
874 const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
875 stack_size = header_rpc->stack_size;
876 procedure_number = header_rpc->proc_num;
877 pFormat += sizeof(NDR_PROC_HEADER_RPC);
879 else
881 stack_size = pProcHeader->stack_size;
882 procedure_number = pProcHeader->proc_num;
883 pFormat += sizeof(NDR_PROC_HEADER);
885 TRACE("stack size: 0x%x\n", stack_size);
886 TRACE("proc num: %d\n", procedure_number);
887 TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
888 TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
890 pHandleFormat = pFormat;
892 /* we only need a handle if this isn't an object method */
893 if (!(pProcHeader->Oi_flags & Oi_OBJECT_PROC))
894 pFormat += get_handle_desc_size(pProcHeader, pFormat);
896 if (is_oicf_stubdesc(pStubDesc)) /* -Oicf format */
898 const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
899 (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
901 Oif_flags = pOIFHeader->Oi2Flags;
902 number_of_params = pOIFHeader->number_of_params;
904 pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
906 TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
908 if (Oif_flags.HasExtensions)
910 const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
911 ext_flags = pExtensions->Flags2;
912 pFormat += pExtensions->Size;
913 #ifdef __x86_64__
914 if (pExtensions->Size > sizeof(*pExtensions) && fpu_stack)
916 int i;
917 unsigned short fpu_mask = *(unsigned short *)(pExtensions + 1);
918 for (i = 0; i < 4; i++, fpu_mask >>= 2)
919 switch (fpu_mask & 3)
921 case 1: *(float *)&stack_top[i] = *(float *)&fpu_stack[i]; break;
922 case 2: *(double *)&stack_top[i] = *(double *)&fpu_stack[i]; break;
925 #endif
928 else
930 pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
931 pProcHeader->Oi_flags & Oi_OBJECT_PROC,
932 old_args, sizeof(old_args), &number_of_params );
935 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
937 __TRY
939 RetVal = do_ndr_client_call(pStubDesc, pFormat, pHandleFormat,
940 stack_top, fpu_stack, &stubMsg, procedure_number, stack_size,
941 number_of_params, Oif_flags, ext_flags, pProcHeader);
943 __EXCEPT_ALL
945 /* 7. FREE */
946 TRACE( "FREE\n" );
947 client_do_args(&stubMsg, pFormat, STUBLESS_FREE, fpu_stack,
948 number_of_params, (unsigned char *)&RetVal);
949 RetVal = NdrProxyErrorHandler(GetExceptionCode());
951 __ENDTRY
953 else if (pProcHeader->Oi_flags & Oi_HAS_COMM_OR_FAULT)
955 __TRY
957 RetVal = do_ndr_client_call(pStubDesc, pFormat, pHandleFormat,
958 stack_top, fpu_stack, &stubMsg, procedure_number, stack_size,
959 number_of_params, Oif_flags, ext_flags, pProcHeader);
961 __EXCEPT_ALL
963 const COMM_FAULT_OFFSETS *comm_fault_offsets = &pStubDesc->CommFaultOffsets[procedure_number];
964 ULONG *comm_status;
965 ULONG *fault_status;
967 TRACE("comm_fault_offsets = {0x%hx, 0x%hx}\n", comm_fault_offsets->CommOffset, comm_fault_offsets->FaultOffset);
969 if (comm_fault_offsets->CommOffset == -1)
970 comm_status = (ULONG *)&RetVal;
971 else if (comm_fault_offsets->CommOffset >= 0)
972 comm_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset);
973 else
974 comm_status = NULL;
976 if (comm_fault_offsets->FaultOffset == -1)
977 fault_status = (ULONG *)&RetVal;
978 else if (comm_fault_offsets->FaultOffset >= 0)
979 fault_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->FaultOffset);
980 else
981 fault_status = NULL;
983 NdrMapCommAndFaultStatus(&stubMsg, comm_status, fault_status,
984 GetExceptionCode());
986 __ENDTRY
988 else
990 RetVal = do_ndr_client_call(pStubDesc, pFormat, pHandleFormat,
991 stack_top, fpu_stack, &stubMsg, procedure_number, stack_size,
992 number_of_params, Oif_flags, ext_flags, pProcHeader);
995 TRACE("RetVal = 0x%lx\n", RetVal);
996 return RetVal;
999 #ifdef __x86_64__
1001 __ASM_GLOBAL_FUNC( NdrClientCall2,
1002 "movq %r8,0x18(%rsp)\n\t"
1003 "movq %r9,0x20(%rsp)\n\t"
1004 "leaq 0x18(%rsp),%r8\n\t"
1005 "xorq %r9,%r9\n\t"
1006 "subq $0x28,%rsp\n\t"
1007 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1008 "call " __ASM_NAME("ndr_client_call") "\n\t"
1009 "addq $0x28,%rsp\n\t"
1010 __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1011 "ret" );
1013 #else /* __x86_64__ */
1015 /***********************************************************************
1016 * NdrClientCall2 [RPCRT4.@]
1018 CLIENT_CALL_RETURN WINAPIV NdrClientCall2( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1020 __ms_va_list args;
1021 LONG_PTR ret;
1023 __ms_va_start( args, format );
1024 ret = ndr_client_call( desc, format, va_arg( args, void ** ), NULL );
1025 __ms_va_end( args );
1026 return *(CLIENT_CALL_RETURN *)&ret;
1029 #endif /* __x86_64__ */
1031 /* Calls a function with the specified arguments, restoring the stack
1032 * properly afterwards as we don't know the calling convention of the
1033 * function */
1034 #if defined __i386__ && defined _MSC_VER
1035 __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
1037 __asm
1039 push ebp
1040 mov ebp, esp
1041 push edi ; Save registers
1042 push esi
1043 mov eax, [ebp+16] ; Get stack size
1044 sub esp, eax ; Make room in stack for arguments
1045 and esp, 0xFFFFFFF0
1046 mov edi, esp
1047 mov ecx, eax
1048 mov esi, [ebp+12]
1049 shr ecx, 2
1051 rep movsd ; Copy dword blocks
1052 call [ebp+8] ; Call function
1053 lea esp, [ebp-8] ; Restore stack
1054 pop esi ; Restore registers
1055 pop edi
1056 pop ebp
1060 #elif defined __i386__ && defined __GNUC__
1061 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1062 __ASM_GLOBAL_FUNC(call_server_func,
1063 "pushl %ebp\n\t"
1064 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1065 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1066 "movl %esp,%ebp\n\t"
1067 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1068 "pushl %edi\n\t" /* Save registers */
1069 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
1070 "pushl %esi\n\t"
1071 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
1072 "movl 16(%ebp), %eax\n\t" /* Get stack size */
1073 "subl %eax, %esp\n\t" /* Make room in stack for arguments */
1074 "andl $~15, %esp\n\t" /* Make sure stack has 16-byte alignment for Mac OS X */
1075 "movl %esp, %edi\n\t"
1076 "movl %eax, %ecx\n\t"
1077 "movl 12(%ebp), %esi\n\t"
1078 "shrl $2, %ecx\n\t" /* divide by 4 */
1079 "cld\n\t"
1080 "rep; movsl\n\t" /* Copy dword blocks */
1081 "call *8(%ebp)\n\t" /* Call function */
1082 "leal -8(%ebp), %esp\n\t" /* Restore stack */
1083 "popl %esi\n\t" /* Restore registers */
1084 __ASM_CFI(".cfi_same_value %esi\n\t")
1085 "popl %edi\n\t"
1086 __ASM_CFI(".cfi_same_value %edi\n\t")
1087 "popl %ebp\n\t"
1088 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1089 __ASM_CFI(".cfi_same_value %ebp\n\t")
1090 "ret" )
1091 #elif defined __x86_64__
1092 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1093 __ASM_GLOBAL_FUNC( call_server_func,
1094 "pushq %rbp\n\t"
1095 __ASM_SEH(".seh_pushreg %rbp\n\t")
1096 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
1097 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
1098 "movq %rsp,%rbp\n\t"
1099 __ASM_SEH(".seh_setframe %rbp,0\n\t")
1100 __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
1101 "pushq %rsi\n\t"
1102 __ASM_SEH(".seh_pushreg %rsi\n\t")
1103 __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
1104 "pushq %rdi\n\t"
1105 __ASM_SEH(".seh_pushreg %rdi\n\t")
1106 __ASM_SEH(".seh_endprologue\n\t")
1107 __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
1108 "movq %rcx,%rax\n\t" /* function to call */
1109 "movq $32,%rcx\n\t" /* allocate max(32,stack_size) bytes of stack space */
1110 "cmpq %rcx,%r8\n\t"
1111 "cmovgq %r8,%rcx\n\t"
1112 "subq %rcx,%rsp\n\t"
1113 "andq $~15,%rsp\n\t"
1114 "movq %r8,%rcx\n\t"
1115 "shrq $3,%rcx\n\t"
1116 "movq %rsp,%rdi\n\t"
1117 "movq %rdx,%rsi\n\t"
1118 "rep; movsq\n\t" /* copy arguments */
1119 "movq 0(%rsp),%rcx\n\t"
1120 "movq 8(%rsp),%rdx\n\t"
1121 "movq 16(%rsp),%r8\n\t"
1122 "movq 24(%rsp),%r9\n\t"
1123 "movq 0(%rsp),%xmm0\n\t"
1124 "movq 8(%rsp),%xmm1\n\t"
1125 "movq 16(%rsp),%xmm2\n\t"
1126 "movq 24(%rsp),%xmm3\n\t"
1127 "callq *%rax\n\t"
1128 "leaq -16(%rbp),%rsp\n\t" /* restore stack */
1129 "popq %rdi\n\t"
1130 __ASM_CFI(".cfi_same_value %rdi\n\t")
1131 "popq %rsi\n\t"
1132 __ASM_CFI(".cfi_same_value %rsi\n\t")
1133 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
1134 "popq %rbp\n\t"
1135 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
1136 __ASM_CFI(".cfi_same_value %rbp\n\t")
1137 "ret")
1138 #elif defined __arm__
1139 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char *args, unsigned int stack_size);
1140 __ASM_GLOBAL_FUNC( call_server_func,
1141 ".arm\n\t"
1142 "push {r4, r5, LR}\n\t"
1143 "mov r4, r0\n\t"
1144 "mov r5, SP\n\t"
1145 "lsr r3, r2, #2\n\t"
1146 "cmp r3, #0\n\t"
1147 "beq 5f\n\t"
1148 "sub SP, SP, r2\n\t"
1149 "tst r3, #1\n\t"
1150 "subeq SP, SP, #4\n\t"
1151 "1:\tsub r2, r2, #4\n\t"
1152 "ldr r0, [r1, r2]\n\t"
1153 "str r0, [SP, r2]\n\t"
1154 "cmp r2, #0\n\t"
1155 "bgt 1b\n\t"
1156 "cmp r3, #1\n\t"
1157 "bgt 2f\n\t"
1158 "pop {r0}\n\t"
1159 "b 5f\n\t"
1160 "2:\tcmp r3, #2\n\t"
1161 "bgt 3f\n\t"
1162 "pop {r0-r1}\n\t"
1163 "b 5f\n\t"
1164 "3:\tcmp r3, #3\n\t"
1165 "bgt 4f\n\t"
1166 "pop {r0-r2}\n\t"
1167 "b 5f\n\t"
1168 "4:\tpop {r0-r3}\n\t"
1169 "5:\tblx r4\n\t"
1170 "mov SP, r5\n\t"
1171 "pop {r4, r5, PC}" )
1172 #else
1173 #warning call_server_func not implemented for your architecture
1174 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
1176 FIXME("Not implemented for your architecture\n");
1177 return 0;
1179 #endif
1181 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
1182 PFORMAT_STRING pFormat, enum stubless_phase phase,
1183 unsigned short number_of_params)
1185 const NDR_PARAM_OIF *params = (const NDR_PARAM_OIF *)pFormat;
1186 unsigned int i;
1187 LONG_PTR *retval_ptr = NULL;
1189 for (i = 0; i < number_of_params; i++)
1191 unsigned char *pArg = pStubMsg->StackTop + params[i].stack_offset;
1192 const unsigned char *pTypeFormat = &pStubMsg->StubDesc->pFormatTypes[params[i].u.type_offset];
1194 TRACE("param[%d]: %p -> %p type %02x %s\n", i,
1195 pArg, *(unsigned char **)pArg,
1196 params[i].attr.IsBasetype ? params[i].u.type_format_char : *pTypeFormat,
1197 debugstr_PROC_PF( params[i].attr ));
1199 switch (phase)
1201 case STUBLESS_MARSHAL:
1202 if (params[i].attr.IsOut || params[i].attr.IsReturn)
1203 call_marshaller(pStubMsg, pArg, &params[i]);
1204 break;
1205 case STUBLESS_MUSTFREE:
1206 if (params[i].attr.MustFree)
1208 call_freer(pStubMsg, pArg, &params[i]);
1210 break;
1211 case STUBLESS_FREE:
1212 if (params[i].attr.ServerAllocSize)
1214 HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1216 else if (param_needs_alloc(params[i].attr) &&
1217 (!params[i].attr.MustFree || params[i].attr.IsSimpleRef))
1219 if (*pTypeFormat != FC_BIND_CONTEXT) pStubMsg->pfnFree(*(void **)pArg);
1221 break;
1222 case STUBLESS_INITOUT:
1223 if (param_needs_alloc(params[i].attr) && !params[i].attr.ServerAllocSize)
1225 if (*pTypeFormat == FC_BIND_CONTEXT)
1227 NDR_SCONTEXT ctxt = NdrContextHandleInitialize(pStubMsg, pTypeFormat);
1228 *(void **)pArg = NDRSContextValue(ctxt);
1229 if (params[i].attr.IsReturn) retval_ptr = (LONG_PTR *)NDRSContextValue(ctxt);
1231 else
1233 DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1234 if (size)
1236 *(void **)pArg = NdrAllocate(pStubMsg, size);
1237 memset(*(void **)pArg, 0, size);
1241 if (!retval_ptr && params[i].attr.IsReturn) retval_ptr = (LONG_PTR *)pArg;
1242 break;
1243 case STUBLESS_UNMARSHAL:
1244 if (params[i].attr.ServerAllocSize)
1245 *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1246 params[i].attr.ServerAllocSize * 8);
1248 if (params[i].attr.IsIn)
1249 call_unmarshaller(pStubMsg, &pArg, &params[i], 0);
1250 break;
1251 case STUBLESS_CALCSIZE:
1252 if (params[i].attr.IsOut || params[i].attr.IsReturn)
1253 call_buffer_sizer(pStubMsg, pArg, &params[i]);
1254 break;
1255 default:
1256 RpcRaiseException(RPC_S_INTERNAL_ERROR);
1258 TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1260 return retval_ptr;
1263 /***********************************************************************
1264 * NdrStubCall2 [RPCRT4.@]
1266 * Unmarshals [in] parameters, calls either a method in an object or a server
1267 * function, marshals any [out] parameters and frees any allocated data.
1269 * NOTES
1270 * Used by stubless MIDL-generated code.
1272 LONG WINAPI NdrStubCall2(
1273 struct IRpcStubBuffer * pThis,
1274 struct IRpcChannelBuffer * pChannel,
1275 PRPC_MESSAGE pRpcMsg,
1276 DWORD * pdwStubPhase)
1278 const MIDL_SERVER_INFO *pServerInfo;
1279 const MIDL_STUB_DESC *pStubDesc;
1280 PFORMAT_STRING pFormat;
1281 MIDL_STUB_MESSAGE stubMsg;
1282 /* pointer to start of stack to pass into stub implementation */
1283 unsigned char * args;
1284 /* size of stack */
1285 unsigned short stack_size;
1286 /* number of parameters. optional for client to give it to us */
1287 unsigned int number_of_params;
1288 /* cache of Oif_flags from v2 procedure header */
1289 INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1290 /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1291 INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1292 /* the type of pass we are currently doing */
1293 enum stubless_phase phase;
1294 /* header for procedure string */
1295 const NDR_PROC_HEADER *pProcHeader;
1296 /* location to put retval into */
1297 LONG_PTR *retval_ptr = NULL;
1298 /* correlation cache */
1299 ULONG_PTR NdrCorrCache[256];
1301 TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1303 if (pThis)
1304 pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1305 else
1306 pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1308 pStubDesc = pServerInfo->pStubDesc;
1309 pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1310 pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1312 TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1314 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1316 const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1317 stack_size = header_rpc->stack_size;
1318 pFormat += sizeof(NDR_PROC_HEADER_RPC);
1321 else
1323 stack_size = pProcHeader->stack_size;
1324 pFormat += sizeof(NDR_PROC_HEADER);
1327 TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1329 /* binding */
1330 switch (pProcHeader->handle_type)
1332 /* explicit binding: parse additional section */
1333 case 0:
1334 switch (*pFormat) /* handle_type */
1336 case FC_BIND_PRIMITIVE: /* explicit primitive */
1337 pFormat += sizeof(NDR_EHD_PRIMITIVE);
1338 break;
1339 case FC_BIND_GENERIC: /* explicit generic */
1340 pFormat += sizeof(NDR_EHD_GENERIC);
1341 break;
1342 case FC_BIND_CONTEXT: /* explicit context */
1343 pFormat += sizeof(NDR_EHD_CONTEXT);
1344 break;
1345 default:
1346 ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1347 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1349 break;
1350 case FC_BIND_GENERIC: /* implicit generic */
1351 case FC_BIND_PRIMITIVE: /* implicit primitive */
1352 case FC_CALLBACK_HANDLE: /* implicit callback */
1353 case FC_AUTO_HANDLE: /* implicit auto handle */
1354 break;
1355 default:
1356 ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1357 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1360 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1361 NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1362 else
1363 NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1365 /* create the full pointer translation tables, if requested */
1366 if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1367 stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1369 /* store the RPC flags away */
1370 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1371 pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1373 /* use alternate memory allocation routines */
1374 if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1375 #if 0
1376 NdrRpcSsEnableAllocate(&stubMsg);
1377 #else
1378 FIXME("Set RPCSS memory allocation routines\n");
1379 #endif
1381 TRACE("allocating memory for stack of size %x\n", stack_size);
1383 args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1384 stubMsg.StackTop = args; /* used by conformance of top-level objects */
1386 /* add the implicit This pointer as the first arg to the function if we
1387 * are calling an object method */
1388 if (pThis)
1389 *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1391 if (is_oicf_stubdesc(pStubDesc))
1393 const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1395 Oif_flags = pOIFHeader->Oi2Flags;
1396 number_of_params = pOIFHeader->number_of_params;
1398 pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1400 TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1402 if (Oif_flags.HasExtensions)
1404 const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
1405 ext_flags = pExtensions->Flags2;
1406 pFormat += pExtensions->Size;
1409 if (Oif_flags.HasPipes)
1411 FIXME("pipes not supported yet\n");
1412 RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1413 /* init pipes package */
1414 /* NdrPipesInitialize(...) */
1416 if (ext_flags.HasNewCorrDesc)
1418 /* initialize extra correlation package */
1419 NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
1420 if (ext_flags.Unused & 0x2) /* has range on conformance */
1421 stubMsg.CorrDespIncrement = 12;
1424 else
1426 pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
1427 pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1428 /* reuse the correlation cache, it's not needed for v1 format */
1429 NdrCorrCache, sizeof(NdrCorrCache), &number_of_params );
1432 /* convert strings, floating point values and endianness into our
1433 * preferred format */
1434 if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1435 NdrConvert(&stubMsg, pFormat);
1437 for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1439 TRACE("phase = %d\n", phase);
1440 switch (phase)
1442 case STUBLESS_CALLSERVER:
1443 /* call the server function */
1444 if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1445 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1446 else
1448 SERVER_ROUTINE func;
1449 LONG_PTR retval;
1451 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1453 SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1454 func = vtbl[pRpcMsg->ProcNum];
1456 else
1457 func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1459 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1460 retval = call_server_func(func, args, stack_size);
1462 if (retval_ptr)
1464 TRACE("stub implementation returned 0x%lx\n", retval);
1465 *retval_ptr = retval;
1467 else
1468 TRACE("void stub implementation\n");
1471 stubMsg.Buffer = NULL;
1472 stubMsg.BufferLength = 0;
1474 break;
1475 case STUBLESS_GETBUFFER:
1476 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1477 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1478 else
1480 RPC_STATUS Status;
1482 pRpcMsg->BufferLength = stubMsg.BufferLength;
1483 /* allocate buffer for [out] and [ret] params */
1484 Status = I_RpcGetBuffer(pRpcMsg);
1485 if (Status)
1486 RpcRaiseException(Status);
1487 stubMsg.Buffer = pRpcMsg->Buffer;
1489 break;
1490 case STUBLESS_UNMARSHAL:
1491 case STUBLESS_INITOUT:
1492 case STUBLESS_CALCSIZE:
1493 case STUBLESS_MARSHAL:
1494 case STUBLESS_MUSTFREE:
1495 case STUBLESS_FREE:
1496 retval_ptr = stub_do_args(&stubMsg, pFormat, phase, number_of_params);
1497 break;
1498 default:
1499 ERR("shouldn't reach here. phase %d\n", phase);
1500 break;
1504 pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1506 if (ext_flags.HasNewCorrDesc)
1508 /* free extra correlation package */
1509 NdrCorrelationFree(&stubMsg);
1512 if (Oif_flags.HasPipes)
1514 /* NdrPipesDone(...) */
1517 /* free the full pointer translation tables */
1518 if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1519 NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1521 /* free server function stack */
1522 HeapFree(GetProcessHeap(), 0, args);
1524 return S_OK;
1527 /***********************************************************************
1528 * NdrServerCall2 [RPCRT4.@]
1530 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1532 DWORD dwPhase;
1533 NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1536 /***********************************************************************
1537 * NdrStubCall [RPCRT4.@]
1539 LONG WINAPI NdrStubCall( struct IRpcStubBuffer *This, struct IRpcChannelBuffer *channel,
1540 PRPC_MESSAGE msg, DWORD *phase )
1542 return NdrStubCall2( This, channel, msg, phase );
1545 /***********************************************************************
1546 * NdrServerCall [RPCRT4.@]
1548 void WINAPI NdrServerCall( PRPC_MESSAGE msg )
1550 DWORD phase;
1551 NdrStubCall( NULL, NULL, msg, &phase );
1554 /***********************************************************************
1555 * NdrServerCallAll [RPCRT4.@]
1557 void WINAPI NdrServerCallAll( PRPC_MESSAGE msg )
1559 FIXME("%p stub\n", msg);
1562 /* Helper for ndr_async_client_call, to factor out the part that may or may not be
1563 * guarded by a try/except block. */
1564 static void do_ndr_async_client_call( const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormat, void **stack_top )
1566 /* pointer to start of stack where arguments start */
1567 PRPC_MESSAGE pRpcMsg;
1568 PMIDL_STUB_MESSAGE pStubMsg;
1569 RPC_ASYNC_STATE *pAsync;
1570 struct async_call_data *async_call_data;
1571 /* procedure number */
1572 unsigned short procedure_number;
1573 /* cache of Oif_flags from v2 procedure header */
1574 INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1575 /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1576 INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1577 /* header for procedure string */
1578 const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1579 RPC_STATUS status;
1581 /* Later NDR language versions probably won't be backwards compatible */
1582 if (pStubDesc->Version > 0x50002)
1584 FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1585 RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1588 async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1589 if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
1590 async_call_data->pProcHeader = pProcHeader;
1592 async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1593 pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
1595 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1597 const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1598 async_call_data->stack_size = header_rpc->stack_size;
1599 procedure_number = header_rpc->proc_num;
1600 pFormat += sizeof(NDR_PROC_HEADER_RPC);
1602 else
1604 async_call_data->stack_size = pProcHeader->stack_size;
1605 procedure_number = pProcHeader->proc_num;
1606 pFormat += sizeof(NDR_PROC_HEADER);
1608 TRACE("stack size: 0x%x\n", async_call_data->stack_size);
1609 TRACE("proc num: %d\n", procedure_number);
1611 /* create the full pointer translation tables, if requested */
1612 if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1613 pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
1615 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1617 ERR("objects not supported\n");
1618 I_RpcFree(async_call_data);
1619 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1622 NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
1624 TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1625 TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
1627 /* needed for conformance of top-level objects */
1628 pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
1629 memcpy(pStubMsg->StackTop, stack_top, async_call_data->stack_size);
1631 pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
1632 pAsync->StubInfo = async_call_data;
1633 async_call_data->pHandleFormat = pFormat;
1635 TRACE("pAsync %p, pAsync->StubInfo %p, NotificationType %d\n", pAsync, pAsync->StubInfo, pAsync->NotificationType);
1637 pFormat += get_handle_desc_size(pProcHeader, pFormat);
1638 async_call_data->hBinding = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat);
1639 if (!async_call_data->hBinding) return;
1641 if (is_oicf_stubdesc(pStubDesc))
1643 const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1644 (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1646 Oif_flags = pOIFHeader->Oi2Flags;
1647 async_call_data->number_of_params = pOIFHeader->number_of_params;
1649 pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1651 TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1653 if (Oif_flags.HasExtensions)
1655 const NDR_PROC_HEADER_EXTS *pExtensions =
1656 (const NDR_PROC_HEADER_EXTS *)pFormat;
1657 ext_flags = pExtensions->Flags2;
1658 pFormat += pExtensions->Size;
1661 else
1663 pFormat = convert_old_args( pStubMsg, pFormat, async_call_data->stack_size,
1664 pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1665 async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache),
1666 &async_call_data->number_of_params );
1669 async_call_data->pParamFormat = pFormat;
1671 pStubMsg->BufferLength = 0;
1673 /* store the RPC flags away */
1674 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1675 pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1677 /* use alternate memory allocation routines */
1678 if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1679 NdrRpcSmSetClientToOsf(pStubMsg);
1681 if (Oif_flags.HasPipes)
1683 FIXME("pipes not supported yet\n");
1684 RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1685 /* init pipes package */
1686 /* NdrPipesInitialize(...) */
1688 if (ext_flags.HasNewCorrDesc)
1690 /* initialize extra correlation package */
1691 NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
1692 if (ext_flags.Unused & 0x2) /* has range on conformance */
1693 pStubMsg->CorrDespIncrement = 12;
1696 /* order of phases:
1697 * 1. CALCSIZE - calculate the buffer size
1698 * 2. GETBUFFER - allocate the buffer
1699 * 3. MARSHAL - marshal [in] params into the buffer
1700 * 4. SENDRECEIVE - send buffer
1701 * Then in NdrpCompleteAsyncClientCall:
1702 * 1. SENDRECEIVE - receive buffer
1703 * 2. UNMARSHAL - unmarshal [out] params from buffer
1706 /* 1. CALCSIZE */
1707 TRACE( "CALCSIZE\n" );
1708 client_do_args(pStubMsg, pFormat, STUBLESS_CALCSIZE, NULL, async_call_data->number_of_params, NULL);
1710 /* 2. GETBUFFER */
1711 TRACE( "GETBUFFER\n" );
1712 if (Oif_flags.HasPipes)
1713 /* NdrGetPipeBuffer(...) */
1714 FIXME("pipes not supported yet\n");
1715 else
1717 if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1718 #if 0
1719 NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1720 #else
1721 FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
1722 #endif
1723 else
1724 NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1726 pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1727 status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
1728 if (status != RPC_S_OK)
1729 RpcRaiseException(status);
1731 /* 3. MARSHAL */
1732 TRACE( "MARSHAL\n" );
1733 client_do_args(pStubMsg, pFormat, STUBLESS_MARSHAL, NULL, async_call_data->number_of_params, NULL);
1735 /* 4. SENDRECEIVE */
1736 TRACE( "SEND\n" );
1737 pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1738 /* send the [in] params only */
1739 if (Oif_flags.HasPipes)
1740 /* NdrPipesSend(...) */
1741 FIXME("pipes not supported yet\n");
1742 else
1744 if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1745 #if 0
1746 NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1747 #else
1748 FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
1749 #endif
1750 else
1752 pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
1753 status = I_RpcSend(pStubMsg->RpcMsg);
1754 if (status != RPC_S_OK)
1755 RpcRaiseException(status);
1760 LONG_PTR CDECL DECLSPEC_HIDDEN ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
1761 void **stack_top )
1763 LONG_PTR ret = 0;
1764 const NDR_PROC_HEADER *pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1766 TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
1768 if (pProcHeader->Oi_flags & Oi_HAS_COMM_OR_FAULT)
1770 __TRY
1772 do_ndr_async_client_call( pStubDesc, pFormat, stack_top );
1774 __EXCEPT_ALL
1776 FIXME("exception %x during ndr_async_client_call()\n", GetExceptionCode());
1777 ret = GetExceptionCode();
1779 __ENDTRY
1781 else
1782 do_ndr_async_client_call( pStubDesc, pFormat, stack_top);
1784 TRACE("returning %ld\n", ret);
1785 return ret;
1788 RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
1790 /* pointer to start of stack where arguments start */
1791 PMIDL_STUB_MESSAGE pStubMsg;
1792 struct async_call_data *async_call_data;
1793 /* header for procedure string */
1794 const NDR_PROC_HEADER * pProcHeader;
1795 RPC_STATUS status = RPC_S_OK;
1797 if (!pAsync->StubInfo)
1798 return RPC_S_INVALID_ASYNC_HANDLE;
1800 async_call_data = pAsync->StubInfo;
1801 pStubMsg = async_call_data->pStubMsg;
1802 pProcHeader = async_call_data->pProcHeader;
1804 /* order of phases:
1805 * 1. CALCSIZE - calculate the buffer size
1806 * 2. GETBUFFER - allocate the buffer
1807 * 3. MARSHAL - marshal [in] params into the buffer
1808 * 4. SENDRECEIVE - send buffer
1809 * Then in NdrpCompleteAsyncClientCall:
1810 * 1. SENDRECEIVE - receive buffer
1811 * 2. UNMARSHAL - unmarshal [out] params from buffer
1814 /* 1. SENDRECEIVE */
1815 TRACE( "RECEIVE\n" );
1816 pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1817 /* receive the [out] params */
1818 if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1819 #if 0
1820 NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1821 #else
1822 FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
1823 #endif
1824 else
1826 status = I_RpcReceive(pStubMsg->RpcMsg);
1827 if (status != RPC_S_OK)
1828 goto cleanup;
1829 pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
1830 pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
1831 pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
1832 pStubMsg->Buffer = pStubMsg->BufferStart;
1835 /* convert strings, floating point values and endianness into our
1836 * preferred format */
1837 #if 0
1838 if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1839 NdrConvert(pStubMsg, pFormat);
1840 #endif
1842 /* 2. UNMARSHAL */
1843 TRACE( "UNMARSHAL\n" );
1844 client_do_args(pStubMsg, async_call_data->pParamFormat, STUBLESS_UNMARSHAL,
1845 NULL, async_call_data->number_of_params, Reply);
1847 cleanup:
1848 if (pStubMsg->fHasNewCorrDesc)
1850 /* free extra correlation package */
1851 NdrCorrelationFree(pStubMsg);
1854 /* free the full pointer translation tables */
1855 if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1856 NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
1858 /* free marshalling buffer */
1859 NdrFreeBuffer(pStubMsg);
1860 client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
1862 I_RpcFree(pStubMsg->StackTop);
1863 I_RpcFree(async_call_data);
1865 TRACE("-- 0x%x\n", status);
1866 return status;
1869 #ifdef __x86_64__
1871 __ASM_GLOBAL_FUNC( NdrAsyncClientCall,
1872 "subq $0x28,%rsp\n\t"
1873 __ASM_SEH(".seh_stackalloc 0x28\n\t")
1874 __ASM_SEH(".seh_endprologue\n\t")
1875 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1876 "movq %r8,0x40(%rsp)\n\t"
1877 "movq %r9,0x48(%rsp)\n\t"
1878 "leaq 0x40(%rsp),%r8\n\t"
1879 "call " __ASM_NAME("ndr_async_client_call") "\n\t"
1880 "addq $0x28,%rsp\n\t"
1881 __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1882 "ret" );
1884 #else /* __x86_64__ */
1886 /***********************************************************************
1887 * NdrAsyncClientCall [RPCRT4.@]
1889 CLIENT_CALL_RETURN WINAPIV NdrAsyncClientCall( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1891 __ms_va_list args;
1892 LONG_PTR ret;
1894 __ms_va_start( args, format );
1895 ret = ndr_async_client_call( desc, format, va_arg( args, void ** ));
1896 __ms_va_end( args );
1897 return *(CLIENT_CALL_RETURN *)&ret;
1900 #endif /* __x86_64__ */
1902 RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
1903 struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
1904 DWORD * pdwStubPhase)
1906 FIXME("unimplemented, expect crash!\n");
1907 return 0;
1910 void RPC_ENTRY NdrAsyncServerCall(PRPC_MESSAGE pRpcMsg)
1912 const MIDL_SERVER_INFO *pServerInfo;
1913 const MIDL_STUB_DESC *pStubDesc;
1914 PFORMAT_STRING pFormat;
1915 /* pointer to start of stack to pass into stub implementation */
1916 unsigned char *args;
1917 /* header for procedure string */
1918 const NDR_PROC_HEADER *pProcHeader;
1919 struct async_call_data *async_call_data;
1920 PRPC_ASYNC_STATE pAsync;
1921 RPC_STATUS status;
1923 TRACE("%p\n", pRpcMsg);
1925 pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1927 pStubDesc = pServerInfo->pStubDesc;
1928 pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1929 pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1931 TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1933 async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1934 if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
1935 async_call_data->pProcHeader = pProcHeader;
1937 async_call_data->pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1938 *(PRPC_MESSAGE)(async_call_data->pStubMsg + 1) = *pRpcMsg;
1940 if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1942 const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1943 async_call_data->stack_size = header_rpc->stack_size;
1944 pFormat += sizeof(NDR_PROC_HEADER_RPC);
1946 else
1948 async_call_data->stack_size = pProcHeader->stack_size;
1949 pFormat += sizeof(NDR_PROC_HEADER);
1952 TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1954 /* binding */
1955 switch (pProcHeader->handle_type)
1957 /* explicit binding: parse additional section */
1958 case 0:
1959 switch (*pFormat) /* handle_type */
1961 case FC_BIND_PRIMITIVE: /* explicit primitive */
1962 pFormat += sizeof(NDR_EHD_PRIMITIVE);
1963 break;
1964 case FC_BIND_GENERIC: /* explicit generic */
1965 pFormat += sizeof(NDR_EHD_GENERIC);
1966 break;
1967 case FC_BIND_CONTEXT: /* explicit context */
1968 pFormat += sizeof(NDR_EHD_CONTEXT);
1969 break;
1970 default:
1971 ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1972 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1974 break;
1975 case FC_BIND_GENERIC: /* implicit generic */
1976 case FC_BIND_PRIMITIVE: /* implicit primitive */
1977 case FC_CALLBACK_HANDLE: /* implicit callback */
1978 case FC_AUTO_HANDLE: /* implicit auto handle */
1979 break;
1980 default:
1981 ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1982 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1985 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1987 ERR("objects not supported\n");
1988 I_RpcFree(async_call_data);
1989 RpcRaiseException(RPC_X_BAD_STUB_DATA);
1992 NdrServerInitializeNew(pRpcMsg, async_call_data->pStubMsg, pStubDesc);
1994 /* create the full pointer translation tables, if requested */
1995 if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1996 async_call_data->pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0, XLAT_SERVER);
1998 /* use alternate memory allocation routines */
1999 if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
2000 #if 0
2001 NdrRpcSsEnableAllocate(&stubMsg);
2002 #else
2003 FIXME("Set RPCSS memory allocation routines\n");
2004 #endif
2006 TRACE("allocating memory for stack of size %x\n", async_call_data->stack_size);
2008 args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, async_call_data->stack_size);
2009 async_call_data->pStubMsg->StackTop = args; /* used by conformance of top-level objects */
2011 pAsync = I_RpcAllocate(sizeof(*pAsync));
2012 if (!pAsync) RpcRaiseException(RPC_X_NO_MEMORY);
2014 status = RpcAsyncInitializeHandle(pAsync, sizeof(*pAsync));
2015 if (status != RPC_S_OK)
2016 RpcRaiseException(status);
2018 pAsync->StubInfo = async_call_data;
2019 TRACE("pAsync %p, pAsync->StubInfo %p, pFormat %p\n", pAsync, pAsync->StubInfo, async_call_data->pHandleFormat);
2021 /* add the implicit pAsync pointer as the first arg to the function */
2022 *(void **)args = pAsync;
2024 if (is_oicf_stubdesc(pStubDesc))
2026 const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
2027 /* cache of Oif_flags from v2 procedure header */
2028 INTERPRETER_OPT_FLAGS Oif_flags;
2029 /* cache of extension flags from NDR_PROC_HEADER_EXTS */
2030 INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
2032 Oif_flags = pOIFHeader->Oi2Flags;
2033 async_call_data->number_of_params = pOIFHeader->number_of_params;
2035 pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
2037 TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
2039 if (Oif_flags.HasExtensions)
2041 const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
2042 ext_flags = pExtensions->Flags2;
2043 pFormat += pExtensions->Size;
2046 if (Oif_flags.HasPipes)
2048 FIXME("pipes not supported yet\n");
2049 RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
2050 /* init pipes package */
2051 /* NdrPipesInitialize(...) */
2053 if (ext_flags.HasNewCorrDesc)
2055 /* initialize extra correlation package */
2056 NdrCorrelationInitialize(async_call_data->pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
2057 if (ext_flags.Unused & 0x2) /* has range on conformance */
2058 async_call_data->pStubMsg->CorrDespIncrement = 12;
2061 else
2063 pFormat = convert_old_args( async_call_data->pStubMsg, pFormat, async_call_data->stack_size,
2064 pProcHeader->Oi_flags & Oi_OBJECT_PROC,
2065 /* reuse the correlation cache, it's not needed for v1 format */
2066 async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), &async_call_data->number_of_params );
2069 /* convert strings, floating point values and endianness into our
2070 * preferred format */
2071 if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
2072 NdrConvert(async_call_data->pStubMsg, pFormat);
2074 async_call_data->pHandleFormat = pFormat;
2076 /* 1. UNMARSHAL */
2077 TRACE("UNMARSHAL\n");
2078 stub_do_args(async_call_data->pStubMsg, pFormat, STUBLESS_UNMARSHAL, async_call_data->number_of_params);
2080 /* 2. INITOUT */
2081 TRACE("INITOUT\n");
2082 async_call_data->retval_ptr = stub_do_args(async_call_data->pStubMsg, pFormat, STUBLESS_INITOUT, async_call_data->number_of_params);
2084 /* 3. CALLSERVER */
2085 TRACE("CALLSERVER\n");
2086 if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
2087 pServerInfo->ThunkTable[pRpcMsg->ProcNum](async_call_data->pStubMsg);
2088 else
2089 call_server_func(pServerInfo->DispatchTable[pRpcMsg->ProcNum], args, async_call_data->stack_size);
2092 RPC_STATUS NdrpCompleteAsyncServerCall(RPC_ASYNC_STATE *pAsync, void *Reply)
2094 /* pointer to start of stack where arguments start */
2095 PMIDL_STUB_MESSAGE pStubMsg;
2096 struct async_call_data *async_call_data;
2097 /* the type of pass we are currently doing */
2098 enum stubless_phase phase;
2099 RPC_STATUS status = RPC_S_OK;
2101 if (!pAsync->StubInfo)
2102 return RPC_S_INVALID_ASYNC_HANDLE;
2104 async_call_data = pAsync->StubInfo;
2105 pStubMsg = async_call_data->pStubMsg;
2107 TRACE("pAsync %p, pAsync->StubInfo %p, pFormat %p\n", pAsync, pAsync->StubInfo, async_call_data->pHandleFormat);
2109 if (async_call_data->retval_ptr)
2111 TRACE("stub implementation returned 0x%lx\n", *(LONG_PTR *)Reply);
2112 *async_call_data->retval_ptr = *(LONG_PTR *)Reply;
2114 else
2115 TRACE("void stub implementation\n");
2117 for (phase = STUBLESS_CALCSIZE; phase <= STUBLESS_FREE; phase++)
2119 TRACE("phase = %d\n", phase);
2120 switch (phase)
2122 case STUBLESS_GETBUFFER:
2123 if (async_call_data->pProcHeader->Oi_flags & Oi_OBJECT_PROC)
2125 ERR("objects not supported\n");
2126 HeapFree(GetProcessHeap(), 0, async_call_data->pStubMsg->StackTop);
2127 I_RpcFree(async_call_data);
2128 I_RpcFree(pAsync);
2129 RpcRaiseException(RPC_X_BAD_STUB_DATA);
2131 else
2133 pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength;
2134 /* allocate buffer for [out] and [ret] params */
2135 status = I_RpcGetBuffer(pStubMsg->RpcMsg);
2136 if (status)
2137 RpcRaiseException(status);
2138 pStubMsg->Buffer = pStubMsg->RpcMsg->Buffer;
2140 break;
2142 case STUBLESS_CALCSIZE:
2143 case STUBLESS_MARSHAL:
2144 case STUBLESS_MUSTFREE:
2145 case STUBLESS_FREE:
2146 stub_do_args(pStubMsg, async_call_data->pHandleFormat, phase, async_call_data->number_of_params);
2147 break;
2148 default:
2149 ERR("shouldn't reach here. phase %d\n", phase);
2150 break;
2154 #if 0 /* FIXME */
2155 if (ext_flags.HasNewCorrDesc)
2157 /* free extra correlation package */
2158 NdrCorrelationFree(pStubMsg);
2161 if (Oif_flags.HasPipes)
2163 /* NdrPipesDone(...) */
2166 /* free the full pointer translation tables */
2167 if (async_call_data->pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
2168 NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
2169 #endif
2171 /* free server function stack */
2172 HeapFree(GetProcessHeap(), 0, async_call_data->pStubMsg->StackTop);
2173 I_RpcFree(async_call_data);
2174 I_RpcFree(pAsync);
2176 return S_OK;