public ArrayMarshalerGenerator(ModuleGenerator generator) { if (generator == null) { throw new ArgumentNullException(nameof(generator)); } this.generator = generator; }
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; }
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")); }
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); }
public EnumVisitor(ModuleGenerator generator) { this.generator = generator; }
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); }
public TypeDefVisitor(ModuleGenerator generator) { this.generator = generator; }
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())); } }
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; } }
public StructVisitor(ModuleGenerator generator) { this.generator = generator; }
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"))); } } }
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); }
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); }
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")); }
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); }
public FunctionVisitor(ModuleGenerator generator, string libraryName) { this.generator = generator; this.libraryName = libraryName; }
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); }
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); }