public InterfaceTransform( NamingRulesManager namingRules, Logger logger, GlobalNamespaceProvider globalNamespace, ITransformPreparer <CppMethod, CsMethod> methodPreparer, ITransformer <CsMethod> methodTransformer, TypeRegistry typeRegistry, NamespaceRegistry namespaceRegistry) : base(namingRules, logger) { MethodPreparer = methodPreparer; MethodTransformer = methodTransformer; this.typeRegistry = typeRegistry; this.namespaceRegistry = namespaceRegistry; propertyBuilder = new PropertyBuilder(globalNamespace); methodOverloadBuilder = new MethodOverloadBuilder(globalNamespace, typeRegistry); CppObjectType = new CsInterface { Name = globalNamespace.GetTypeName(WellKnownName.CppObject) }; DefaultCallbackable = new CsInterface { Name = globalNamespace.GetTypeName(WellKnownName.ICallbackable), ShadowName = globalNamespace.GetTypeName(WellKnownName.CppObjectShadow), VtblName = globalNamespace.GetTypeName(WellKnownName.CppObjectVtbl) }; }
/// <summary> /// Processes the specified method. /// </summary> /// <param name="method">The method.</param> private void ProcessMethod(CsCallable method) { var cppMethod = (CppCallable)method.CppElement; method.Name = NamingRules.Rename(cppMethod); // For methods, the tag "type" is only used for return type // So we are overriding the return type here var methodRule = cppMethod.GetMappingRule(); if (methodRule.MappingType != null) { cppMethod.ReturnValue.Rule = new MappingRule { MappingType = methodRule.MappingType } } ; // Get the inferred return type method.ReturnValue = factory.Create(cppMethod.ReturnValue); if (method.ReturnValue.PublicType is CsInterface iface && iface.IsCallback) { method.ReturnValue.PublicType = iface.GetNativeImplementationOrThis(); } // Hide return type only if it is a HRESULT and AlwaysReturnHResult is false if (method.CheckReturnType && method.ReturnValue.PublicType != null && method.ReturnValue.PublicType.QualifiedName == globalNamespace.GetTypeName(WellKnownName.Result)) { method.HideReturnType = !method.AlwaysReturnHResult; } // Iterates on parameters to convert them to C# parameters foreach (var cppParameter in cppMethod.Parameters) { var paramMethod = factory.Create(cppParameter); paramMethod.Name = NamingRules.Rename(cppParameter); method.Add(paramMethod); } }
private bool ValidateGetter(CsMethod getter) { if (getter == null) { return(true); } if ((getter.ReturnValue.PublicType.Name == globalNamespace.GetTypeName(WellKnownName.Result) || !getter.HasReturnType) && getter.Parameters.Count == 1 && getter.Parameters[0].IsOut && !getter.Parameters[0].IsArray) { return(true); } else if (getter.Parameters.Count == 0 && getter.HasReturnType) { return(true); } return(false); }
private InteropType GetInteropTypeForParameter(CsParameter param) { InteropType interopType; var publicName = param.PublicType.QualifiedName; if (publicName == provider.GetTypeName(WellKnownName.PointerSize)) { interopType = typeof(void *); } else if (param.HasPointer) { interopType = typeof(void *); } else if (param.MarshalType is CsFundamentalType marshalFundamental) { var type = marshalFundamental.Type; if (type == typeof(IntPtr)) { type = typeof(void *); } interopType = type; } else if (param.PublicType is CsFundamentalType publicFundamental) { var type = publicFundamental.Type; if (type == typeof(IntPtr)) { type = typeof(void *); } interopType = type; } else if (param.PublicType is CsStruct csStruct) { // If parameter is a struct, then a LocalInterop is needed if (csStruct.HasMarshalType) { interopType = $"{csStruct.QualifiedName}.__Native"; } else { interopType = csStruct.QualifiedName; } } else if (param.PublicType is CsEnum csEnum) { interopType = csEnum.UnderlyingType.Type; } else { interopType = null; } return(interopType); }
public InteropSignatureTransform(GlobalNamespaceProvider provider, Logger logger) { this.provider = provider; this.logger = logger; returnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.Result), typeof(int) }, { provider.GetTypeName(WellKnownName.PointerSize), typeof(void *) } }; windowsOnlyReturnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.NativeLong), new SignatureInteropTypeOverride(typeof(int), InteropMethodSignatureFlags.CastToNativeLong) }, { provider.GetTypeName(WellKnownName.NativeULong), new SignatureInteropTypeOverride(typeof(uint), InteropMethodSignatureFlags.CastToNativeULong) } }; systemvOnlyReturnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.NativeLong), new SignatureInteropTypeOverride(typeof(IntPtr), InteropMethodSignatureFlags.CastToNativeLong) }, { provider.GetTypeName(WellKnownName.NativeULong), new SignatureInteropTypeOverride(typeof(UIntPtr), InteropMethodSignatureFlags.CastToNativeULong) } }; }
public CsMethod CreateInterfaceArrayOverload(CsMethod original) { // Create a new method and transforms all array of CppObject to InterfaceArray<CppObject> var newMethod = (CsMethod)original.Clone(); foreach (var csParameter in newMethod.PublicParameters) { if (!csParameter.IsInInterfaceArrayLike) { continue; } csParameter.PublicType = new CsInterfaceArray( (CsInterface)csParameter.PublicType, globalNamespace.GetTypeName(WellKnownName.InterfaceArray) ); csParameter.MarshalType = TypeRegistry.IntPtr; } return(newMethod); }
public InteropSignatureTransform(GlobalNamespaceProvider provider, Logger logger) { this.provider = provider; this.logger = logger; returnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.Result), TypeRegistry.Int32 }, { provider.GetTypeName(WellKnownName.PointerSize), TypeRegistry.VoidPtr } }; const InteropMethodSignatureFlags castToNativeLong = InteropMethodSignatureFlags.CastToNativeLong; const InteropMethodSignatureFlags castToNativeULong = InteropMethodSignatureFlags.CastToNativeULong; windowsOnlyReturnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.NativeLong), new SignatureInteropTypeOverride(TypeRegistry.Int32, castToNativeLong) }, { provider.GetTypeName(WellKnownName.NativeULong), new SignatureInteropTypeOverride(TypeRegistry.UInt32, castToNativeULong) } }; systemvOnlyReturnTypeOverrides = new Dictionary <string, SignatureInteropTypeOverride> { { provider.GetTypeName(WellKnownName.NativeLong), new SignatureInteropTypeOverride(TypeRegistry.IntPtr, castToNativeLong) }, { provider.GetTypeName(WellKnownName.NativeULong), new SignatureInteropTypeOverride(TypeRegistry.UIntPtr, castToNativeULong) } }; }
public bool IsWellKnownType(GlobalNamespaceProvider globalNamespace, WellKnownName name) => QualifiedName == globalNamespace.GetTypeName(name);
public override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement) { // Documentation var documentationTrivia = GenerateDocumentationTrivia(csElement); // method signature var methodDeclaration = MethodDeclaration(ParseTypeName(csElement.PublicReturnTypeQualifiedName), csElement.Name) .WithModifiers(TokenList(ParseTokens(csElement.VisibilityName)).Add(Token(SyntaxKind.UnsafeKeyword))) .WithParameterList( ParameterList( SeparatedList( csElement.PublicParameters.Select(param => Generators.Marshalling.GetMarshaller(param).GenerateManagedParameter(param) .WithDefault(param.DefaultValue == null ? default : EqualsValueClause(ParseExpression(param.DefaultValue))) ) ) ) ) .WithLeadingTrivia(Trivia(documentationTrivia)); if (csElement.SignatureOnly) { yield return(methodDeclaration .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList())); yield break; } var statements = new List <StatementSyntax>(); foreach (var param in csElement.Parameters) { if (param.Relation == null) { if (param.UsedAsReturn) { statements.Add(GenerateManagedHiddenMarshallableProlog(param)); } statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param)); } else { statements.Add(GenerateManagedHiddenMarshallableProlog(param)); if (!ValidRelationInScenario(param.Relation)) { logger.Error(LoggingCodes.InvalidRelationInScenario, $"The relation \"{param.Relation}\" is invalid in a method/function."); continue; } var marshaller = Generators.Marshalling.GetRelationMarshaller(param.Relation); StatementSyntax marshalToNative; var relatedMarshallableName = (param.Relation as IHasRelatedMarshallable)?.RelatedMarshallableName; if (relatedMarshallableName is null) { marshalToNative = marshaller.GenerateManagedToNative(null, param); } else { marshalToNative = marshaller.GenerateManagedToNative( csElement.Parameters.First(p => p.CppElementName == relatedMarshallableName), param); } if (marshalToNative != null) { statements.Add(marshalToNative); } statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param)); } } if (csElement.HasReturnType) { statements.Add(GenerateManagedHiddenMarshallableProlog(csElement.ReturnValue)); statements.AddRange( Generators.Marshalling.GetMarshaller(csElement.ReturnValue) .GenerateManagedToNativeProlog(csElement.ReturnValue)); } foreach (var param in csElement.Parameters) { if (param.IsIn || param.IsRefIn || param.IsRef) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalToNative = marshaller.GenerateManagedToNative(param, true); if (marshalToNative != null) { statements.Add(marshalToNative); } } } var fixedStatements = csElement.PublicParameters .Select(param => Generators.Marshalling.GetMarshaller(param).GeneratePin(param)) .Where(stmt => stmt != null).ToList(); var callStmt = GeneratorHelpers.GetPlatformSpecificStatements( globalNamespace, Generators.Config, csElement.InteropSignatures.Keys, (platform) => ExpressionStatement( Generators.NativeInvocation.GenerateCode((csElement, platform, csElement.InteropSignatures[platform])))); var fixedStatement = fixedStatements.FirstOrDefault()?.WithStatement(callStmt); foreach (var statement in fixedStatements.Skip(1)) { fixedStatement = statement.WithStatement(fixedStatement); } statements.Add(fixedStatement ?? callStmt); foreach (var param in csElement.Parameters) { if (param.IsRef || param.IsOut) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalFromNative = marshaller.GenerateNativeToManaged(param, true); if (marshalFromNative != null) { statements.Add(marshalFromNative); } } } if (csElement.HasReturnType) { var marshaller = Generators.Marshalling.GetMarshaller(csElement.ReturnValue); var marshalReturnType = marshaller.GenerateNativeToManaged(csElement.ReturnValue, true); if (marshalReturnType != null) { statements.Add(marshalReturnType); } } statements.AddRange(csElement.Parameters .Where(param => !param.IsOut) .Select(param => Generators.Marshalling.GetMarshaller(param).GenerateNativeCleanup(param, true)) .Where(param => param != null)); if ((csElement.ReturnValue.PublicType.Name == globalNamespace.GetTypeName(WellKnownName.Result)) && csElement.CheckReturnType) { statements.Add(ExpressionStatement( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(csElement.ReturnValue.Name), IdentifierName("CheckError"))))); } // Return if (csElement.HasPublicReturnType) { if (csElement.HasReturnTypeParameter || csElement.ForceReturnType || !csElement.HideReturnType) { statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName))); } } yield return(methodDeclaration.WithBody(Block(statements))); }
/// <summary> /// Gets the C# type from a C++ type. /// </summary> /// <typeparam name="T">The C# type to return</typeparam> /// <param name="marshallable">The marshallable element to create the C# type from.</param> /// <returns>An instantiated C# type</returns> private T CreateCore <T>(CppMarshallable marshallable) where T : CsMarshalBase, new() { CsTypeBase publicType = null; CsTypeBase marshalType = null; var csMarshallable = new T { CppElement = marshallable, IsArray = marshallable.IsArray, HasPointer = !string.IsNullOrEmpty(marshallable.Pointer) && (marshallable.Pointer.Contains("*") || marshallable.Pointer.Contains("&")), }; // TODO: handle multidimensional arrays // Calculate ArrayDimension int arrayDimensionValue = 0; if (marshallable.IsArray) { if (string.IsNullOrEmpty(marshallable.ArrayDimension)) { arrayDimensionValue = 0; } else if (!int.TryParse(marshallable.ArrayDimension, out arrayDimensionValue)) { arrayDimensionValue = 1; } } // If array Dimension is 0, then it is not an array if (arrayDimensionValue == 0) { marshallable.IsArray = false; csMarshallable.IsArray = false; } csMarshallable.ArrayDimensionValue = arrayDimensionValue; string publicTypeName = marshallable.GetTypeNameWithMapping(); switch (publicTypeName) { case "char": publicType = typeRegistry.ImportType(typeof(byte)); if (csMarshallable.HasPointer) { publicType = typeRegistry.ImportType(typeof(string)); } if (csMarshallable.IsArray) { publicType = typeRegistry.ImportType(typeof(string)); marshalType = typeRegistry.ImportType(typeof(byte)); } break; case "wchar_t": publicType = typeRegistry.ImportType(typeof(char)); csMarshallable.IsWideChar = true; if (csMarshallable.HasPointer) { publicType = typeRegistry.ImportType(typeof(string)); } if (csMarshallable.IsArray) { publicType = typeRegistry.ImportType(typeof(string)); marshalType = typeRegistry.ImportType(typeof(char)); } break; default: // If CppType is an array, try first to get the binding for this array if (marshallable.IsArray) { publicType = typeRegistry.FindBoundType(publicTypeName + "[" + marshallable.ArrayDimension + "]"); } // Else get the typeName if (publicType == null) { // Try to get a declared type // If it fails, then this type is unknown publicType = typeRegistry.FindBoundType(publicTypeName); if (publicType == null) { logger.Fatal("Unknown type found [{0}]", publicTypeName); } } else { csMarshallable.ArrayDimensionValue = 0; csMarshallable.IsArray = false; } // By default, use the underlying native type as the marshal type // if it differs from the public type. marshalType = typeRegistry.FindBoundType(marshallable.TypeName); if (publicType == marshalType) { marshalType = null; } if (marshalType == null) { // Otherwise, get the registered marshal type if one exists marshalType = typeRegistry.FindBoundMarshalType(publicTypeName); } if (publicType is CsStruct csStruct) { // If a structure was not already parsed, then parse it before going further if (!csStruct.IsFullyMapped) { RequestStructProcessing?.Invoke(csStruct); } if (!csStruct.IsFullyMapped) // No one tried to map the struct so we can't continue. { logger.Fatal($"No struct processor processed {csStruct.QualifiedName}. Cannot continue processing"); } // If referenced structure has a specialized marshalling, then use the structure's built-in marshalling if (csStruct.HasMarshalType && !csMarshallable.HasPointer) { marshalType = publicType; } } else if (publicType is CsEnum referenceEnum) { marshalType = null; // enums don't need a marshal type. They can always marshal as their underlying type. } break; } // Set bool to int conversion case csMarshallable.IsBoolToInt = marshalType is CsFundamentalType marshalFundamental && IsIntegerFundamentalType(marshalFundamental) && publicType is CsFundamentalType publicFundamental && publicFundamental.Type == typeof(bool); if (publicType.QualifiedName == globalNamespace.GetTypeName(WellKnownName.PointerSize)) { marshalType = typeRegistry.ImportType(typeof(IntPtr)); } // Present void* elements as IntPtr. Marshal strings as IntPtr if (csMarshallable.HasPointer) { if (publicTypeName == "void") { publicType = typeRegistry.ImportType(typeof(IntPtr)); marshalType = typeRegistry.ImportType(typeof(IntPtr)); } else if (publicType == typeRegistry.ImportType(typeof(string))) { marshalType = typeRegistry.ImportType(typeof(IntPtr)); } } csMarshallable.PublicType = publicType; csMarshallable.MarshalType = marshalType ?? publicType; csMarshallable.Relations = RelationParser.ParseRelation(marshallable.GetMappingRule().Relation, logger); return(csMarshallable); }
public override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement) { // Documentation var documentationTrivia = GenerateDocumentationTrivia(csElement); // method signature var methodDeclaration = MethodDeclaration(ParseTypeName(csElement.PublicReturnTypeQualifiedName), csElement.Name) .WithModifiers(TokenList(ParseTokens(csElement.VisibilityName)).Add(Token(SyntaxKind.UnsafeKeyword))) .WithParameterList( ParameterList( SeparatedList( csElement.PublicParameters.Select(param => Generators.Marshalling.GetMarshaller(param).GenerateManagedParameter(param) .WithDefault(param.DefaultValue == null ? default : EqualsValueClause(ParseExpression(param.DefaultValue))) ) ) ) ) .WithLeadingTrivia(Trivia(documentationTrivia)); if (csElement.SignatureOnly) { yield return(methodDeclaration .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList())); yield break; } var statements = new List <StatementSyntax>(); foreach (var param in csElement.Parameters) { if (param.UsedAsReturn) { statements.Add(GenerateManagedReturnProlog(param)); } statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param)); } if (csElement.HasReturnType) { statements.Add(GenerateManagedReturnProlog(csElement.ReturnValue)); statements.AddRange( Generators.Marshalling.GetMarshaller(csElement.ReturnValue) .GenerateManagedToNativeProlog(csElement.ReturnValue)); } foreach (var param in csElement.Parameters) { if (param.IsIn || param.IsRefIn || param.IsRef) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalToNative = marshaller.GenerateManagedToNative(param, true); if (marshalToNative != null) { statements.Add(marshalToNative); } } } var fixedStatements = csElement.PublicParameters .Select(param => Generators.Marshalling.GetMarshaller(param).GeneratePin(param)) .Where(stmt => stmt != null).ToList(); var callStmt = ExpressionStatement(Generators.NativeInvocation.GenerateCode(csElement)); var fixedStatement = fixedStatements.FirstOrDefault()?.WithStatement(callStmt); foreach (var statement in fixedStatements.Skip(1)) { fixedStatement = statement.WithStatement(fixedStatement); } statements.Add((StatementSyntax)fixedStatement ?? callStmt); foreach (var param in csElement.Parameters) { if (param.IsRef || param.IsOut) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalFromNative = marshaller.GenerateNativeToManaged(param, true); if (marshalFromNative != null) { statements.Add(marshalFromNative); } } } if (csElement.HasReturnType) { var marshaller = Generators.Marshalling.GetMarshaller(csElement.ReturnValue); var marshalReturnType = marshaller.GenerateNativeToManaged(csElement.ReturnValue, true); if (marshalReturnType != null) { statements.Add(marshalReturnType); } } statements.AddRange(csElement.Parameters .Where(param => !param.IsOut) .Select(param => Generators.Marshalling.GetMarshaller(param).GenerateNativeCleanup(param, true)) .Where(param => param != null)); if ((csElement.ReturnValue.PublicType.Name == globalNamespace.GetTypeName(WellKnownName.Result)) && csElement.CheckReturnType) { statements.Add(ExpressionStatement( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(csElement.ReturnValue.Name), IdentifierName("CheckError"))))); } // Return if (csElement.HasPublicReturnType) { if (csElement.HasReturnTypeParameter || csElement.ForceReturnType || !csElement.HideReturnType) { statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName))); } } yield return(methodDeclaration.WithBody(Block(statements))); }