Пример #1
0
        public ArrayMarshalerGenerator(ModuleGenerator generator)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }

            this.generator = generator;
        }
Пример #2
0
        public ApiExtractor(ModuleGenerator generator, FunctionVisitor visitor)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }

            if (visitor == null)
            {
                throw new ArgumentNullException(nameof(visitor));
            }

            this.generator = generator;
            this.visitor   = visitor;
        }
Пример #3
0
        public static void Main(string[] args)
        {
            string sourceDirectory = null;
            string targetDirectory = null;

            if (args.Length >= 1)
            {
                sourceDirectory = args[0];
            }
            else
            {
                // Default value so that you can just F5 from within Visual Studio
                sourceDirectory = @"..\..\..\..\";
            }

            if (args.Length >= 2)
            {
                targetDirectory = args[1];
            }
            else
            {
                targetDirectory = @"..\..\..\..\iMobileDevice-net";
            }

            sourceDirectory = Path.GetFullPath(sourceDirectory);
            targetDirectory = Path.GetFullPath(targetDirectory);

            Console.WriteLine($"Reading libimobiledevice headers from: {sourceDirectory}");
            Console.WriteLine($"Writing the C# files to: {targetDirectory}");

            ModuleGenerator generator = new ModuleGenerator();

            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio 14.0\VC\include"));
            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio\Shared\14.0\VC\include"));
            generator.IncludeDirectories.Add(GetWindowsKitUcrtFolder());
            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Windows Kits", "8.1", "include", "shared"));
            generator.IncludeDirectories.Add(Path.Combine(sourceDirectory, @"packages\libusbmuxd.1.0.10.92\build\native\include\"));
            generator.IncludeDirectories.Add(Path.Combine(sourceDirectory, @"packages\libimobiledevice.1.2.1.196\build\native\include\"));
            generator.IncludeDirectories.Add(Path.Combine(sourceDirectory, @"packages\libplist.2.0.1.171\build\native\include"));
            generator.IncludeDirectories.Add(Path.Combine(sourceDirectory, @"packages\libideviceactivation.1.0.0.23\build\native\include\libideviceactivation"));

            Collection <string> names = new Collection <string>();

            var files = new List <string>();

            files.Add(Path.Combine(sourceDirectory, @"packages\libusbmuxd.1.0.10.92\build\native\include\usbmuxd.h"));
            files.Add(Path.Combine(sourceDirectory, @"packages\libplist.2.0.1.171\build\native\include\plist\plist.h"));
            files.Add(Path.Combine(sourceDirectory, @"packages\libideviceactivation.1.0.0.23\build\native\include\libideviceactivation\libideviceactivation.h"));

            var iMobileDeviceDirectory = Path.Combine(sourceDirectory, @"packages\libimobiledevice.1.2.1.196\build\native\include\libimobiledevice");

            files.Add(Path.Combine(iMobileDeviceDirectory, "libimobiledevice.h"));
            files.Add(Path.Combine(iMobileDeviceDirectory, "lockdown.h"));
            files.Add(Path.Combine(iMobileDeviceDirectory, "afc.h"));

            var iMobileDeviceFileNames = Directory.GetFiles(iMobileDeviceDirectory, "*.h")
                                         .Where(f => !files.Contains(f, StringComparer.OrdinalIgnoreCase));

            files.AddRange(iMobileDeviceFileNames);

            foreach (var file in files)
            {
                Console.WriteLine($"Processing {Path.GetFileName(file)}");
                generator.InputFile = file;

                if (string.Equals(Path.GetFileName(file), "libideviceactivation.h", StringComparison.OrdinalIgnoreCase))
                {
                    generator.Generate(targetDirectory, "ideviceactivation");
                }
                else
                {
                    generator.Generate(targetDirectory);
                }

                generator.Types.Clear();

                names.Add(generator.Name);
            }

            ApiGenerator apiGenerator = new ApiGenerator();

            apiGenerator.Generate(names, targetDirectory);

            // StylecopFixer.Run(Path.Combine(targetDirectory, "iMobileDevice.csproj"));
        }
Пример #4
0
        public static CodeParameterDeclarationExpression GenerateArgument(this ModuleGenerator generator, CXType functionType, CXCursor paramCXCursor, uint index, FunctionType functionKind)
        {
            var numArgTypes = functionType.NumArgTypes;
            var type        = functionType.GetArgType(index);
            var cursorType  = paramCXCursor.Type;

            var name = paramCXCursor.Spelling.CString;

            if (string.IsNullOrEmpty(name))
            {
                name = "param" + index;
            }

            name = NameConversions.ToClrName(name, NameConversion.Parameter);

            CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression();

            parameter.Name = name;

            bool isPointer = false;

            if (functionKind != FunctionType.Free &&
                functionKind != FunctionType.Delegate &&
                type.IsDoubleCharPointer() &&
                !name.Contains("data") &&
                name != "appids")
            {
                parameter.Type      = new CodeTypeReference(typeof(string));
                parameter.Direction = FieldDirection.Out;

                parameter.CustomAttributes.Add(MarshalAsUtf8String());
            }
            else if (functionKind != FunctionType.Delegate && type.IsTripleCharPointer() && generator.StringArrayMarshalerType != null)
            {
                parameter.Type      = new CodeTypeReference(typeof(ReadOnlyCollection <string>));
                parameter.Direction = FieldDirection.Out;

                parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.CustomMarshaler, new CodeTypeReference(generator.StringArrayMarshalerType.Name)));
            }
            else if (functionKind != FunctionType.Delegate && (type.IsArrayOfCharPointers() || type.IsDoublePtrToConstChar()))
            {
                parameter.Type      = new CodeTypeReference(typeof(ReadOnlyCollection <string>));
                parameter.Direction = FieldDirection.In;

                parameter.CustomAttributes.Add(MarshalAsUtf8StringArray());
            }
            else
            {
                switch (type.kind)
                {
                case CXTypeKind.CXType_Pointer:
                    var pointee = type.PointeeType;
                    switch (pointee.kind)
                    {
                    case CXTypeKind.CXType_Pointer:
                        parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        isPointer      = true;
                        break;

                    case CXTypeKind.CXType_FunctionProto:
                        parameter.Type = new CodeTypeReference(cursorType.ToClrType());
                        break;

                    case CXTypeKind.CXType_Void:
                        parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        break;

                    case CXTypeKind.CXType_Char_S:
                        // In some of the read/write functions, const char is also used to represent data -- in that
                        // case, it maps to a byte[] array or just an IntPtr.
                        if (functionKind != FunctionType.PInvoke && type.IsPtrToConstChar())
                        {
                            if (!name.Contains("data") && name != "signature")
                            {
                                parameter.Type = new CodeTypeReference(typeof(string));
                                parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPStr));
                            }
                            else
                            {
                                parameter.Type = new CodeTypeReference(typeof(byte[]));
                            }
                        }
                        else if (functionKind != FunctionType.PInvoke && functionKind != FunctionType.Delegate && type.IsPtrToChar() && name.Contains("data"))
                        {
                            parameter.Type = new CodeTypeReference(typeof(byte[]));
                        }
                        else
                        {
                            // if it's not a const, it's best to go with IntPtr
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }

                        break;

                    case CXTypeKind.CXType_WChar:
                        if (type.IsPtrToConstChar())
                        {
                            parameter.Type = new CodeTypeReference(typeof(string));
                            parameter.CustomAttributes.Add(MarshalAsDeclaration(UnmanagedType.LPWStr));
                        }
                        else
                        {
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }

                        break;

                    case CXTypeKind.CXType_Record:
                        if (functionKind != FunctionType.Delegate)
                        {
                            var recordTypeCXCursor = pointee.Declaration;
                            var recordType         = recordTypeCXCursor.Type;

                            // Get the CLR name for the record
                            var clrName = generator.NameMapping[recordType.Spelling.CString.ToString()];
                            parameter.Type = new CodeTypeReference(clrName);
                            isPointer      = true;
                        }
                        else
                        {
                            // if it's not a const, it's best to go with IntPtr
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                            isPointer      = true;
                        }

                        break;

                    default:
                        parameter.Type = pointee.ToCodeTypeReference(paramCXCursor, generator);
                        isPointer      = true;
                        break;
                    }

                    break;

                default:
                    if (generator.NameMapping.ContainsKey(type.Spelling.CString.ToString()))
                    {
                        if (functionKind != FunctionType.Delegate)
                        {
                            parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator);
                        }
                        else
                        {
                            parameter.Type = new CodeTypeReference(typeof(IntPtr));
                        }
                    }
                    else
                    {
                        parameter.Type = type.ToCodeTypeReference(paramCXCursor, generator);
                    }

                    break;
                }
            }

            if (functionKind == FunctionType.Delegate && parameter.Type.BaseType.EndsWith("Handle"))
            {
                // Use a custom marshaler
                parameter.CustomAttributes.Add(
                    MarshalAsDeclaration(
                        UnmanagedType.CustomMarshaler,
                        new CodeTypeReference(parameter.Type.BaseType + "DelegateMarshaler")));
            }

            if (isPointer)
            {
                switch (functionKind)
                {
                case FunctionType.None:
                case FunctionType.Delegate:
                    if (parameter.Type.BaseType.EndsWith("Handle"))
                    {
                        // Handles are always out parameters
                        parameter.Direction = FieldDirection.Out;
                    }
                    else
                    {
                        // For IntPtrs, we don't know - so we play on the safe side.
                        parameter.Direction = FieldDirection.Ref;
                    }

                    break;

                case FunctionType.New:
                case FunctionType.PInvoke:
                    parameter.Direction = FieldDirection.Out;
                    break;

                case FunctionType.Free:
                    parameter.Direction = FieldDirection.In;
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            return(parameter);
        }
Пример #5
0
 public EnumVisitor(ModuleGenerator generator)
 {
     this.generator = generator;
 }
Пример #6
0
        public static int Main(string[] args)
        {
            CommandLineApplication commandLineApplication =
                new CommandLineApplication(throwOnUnexpectedArg: true);

            commandLineApplication.Name = ThisAssembly.AssemblyName;
            commandLineApplication.HelpOption("-?|-h|--help");
            commandLineApplication.ShortVersionGetter = () => ThisAssembly.AssemblyFileVersion;
            commandLineApplication.LongVersionGetter  = () => ThisAssembly.AssemblyInformationalVersion;

            commandLineApplication.Command(
                "generate",
                (runCommand) =>
            {
                runCommand.Description = "Generates the Interop source for imobiledevice-net based on the libimobiledevice headers";

                CommandOption outputArgument = runCommand.Option(
                    "-o|--output <dir>",
                    "The output directory. The C# code will be generated in this directory.",
                    CommandOptionType.SingleValue);

                CommandOption headerArgument = runCommand.Option(
                    "-s|--source <dir>",
                    "Include directory to use, which contains the libimobiledevice headers. Defaults to the include directory in VCPKG_ROOT.",
                    CommandOptionType.SingleValue);

                CommandOption includeArgument = runCommand.Option(
                    "-i|--include <dir>",
                    "Include directory to use. Defaults to the include directory in VCPKG_ROOT.",
                    CommandOptionType.MultipleValue);

                runCommand.HelpOption("-? | -h | --help");

                runCommand.OnExecute(() =>
                {
                    string targetDirectory = @"..\..\..\..\..\iMobileDevice-net";
                    if (outputArgument.HasValue())
                    {
                        targetDirectory = outputArgument.Value();
                    }

                    targetDirectory = Path.GetFullPath(targetDirectory);

                    RestoreClang();

                    ModuleGenerator generator = new ModuleGenerator();
                    generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio 14.0\VC\include"));
                    generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio\Shared\14.0\VC\include"));
                    generator.IncludeDirectories.Add(GetWindowsKitUcrtFolder());
                    generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Windows Kits", "8.1", "include", "shared"));

                    if (includeArgument.HasValue())
                    {
                        foreach (var path in includeArgument.Values)
                        {
                            generator.IncludeDirectories.Add(path);
                        }
                    }

                    string sourceDir = null;

                    if (headerArgument.HasValue())
                    {
                        sourceDir = headerArgument.Value();
                    }
                    else
                    {
                        var vcpkgPath = Environment.GetEnvironmentVariable("VCPKG_ROOT");

                        if (vcpkgPath == null)
                        {
                            Console.Error.WriteLine("Please set the VCPKG_ROOT environment variable to the folder where you've installed VCPKG.");
                            return(-1);
                        }

                        vcpkgPath = Path.Combine(vcpkgPath, "installed", "x86-windows", "include");
                        Console.WriteLine($"Reading include files from {vcpkgPath}");
                        sourceDir = vcpkgPath;
                    }

                    generator.IncludeDirectories.Add(sourceDir);

                    Console.WriteLine($"Writing the C# files to: {targetDirectory}");

                    Collection <string> names = new Collection <string>();

                    var files = new List <string>();
                    files.Add(Path.Combine(sourceDir, "usbmuxd.h"));
                    files.Add(Path.Combine(sourceDir, "plist/plist.h"));
                    files.Add(Path.Combine(sourceDir, "libideviceactivation.h"));
                    files.Add(Path.Combine(sourceDir, "libirecovery.h"));
                    var iMobileDeviceDirectory = Path.Combine(sourceDir, "libimobiledevice");
                    files.Add(Path.Combine(iMobileDeviceDirectory, "libimobiledevice.h"));
                    files.Add(Path.Combine(iMobileDeviceDirectory, "lockdown.h"));
                    files.Add(Path.Combine(iMobileDeviceDirectory, "afc.h"));

                    var iMobileDeviceFileNames = Directory.GetFiles(iMobileDeviceDirectory, "*.h")
                                                 .Where(f => !files.Contains(f, StringComparer.OrdinalIgnoreCase));

                    files.AddRange(iMobileDeviceFileNames);

                    foreach (var file in files)
                    {
                        Console.WriteLine($"Processing {Path.GetFileName(file)}");

                        if (!File.Exists(file))
                        {
                            Console.WriteLine($"WARNING: Skipping file {file} because it does not exist.");
                            continue;
                        }

                        generator.InputFile = file;

                        if (string.Equals(Path.GetFileName(file), "libideviceactivation.h", StringComparison.OrdinalIgnoreCase))
                        {
                            generator.Generate(targetDirectory, "ideviceactivation");
                        }
                        else if (string.Equals(Path.GetFileName(file), "plist.h", StringComparison.OrdinalIgnoreCase))
                        {
                            generator.Generate(targetDirectory, "plist");
                        }
                        else if (string.Equals(Path.GetFileName(file), "usbmuxd.h", StringComparison.OrdinalIgnoreCase))
                        {
                            generator.Generate(targetDirectory, "usbmuxd");
                        }
                        else if (string.Equals(Path.GetFileName(file), "libirecovery.h", StringComparison.OrdinalIgnoreCase))
                        {
                            generator.Generate(targetDirectory, "irecovery");
                        }
                        else
                        {
                            generator.Generate(targetDirectory);
                        }

                        generator.Types.Clear();

                        names.Add(generator.Name);
                    }

                    ApiGenerator apiGenerator = new ApiGenerator();
                    apiGenerator.Generate(names, targetDirectory);

                    return(0);
                });
            });

            Console.WriteLine(ThisAssembly.AssemblyName);
            commandLineApplication.ShowVersion();

            var exit = commandLineApplication.Execute(args);

            Console.WriteLine($"Exiting with code {exit}");
            return(exit);
        }
Пример #7
0
 public TypeDefVisitor(ModuleGenerator generator)
 {
     this.generator = generator;
 }
Пример #8
0
        public static CodeTypeReference ToCodeTypeReference(this TypeInfo type, Cursor cursor, ModuleGenerator generator)
        {
            var nativeName = type.GetSpelling();
            var canonical  = type.GetCanonicalType();

            // Special case: function prototypes embedded in the function declaration
            if (canonical.Kind == TypeKind.FunctionProto)
            {
                // Generate the delegate and add it to the list of members
                nativeName = cursor.GetSpelling();
                var delegateType = type.ToDelegate(nativeName, cursor, generator);
                generator.AddType(nativeName, delegateType);
            }

            if (nativeName.StartsWith("const "))
            {
                nativeName = nativeName.Substring(6);
            }

            if (generator.NameMapping.ContainsKey(nativeName))
            {
                return(new CodeTypeReference(generator.NameMapping[nativeName]));
            }
            else
            {
                return(new CodeTypeReference(type.ToClrType()));
            }
        }
Пример #9
0
        public static IEnumerable <CodeTypeMember> ToCodeTypeMember(this Cursor cursor, string cursorSpelling, ModuleGenerator generator)
        {
            var canonical = cursor.GetTypeInfo().GetCanonicalType();

            switch (canonical.Kind)
            {
            case TypeKind.ConstantArray:
                if (canonical.GetArrayElementType().GetCanonicalType().Kind == TypeKind.Char_S)
                {
                    var size = canonical.GetArraySize();

                    CodeMemberField fixedLengthString = new CodeMemberField();
                    fixedLengthString.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                    fixedLengthString.Name       = cursorSpelling;
                    fixedLengthString.Type       = new CodeTypeReference(typeof(string));
                    fixedLengthString.CustomAttributes.Add(Argument.MarshalAsFixedLengthStringDeclaration((int)size));
                    yield return(fixedLengthString);
                }
                else
                {
                    throw new NotImplementedException();
                }
                break;

            case TypeKind.Pointer:
                var pointeeType = canonical.GetPointeeType().GetCanonicalType();

                CodeMemberField intPtrMember = new CodeMemberField();
                intPtrMember.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                intPtrMember.Name       = cursorSpelling;
                intPtrMember.Type       = new CodeTypeReference(typeof(IntPtr));
                yield return(intPtrMember);

                if (pointeeType.Kind == TypeKind.Char_S)
                {
                    CodeMemberProperty stringMember = new CodeMemberProperty();
                    stringMember.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                    stringMember.Name       = cursorSpelling + "String";
                    stringMember.Type       = new CodeTypeReference(typeof(string));

                    stringMember.HasGet = true;
                    stringMember.GetStatements.Add(
                        new CodeMethodReturnStatement(
                            new CodeMethodInvokeExpression(
                                new CodeMethodReferenceExpression(
                                    new CodeTypeReferenceExpression("Utf8Marshal"),
                                    "PtrToStringUtf8"),
                                new CodeFieldReferenceExpression(
                                    new CodeThisReferenceExpression(),
                                    intPtrMember.Name))));

                    yield return(stringMember);
                }

                break;

            case TypeKind.Enum:
                var enumField = new CodeMemberField();
                enumField.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                enumField.Name       = cursorSpelling;
                enumField.Type       = new CodeTypeReference(generator.NameMapping[canonical.GetSpelling()]);
                yield return(enumField);

                break;

            case TypeKind.Record:
                var recordField = new CodeMemberField();
                recordField.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                recordField.Name       = cursorSpelling;
                recordField.Type       = new CodeTypeReference(generator.NameMapping[canonical.GetSpelling()]);
                yield return(recordField);

                break;

            default:
                var field = new CodeMemberField();
                field.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                field.Name       = cursorSpelling;
                field.Type       = new CodeTypeReference(canonical.ToClrType());
                yield return(field);

                break;
            }
        }
Пример #10
0
 public StructVisitor(ModuleGenerator generator)
 {
     this.generator = generator;
 }
Пример #11
0
        public static void Generate(ModuleGenerator generator)
        {
            var nativeMethods = generator.Types.Single(t => t.Name.EndsWith("NativeMethods"));

            CodeTypeDeclaration overloads = new CodeTypeDeclaration();

            generator.Types.Add(overloads);
            overloads.UserData.Add("FileNameSuffix", ".Extensions");
            overloads.Name          = nativeMethods.Name;
            overloads.IsPartial     = true;
            overloads.Attributes    = MemberAttributes.Public | MemberAttributes.Final;
            nativeMethods.IsPartial = true;

            overloads.Name = nativeMethods.Name;

            foreach (var method in nativeMethods.Members.OfType <CodeMemberMethod>())
            {
                bool needsPatching = method
                                     .Parameters
                                     .OfType <CodeParameterDeclarationExpression>()
                                     .Any(p => HasCustomMarshaler(p));

                if (!needsPatching)
                {
                    continue;
                }

                CodeMemberMethod customMethod = new CodeMemberMethod();
                overloads.Members.Add(customMethod);
                customMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
                customMethod.Name       = method.Name;
                customMethod.ReturnType = method.ReturnType;

                bool hasReturnValue = customMethod.ReturnType != null &&
                                      customMethod.ReturnType.BaseType != "System.Void";

                var invokeStatement = new CodeMethodInvokeExpression(
                    new CodeMethodReferenceExpression(
                        new CodeTypeReferenceExpression(nativeMethods.Name),
                        method.Name));

                if (!hasReturnValue)
                {
                    customMethod.Statements.Add(invokeStatement);
                }
                else
                {
                    var resultStatement = new CodeVariableDeclarationStatement(
                        customMethod.ReturnType,
                        "returnValue",
                        invokeStatement);

                    customMethod.Statements.Add(resultStatement);
                }

                foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
                {
                    var customParameter =
                        new CodeParameterDeclarationExpression(
                            parameter.Type,
                            parameter.Name);
                    customParameter.Direction = parameter.Direction;

                    customMethod.Parameters.Add(customParameter);

                    var marshalerAttribute = GetCustomMarshaler(parameter);

                    if (marshalerAttribute != null)
                    {
                        Debug.Assert(marshalerAttribute.Name.EndsWith("MarshalAsAttribute"), "Marshaler");
                        var marshaler = ((CodeTypeOfExpression)marshalerAttribute.Arguments[1].Value).Type;

                        parameter.CustomAttributes.Clear();
                        bool marshalInput  = parameter.Direction == FieldDirection.In || parameter.Direction == FieldDirection.Ref;
                        bool marshalOutput = parameter.Direction == FieldDirection.Out || parameter.Direction == FieldDirection.Ref;

                        // Create the marshaler
                        // ICustomMarshaler [paramName]marshaler = [Marshaler].GetInstance(null);
                        customMethod.Statements.Insert(0,
                                                       new CodeVariableDeclarationStatement(
                                                           new CodeTypeReference(typeof(ICustomMarshaler)),
                                                           parameter.Name + "Marshaler",
                                                           new CodeMethodInvokeExpression(
                                                               new CodeMethodReferenceExpression(
                                                                   new CodeTypeReferenceExpression(marshaler),
                                                                   "GetInstance"),
                                                               new CodePrimitiveExpression(null))));

                        // If the variable is [in] or [ref],
                        // marshal the type from managed to unmanaged,
                        // else, initialize to IntPtr.Zero
                        if (marshalInput)
                        {
                            customMethod.Statements.Insert(1,
                                                           new CodeVariableDeclarationStatement(
                                                               new CodeTypeReference(typeof(IntPtr)),
                                                               parameter.Name + "Native",
                                                               new CodeMethodInvokeExpression(
                                                                   new CodeMethodReferenceExpression(
                                                                       new CodeVariableReferenceExpression(parameter.Name + "Marshaler"),
                                                                       "MarshalManagedToNative"),
                                                                   new CodeArgumentReferenceExpression(
                                                                       parameter.Name))));
                        }
                        else
                        {
                            customMethod.Statements.Insert(1,
                                                           new CodeVariableDeclarationStatement(
                                                               new CodeTypeReference(typeof(IntPtr)),
                                                               parameter.Name + "Native",
                                                               new CodePropertyReferenceExpression(
                                                                   new CodeTypeReferenceExpression(typeof(IntPtr)),
                                                                   "Zero")));
                        }

                        // Invoke the method with the base type
                        invokeStatement.Parameters.Add(
                            new CodeDirectionExpression(
                                parameter.Direction,
                                new CodeVariableReferenceExpression(parameter.Name + "Native")));

                        // Convert from unmanaged to managed, if required
                        if (marshalOutput)
                        {
                            customMethod.Statements.Add(
                                new CodeAssignStatement(
                                    new CodeArgumentReferenceExpression(parameter.Name),
                                    new CodeCastExpression(
                                        parameter.Type,
                                        new CodeMethodInvokeExpression(
                                            new CodeMethodReferenceExpression(
                                                new CodeVariableReferenceExpression(parameter.Name + "Marshaler"),
                                                "MarshalNativeToManaged"),
                                            new CodeArgumentReferenceExpression(
                                                parameter.Name + "Native")))));

                            customMethod.Statements.Add(
                                new CodeMethodInvokeExpression(
                                    new CodeMethodReferenceExpression(
                                        new CodeVariableReferenceExpression(parameter.Name + "Marshaler"),
                                        "CleanUpNativeData"),
                                    new CodeArgumentReferenceExpression(
                                        parameter.Name + "Native")));
                        }

                        // Set the unmanaged type to the primitive
                        parameter.Type = new CodeTypeReference(typeof(IntPtr));
                    }
                    else
                    {
                        invokeStatement.Parameters.Add(
                            new CodeDirectionExpression(
                                parameter.Direction,
                                new CodeArgumentReferenceExpression(parameter.Name)));
                    }
                }

                if (hasReturnValue)
                {
                    customMethod.Statements.Add(
                        new CodeMethodReturnStatement(
                            new CodeVariableReferenceExpression("returnValue")));
                }
            }
        }
Пример #12
0
        public static void Main(string[] args)
        {
            string sourceDirectory = null;
            string targetDirectory = null;

            if (args.Length >= 1)
            {
                sourceDirectory = args[0];
            }
            else
            {
                // Default value so that you can just F5 from within Visual Studio
                sourceDirectory = @"..\..\..\..\";
            }

            if (args.Length >= 2)
            {
                targetDirectory = args[1];
            }
            else
            {
                targetDirectory = @"..\..\..\..\..\iMobileDevice-net";
            }

            RestoreClang();

            var packagesDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");

            sourceDirectory = Path.GetFullPath(sourceDirectory);
            targetDirectory = Path.GetFullPath(targetDirectory);

            Console.WriteLine($"Reading libimobiledevice headers from: {sourceDirectory}");
            Console.WriteLine($"Writing the C# files to: {targetDirectory}");

            var vcpkgPath = Environment.GetEnvironmentVariable("VCPKG_ROOT");

            vcpkgPath = Path.Combine(vcpkgPath, "installed", "x86-windows", "include");
            Console.WriteLine($"Reading include files from {vcpkgPath}");

            ModuleGenerator generator = new ModuleGenerator();

            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio 14.0\VC\include"));
            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio\Shared\14.0\VC\include"));
            generator.IncludeDirectories.Add(GetWindowsKitUcrtFolder());
            generator.IncludeDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Windows Kits", "8.1", "include", "shared"));
            generator.IncludeDirectories.Add(Path.Combine(vcpkgPath));

            Collection <string> names = new Collection <string>();

            var files = new List <string>();

            files.Add(Path.Combine(packagesDirectory, Path.Combine(vcpkgPath, "usbmuxd.h")));
            files.Add(Path.Combine(packagesDirectory, Path.Combine(vcpkgPath, "plist/plist.h")));
            files.Add(Path.Combine(packagesDirectory, Path.Combine(vcpkgPath, "libideviceactivation.h")));

            var iMobileDeviceDirectory = Path.Combine(vcpkgPath, "libimobiledevice");

            files.Add(Path.Combine(iMobileDeviceDirectory, "libimobiledevice.h"));
            files.Add(Path.Combine(iMobileDeviceDirectory, "lockdown.h"));
            files.Add(Path.Combine(iMobileDeviceDirectory, "afc.h"));

            var iMobileDeviceFileNames = Directory.GetFiles(iMobileDeviceDirectory, "*.h")
                                         .Where(f => !files.Contains(f, StringComparer.OrdinalIgnoreCase));

            files.AddRange(iMobileDeviceFileNames);

            foreach (var file in files)
            {
                Console.WriteLine($"Processing {Path.GetFileName(file)}");
                generator.InputFile = file;

                if (string.Equals(Path.GetFileName(file), "libideviceactivation.h", StringComparison.OrdinalIgnoreCase))
                {
                    generator.Generate(targetDirectory, "ideviceactivation");
                }
                else
                {
                    generator.Generate(targetDirectory);
                }

                generator.Types.Clear();

                names.Add(generator.Name);
            }

            ApiGenerator apiGenerator = new ApiGenerator();

            apiGenerator.Generate(names, targetDirectory);
        }
Пример #13
0
        public static CodeTypeDelegate ToDelegate(this CXType type, string nativeName, CXCursor cursor, ModuleGenerator generator)
        {
            if (type.kind != CXTypeKind.CXType_FunctionProto &&
                type.kind != CXTypeKind.CXType_Unexposed)
            {
                throw new InvalidOperationException();
            }

            var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

            CodeTypeDelegate delegateType = new CodeTypeDelegate();

            delegateType.CustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(UnmanagedFunctionPointerAttribute)),
                    new CodeAttributeArgument(
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(CallingConvention)),
                            type.GetCallingConvention().ToString()))));

            delegateType.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            delegateType.Name       = clrName;
            delegateType.ReturnType = new CodeTypeReference(clang.getResultType(type).ToClrType());

            uint argumentCounter = 0;

            clang.visitChildren(
                cursor,
                delegate(CXCursor cxCursor, CXCursor parent1, IntPtr ptr)
            {
                if (cxCursor.kind == CXCursorKind.CXCursor_ParmDecl)
                {
                    delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, cxCursor, argumentCounter++, FunctionType.Delegate));
                }

                return(CXChildVisitResult.CXChildVisit_Continue);
            },
                new CXClientData(IntPtr.Zero));

            return(delegateType);
        }
Пример #14
0
        public static IEnumerable <NustacheGeneratedType> CreateSafeHandle(string name, ModuleGenerator generator)
        {
            yield return(new NustacheGeneratedType(
                             new HandleType(generator.Name, $"{name}Handle"), "Handle.cs.template"));

            yield return(new NustacheGeneratedType(
                             new HandleMarshalerType(generator.Name, $"{name}HandleDelegateMarshaler", $"{name}Handle"), "HandleDelegateMarshaler.cs.template"));
        }
Пример #15
0
        public static IEnumerable <CodeTypeDeclaration> CreateSafeHandle(string name, ModuleGenerator generator)
        {
            CodeTypeDeclaration safeHandle = new CodeTypeDeclaration(name + "Handle");

#if !NETSTANDARD1_5
            safeHandle.CustomAttributes.Add(SecurityPermissionDeclaration(SecurityAction.InheritanceDemand, true));
            safeHandle.CustomAttributes.Add(SecurityPermissionDeclaration(SecurityAction.Demand, true));
#endif
            safeHandle.IsPartial  = true;
            safeHandle.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            safeHandle.BaseTypes.Add(typeof(SafeHandleZeroOrMinusOneIsInvalid));

            // Add a field which stores the stack used to create this object. Useful for troubleshooting issues
            // that may occur when a plist object is being disposed of.
            CodeMemberField stackTraceField = new CodeMemberField();
            stackTraceField.Name       = "creationStackTrace";
            stackTraceField.Type       = new CodeTypeReference(typeof(string));
            stackTraceField.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            safeHandle.Members.Add(stackTraceField);

            var setCreationStackTrace =
                new CodeAssignStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        "creationStackTrace"),
                    new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(typeof(Environment)),
                        "StackTrace"));

            CodeConstructor constructor = new CodeConstructor();
            constructor.Attributes = MemberAttributes.Family;
            constructor.BaseConstructorArgs.Add(new CodePrimitiveExpression(true));
            constructor.Statements.Add(setCreationStackTrace);
            safeHandle.Members.Add(constructor);

            CodeConstructor ownsHandleConstructor = new CodeConstructor();
            ownsHandleConstructor.Attributes = MemberAttributes.Family;
            ownsHandleConstructor.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(bool)), "ownsHandle"));
            ownsHandleConstructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("ownsHandle"));
            ownsHandleConstructor.Statements.Add(setCreationStackTrace);
            safeHandle.Members.Add(ownsHandleConstructor);

            CodeMemberMethod releaseHandle = new CodeMemberMethod();
            releaseHandle.Name       = "ReleaseHandle";
            releaseHandle.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            releaseHandle.ReturnType = new CodeTypeReference(typeof(bool));
            releaseHandle.CustomAttributes.Add(ReliabilityContractDeclaration(Consistency.WillNotCorruptState, Cer.MayFail));

            releaseHandle.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(true)));
            safeHandle.Members.Add(releaseHandle);

            // Add an "Api" property which provides a reference to the instance of the API which was used to
            // create this handle - and which will also be used to destroy this handle.
            CodeMemberField apiField = new CodeMemberField();
            apiField.Name       = "api";
            apiField.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            apiField.Type       = new CodeTypeReference("ILibiMobileDevice");
            safeHandle.Members.Add(apiField);

            CodeMemberProperty apiProperty = new CodeMemberProperty();
            apiProperty.Name       = "Api";
            apiProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            apiProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        apiField.Name)));
            apiProperty.SetStatements.Add(
                new CodeAssignStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        apiField.Name),
                    new CodeVariableReferenceExpression("value")));
            apiProperty.Type = new CodeTypeReference("ILibiMobileDevice");
            safeHandle.Members.Add(apiProperty);

            // Add a "DangeousCreate" method which creates a new safe handle from an IntPtr
            CodeMemberMethod dangerousCreate = new CodeMemberMethod();
            dangerousCreate.Name       = "DangerousCreate";
            dangerousCreate.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            dangerousCreate.ReturnType = new CodeTypeReference(safeHandle.Name);

            dangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(IntPtr)),
                    "unsafeHandle"));

            dangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(bool)),
                    "ownsHandle"));

            dangerousCreate.Statements.Add(
                new CodeVariableDeclarationStatement(
                    new CodeTypeReference(safeHandle.Name),
                    "safeHandle"));

            dangerousCreate.Statements.Add(
                new CodeAssignStatement(
                    new CodeVariableReferenceExpression("safeHandle"),
                    new CodeObjectCreateExpression(
                        new CodeTypeReference(safeHandle.Name),
                        new CodeArgumentReferenceExpression("ownsHandle"))));

            dangerousCreate.Statements.Add(
                new CodeMethodInvokeExpression(
                    new CodeMethodReferenceExpression(
                        new CodeVariableReferenceExpression("safeHandle"),
                        "SetHandle"),
                    new CodeArgumentReferenceExpression("unsafeHandle")));

            dangerousCreate.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeVariableReferenceExpression("safeHandle")));

            safeHandle.Members.Add(dangerousCreate);

            // Add a "DangeousCreate" method which creates a new safe handle from an IntPtr
            CodeMemberMethod simpleDangerousCreate = new CodeMemberMethod();
            simpleDangerousCreate.Name       = "DangerousCreate";
            simpleDangerousCreate.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            simpleDangerousCreate.ReturnType = new CodeTypeReference(safeHandle.Name);

            simpleDangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(IntPtr)),
                    "unsafeHandle"));

            simpleDangerousCreate.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            "DangerousCreate"),
                        new CodeArgumentReferenceExpression("unsafeHandle"),
                        new CodePrimitiveExpression(true))));

            safeHandle.Members.Add(simpleDangerousCreate);

            // Add a "Zero" property which returns an invalid handle
            CodeMemberProperty zeroProperty = new CodeMemberProperty();
            zeroProperty.Name       = "Zero";
            zeroProperty.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            zeroProperty.Type       = new CodeTypeReference(safeHandle.Name);

            zeroProperty.HasGet = true;

            zeroProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            dangerousCreate.Name),
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(IntPtr)),
                            nameof(IntPtr.Zero)))));

            safeHandle.Members.Add(zeroProperty);

            // Create the ToString method which returns:
            // {handle} ({type})
            CodeMemberMethod toStringMethod = new CodeMemberMethod();
            toStringMethod.Name       = "ToString";
            toStringMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            toStringMethod.ReturnType = new CodeTypeReference(typeof(string));
            toStringMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(typeof(string)),
                        "Format",
                        new CodePrimitiveExpression("{0} ({1})"),
                        new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "handle"),
                        new CodePrimitiveExpression(safeHandle.Name))));
            safeHandle.Members.Add(toStringMethod);

            // Create the Equals method:
            //
            // if (!(obj is AfcClientHandle))
            // {
            //    return false;
            // }
            //
            // return ((AfcClientHandle)obj).handle.Equals(this.handle);
            CodeMemberMethod equalsMethod = new CodeMemberMethod();
            equalsMethod.Name       = "Equals";
            equalsMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            equalsMethod.ReturnType = new CodeTypeReference(typeof(bool));
            equalsMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(object)),
                    "obj"));

            equalsMethod.Statements.Add(
                new CodeConditionStatement(
                    new CodeBinaryOperatorExpression(
                        new CodeBinaryOperatorExpression(
                            new CodeArgumentReferenceExpression("obj"),
                            CodeBinaryOperatorType.IdentityInequality,
                            new CodePrimitiveExpression(null)),
                        CodeBinaryOperatorType.BooleanAnd,
                        new CodeBinaryOperatorExpression(
                            new CodeMethodInvokeExpression(
                                new CodeArgumentReferenceExpression("obj"),
                                "GetType"),
                            CodeBinaryOperatorType.IdentityEquality,
                            new CodeTypeOfExpression(safeHandle.Name))),
                    new CodeStatement[]
            {
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeFieldReferenceExpression(
                            new CodeCastExpression(
                                new CodeTypeReference(safeHandle.Name),
                                new CodeArgumentReferenceExpression("obj")),
                            "handle"),
                        "Equals",
                        new CodeFieldReferenceExpression(
                            new CodeThisReferenceExpression(),
                            "handle")))
            },
                    new CodeStatement[]
            {
                new CodeMethodReturnStatement(
                    new CodePrimitiveExpression(false))
            }));

            safeHandle.Members.Add(equalsMethod);

            // Create the GetHashCode method
            // return this.handle.GetHashCode();
            CodeMemberMethod getHashCodeMethod = new CodeMemberMethod();
            getHashCodeMethod.Name       = "GetHashCode";
            getHashCodeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            getHashCodeMethod.ReturnType = new CodeTypeReference(typeof(int));
            getHashCodeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeFieldReferenceExpression(
                            new CodeThisReferenceExpression(),
                            "handle"),
                        "GetHashCode")));
            safeHandle.Members.Add(getHashCodeMethod);

            yield return(safeHandle);

            // Create the marshaler type
            CodeTypeDeclaration safeHandleMarshaler = new CodeTypeDeclaration();
            safeHandleMarshaler.Name       = name + "HandleDelegateMarshaler";
            safeHandleMarshaler.IsPartial  = true;
            safeHandleMarshaler.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            safeHandleMarshaler.BaseTypes.Add(typeof(ICustomMarshaler));

            // Create the GetInstance method
            CodeMemberMethod getInstanceMethod = new CodeMemberMethod();
            getInstanceMethod.Name       = "GetInstance";
            getInstanceMethod.ReturnType = new CodeTypeReference(typeof(ICustomMarshaler));
            getInstanceMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public;
            getInstanceMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "cookie"));
            getInstanceMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeObjectCreateExpression(safeHandleMarshaler.Name)));
            safeHandleMarshaler.Members.Add(getInstanceMethod);

            // Create the CleanUpManagedData method
            CodeMemberMethod cleanUpManagedData = new CodeMemberMethod();
            cleanUpManagedData.Name       = "CleanUpManagedData";
            cleanUpManagedData.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            cleanUpManagedData.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "managedObject"));
            safeHandleMarshaler.Members.Add(cleanUpManagedData);

            // Create the CleanUpNativeData method
            CodeMemberMethod cleanUpNativeDataMethod = new CodeMemberMethod();
            cleanUpNativeDataMethod.Name       = "CleanUpNativeData";
            cleanUpNativeDataMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            cleanUpNativeDataMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IntPtr), "nativeData"));
            safeHandleMarshaler.Members.Add(cleanUpNativeDataMethod);

            // Create the GetNativeDataSize method
            CodeMemberMethod getNativeDataSizeMethod = new CodeMemberMethod();
            getNativeDataSizeMethod.Name       = "GetNativeDataSize";
            getNativeDataSizeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            getNativeDataSizeMethod.ReturnType = new CodeTypeReference(typeof(int));
            getNativeDataSizeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodePrimitiveExpression(-1)));
            safeHandleMarshaler.Members.Add(getNativeDataSizeMethod);

            // Create the MarshalManagedToNative method
            CodeMemberMethod marshalManagedToNativeMethod = new CodeMemberMethod();
            marshalManagedToNativeMethod.Name       = "MarshalManagedToNative";
            marshalManagedToNativeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            marshalManagedToNativeMethod.ReturnType = new CodeTypeReference(typeof(IntPtr));
            marshalManagedToNativeMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    typeof(object),
                    "managedObject"));
            marshalManagedToNativeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(typeof(IntPtr)),
                        nameof(IntPtr.Zero))));
            safeHandleMarshaler.Members.Add(marshalManagedToNativeMethod);

            // Create the MarshalNativeToManaged method
            CodeMemberMethod marshalNativeToManagedMethod = new CodeMemberMethod();
            marshalNativeToManagedMethod.Name       = "MarshalNativeToManaged";
            marshalNativeToManagedMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            marshalNativeToManagedMethod.ReturnType = new CodeTypeReference(typeof(object));
            marshalNativeToManagedMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    typeof(IntPtr),
                    "nativeData"));
            marshalNativeToManagedMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            "DangerousCreate"),
                        new CodeArgumentReferenceExpression("nativeData"),

                        // ownsHandle: false
                        new CodePrimitiveExpression(false))));
            safeHandleMarshaler.Members.Add(marshalNativeToManagedMethod);

            yield return(safeHandleMarshaler);
        }
Пример #16
0
 public FunctionVisitor(ModuleGenerator generator, string libraryName)
 {
     this.generator   = generator;
     this.libraryName = libraryName;
 }
Пример #17
0
        public static CodeTypeDelegate ToDelegate(this TypeInfo type, string nativeName, Cursor cursor, ModuleGenerator generator)
        {
            if (type.Kind != TypeKind.FunctionProto &&
                type.Kind != TypeKind.Unexposed)
            {
                throw new InvalidOperationException();
            }

            var clrName = NameConversions.ToClrName(nativeName, NameConversion.Type);

            CodeTypeDelegate delegateType = new CodeTypeDelegate();

            delegateType.CustomAttributes.Add(
                new CodeAttributeDeclaration(
                    new CodeTypeReference(typeof(UnmanagedFunctionPointerAttribute)),
                    new CodeAttributeArgument(
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(CallingConvention)),
                            type.GetCallingConvention().ToString()))));

            delegateType.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            delegateType.Name       = clrName;
            delegateType.ReturnType = new CodeTypeReference(type.GetResultType().ToClrType());

            uint argumentCounter = 0;

            var cursorVisitor = new DelegatingCursorVisitor(
                delegate(Cursor c, Cursor parent1)
            {
                if (c.Kind == CursorKind.ParmDecl)
                {
                    delegateType.Parameters.Add(Argument.GenerateArgument(generator, type, c, argumentCounter++, FunctionType.Delegate));
                }

                return(ChildVisitResult.Continue);
            });

            cursorVisitor.VisitChildren(cursor);

            return(delegateType);
        }
Пример #18
0
        public static IEnumerable <CodeTypeDeclaration> CreateSafeHandle(string name, ModuleGenerator generator)
        {
            CodeTypeDeclaration safeHandle = new CodeTypeDeclaration(name + "Handle");

#if !NETSTANDARD1_5
            safeHandle.CustomAttributes.Add(SecurityPermissionDeclaration(SecurityAction.InheritanceDemand, true));
            safeHandle.CustomAttributes.Add(SecurityPermissionDeclaration(SecurityAction.Demand, true));
#endif
            safeHandle.IsPartial  = true;
            safeHandle.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            safeHandle.BaseTypes.Add(typeof(SafeHandleZeroOrMinusOneIsInvalid));

            // Add a field which stores the stack used to create this object. Useful for troubleshooting issues
            // that may occur when a plist object is being disposed of.
            CodeMemberField stackTraceField = new CodeMemberField();
            stackTraceField.Name       = "creationStackTrace";
            stackTraceField.Type       = new CodeTypeReference(typeof(string));
            stackTraceField.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            safeHandle.Members.Add(stackTraceField);

            var setCreationStackTrace =
                new CodeAssignStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        "creationStackTrace"),
                    new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(typeof(Environment)),
                        "StackTrace"));

            CodeConstructor constructor = new CodeConstructor();
            constructor.Attributes = MemberAttributes.Family;
            constructor.BaseConstructorArgs.Add(new CodePrimitiveExpression(true));
            constructor.Statements.Add(setCreationStackTrace);
            constructor.Comments.Add(new CodeCommentStatement($@"<summary>
Initializes a new instance of the <see cref=""{safeHandle.Name}""/> class.
</summary>"));
            safeHandle.Members.Add(constructor);

            CodeConstructor ownsHandleConstructor = new CodeConstructor();
            ownsHandleConstructor.Attributes = MemberAttributes.Family;
            ownsHandleConstructor.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(bool)), "ownsHandle"));
            ownsHandleConstructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("ownsHandle"));
            ownsHandleConstructor.Statements.Add(setCreationStackTrace);
            ownsHandleConstructor.Comments.Add(new CodeCommentStatement($@"<summary>
Initializes a new instance of the <see cref=""{safeHandle.Name}""/> class, specifying whether the handle is to be reliably released.
</summary>
<param name=""ownsHandle"">
<see langword=""true""/> to reliably release the handle during the finalization phase; <see langword=""false""/> to prevent reliable release (not recommended).
</param>"));
            safeHandle.Members.Add(ownsHandleConstructor);

            CodeMemberMethod releaseHandle = new CodeMemberMethod();
            releaseHandle.Name       = "ReleaseHandle";
            releaseHandle.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            releaseHandle.ReturnType = new CodeTypeReference(typeof(bool));
            releaseHandle.CustomAttributes.Add(ReliabilityContractDeclaration(Consistency.WillNotCorruptState, Cer.MayFail));
            releaseHandle.Comments.Add(new CodeCommentStatement("<inheritdoc/>"));

            releaseHandle.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(true)));
            safeHandle.Members.Add(releaseHandle);

            // Add an "Api" property which provides a reference to the instance of the API which was used to
            // create this handle - and which will also be used to destroy this handle.
            CodeMemberField apiField = new CodeMemberField();
            apiField.Name       = "api";
            apiField.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            apiField.Type       = new CodeTypeReference("ILibiMobileDevice");
            safeHandle.Members.Add(apiField);

            CodeMemberProperty apiProperty = new CodeMemberProperty();
            apiProperty.Name       = "Api";
            apiProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            apiProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        apiField.Name)));
            apiProperty.SetStatements.Add(
                new CodeAssignStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        apiField.Name),
                    new CodeVariableReferenceExpression("value")));
            apiProperty.Type = new CodeTypeReference("ILibiMobileDevice");
            apiProperty.Comments.Add(new CodeCommentStatement(@"<summary>
Gets or sets the API to use
</summary>"));
            safeHandle.Members.Add(apiProperty);

            // Add a "DangeousCreate" method which creates a new safe handle from an IntPtr
            CodeMemberMethod dangerousCreate = new CodeMemberMethod();
            dangerousCreate.Name       = "DangerousCreate";
            dangerousCreate.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            dangerousCreate.ReturnType = new CodeTypeReference(safeHandle.Name);
            dangerousCreate.Comments.Add(new CodeCommentStatement($@"<summary>
Creates a new <see cref=""{safeHandle.Name}""/> from a <see cref=""IntPtr""/>.
</summary>
<param name=""unsafeHandle"">
The underlying <see cref=""IntPtr""/>
</param>
<param name=""ownsHandle"">
<see langword=""true""/> to reliably release the handle during the finalization phase; <see langword=""false""/> to prevent reliable release (not recommended).
</param>
<returns>
</returns>"));

            dangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(IntPtr)),
                    "unsafeHandle"));

            dangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(bool)),
                    "ownsHandle"));

            dangerousCreate.Statements.Add(
                new CodeVariableDeclarationStatement(
                    new CodeTypeReference(safeHandle.Name),
                    "safeHandle"));

            dangerousCreate.Statements.Add(
                new CodeAssignStatement(
                    new CodeVariableReferenceExpression("safeHandle"),
                    new CodeObjectCreateExpression(
                        new CodeTypeReference(safeHandle.Name),
                        new CodeArgumentReferenceExpression("ownsHandle"))));

            dangerousCreate.Statements.Add(
                new CodeMethodInvokeExpression(
                    new CodeMethodReferenceExpression(
                        new CodeVariableReferenceExpression("safeHandle"),
                        "SetHandle"),
                    new CodeArgumentReferenceExpression("unsafeHandle")));

            dangerousCreate.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeVariableReferenceExpression("safeHandle")));

            safeHandle.Members.Add(dangerousCreate);

            // Add a "DangeousCreate" method which creates a new safe handle from an IntPtr
            CodeMemberMethod simpleDangerousCreate = new CodeMemberMethod();
            simpleDangerousCreate.Name       = "DangerousCreate";
            simpleDangerousCreate.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            simpleDangerousCreate.ReturnType = new CodeTypeReference(safeHandle.Name);
            simpleDangerousCreate.Comments.Add(new CodeCommentStatement($@"<summary>
Creates a new <see cref=""{safeHandle.Name}""/> from a <see cref=""IntPtr""/>.
</summary>
<param name=""unsafeHandle"">
The underlying <see cref=""IntPtr""/>
</param>
<returns>
</returns>"));

            simpleDangerousCreate.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(IntPtr)),
                    "unsafeHandle"));

            simpleDangerousCreate.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            "DangerousCreate"),
                        new CodeArgumentReferenceExpression("unsafeHandle"),
                        new CodePrimitiveExpression(true))));

            safeHandle.Members.Add(simpleDangerousCreate);

            // Add a "Zero" property which returns an invalid handle
            CodeMemberProperty zeroProperty = new CodeMemberProperty();
            zeroProperty.Name       = "Zero";
            zeroProperty.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            zeroProperty.Type       = new CodeTypeReference(safeHandle.Name);
            zeroProperty.Comments.Add(new CodeCommentStatement(@"<summary>
Gets a value which represents a pointer or handle that has been initialized to zero.
</summary>"));

            zeroProperty.HasGet = true;

            zeroProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            dangerousCreate.Name),
                        new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(typeof(IntPtr)),
                            nameof(IntPtr.Zero)))));

            safeHandle.Members.Add(zeroProperty);

            // Create the ToString method which returns:
            // {handle} ({type})
            CodeMemberMethod toStringMethod = new CodeMemberMethod();
            toStringMethod.Name       = "ToString";
            toStringMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            toStringMethod.ReturnType = new CodeTypeReference(typeof(string));
            toStringMethod.Comments.Add(new CodeCommentStatement("<inheritdoc/>"));
            toStringMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(typeof(string)),
                        "Format",
                        new CodePrimitiveExpression("{0} ({1})"),
                        new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "handle"),
                        new CodePrimitiveExpression(safeHandle.Name))));
            safeHandle.Members.Add(toStringMethod);

            // Create the Equals method:
            //
            // if (!(obj is AfcClientHandle))
            // {
            //    return false;
            // }
            //
            // return ((AfcClientHandle)obj).handle.Equals(this.handle);
            CodeMemberMethod equalsMethod = new CodeMemberMethod();
            equalsMethod.Name       = "Equals";
            equalsMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            equalsMethod.ReturnType = new CodeTypeReference(typeof(bool));
            equalsMethod.Comments.Add(new CodeCommentStatement("<inheritdoc/>"));
            equalsMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(object)),
                    "obj"));

            equalsMethod.Statements.Add(
                new CodeConditionStatement(
                    new CodeBinaryOperatorExpression(
                        new CodeBinaryOperatorExpression(
                            new CodeArgumentReferenceExpression("obj"),
                            CodeBinaryOperatorType.IdentityInequality,
                            new CodePrimitiveExpression(null)),
                        CodeBinaryOperatorType.BooleanAnd,
                        new CodeBinaryOperatorExpression(
                            new CodeMethodInvokeExpression(
                                new CodeArgumentReferenceExpression("obj"),
                                "GetType"),
                            CodeBinaryOperatorType.IdentityEquality,
                            new CodeTypeOfExpression(safeHandle.Name))),
                    new CodeStatement[]
            {
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeFieldReferenceExpression(
                            new CodeCastExpression(
                                new CodeTypeReference(safeHandle.Name),
                                new CodeArgumentReferenceExpression("obj")),
                            "handle"),
                        "Equals",
                        new CodeFieldReferenceExpression(
                            new CodeThisReferenceExpression(),
                            "handle")))
            },
                    new CodeStatement[]
            {
                new CodeMethodReturnStatement(
                    new CodePrimitiveExpression(false))
            }));

            safeHandle.Members.Add(equalsMethod);

            // Override the operators
            safeHandle.Members.Add(new CodeSnippetTypeMember($@"/// <summary>
/// Determines whether two specified instances of <see cref=""{safeHandle.Name}""/> are equal.
/// </summary>
/// <param name=""value1"">
/// The first pointer or handle to compare.
/// </param>
/// <param name=""value2"">
/// The second pointer or handle to compare.
/// </param>
/// <returns>
/// <see langword=""true""/> if <paramref name=""value1""/> equals <paramref name=""value2""/>; otherwise, <see langword=""false""/>.
/// </returns>
public static bool operator == ({safeHandle.Name} value1, {safeHandle.Name} value2) 
{{
    if (object.Equals(value1, null) && object.Equals(value2, null))
    {{
        return true;
    }}

    if (object.Equals(value1, null) || object.Equals(value2, null))
    {{
        return false;
    }}

    return value1.handle == value2.handle;
}}"));

            safeHandle.Members.Add(new CodeSnippetTypeMember($@"/// <summary>
/// Determines whether two specified instances of <see cref=""{safeHandle.Name}""/> are not equal.
/// </summary>
/// <param name=""value1"">
/// The first pointer or handle to compare.
/// </param>
/// <param name=""value2"">
/// The second pointer or handle to compare.
/// </param>
/// <returns>
/// <see langword=""true""/> if <paramref name=""value1""/> does not equal <paramref name=""value2""/>; otherwise, <see langword=""false""/>.
/// </returns>
public static bool operator != ({safeHandle.Name} value1, {safeHandle.Name} value2) 
{{
    if (object.Equals(value1, null) && object.Equals(value2, null))
    {{
        return false;
    }}

    if (object.Equals(value1, null) || object.Equals(value2, null))
    {{
        return true;
    }}

    return value1.handle != value2.handle;
}}"));

            // Create the GetHashCode method
            // return this.handle.GetHashCode();
            CodeMemberMethod getHashCodeMethod = new CodeMemberMethod();
            getHashCodeMethod.Name       = "GetHashCode";
            getHashCodeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            getHashCodeMethod.ReturnType = new CodeTypeReference(typeof(int));
            getHashCodeMethod.Comments.Add(new CodeCommentStatement("<inheritdoc/>"));
            getHashCodeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeFieldReferenceExpression(
                            new CodeThisReferenceExpression(),
                            "handle"),
                        "GetHashCode")));
            safeHandle.Members.Add(getHashCodeMethod);

            yield return(safeHandle);

            // Create the marshaler type
            CodeTypeDeclaration safeHandleMarshaler = new CodeTypeDeclaration();
            safeHandleMarshaler.Name       = name + "HandleDelegateMarshaler";
            safeHandleMarshaler.IsPartial  = true;
            safeHandleMarshaler.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            safeHandleMarshaler.BaseTypes.Add(typeof(ICustomMarshaler));

            // Create the GetInstance method
            CodeMemberMethod getInstanceMethod = new CodeMemberMethod();
            getInstanceMethod.Name       = "GetInstance";
            getInstanceMethod.ReturnType = new CodeTypeReference(typeof(ICustomMarshaler));
            getInstanceMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public;
            getInstanceMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "cookie"));
            getInstanceMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeObjectCreateExpression(safeHandleMarshaler.Name)));
            safeHandleMarshaler.Members.Add(getInstanceMethod);

            // Create the CleanUpManagedData method
            CodeMemberMethod cleanUpManagedData = new CodeMemberMethod();
            cleanUpManagedData.Name       = "CleanUpManagedData";
            cleanUpManagedData.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            cleanUpManagedData.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "managedObject"));
            safeHandleMarshaler.Members.Add(cleanUpManagedData);

            // Create the CleanUpNativeData method
            CodeMemberMethod cleanUpNativeDataMethod = new CodeMemberMethod();
            cleanUpNativeDataMethod.Name       = "CleanUpNativeData";
            cleanUpNativeDataMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            cleanUpNativeDataMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IntPtr), "nativeData"));
            safeHandleMarshaler.Members.Add(cleanUpNativeDataMethod);

            // Create the GetNativeDataSize method
            CodeMemberMethod getNativeDataSizeMethod = new CodeMemberMethod();
            getNativeDataSizeMethod.Name       = "GetNativeDataSize";
            getNativeDataSizeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            getNativeDataSizeMethod.ReturnType = new CodeTypeReference(typeof(int));
            getNativeDataSizeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodePrimitiveExpression(-1)));
            safeHandleMarshaler.Members.Add(getNativeDataSizeMethod);

            // Create the MarshalManagedToNative method
            CodeMemberMethod marshalManagedToNativeMethod = new CodeMemberMethod();
            marshalManagedToNativeMethod.Name       = "MarshalManagedToNative";
            marshalManagedToNativeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            marshalManagedToNativeMethod.ReturnType = new CodeTypeReference(typeof(IntPtr));
            marshalManagedToNativeMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    typeof(object),
                    "managedObject"));
            marshalManagedToNativeMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(typeof(IntPtr)),
                        nameof(IntPtr.Zero))));
            safeHandleMarshaler.Members.Add(marshalManagedToNativeMethod);

            // Create the MarshalNativeToManaged method
            CodeMemberMethod marshalNativeToManagedMethod = new CodeMemberMethod();
            marshalNativeToManagedMethod.Name       = "MarshalNativeToManaged";
            marshalNativeToManagedMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            marshalNativeToManagedMethod.ReturnType = new CodeTypeReference(typeof(object));
            marshalNativeToManagedMethod.Parameters.Add(
                new CodeParameterDeclarationExpression(
                    typeof(IntPtr),
                    "nativeData"));
            marshalNativeToManagedMethod.Statements.Add(
                new CodeMethodReturnStatement(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodeTypeReferenceExpression(safeHandle.Name),
                            "DangerousCreate"),
                        new CodeArgumentReferenceExpression("nativeData"),

                        // ownsHandle: false
                        new CodePrimitiveExpression(false))));
            safeHandleMarshaler.Members.Add(marshalNativeToManagedMethod);

            yield return(safeHandleMarshaler);
        }