private void WriteMethodDeclaration(ManagedMethod method, int numParameters, int level, int overloadIndex) { var nativeMethod = method.Native; EnsureWhiteSpace(WriteTo.CS); WriteTo cs; WriteTo dllImport = WriteTo.Buffer; if (method.Property != null) { // Do not write accessor methods of C# properties here cs = WriteTo.None; // Cached properties that are initialized only once // do not need a DllImport for the get method if (method.Parent.CachedProperties.ContainsKey(method.Property.Name) && method.Equals(method.Property.Getter)) { dllImport = WriteTo.None; } } else if (method.Name.Equals("delete")) { WriteDeleteMethodCS(method, level); cs = WriteTo.None; } else { Write(level + 1, "public ", WriteTo.CS); cs = WriteTo.CS; } // DllImport clause WriteLine(level + 1, "[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]", dllImport); if (nativeMethod.ReturnType != null && nativeMethod.ReturnType.Kind == TypeKind.Bool) { WriteLine(level + 1, "[return: MarshalAs(UnmanagedType.I1)]", dllImport); } Write(level + 1, "static extern ", dllImport); // Return type if (nativeMethod.IsConstructor) { Write("IntPtr ", dllImport); } else { var returnType = nativeMethod.ReturnType.Canonical; if (nativeMethod.IsStatic) Write("static ", cs); Write($"{GetTypeNameCS(returnType)} ", cs); if (method.OutValueParameter != null) { Write("void ", dllImport); } else { if (returnType.IsBasic) { Write(GetTypeNameCS(returnType), dllImport); } else if (returnType.Referenced != null) { if (returnType.Kind == TypeKind.LValueReference && returnType.Referenced.IsConst && returnType.Referenced.Canonical.IsBasic) { Write(GetTypeNameCS(returnType.Referenced.Canonical), dllImport); } else { Write("IntPtr", dllImport); } } else { // Return structures to an additional out parameter, not immediately Write("void", dllImport); } Write(' ', dllImport); } } // Name string methodName = nativeMethod.IsConstructor ? "new" : method.Native.Name; if (overloadIndex != 0) { methodName += (overloadIndex + 1).ToString(); } Write($"{GetFullNameC(method.Parent.Native)}_{methodName}(", dllImport); Write($"{method.Name}(", cs); // Parameters var parameters = method.Parameters.Take(numParameters); var parametersCs = parameters.Select(p => $"{GetParameterTypeNameCS(p.Native)} {p.Name}"); WriteLine($"{ListToLines(parametersCs, WriteTo.CS, level + 1)})", cs); if (method.OutValueParameter != null) parameters = parameters.Concat(new[] { method.OutValueParameter }); var parametersDllImport = parameters.Select(p => $"{GetParameterTypeNameDllImport(p.Native)} {p.Native.Name}"); // The first parameter is the instance pointer (if not constructor or static method) if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic) { parametersDllImport = new[] { "IntPtr obj" }.Concat(parametersDllImport); } WriteLine($"{string.Join(", ", parametersDllImport)});", dllImport); }
private void WriteMethod(ManagedMethod method, int level, int numOptionalParams = 0) { var nativeMethod = method.Native; var parentClass = method.Parent; // No whitespace between get/set methods if (!(method.Property != null && method.Equals(method.Property.Setter))) { EnsureSourceWhiteSpace(); hasHeaderWhiteSpace = false; } // #ifndef DISABLE_FEATURE bool hasConditional = false; if (method.Property == null) { foreach (var param in method.Parameters) { string typeConditional = GetTypeConditional(param.Native.Type, parentClass.Header); if (typeConditional != null) { WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source); hasSourceWhiteSpace = true; hasConditional = true; } } } WriteMethodDeclaration(method, level, numOptionalParams); var prevTo = To; To = WriteTo.Source; // Constructor chaining int numParameters = method.Parameters.Length - numOptionalParams; // Getters with parameter for return value if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter)) { numParameters = 0; } var currentParams = method.Parameters.Take(numParameters).ToList(); bool doConstructorChaining = false; if (nativeMethod.IsConstructor && parentClass.BaseClass != null) { // If there is no need for marshalling code, we can chain constructors doConstructorChaining = currentParams.All(p => !DefaultParser.TypeRequiresMarshal(p.Native.Type)); Write(1, $": {parentClass.BaseClass.Name}("); if (doConstructorChaining) { Write("new "); WriteMethodMarshal(method, numParameters); if (parentClass.BaseClass.Native.HasPreventDelete) { Write(", false"); } } else { Write('0'); } WriteLine(')'); } // Method body WriteLine('{'); if (!doConstructorChaining) { WriteMethodDefinition(method, numParameters); } // Cache property values if (nativeMethod.IsConstructor) { var assignments = new List<string>(); var methodParent = method.Parent; while (methodParent != null) { foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key)) { foreach (var param in currentParams) { if (!param.Name.ToLower().Equals(cachedProperty.Key.ToLower())) continue; var paramType = GetName(param.Native.Type); var propType = GetName(cachedProperty.Value.Property.Type); if (!paramType.Equals(propType)) return; string assignment = $"\t{cachedProperty.Value.CacheFieldName} = {param.Name};"; assignments.Add(assignment); } } methodParent = methodParent.BaseClass; } if (assignments.Count != 0) { EnsureSourceWhiteSpace(); foreach (string assignment in assignments) { WriteLine(assignment); } hasSourceWhiteSpace = false; } } WriteLine('}'); hasSourceWhiteSpace = false; // #endif // DISABLE_FEATURE if (hasConditional) { foreach (var param in currentParams) { string typeConditional = GetTypeConditional(param.Native.Type, method.Parent.Header); if (typeConditional != null) { WriteLine("#endif", WriteTo.Header | WriteTo.Source); hasHeaderWhiteSpace = true; } } } // If there are optional parameters, then output all possible combinations of calls if (currentParams.Any() && currentParams.Last().Native.IsOptional) { WriteMethod(method, level, numOptionalParams + 1); } To = prevTo; }
private void WriteMethodDeclaration(ManagedMethod method, int numParameters, int level, int overloadIndex, ManagedParameter outValueParameter = null) { var nativeMethod = method.Native; EnsureWhiteSpace(WriteTo.CS); WriteTo cs; WriteTo dllImport = WriteTo.Buffer; if (method.Property != null) { // Do not write accessor methods of C# properties here cs = WriteTo.None; // Cached properties that are initialized only once // do not need a DllImport for the get method if (method.Parent.CachedProperties.ContainsKey(method.Property.Name) && method.Equals(method.Property.Getter)) { dllImport = WriteTo.None; } } else if (method.Name.Equals("delete")) { WriteDeleteMethodCS(method, level); cs = WriteTo.None; } else { Write(level + 1, "public ", WriteTo.CS); cs = WriteTo.CS; } // DllImport clause WriteLine(level + 1, "[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]", dllImport); if (nativeMethod.ReturnType != null && nativeMethod.ReturnType.Kind == TypeKind.Bool) { WriteLine(level + 1, "[return: MarshalAs(UnmanagedType.I1)]", dllImport); } Write(level + 1, "static extern ", dllImport); // Return type if (nativeMethod.IsConstructor) { Write("IntPtr ", dllImport); } else { var returnType = nativeMethod.ReturnType.Canonical; if (nativeMethod.IsStatic) { Write("static ", cs); } Write($"{GetTypeNameCS(returnType)} ", cs); if (outValueParameter != null) { Write("void ", dllImport); } else { if (returnType.IsBasic) { Write(GetTypeNameCS(returnType), dllImport); } else if (returnType.Referenced != null) { if (returnType.Kind == TypeKind.LValueReference && returnType.Referenced.IsConst && returnType.Referenced.Canonical.IsBasic) { Write(GetTypeNameCS(returnType.Referenced.Canonical), dllImport); } else { Write("IntPtr", dllImport); } } else { // Return structures to an additional out parameter, not immediately Write("void", dllImport); } Write(' ', dllImport); } } // Name string methodName = nativeMethod.IsConstructor ? "new" : method.Native.Name; if (overloadIndex != 0) { methodName += (overloadIndex + 1).ToString(); } Write($"{GetFullNameC(method.Parent.Native)}_{methodName}(", dllImport); Write($"{method.Name}(", cs); // Parameters var parameters = method.Parameters.Take(numParameters); var parametersCs = parameters.Select(p => $"{GetParameterTypeNameCS(p.Native)} {p.Name}"); WriteLine($"{ListToLines(parametersCs, WriteTo.CS, level + 1)})", cs); if (outValueParameter != null) { parameters = parameters.Concat(new[] { outValueParameter }); } var parametersDllImport = parameters.Select(p => $"{GetParameterTypeNameDllImport(p.Native)} {p.Native.Name}"); // The first parameter is the instance pointer (if not constructor or static method) if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic) { parametersDllImport = new[] { "IntPtr obj" }.Concat(parametersDllImport); } WriteLine($"{string.Join(", ", parametersDllImport)});", dllImport); }
private void WriteMethodDeclaration(ManagedMethod method, int level, int numOptionalParams) { var nativeMethod = method.Native; WriteTabs(level + 1, WriteTo.Header); if (nativeMethod.IsStatic) Write("static ", WriteTo.Header); // Return type if (!nativeMethod.IsConstructor) { var returnType = nativeMethod.ReturnType; if (method.Property != null) { if (method.Equals(method.Property.Getter)) { // If property name matches type name, resolve ambiguity if (method.Property.Name.Equals(GetName(method.Property.Type))) { Write(Project.NamespaceName + "::", WriteTo.Header); } // Getter with parameter for return value if (method.Parameters.Length == 1) { returnType = method.Parameters[0].Native.Type; } } } Write($"{GetTypeName(returnType)} ", WriteTo.Header | WriteTo.Source); } // Name string headerMethodName; string sourceMethodName; if (nativeMethod.IsConstructor) { headerMethodName = method.Parent.Name; sourceMethodName = headerMethodName; } else if (method.Property != null) { headerMethodName = method.Property.Getter.Equals(method) ? "get" : "set"; sourceMethodName = $"{method.Property.Name}::{headerMethodName}"; } else { headerMethodName = method.Name; sourceMethodName = headerMethodName; } Write($"{headerMethodName}(", WriteTo.Header); Write($"{GetFullNameManaged(method.Parent)}::{sourceMethodName}(", WriteTo.Source); // Parameters int numParameters = method.Parameters.Length - numOptionalParams; // Getters with parameter for return value if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter)) { numParameters = 0; } var currentParams = method.Parameters.Take(numParameters).ToList(); var paramStrings = currentParams .Select(p => $"{GetParameterMarshal(p.Native)} {p.Name}").ToList(); string parameters = ListToLines(paramStrings, WriteTo.Header, level + 1); WriteLine($"{parameters});", WriteTo.Header); parameters = ListToLines(paramStrings, WriteTo.Source); WriteLine($"{parameters})", WriteTo.Source); }
void WriteMethodDefinition(ManagedMethod method, int numParameters) { var nativeMethod = method.Native; var parentClass = method.Parent.Native; // Type marshalling prologue bool needTypeMarshalEpilogue = false; if (nativeMethod.Field == null) { foreach (var param in method.Parameters) { string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param); if (!string.IsNullOrEmpty(prologue)) { WriteLine(1, prologue); } // Do we need a type marshalling epilogue? if (!needTypeMarshalEpilogue) { string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param); if (!string.IsNullOrEmpty(epilogue)) { needTypeMarshalEpilogue = true; } } } } WriteTabs(1); if (nativeMethod.IsConstructor) { Write("_native = new "); } else if (!nativeMethod.IsVoid) { //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null) if (needTypeMarshalEpilogue) { // Return after epilogue (cleanup) Write($"{GetTypeName(nativeMethod.ReturnType)} ret = "); } else { // Return immediately Write("return "); } Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod)); } else if (method.Property != null && method.Equals(method.Property.Getter)) { Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod)); } // Native is defined as static_cast<className*>(_native) string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native"; if (nativeMethod.Field != null) { var property = method.Property; if (method.Equals(property.Getter)) { CachedProperty cachedProperty; if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty)) { Write(cachedProperty.CacheFieldName); } else { Write($"{nativePointer}->{nativeMethod.Field.Name}"); } } else if (property.Setter != null && method.Equals(property.Setter)) { var param = method.Parameters[0]; var paramType = param.Native.Type; var fieldSet = BulletParser.GetTypeMarshalFieldSetCppCli(nativeMethod.Field, param, nativePointer); if (!string.IsNullOrEmpty(fieldSet)) { Write(fieldSet); } else { Write($"{nativePointer}->{nativeMethod.Field.Name} = "); switch (paramType.Kind) { case TypeKind.Pointer: case TypeKind.LValueReference: if (paramType.Kind == TypeKind.LValueReference) { // Dereference Write('*'); } if (paramType.Referenced.Target != null && paramType.Referenced.Target.BaseClass != null) { // Cast native pointer from base class Write($"({paramType.Referenced.FullName}*)"); } break; } Write(param.Name); if (!paramType.IsBasic) { Write("->_native"); } } } } else { if (nativeMethod.IsConstructor) { } else if (nativeMethod.IsStatic) { Write(parentClass.FullyQualifiedName + "::"); } else { Write(nativePointer + "->"); } To = WriteTo.Source; WriteMethodMarshal(method, numParameters); } if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid) { Write(BulletParser.GetTypeMarshalConstructorEnd(nativeMethod)); } WriteLine(';'); // Write type marshalling epilogue if (needTypeMarshalEpilogue) { foreach (var param in method.Parameters) { string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param); if (!string.IsNullOrEmpty(epilogue)) { WriteLine(1, epilogue); } } if (!nativeMethod.IsVoid) { WriteLine(1, "return ret;"); } } }
private void WriteMethod(ManagedMethod method, int level, int numOptionalParams = 0) { var nativeMethod = method.Native; var parentClass = method.Parent; // No whitespace between get/set methods if (!(method.Property != null && method.Equals(method.Property.Setter))) { EnsureSourceWhiteSpace(); hasHeaderWhiteSpace = false; } // #ifndef DISABLE_FEATURE bool hasConditional = false; if (method.Property == null) { foreach (var param in method.Parameters) { string typeConditional = GetTypeConditional(param.Native.Type, parentClass.Header); if (typeConditional != null) { WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source); hasSourceWhiteSpace = true; hasConditional = true; } } } WriteMethodDeclaration(method, level, numOptionalParams); var prevTo = To; To = WriteTo.Source; // Constructor chaining int numParameters = method.Parameters.Length - numOptionalParams; // Getters with parameter for return value if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter)) { numParameters = 0; } var currentParams = method.Parameters.Take(numParameters).ToList(); bool doConstructorChaining = false; if (nativeMethod.IsConstructor && parentClass.BaseClass != null) { // If there is no need for marshalling code, we can chain constructors doConstructorChaining = currentParams.All(p => !DefaultParser.TypeRequiresMarshal(p.Native.Type)); Write(1, $": {parentClass.BaseClass.Name}("); if (doConstructorChaining) { Write("new "); WriteMethodMarshal(method, numParameters); if (parentClass.BaseClass.Native.HasPreventDelete) { Write(", false"); } } else { Write('0'); } WriteLine(')'); } // Method body WriteLine('{'); if (!doConstructorChaining) { WriteMethodDefinition(method, numParameters); } // Cache property values if (nativeMethod.IsConstructor) { var assignments = new List <string>(); var methodParent = method.Parent; while (methodParent != null) { foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key)) { foreach (var param in currentParams) { if (!param.Name.ToLower().Equals(cachedProperty.Key.ToLower())) { continue; } var paramType = GetName(param.Native.Type); var propType = GetName(cachedProperty.Value.Property.Type); if (!paramType.Equals(propType)) { return; } string assignment = $"\t{cachedProperty.Value.CacheFieldName} = {param.Name};"; assignments.Add(assignment); } } methodParent = methodParent.BaseClass; } if (assignments.Count != 0) { EnsureSourceWhiteSpace(); foreach (string assignment in assignments) { WriteLine(assignment); } hasSourceWhiteSpace = false; } } WriteLine('}'); hasSourceWhiteSpace = false; // #endif // DISABLE_FEATURE if (hasConditional) { foreach (var param in currentParams) { string typeConditional = GetTypeConditional(param.Native.Type, method.Parent.Header); if (typeConditional != null) { WriteLine("#endif", WriteTo.Header | WriteTo.Source); hasHeaderWhiteSpace = true; } } } // If there are optional parameters, then output all possible combinations of calls if (currentParams.Any() && currentParams.Last().Native.IsOptional) { WriteMethod(method, level, numOptionalParams + 1); } To = prevTo; }
private void WriteMethodDeclaration(ManagedMethod method, int level, int numOptionalParams) { var nativeMethod = method.Native; WriteTabs(level + 1, WriteTo.Header); if (nativeMethod.IsStatic) { Write("static ", WriteTo.Header); } // Return type if (!nativeMethod.IsConstructor) { var returnType = nativeMethod.ReturnType; if (method.Property != null) { if (method.Equals(method.Property.Getter)) { // If property name matches type name, resolve ambiguity if (method.Property.Name.Equals(GetName(method.Property.Type))) { Write(Project.NamespaceName + "::", WriteTo.Header); } // Getter with parameter for return value if (method.Parameters.Length == 1) { returnType = method.Parameters[0].Native.Type; } } } Write($"{GetTypeName(returnType)} ", WriteTo.Header | WriteTo.Source); } // Name string headerMethodName; string sourceMethodName; if (nativeMethod.IsConstructor) { headerMethodName = method.Parent.Name; sourceMethodName = headerMethodName; } else if (method.Property != null) { headerMethodName = method.Property.Getter.Equals(method) ? "get" : "set"; sourceMethodName = $"{method.Property.Name}::{headerMethodName}"; } else { headerMethodName = method.Name; sourceMethodName = headerMethodName; } Write($"{headerMethodName}(", WriteTo.Header); Write($"{GetFullNameManaged(method.Parent)}::{sourceMethodName}(", WriteTo.Source); // Parameters int numParameters = method.Parameters.Length - numOptionalParams; // Getters with parameter for return value if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter)) { numParameters = 0; } var currentParams = method.Parameters.Take(numParameters).ToList(); var paramStrings = currentParams .Select(p => $"{GetParameterMarshal(p.Native)} {p.Name}").ToList(); string parameters = ListToLines(paramStrings, WriteTo.Header, level + 1); WriteLine($"{parameters});", WriteTo.Header); parameters = ListToLines(paramStrings, WriteTo.Source); WriteLine($"{parameters})", WriteTo.Source); }
void WriteMethodDefinition(ManagedMethod method, int numParameters) { var nativeMethod = method.Native; var parentClass = method.Parent.Native; // Type marshalling prologue bool needTypeMarshalEpilogue = false; if (nativeMethod.Field == null) { foreach (var param in method.Parameters) { string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param); if (!string.IsNullOrEmpty(prologue)) { WriteLine(1, prologue); } // Do we need a type marshalling epilogue? if (!needTypeMarshalEpilogue) { string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param); if (!string.IsNullOrEmpty(epilogue)) { needTypeMarshalEpilogue = true; } } } } WriteTabs(1); if (nativeMethod.IsConstructor) { Write("_native = new "); } else if (!nativeMethod.IsVoid) { //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null) if (needTypeMarshalEpilogue) { // Return after epilogue (cleanup) Write($"{GetTypeName(nativeMethod.ReturnType)} ret = "); } else { // Return immediately Write("return "); } Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod)); } else if (method.Property != null && method.Equals(method.Property.Getter)) { Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod)); } // Native is defined as static_cast<className*>(_native) string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native"; if (nativeMethod.Field != null) { var property = method.Property; if (method.Equals(property.Getter)) { CachedProperty cachedProperty; if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty)) { Write(cachedProperty.CacheFieldName); } else { Write($"{nativePointer}->{nativeMethod.Field.Name}"); } } else if (property.Setter != null && method.Equals(property.Setter)) { var param = method.Parameters[0]; var paramType = param.Native.Type; var fieldSet = BulletParser.GetTypeMarshalFieldSetCppCli(nativeMethod.Field, param, nativePointer); if (!string.IsNullOrEmpty(fieldSet)) { Write(fieldSet); } else { Write($"{nativePointer}->{nativeMethod.Field.Name} = "); switch (paramType.Kind) { case TypeKind.Pointer: case TypeKind.LValueReference: if (paramType.Kind == TypeKind.LValueReference) { // Dereference Write('*'); } if (paramType.Referenced.Target != null && paramType.Referenced.Target.BaseClass != null) { // Cast native pointer from base class Write($"({paramType.Referenced.FullName}*)"); } break; } Write(param.Name); if (!paramType.IsBasic) { Write("->_native"); } } } } else { if (nativeMethod.IsConstructor) { } else if (nativeMethod.IsStatic) { Write(parentClass.FullyQualifiedName + "::"); } else { Write(nativePointer + "->"); } To = WriteTo.Source; WriteMethodMarshal(method, numParameters); } if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid) { Write(BulletParser.GetTypeMarshalConstructorEnd(nativeMethod)); } WriteLine(';'); // Write type marshalling epilogue if (needTypeMarshalEpilogue) { foreach (var param in method.Parameters) { string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param); if (!string.IsNullOrEmpty(epilogue)) { WriteLine(1, epilogue); } } if (!nativeMethod.IsVoid) { WriteLine(1, "return ret;"); } } }