/// <summary>
        /// Initialize a RpceStubEncoder.
        /// </summary>
        /// <param name="runtimeTargetPlatform">Runtime platform, x86 or amd64.</param>
        /// <param name="typeFormatString">Type format string generated by MIDL.</param>
        /// <param name="exprEvalRoutines">ExprEvalRoutines generated by MIDL if exists.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when typeFormatString is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when runtimeTargetPlatform doesn't match current platform at runtime.
        /// </exception>
        public RpceStubEncoder(
            RpceStubTargetPlatform runtimeTargetPlatform,
            byte[] typeFormatString,
            RpceStubExprEval[] exprEvalRoutines)
            : base(runtimeTargetPlatform, typeFormatString, exprEvalRoutines)
        {
            int status;
            IntPtr bindingString;

            status = NativeMethods.RpcStringBindingCompose(
                null,
                "ncalrpc",
                null,
                localRpcEndpoint,
                null,
                out bindingString);
            if (status != NativeMethods.RPC_S_OK)
            {
                throw new InvalidOperationException(
                    string.Format("RpcStringBindingCompose failed with error code {0}.", status));
            }

            status = NativeMethods.RpcBindingFromStringBinding(bindingString, out localRpcHandle);
            if (status != NativeMethods.RPC_S_OK)
            {
                throw new InvalidOperationException(
                    string.Format("RpcBindingFromStringBinding failed with error code {0}.", status));
            }

            status = NativeMethods.RpcStringFree(ref bindingString);
            if (status != NativeMethods.RPC_S_OK)
            {
                throw new InvalidOperationException(
                    string.Format("RpcStringFree failed with error code {0}.", status));
            }
        }
        /// <summary>
        /// constructor.
        /// </summary>
        /// <param name="runtimeTargetPlatform">Runtime platform, x86 or amd64.</param>
        /// <param name="typeFormatString">Type format string generated by MIDL.</param>
        /// <param name="exprEvalRoutines">ExprEvalRoutines generated by MIDL if exists.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when typeFormatString is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when runtimeTargetPlatform doesn't match current platform at runtime.
        /// </exception>
        protected RpceStub(
            RpceStubTargetPlatform runtimeTargetPlatform,
            byte[] typeFormatString,
            RpceStubExprEval[] exprEvalRoutines)
        {
            if (typeFormatString == null)
            {
                throw new ArgumentNullException("typeFormatString");
            }
            if ((IntPtr.Size == sizeof(Int32) && (runtimeTargetPlatform & RpceStubTargetPlatform.X86) != RpceStubTargetPlatform.X86) ||
                (IntPtr.Size == sizeof(Int64) && (runtimeTargetPlatform & RpceStubTargetPlatform.Amd64) != RpceStubTargetPlatform.Amd64))
            {
                throw new InvalidOperationException("Invalid target platform.");
            }

            allocatedMemoryList = new List<IntPtr>();

            #region RPC_CLIENT_INTERFACE rpcClientInterface

            NativeMethods.RPC_CLIENT_INTERFACE rpcClientInterface = new NativeMethods.RPC_CLIENT_INTERFACE();
            rpcClientInterface.Length = (uint)Marshal.SizeOf(typeof(NativeMethods.RPC_CLIENT_INTERFACE));

            rpcClientInterface.InterfaceId.SyntaxGUID = RpceStubEncoder.RPCE_BIND_ONLY_SERVER.IF_ID;
            rpcClientInterface.InterfaceId.SyntaxVersion.MajorVersion = RpceStubEncoder.RPCE_BIND_ONLY_SERVER.IF_VERS_MAJOR;
            rpcClientInterface.InterfaceId.SyntaxVersion.MinorVersion = RpceStubEncoder.RPCE_BIND_ONLY_SERVER.IF_VERS_MINOR;

            rpcClientInterface.TransferSyntax.SyntaxGUID = RpceUtility.NDR_INTERFACE_UUID;
            rpcClientInterface.TransferSyntax.SyntaxVersion.MajorVersion = RpceUtility.NDR_INTERFACE_MAJOR_VERSION;
            rpcClientInterface.TransferSyntax.SyntaxVersion.MinorVersion = RpceUtility.NDR_INTERFACE_MINOR_VERSION;

            rpcClientInterface.DispatchTable = IntPtr.Zero;
            rpcClientInterface.RpcProtseqEndpointCount = 0;
            rpcClientInterface.RpcProtseqEndpoint = IntPtr.Zero;
            rpcClientInterface.Reserved = 0;
            rpcClientInterface.InterpreterInfo = IntPtr.Zero;
            rpcClientInterface.Flags = 0x00000000;

            #endregion

            #region MIDL_STUB_DESC stubDesc

            stubDesc = new NativeMethods.MIDL_STUB_DESC();
            stubDesc.RpcInterfaceInformation = Marshal.AllocHGlobal(Marshal.SizeOf(rpcClientInterface));
            Marshal.StructureToPtr(rpcClientInterface, stubDesc.RpcInterfaceInformation, false);

            stubDesc.pfnAllocate = new NativeMethods.PfnAllocate(MIDL_user_allocate);
            stubDesc.pfnFree = new NativeMethods.PfnFree(MIDL_user_free);

            stubDesc.apfnNdrRundownRoutines = IntPtr.Zero;
            stubDesc.aGenericBindingRoutinePairs = IntPtr.Zero;

            if (exprEvalRoutines == null || exprEvalRoutines.Length == 0)
            {
                stubDesc.apfnExprEval = IntPtr.Zero;
            }
            else
            {
                exprEvalList = new List<NativeMethods.EXPR_EVAL>(exprEvalRoutines.Length);
                stubDesc.apfnExprEval = Marshal.AllocHGlobal(IntPtr.Size * exprEvalRoutines.Length);
                for (int i = 0; i < exprEvalRoutines.Length; i++)
                {
                    RpceStubExprEvalCallback callback = new RpceStubExprEvalCallback(this, exprEvalRoutines[i]);
                    NativeMethods.EXPR_EVAL exprEval = new NativeMethods.EXPR_EVAL(callback.EXPR_EVAL);
                    IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(exprEval);
                    Marshal.WriteIntPtr(stubDesc.apfnExprEval, IntPtr.Size * i, funcPtr);

                    //http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getfunctionpointerfordelegate.aspx
                    //Caller must manually keep the delegate from being collected by
                    // the garbage collector from managed code.
                    exprEvalList.Add(exprEval);
                }
            }
            stubDesc.aXmitQuintuple = IntPtr.Zero;

            stubDesc.pFormatTypes = Marshal.AllocHGlobal(typeFormatString.Length);
            Marshal.Copy(typeFormatString, 0, stubDesc.pFormatTypes, typeFormatString.Length);

            stubDesc.fCheckBounds = 0; /* -error bounds_check flag : "midl /error none" */
            stubDesc.Version = 0x50000; /* Ndr library version */
            stubDesc.pMallocFreeStruct = IntPtr.Zero;
            stubDesc.MIDLVersion = 0x70001e6; /* MIDL Version 7.0.486 */
            stubDesc.CommFaultOffsets = IntPtr.Zero;
            stubDesc.aUserMarshalQuadruple = IntPtr.Zero;
            stubDesc.NotifyRoutineTable = IntPtr.Zero;  /* notify & notify_flag routine table */
            stubDesc.mFlags = 0x1; /* MIDL flag */
            stubDesc.CsRoutineTables = IntPtr.Zero; /* cs routines */
            stubDesc.ProxyServerInfo = IntPtr.Zero; /* proxy/server native */
            stubDesc.pExprInfo = IntPtr.Zero; /* Reserved5 */

            #endregion
        }
 /// <summary>
 /// Initialize a RpceStubExprEvalCallback.
 /// </summary>
 /// <param name="stub">RpceStub which contain the EXPR_EVAL.</param>
 /// <param name="exprEvalRoutine">A EXPR_EVAL.</param>
 internal RpceStubExprEvalCallback(RpceStub stub, RpceStubExprEval exprEvalRoutine)
 {
     RpceStub = stub;
     exprEval = exprEvalRoutine;
 }
        /// <summary>
        /// Encode parameter list to byte array in one method call.
        /// </summary>
        /// <param name="runtimeTargetPlatform">Runtime platform, x86 or amd64.</param>
        /// <param name="typeFormatString">Type format string generated by MIDL.</param>
        /// <param name="exprEvalRoutines">ExprEvalRoutines generated by MIDL if exists.</param>
        /// <param name="procFormatString">Proc format string generated by MIDL.</param>
        /// <param name="procFormatStringOffset">Offset of the procedure in procFormatString.</param>
        /// <param name="isClient">Is client side.</param>
        /// <param name="parameters">Parameters.</param>
        /// <returns>The byte array contains encoded parameters.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when typeFormatString is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when runtimeTargetPlatform doesn't match current platform at runtime.
        /// </exception>
        public static byte[] ToBytes(
            RpceStubTargetPlatform runtimeTargetPlatform,
            byte[] typeFormatString,
            RpceStubExprEval[] exprEvalRoutines,
            byte[] procFormatString,
            int procFormatStringOffset,
            bool isClient,
            params Int3264[] parameters)
        {
            using (RpceStubEncoder encoder = new RpceStubEncoder(
                runtimeTargetPlatform,
                typeFormatString,
                exprEvalRoutines))
            {
                encoder.NdrClientInitializeNew();

                encoder.NdrParametersBufferSize(procFormatString, procFormatStringOffset, isClient, parameters);

                encoder.NdrGetBuffer();

                encoder.NdrParametersMarshall(procFormatString, procFormatStringOffset, isClient, parameters);

                return encoder.ToBytes();
            }
        }
 /// <summary>
 /// Initialize a RpceStubExprEvalCallback.
 /// </summary>
 /// <param name="stub">RpceStub which contain the EXPR_EVAL.</param>
 /// <param name="exprEvalRoutine">A EXPR_EVAL.</param>
 internal RpceStubExprEvalCallback(RpceStub stub, RpceStubExprEval exprEvalRoutine)
 {
     RpceStub = stub;
     exprEval = exprEvalRoutine;
 }