Ejemplo n.º 1
0
        private static void EmitOverload(
            CSharpCodeWriter writer,
            OverloadDefinition overload,
            Dictionary <string, string> defaultValues,
            string selfName)
        {
            if (overload.Parameters.Where(tr => tr.Name.EndsWith("_begin") || tr.Name.EndsWith("_end"))
                .Any(tr => !defaultValues.ContainsKey(tr.Name)))
            {
                return;
            }

            Debug.Assert(!overload.IsMemberFunction || selfName != null);

            string nativeRet     = GetTypeString(overload.ReturnType, false);
            bool   isWrappedType = GetWrappedType(nativeRet, out string safeRet);

            if (!isWrappedType)
            {
                safeRet = GetSafeType(overload.ReturnType);
            }

            List <string> invocationArgs = new List <string>();

            MarshalledParameter[] marshalledParameters = new MarshalledParameter[overload.Parameters.Length];
            List <string>         preCallLines         = new List <string>();
            List <string>         postCallLines        = new List <string>();
            List <string>         byRefParams          = new List <string>();

            for (int i = 0; i < overload.Parameters.Length; i++)
            {
                if (i == 0 && selfName != null)
                {
                    continue;
                }

                TypeReference tr = overload.Parameters[i];
                if (tr.Name == "...")
                {
                    continue;
                }

                string correctedIdentifier = CorrectIdentifier(tr.Name);
                string nativeTypeName      = GetTypeString(tr.Type, tr.IsFunctionPointer);

                if (tr.Type == "char*")
                {
                    string textToEncode = correctedIdentifier;
                    bool   hasDefault   = false;
                    if (defaultValues.TryGetValue(tr.Name, out string defaultStrVal))
                    {
                        hasDefault = true;
                        if (!CorrectDefaultValue(defaultStrVal, tr, out string correctedDefault))
                        {
                            correctedDefault = defaultStrVal;
                        }

                        textToEncode = correctedDefault;
                    }

                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("string", false, nativeArgName, hasDefault);

                    if (textToEncode == "null")
                    {
                        preCallLines.Add($"byte* {nativeArgName} = null;");
                    }
                    else
                    {
                        preCallLines.Add($"int {correctedIdentifier}_byteCount = Encoding.UTF8.GetByteCount({textToEncode});");
                        preCallLines.Add($"byte* {nativeArgName} = stackalloc byte[{correctedIdentifier}_byteCount + 1];");
                        preCallLines.Add($"fixed (char* {correctedIdentifier}_ptr = {textToEncode})");
                        preCallLines.Add("{");
                        preCallLines.Add($"    int {nativeArgName}_offset = Encoding.UTF8.GetBytes({correctedIdentifier}_ptr, {textToEncode}.Length, {nativeArgName}, {correctedIdentifier}_byteCount);");
                        preCallLines.Add($"    {nativeArgName}[{nativeArgName}_offset] = 0;");
                        preCallLines.Add("}");
                    }
                }
                else if (tr.Type == "char* []")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("string[]", false, nativeArgName, false);

                    preCallLines.Add($"int* {correctedIdentifier}_byteCounts = stackalloc int[{correctedIdentifier}.Length];");

                    preCallLines.Add($"int {correctedIdentifier}_byteCount = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    string s = {correctedIdentifier}[i];");
                    preCallLines.Add($"    {correctedIdentifier}_byteCounts[i] = Encoding.UTF8.GetByteCount(s);");
                    preCallLines.Add($"    {correctedIdentifier}_byteCount += {correctedIdentifier}_byteCounts[i] + 1;");
                    preCallLines.Add("}");

                    preCallLines.Add($"byte* {nativeArgName}_data = stackalloc byte[{correctedIdentifier}_byteCount];");

                    preCallLines.Add("int offset = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    string s = {correctedIdentifier}[i];");
                    preCallLines.Add($"    fixed (char* sPtr = s)");
                    preCallLines.Add("    {");
                    preCallLines.Add($"        offset += Encoding.UTF8.GetBytes(sPtr, s.Length, {nativeArgName}_data + offset, {correctedIdentifier}_byteCounts[i]);");
                    preCallLines.Add($"        offset += 1;");
                    preCallLines.Add($"        {nativeArgName}_data[offset] = 0;");
                    preCallLines.Add("    }");
                    preCallLines.Add("}");

                    preCallLines.Add($"byte** {nativeArgName} = stackalloc byte*[{correctedIdentifier}.Length];");
                    preCallLines.Add("offset = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    {nativeArgName}[i] = &{nativeArgName}_data[offset];");
                    preCallLines.Add($"    offset += {correctedIdentifier}_byteCounts[i] + 1;");
                    preCallLines.Add("}");
                }
                else if (defaultValues.TryGetValue(tr.Name, out string defaultVal))
                {
                    if (!CorrectDefaultValue(defaultVal, tr, out string correctedDefault))
                    {
                        correctedDefault = defaultVal;
                    }
                    marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, true);
                    preCallLines.Add($"{nativeTypeName} {correctedIdentifier} = {correctedDefault};");
                }
                else if (tr.Type == "bool")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("bool", false, nativeArgName, false);
                    preCallLines.Add($"byte {nativeArgName} = {tr.Name} ? (byte)1 : (byte)0;");
                }
                else if (tr.Type == "bool*")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("ref bool", false, nativeArgName, false);
                    preCallLines.Add($"byte {nativeArgName}_val = {correctedIdentifier} ? (byte)1 : (byte)0;");
                    preCallLines.Add($"byte* {nativeArgName} = &{nativeArgName}_val;");
                    postCallLines.Add($"{correctedIdentifier} = {nativeArgName}_val != 0;");
                }
                else if (tr.Type == "void*")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("IntPtr", false, nativeArgName, false);
                    preCallLines.Add($"void* {nativeArgName} = {correctedIdentifier}.ToPointer();");
                }
                else if (GetWrappedType(tr.Type, out string wrappedParamType) &&
                         !s_wellKnownTypes.ContainsKey(tr.Type) &&
                         !s_wellKnownTypes.ContainsKey(tr.Type.Substring(0, tr.Type.Length - 1)))
                {
                    marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, "native_" + tr.Name, false);
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, nativeArgName, false);
                    preCallLines.Add($"{tr.Type} {nativeArgName} = {correctedIdentifier}.NativePtr;");
                }
                else if ((tr.Type.EndsWith("*") || tr.Type.Contains("[") || tr.Type.EndsWith("&")) && tr.Type != "void*" && tr.Type != "ImGuiContext*")
                {
                    string nonPtrType;
                    if (tr.Type.Contains("["))
                    {
                        string wellKnown = s_wellKnownTypes[tr.Type];
                        nonPtrType = GetTypeString(wellKnown.Substring(0, wellKnown.Length - 1), false);
                    }
                    else
                    {
                        nonPtrType = GetTypeString(tr.Type.Substring(0, tr.Type.Length - 1), false);
                    }
                    string nativeArgName = "native_" + tr.Name;
                    bool   isOutParam    = tr.Name.Contains("out_");
                    string direction     = isOutParam ? "out" : "ref";
                    marshalledParameters[i]           = new MarshalledParameter($"{direction} {nonPtrType}", true, nativeArgName, false);
                    marshalledParameters[i].PinTarget = CorrectIdentifier(tr.Name);
                }
                else
                {
                    marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, false);
                }

                if (!marshalledParameters[i].HasDefaultValue)
                {
                    invocationArgs.Add($"{marshalledParameters[i].MarshalledType} {correctedIdentifier}");
                }
            }

            string invocationList = string.Join(", ", invocationArgs);
            string friendlyName   = overload.FriendlyName;

            string staticPortion = selfName == null ? "static " : string.Empty;

            writer.PushBlock($"public {staticPortion}{safeRet} {friendlyName}({invocationList})");
            foreach (string line in preCallLines)
            {
                writer.WriteLine(line);
            }

            List <string> nativeInvocationArgs = new List <string>();

            if (selfName != null)
            {
                nativeInvocationArgs.Add(selfName);
            }

            for (int i = 0; i < marshalledParameters.Length; i++)
            {
                TypeReference       tr = overload.Parameters[i];
                MarshalledParameter mp = marshalledParameters[i];
                if (mp == null)
                {
                    continue;
                }
                if (mp.IsPinned)
                {
                    string nativePinType = GetTypeString(tr.Type, false);
                    writer.PushBlock($"fixed ({nativePinType} native_{tr.Name} = &{mp.PinTarget})");
                }

                nativeInvocationArgs.Add(mp.VarName);
            }

            string nativeInvocationStr = string.Join(", ", nativeInvocationArgs);
            string ret = safeRet == "void" ? string.Empty : $"{nativeRet} ret = ";

            string targetName = overload.ExportedName;

            if (targetName.Contains("nonUDT"))
            {
                targetName = targetName.Substring(0, targetName.IndexOf("_nonUDT"));
            }

            writer.WriteLine($"{ret}ImGuiNative.{targetName}({nativeInvocationStr});");

            foreach (string line in postCallLines)
            {
                writer.WriteLine(line);
            }

            if (safeRet != "void")
            {
                if (safeRet == "bool")
                {
                    writer.WriteLine("return ret != 0;");
                }
                else if (overload.ReturnType == "char*")
                {
                    writer.WriteLine("return Util.StringFromPtr(ret);");
                }
                else if (overload.ReturnType == "void*")
                {
                    writer.WriteLine("return (IntPtr)ret;");
                }
                else
                {
                    string retVal = isWrappedType ? $"new {safeRet}(ret)" : "ret";
                    writer.WriteLine($"return {retVal};");
                }
            }

            for (int i = 0; i < marshalledParameters.Length; i++)
            {
                MarshalledParameter mp = marshalledParameters[i];
                if (mp == null)
                {
                    continue;
                }
                if (mp.IsPinned)
                {
                    writer.PopBlock();
                }
            }

            writer.PopBlock();
        }
Ejemplo n.º 2
0
        private static void EmitOverload(
            CSharpCodeWriter writer,
            OverloadDefinition overload,
            Dictionary <string, string> defaultValues,
            string selfName,
            string classPrefix,
            int primitiveOverloadIndex       = -1,
            string primitiveOverloadEnumName = null)
        {
            if (overload.Parameters.Where(tr => tr.Name.EndsWith("_begin") || tr.Name.EndsWith("_end"))
                .Any(tr => !defaultValues.ContainsKey(tr.Name)))
            {
                return;
            }

            Debug.Assert(!overload.IsMemberFunction || selfName != null);

            string nativeRet     = GetTypeString(overload.ReturnType, false);
            bool   isWrappedType = GetWrappedType(nativeRet, out string safeRet);

            if (!isWrappedType)
            {
                safeRet = GetSafeType(overload.ReturnType);
            }

            List <string> invocationArgs = new List <string>();

            MarshalledParameter[] marshalledParameters = new MarshalledParameter[overload.Parameters.Length];
            List <string>         preCallLines         = new List <string>();
            List <string>         postCallLines        = new List <string>();
            List <string>         byRefParams          = new List <string>();
            int    selfIndex   = -1;
            int    pOutIndex   = -1;
            string overrideRet = null;

            for (int i = 0; i < overload.Parameters.Length; i++)
            {
                TypeReference tr = overload.Parameters[i];
                if (tr.Name == "self")
                {
                    selfIndex = i;
                    continue;
                }
                if (tr.Name == "...")
                {
                    continue;
                }

                string correctedIdentifier = CorrectIdentifier(tr.Name);
                string nativeTypeName      = GetTypeString(tr.Type, tr.IsFunctionPointer);
                if (correctedIdentifier == "pOut" && overload.ReturnType == "void")
                {
                    pOutIndex   = i;
                    overrideRet = nativeTypeName.TrimEnd('*');
                    preCallLines.Add($"{overrideRet} __retval;");
                    continue;
                }
                if (tr.Type == "char*")
                {
                    string textToEncode = correctedIdentifier;
                    bool   hasDefault   = false;
                    if (defaultValues.TryGetValue(tr.Name, out string defaultStrVal))
                    {
                        hasDefault = true;
                        if (!CorrectDefaultValue(defaultStrVal, tr, out string correctedDefault))
                        {
                            correctedDefault = defaultStrVal;
                        }

                        textToEncode = correctedDefault;
                    }

                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("string", false, nativeArgName, hasDefault);

                    if (textToEncode == "null")
                    {
                        preCallLines.Add($"byte* {nativeArgName} = null;");
                    }
                    else
                    {
                        preCallLines.Add($"byte* {nativeArgName};");
                        preCallLines.Add($"int {correctedIdentifier}_byteCount = 0;");
                        if (!hasDefault)
                        {
                            preCallLines.Add($"if ({textToEncode} != null)");
                            preCallLines.Add("{");
                        }
                        preCallLines.Add($"    {correctedIdentifier}_byteCount = Encoding.UTF8.GetByteCount({textToEncode});");
                        preCallLines.Add($"    if ({correctedIdentifier}_byteCount > Util.StackAllocationSizeLimit)");
                        preCallLines.Add($"    {{");
                        preCallLines.Add($"        {nativeArgName} = Util.Allocate({correctedIdentifier}_byteCount + 1);");
                        preCallLines.Add($"    }}");
                        preCallLines.Add($"    else");
                        preCallLines.Add($"    {{");
                        preCallLines.Add($"        byte* {nativeArgName}_stackBytes = stackalloc byte[{correctedIdentifier}_byteCount + 1];");
                        preCallLines.Add($"        {nativeArgName} = {nativeArgName}_stackBytes;");
                        preCallLines.Add($"    }}");
                        preCallLines.Add($"    int {nativeArgName}_offset = Util.GetUtf8({textToEncode}, {nativeArgName}, {correctedIdentifier}_byteCount);");
                        preCallLines.Add($"    {nativeArgName}[{nativeArgName}_offset] = 0;");

                        if (!hasDefault)
                        {
                            preCallLines.Add("}");
                            preCallLines.Add($"else {{ {nativeArgName} = null; }}");
                        }

                        postCallLines.Add($"if ({correctedIdentifier}_byteCount > Util.StackAllocationSizeLimit)");
                        postCallLines.Add($"{{");
                        postCallLines.Add($"    Util.Free({nativeArgName});");
                        postCallLines.Add($"}}");
                    }
                }
                else if (defaultValues.TryGetValue(tr.Name, out string defaultVal))
                {
                    if (!CorrectDefaultValue(defaultVal, tr, out string correctedDefault))
                    {
                        correctedDefault = defaultVal;
                    }
                    marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, true);
                    preCallLines.Add($"{nativeTypeName} {correctedIdentifier} = {correctedDefault};");
                }
                else if (tr.Type == "char* []")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("string[]", false, nativeArgName, false);

                    preCallLines.Add($"int* {correctedIdentifier}_byteCounts = stackalloc int[{correctedIdentifier}.Length];");

                    preCallLines.Add($"int {correctedIdentifier}_byteCount = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    string s = {correctedIdentifier}[i];");
                    preCallLines.Add($"    {correctedIdentifier}_byteCounts[i] = Encoding.UTF8.GetByteCount(s);");
                    preCallLines.Add($"    {correctedIdentifier}_byteCount += {correctedIdentifier}_byteCounts[i] + 1;");
                    preCallLines.Add("}");

                    preCallLines.Add($"byte* {nativeArgName}_data = stackalloc byte[{correctedIdentifier}_byteCount];");

                    preCallLines.Add("int offset = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    string s = {correctedIdentifier}[i];");
                    preCallLines.Add($"    fixed (char* sPtr = s)");
                    preCallLines.Add("    {");
                    preCallLines.Add($"        offset += Encoding.UTF8.GetBytes(sPtr, s.Length, {nativeArgName}_data + offset, {correctedIdentifier}_byteCounts[i]);");
                    preCallLines.Add($"        {nativeArgName}_data[offset] = 0;");
                    preCallLines.Add($"        offset += 1;");
                    preCallLines.Add("    }");
                    preCallLines.Add("}");

                    preCallLines.Add($"byte** {nativeArgName} = stackalloc byte*[{correctedIdentifier}.Length];");
                    preCallLines.Add("offset = 0;");
                    preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
                    preCallLines.Add("{");
                    preCallLines.Add($"    {nativeArgName}[i] = &{nativeArgName}_data[offset];");
                    preCallLines.Add($"    offset += {correctedIdentifier}_byteCounts[i] + 1;");
                    preCallLines.Add("}");
                }
                else if (tr.Type == "bool")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("bool", false, nativeArgName, false);
                    preCallLines.Add($"byte {nativeArgName} = {tr.Name} ? (byte)1 : (byte)0;");
                }
                else if (tr.Type == "bool*")
                {
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("ref bool", false, nativeArgName, false);
                    preCallLines.Add($"byte {nativeArgName}_val = {correctedIdentifier} ? (byte)1 : (byte)0;");
                    preCallLines.Add($"byte* {nativeArgName} = &{nativeArgName}_val;");
                    postCallLines.Add($"{correctedIdentifier} = {nativeArgName}_val != 0;");
                }
                else if (tr.Type == "void*" || tr.Type == "ImWchar*")
                {
                    string nativePtrTypeName = tr.Type == "void*" ? "void*" : "ushort*";
                    string nativeArgName     = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter("IntPtr", false, nativeArgName, false);
                    preCallLines.Add($"{nativePtrTypeName} {nativeArgName} = ({nativePtrTypeName}){correctedIdentifier}.ToPointer();");
                }
                else if (GetWrappedType(tr.Type, out string wrappedParamType) &&
                         !TypeInfo.WellKnownTypes.ContainsKey(tr.Type) &&
                         !TypeInfo.WellKnownTypes.ContainsKey(tr.Type.Substring(0, tr.Type.Length - 1)))
                {
                    marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, "native_" + tr.Name, false);
                    string nativeArgName = "native_" + tr.Name;
                    marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, nativeArgName, false);
                    preCallLines.Add($"{tr.Type} {nativeArgName} = {correctedIdentifier}.NativePtr;");
                }
                else if ((tr.Type.EndsWith("*") || tr.Type.Contains("[") || tr.Type.EndsWith("&")) && tr.Type != "void*" && tr.Type != "ImGuiContext*" && tr.Type != "ImPlotContext*" && tr.Type != "EditorContext*")
                {
                    string nonPtrType;
                    if (tr.Type.Contains("["))
                    {
                        string wellKnown = TypeInfo.WellKnownTypes[tr.Type];
                        nonPtrType = GetTypeString(wellKnown.Substring(0, wellKnown.Length - 1), false);
                    }
                    else
                    {
                        nonPtrType = GetTypeString(tr.Type.Substring(0, tr.Type.Length - 1), false);
                    }
                    string nativeArgName = "native_" + tr.Name;
                    bool   isOutParam    = tr.Name.Contains("out_") || tr.Name == "out";
                    string direction     = isOutParam ? "out" : "ref";
                    marshalledParameters[i]           = new MarshalledParameter($"{direction} {nonPtrType}", true, nativeArgName, false);
                    marshalledParameters[i].PinTarget = CorrectIdentifier(tr.Name);
                }
                else
                {
                    marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, false);
                }

                if (!marshalledParameters[i].HasDefaultValue)
                {
                    invocationArgs.Add($"{marshalledParameters[i].MarshalledType} {correctedIdentifier}");
                }
            }

            string invocationList = string.Join(", ", invocationArgs);
            string friendlyName   = overload.FriendlyName;

            // If we have a primitive overload, we want to notify callers that they should be using the enum-based signatures instead
            if (primitiveOverloadIndex != -1)
            {
                writer.WriteLine("[Obsolete(\"Use method with non-primitive (enum) arguments instead.\")]");
            }

            string staticPortion = selfName == null ? "static " : string.Empty;

            writer.PushBlock($"public {staticPortion}{overrideRet ?? safeRet} {friendlyName}({invocationList})");
            foreach (string line in preCallLines)
            {
                writer.WriteLine(line);
            }

            List <string> nativeInvocationArgs = new List <string>();

            for (int i = 0; i < marshalledParameters.Length; i++)
            {
                TypeReference tr = overload.Parameters[i];
                if (selfIndex == i)
                {
                    //Some overloads seem to be generated with IntPtr as self
                    //instead of the proper pointer type. TODO: investigate
                    string tstr = GetTypeString(tr.Type, false);
                    nativeInvocationArgs.Add($"({tstr})({selfName})");
                    continue;
                }
                if (pOutIndex == i)
                {
                    nativeInvocationArgs.Add("&__retval");
                    continue;
                }
                MarshalledParameter mp = marshalledParameters[i];
                if (mp == null)
                {
                    continue;
                }
                if (mp.IsPinned)
                {
                    string nativePinType = GetTypeString(tr.Type, false);
                    writer.PushBlock($"fixed ({nativePinType} native_{tr.Name} = &{mp.PinTarget})");
                }

                var argString = mp.VarName;
                if (i == primitiveOverloadIndex)
                {
                    argString = $"({primitiveOverloadEnumName}){mp.VarName}";
                }
                nativeInvocationArgs.Add(argString);
            }

            string nativeInvocationStr = string.Join(", ", nativeInvocationArgs);
            string ret = safeRet == "void" ? string.Empty : $"{nativeRet} ret = ";

            string targetName = overload.ExportedName;

            if (targetName.Contains("nonUDT"))
            {
                targetName = targetName.Substring(0, targetName.IndexOf("_nonUDT"));
            }

            writer.WriteLine($"{ret}{classPrefix}Native.{targetName}({nativeInvocationStr});");

            foreach (string line in postCallLines)
            {
                writer.WriteLine(line);
            }

            if (safeRet != "void")
            {
                if (safeRet == "bool")
                {
                    writer.WriteLine("return ret != 0;");
                }
                else if (overload.ReturnType == "char*")
                {
                    writer.WriteLine("return Util.StringFromPtr(ret);");
                }
                else if (overload.ReturnType == "ImWchar*")
                {
                    writer.WriteLine("return (IntPtr)ret;");
                }
                else if (overload.ReturnType == "void*")
                {
                    writer.WriteLine("return (IntPtr)ret;");
                }
                else
                {
                    string retVal = isWrappedType ? $"new {safeRet}(ret)" : "ret";
                    writer.WriteLine($"return {retVal};");
                }
            }

            if (overrideRet != null)
            {
                writer.WriteLine("return __retval;");
            }

            for (int i = 0; i < marshalledParameters.Length; i++)
            {
                MarshalledParameter mp = marshalledParameters[i];
                if (mp == null)
                {
                    continue;
                }
                if (mp.IsPinned)
                {
                    writer.PopBlock();
                }
            }

            writer.PopBlock();
        }