void WriteDeleteMethodCS(ManagedMethod method, int level) { WriteLine(level + 1, "public void Dispose()"); WriteLine(level + 1, "{"); WriteLine(level + 2, "Dispose(true);"); WriteLine(level + 2, "GC.SuppressFinalize(this);"); WriteLine(level + 1, "}"); WriteLine(); WriteLine(level + 1, "protected virtual void Dispose(bool disposing)"); WriteLine(level + 1, "{"); WriteLine(level + 2, "if (_native != IntPtr.Zero)"); WriteLine(level + 2, "{"); if (method.Parent.Native.HasPreventDelete) { WriteLine(level + 3, "if (!_preventDelete)"); WriteLine(level + 3, "{"); WriteLine(level + 4, $"{GetFullNameC(method.Parent.Native)}_delete(_native);"); WriteLine(level + 3, "}"); } else { WriteLine(level + 3, $"{GetFullNameC(method.Parent.Native)}_delete(_native);"); } WriteLine(level + 3, "_native = IntPtr.Zero;"); WriteLine(level + 2, "}"); WriteLine(level + 1, "}"); // C# Destructor WriteLine(); WriteLine(level + 1, $"~{method.Parent.Name}()"); WriteLine(level + 1, "{"); WriteLine(level + 2, "Dispose(false);"); WriteLine(level + 1, "}"); }
public ManagedMethod Copy(ManagedClass parent) { var m = new ManagedMethod(Native, parent, Name) { Property = Property }; //TODO: params return m; }
private void WriteMethodMarshal(ManagedMethod method, int numParameters) { var nativeMethod = method.Native; string methodName = nativeMethod.IsConstructor ? $"{nativeMethod.Parent.FullyQualifiedName}" : $"{nativeMethod.Name}"; var currentParams = method.Parameters.Take(numParameters); var paramStrings = currentParams.Select(p => { string marshal = BulletParser.GetTypeMarshalCppCli(p); if (!string.IsNullOrEmpty(marshal)) { return(marshal); } var paramType = p.Native.Type; if (paramType.IsBasic) { return(p.Name); } string paramString = ""; switch (paramType.Kind) { case TypeKind.Pointer: case TypeKind.LValueReference: if (paramType.Kind == TypeKind.LValueReference) { // Dereference paramString = "*"; } if (paramType.Referenced.Target?.BaseClass != null) { // Cast native pointer from base class paramString += $"({paramType.Referenced.FullName}*)"; } break; } paramString += p.Name; if (paramType.Kind == TypeKind.Pointer && paramType.Referenced.Kind == TypeKind.Void) { paramString += ".ToPointer()"; } else { paramString += "->_native"; } return(paramString); }); Write($"{methodName}("); string parameters = ListToLines(paramStrings, WriteTo.Source, 1); Write($"{parameters})"); }
public ManagedMethod Copy(ManagedClass parent) { var m = new ManagedMethod(Native, parent, Name) { Property = Property }; //TODO: params return(m); }
private ManagedClass GetManagedClass(ClassDefinition @class) { if (@class == null) { return(null); } ManagedClass managedClass; if (Classes.TryGetValue(@class.FullyQualifiedName, out managedClass)) { return(managedClass); } if (@class.IsExcluded) { return(null); } string managedName = GetManagedClassName(@class); var parent = GetManagedClass(@class.Parent); managedClass = new ManagedClass(@class, managedName, parent); managedClass.BaseClass = GetManagedClass(@class.BaseClass); Classes[@class.FullyQualifiedName] = managedClass; // Set parent header or class managedClass.Header = GetManagedHeader(@class.Header); if (parent != null) { parent.NestedClasses.Add(managedClass); } else { managedClass.Header.Classes.Add(managedClass); } // Managed methods foreach (var method in @class.Methods) { managedName = GetManagedMethodName(method); var managedMethod = new ManagedMethod(method, managedClass, managedName); foreach (var param in managedMethod.Parameters) { param.Name = GetManagedParameterName(param.Native); } } return(managedClass); }
bool MethodNeedsExtensions(ManagedMethod method) { // Extension constructors & static extension methods not supported if (method.Native.IsConstructor || method.Native.IsStatic) { return false; } foreach (var param in method.Parameters) { if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { return true; } } return false; }
bool MethodNeedsExtensions(ManagedMethod method) { // Extension constructors & static extension methods not supported if (method.Native.IsConstructor || method.Native.IsStatic) { return(false); } foreach (var param in method.Parameters) { if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { return(true); } } return(false); }
string GetPropertyName(ManagedMethod getter) { string name = getter.Name; var propertyType = getter.Native.IsVoid ? getter.Parameters[0].Native.Type : getter.Native.ReturnType; if ("bool".Equals(propertyType.Name) && _booleanVerbs.Any(v => name.StartsWith(v))) { return(name); } if (name.StartsWith("Get")) { return(name.Substring(3)); } throw new NotImplementedException(); }
void WriteMethod(ManagedMethod method, int level, ref int overloadIndex, int numOptionalParams = 0) { var nativeMethod = method.Native; int numOptionalParamsTotal = nativeMethod.NumOptionalParameters; int numParameters = method.Parameters.Length - numOptionalParamsTotal + numOptionalParams; // TODO: outValueParameter WriteMethodDeclaration(method, numParameters, level, overloadIndex, null); // Skip methods wrapped by C# properties if (method.Property == null) { // Constructor base call if (nativeMethod.IsConstructor && method.Parent.BaseClass != null) { Write(level + 2, ": base(", WriteTo.CS); } else { WriteLine(level + 1, "{", WriteTo.CS); WriteTabs(level + 2, WriteTo.CS); } // TODO: outValueParameter WriteMethodDefinition(method, numParameters, overloadIndex, level, null); WriteLine(level + 1, "}", WriteTo.CS); hasCSWhiteSpace = false; } // If there was an optional parameter, // write the method again without it. overloadIndex++; if (numOptionalParams < numOptionalParamsTotal) { WriteMethod(method, level, ref overloadIndex, numOptionalParams + 1); } }
void WriteMethodDefinition(ManagedMethod method, int numParameters, int overloadIndex, int level, ManagedParameter outValueParameter) { var nativeMethod = method.Native; if (nativeMethod.IsConstructor) { if (method.Parent.BaseClass == null) { Write("_native = "); } Write($"{GetFullNameC(method.Parent.Native)}_new"); } else { if (!nativeMethod.IsVoid) { if (outValueParameter != null) { // Temporary variable WriteLine(string.Format("{0} {1};", DotNetParser.GetManaged(outValueParameter.Native.Type.Referenced.Target).Name, outValueParameter.Name)); WriteTabs(level + 2); } else { Write($"return {BulletParser.GetTypeMarshalConstructorStartCS(nativeMethod)}"); } } Write($"{GetFullNameC(method.Parent.Native)}_{method.Native.Name}"); } if (overloadIndex != 0) { Write((overloadIndex + 1).ToString()); } Write('('); var parameters = method.Parameters.Take(numParameters) .Select(p => GetParameterMarshal(p)); if (outValueParameter != null) { parameters = parameters.Concat(new[] { $"out {outValueParameter.Name }" }); } // The first parameter is the instance pointer (if not constructor or static method) if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic) { parameters = new[] { "_native" }.Concat(parameters); } Write(ListToLines(parameters, WriteTo.CS, level + 2)); if (nativeMethod.IsConstructor && method.Parent.BaseClass != null) { Write(")"); if (method.Parent.BaseClass.Native.HasPreventDelete) { Write(", false"); } WriteLine(")"); WriteLine(level + 1, "{"); } else { if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid) { Write(BulletParser.GetTypeMarshalConstructorEndCS(nativeMethod)); } WriteLine(");"); } // Cache property values if (nativeMethod.IsConstructor) { var methodParent = method.Parent; while (methodParent != null) { foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key)) { foreach (var param in method.Parameters) { if (param.Name.ToLower().Equals(cachedProperty.Key.ToLower()) && GetName(param.Native.Type).Equals(GetName(cachedProperty.Value.Property.Type))) { WriteLine(level + 2, $"{cachedProperty.Value.CacheFieldName} = {param.Name};"); } } } methodParent = methodParent.BaseClass; } } // Return temporary variable if (outValueParameter != null) { WriteLine(level + 2, $"return {outValueParameter.Name};"); } }
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 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); }
string GetPropertyName(ManagedMethod getter) { string name = getter.Name; var propertyType = getter.Native.IsVoid ? getter.Parameters[0].Native.Type : getter.Native.ReturnType; if ("bool".Equals(propertyType.Name) && _booleanVerbs.Any(v => name.StartsWith(v))) { return name; } if (name.StartsWith("Get")) { return name.Substring(3); } throw new NotImplementedException(); }
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; }
void WriteMethod(ManagedMethod method, int level, ref int overloadIndex, int numOptionalParams = 0) { var nativeMethod = method.Native; int numOptionalParamsTotal = nativeMethod.NumOptionalParameters; int numParameters = method.Parameters.Length - numOptionalParamsTotal + numOptionalParams; WriteMethodDeclaration(method, numParameters, level, overloadIndex); // Skip methods wrapped by C# properties if (method.Property == null) { // Constructor base call if (nativeMethod.IsConstructor && method.Parent.BaseClass != null) { Write(level + 2, ": base(", WriteTo.CS); } else { WriteLine(level + 1, "{", WriteTo.CS); WriteTabs(level + 2, WriteTo.CS); } WriteMethodDefinition(method, numParameters, overloadIndex, level); WriteLine(level + 1, "}", WriteTo.CS); hasCSWhiteSpace = false; } // If there was an optional parameter, // write the method again without it. overloadIndex++; if (numOptionalParams < numOptionalParamsTotal) { WriteMethod(method, level, ref overloadIndex, numOptionalParams + 1); } }
private void WriteMethod(ManagedMethod method, int numOptionalParams = 0) { var returnType = method.Native.ReturnType; bool convertReturnType = _extensionClassesInternal.ContainsKey(GetName(returnType)); ClearBuffer(); Write(2, "public unsafe static "); if (convertReturnType) { Write(_extensionClassesExternal[GetName(returnType)]); } else { Write(GetName(returnType)); } Write($" {method.Name}(this {method.Parent.Name} obj"); var extendedParams = new List<ParameterDefinition>(); int numParameters = method.Parameters.Length - numOptionalParams; for (int i = 0; i < numParameters; i++) { Write(", "); var param = method.Parameters[i]; if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { Write($"ref {_extensionClassesExternal[GetName(param.Native.Type)]} {param.Name}"); extendedParams.Add(param.Native); } else { Write($"{GetName(param.Native.Type)} {param.Name}"); } } WriteLine(')'); WriteLine(2, "{"); // Fix parameter pointers int tabs = 3; foreach (var param in extendedParams) { WriteLine(tabs, string.Format("fixed ({0}* {1}Ptr = &{2})", _extensionClassesExternal[GetName(param.Type)], param.Name, param.Name)); WriteLine(tabs, "{"); tabs++; } WriteTabs(tabs); if (returnType.Kind != ClangSharp.TypeKind.Void) { Write("return "); } Write($"obj.{method.Name}("); bool hasOptionalParam = false; for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { Write(string.Format("ref *({0}*){1}Ptr", _extensionClassesInternal[GetName(param.Native.Type)], param.Name)); } else { Write(param.Name); } if (param.Native.IsOptional) { hasOptionalParam = true; } if (i != numParameters - 1) { Write(", "); } } Write(')'); if (convertReturnType) { Write(_returnTypeConversion[GetName(returnType)]); } WriteLine(';'); // Close fixed blocks while (tabs != 2) { tabs--; WriteLine(tabs, "}"); } _extensionMethods.Add(new KeyValuePair<string, string>(method.Name, GetBufferString())); if (hasOptionalParam) { WriteMethod(method, numOptionalParams + 1); } }
private void WriteMethod(ManagedMethod method, int numOptionalParams = 0) { var returnType = method.Native.ReturnType; bool convertReturnType = _extensionClassesInternal.ContainsKey(GetName(returnType)); ClearBuffer(); Write(2, "public unsafe static "); if (convertReturnType) { Write(_extensionClassesExternal[GetName(returnType)]); } else { Write(GetName(returnType)); } Write($" {method.Name}(this {method.Parent.Name} obj"); var extendedParams = new List <ParameterDefinition>(); int numParameters = method.Parameters.Length - numOptionalParams; for (int i = 0; i < numParameters; i++) { Write(", "); var param = method.Parameters[i]; if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { Write($"ref {_extensionClassesExternal[GetName(param.Native.Type)]} {param.Name}"); extendedParams.Add(param.Native); } else { Write($"{GetName(param.Native.Type)} {param.Name}"); } } WriteLine(')'); WriteLine(2, "{"); // Fix parameter pointers int tabs = 3; foreach (var param in extendedParams) { WriteLine(tabs, string.Format("fixed ({0}* {1}Ptr = &{2})", _extensionClassesExternal[GetName(param.Type)], param.Name, param.Name)); WriteLine(tabs, "{"); tabs++; } WriteTabs(tabs); if (returnType.Kind != ClangSharp.TypeKind.Void) { Write("return "); } Write($"obj.{method.Name}("); bool hasOptionalParam = false; for (int i = 0; i < numParameters; i++) { var param = method.Parameters[i]; if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type))) { Write(string.Format("ref *({0}*){1}Ptr", _extensionClassesInternal[GetName(param.Native.Type)], param.Name)); } else { Write(param.Name); } if (param.Native.IsOptional) { hasOptionalParam = true; } if (i != numParameters - 1) { Write(", "); } } Write(')'); if (convertReturnType) { Write(_returnTypeConversion[GetName(returnType)]); } WriteLine(';'); // Close fixed blocks while (tabs != 2) { tabs--; WriteLine(tabs, "}"); } _extensionMethods.Add(new KeyValuePair <string, string>(method.Name, GetBufferString())); if (hasOptionalParam) { WriteMethod(method, numOptionalParams + 1); } }
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 WriteMethodMarshal(ManagedMethod method, int numParameters) { var nativeMethod = method.Native; string methodName = nativeMethod.IsConstructor ? $"{nativeMethod.Parent.FullyQualifiedName}" : $"{nativeMethod.Name}"; var currentParams = method.Parameters.Take(numParameters); var paramStrings = currentParams.Select(p => { string marshal = BulletParser.GetTypeMarshalCppCli(p); if (!string.IsNullOrEmpty(marshal)) { return marshal; } var paramType = p.Native.Type; if (paramType.IsBasic) { return p.Name; } string paramString = ""; switch (paramType.Kind) { case TypeKind.Pointer: case TypeKind.LValueReference: if (paramType.Kind == TypeKind.LValueReference) { // Dereference paramString = "*"; } if (paramType.Referenced.Target?.BaseClass != null) { // Cast native pointer from base class paramString += $"({paramType.Referenced.FullName}*)"; } break; } paramString += p.Name; if (paramType.Kind == TypeKind.Pointer && paramType.Referenced.Kind == TypeKind.Void) { paramString += ".ToPointer()"; } else { paramString += "->_native"; } return paramString; }); Write($"{methodName}("); string parameters = ListToLines(paramStrings, WriteTo.Source, 1); Write($"{parameters})"); }
void WriteMethodDefinition(ManagedMethod method, int numParameters, int overloadIndex, int level) { var nativeMethod = method.Native; if (nativeMethod.IsConstructor) { if (method.Parent.BaseClass == null) { Write("_native = "); } Write($"{GetFullNameC(method.Parent.Native)}_new"); } else { if (!nativeMethod.IsVoid) { if (method.OutValueParameter != null) { // Temporary variable WriteLine(string.Format("{0} {1};", DotNetParser.GetManaged(method.OutValueParameter.Native.Type.Referenced.Target).Name, method.OutValueParameter.Name)); WriteTabs(level + 2); } else { Write($"return {BulletParser.GetTypeMarshalConstructorStartCS(nativeMethod)}"); } } Write($"{GetFullNameC(method.Parent.Native)}_{method.Native.Name}"); } if (overloadIndex != 0) { Write((overloadIndex + 1).ToString()); } Write('('); var parameters = method.Parameters.Take(numParameters) .Select(p => GetParameterMarshal(p)); if (method.OutValueParameter != null) { parameters = parameters.Concat(new[] { $"out {method.OutValueParameter.Name }" }); } // The first parameter is the instance pointer (if not constructor or static method) if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic) { parameters = new[] { "_native" }.Concat(parameters); } Write(ListToLines(parameters, WriteTo.CS, level + 2)); if (nativeMethod.IsConstructor && method.Parent.BaseClass != null) { Write(")"); if (method.Parent.BaseClass.Native.HasPreventDelete) { Write(", false"); } WriteLine(")"); WriteLine(level + 1, "{"); } else { if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid) { Write(BulletParser.GetTypeMarshalConstructorEndCS(nativeMethod)); } WriteLine(");"); } // Cache property values if (nativeMethod.IsConstructor) { var methodParent = method.Parent; while (methodParent != null) { foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key)) { foreach (var param in method.Parameters) { if (param.Name.ToLower().Equals(cachedProperty.Key.ToLower()) && GetName(param.Native.Type).Equals(GetName(cachedProperty.Value.Property.Type))) { WriteLine(level + 2, $"{cachedProperty.Value.CacheFieldName} = {param.Name};"); } } } methodParent = methodParent.BaseClass; } } // Return temporary variable if (method.OutValueParameter != null) { WriteLine(level + 2, $"return {method.OutValueParameter.Name};"); } }
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 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); }
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 ManagedClass GetManagedClass(ClassDefinition @class) { if (@class == null) return null; ManagedClass managedClass; if (Classes.TryGetValue(@class.FullyQualifiedName, out managedClass)) { return managedClass; } if (@class.IsExcluded) return null; string managedName = GetManagedClassName(@class); var parent = GetManagedClass(@class.Parent); managedClass = new ManagedClass(@class, managedName, parent); managedClass.BaseClass = GetManagedClass(@class.BaseClass); Classes[@class.FullyQualifiedName] = managedClass; // Set parent header or class managedClass.Header = GetManagedHeader(@class.Header); if (parent != null) { parent.NestedClasses.Add(managedClass); } else { managedClass.Header.Classes.Add(managedClass); } // Managed methods foreach (var method in @class.Methods) { managedName = GetManagedMethodName(method); var managedMethod = new ManagedMethod(method, managedClass, managedName); foreach (var param in managedMethod.Parameters) { param.Name = GetManagedParameterName(param.Native); } } return managedClass; }