Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions DllImportGenerator/Ancillary.Interop/Ancillary.Interop.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#nullable enable

namespace System.Runtime.InteropServices
{
// [TODO] Remove once the attribute has been added to the BCL
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class GeneratedDllImportAttribute : Attribute
{
public bool BestFitMapping;
public CallingConvention CallingConvention;
public CharSet CharSet;
public string? EntryPoint;
public bool ExactSpelling;
public bool PreserveSig;
public bool SetLastError;
public bool ThrowOnUnmappableChar;

public GeneratedDllImportAttribute(string dllName)
{
this.Value = dllName;
}

public string Value { get; private set; }
}
}
1 change: 1 addition & 0 deletions DllImportGenerator/Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Ancillary.Interop\Ancillary.Interop.csproj" />
<ProjectReference Include="..\DllImportGenerator\DllImportGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

Expand Down
90 changes: 90 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/CodeSnippets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,50 @@ partial class Test
[GeneratedDllImport(""DoesNotExist"", EntryPoint=""UserDefinedEntryPoint"")]
public static partial void NotAnExport();
}
";

/// <summary>
/// Declaration with all DllImport named arguments.
/// </summary>
public static readonly string AllDllImportNamedArguments = @"
using System.Runtime.InteropServices;
partial class Test
{
[GeneratedDllImport(""DoesNotExist"",
BestFitMapping = false,
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Unicode,
EntryPoint = ""UserDefinedEntryPoint"",
ExactSpelling = true,
PreserveSig = false,
SetLastError = true,
ThrowOnUnmappableChar = true)]
public static partial void Method();
}
";

/// <summary>
/// Declaration using various methods to compute constants in C#.
/// </summary>
public static readonly string UseCSharpFeaturesForConstants = @"
using System.Runtime.InteropServices;
partial class Test
{
private const bool IsTrue = true;
private const bool IsFalse = false;
private const string EntryPointName = nameof(Test) + nameof(IsFalse);

[GeneratedDllImport(nameof(Test),
BestFitMapping = 0 != 1,
CallingConvention = (CallingConvention)1,
CharSet = (CharSet)2,
EntryPoint = EntryPointName,
ExactSpelling = IsTrue,
PreserveSig = IsFalse,
SetLastError = !IsFalse,
ThrowOnUnmappableChar = !IsTrue)]
public static partial void Method();
}
";

/// <summary>
Expand Down Expand Up @@ -181,6 +225,52 @@ partial class Test
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method(int t = 0);
}
";

/// <summary>
/// Apply MarshalAsAttribute to parameters and return types.
/// </summary>
public static readonly string MarshalAsAttributeOnTypes = @"
using System;
using System.Runtime.InteropServices;
namespace NS
{
class MyCustomMarshaler : ICustomMarshaler
{
static ICustomMarshaler GetInstance(string pstrCookie)
=> new MyCustomMarshaler();

public void CleanUpManagedData(object ManagedObj)
=> throw new NotImplementedException();

public void CleanUpNativeData(IntPtr pNativeData)
=> throw new NotImplementedException();

public int GetNativeDataSize()
=> throw new NotImplementedException();

public IntPtr MarshalManagedToNative(object ManagedObj)
=> throw new NotImplementedException();

public object MarshalNativeToManaged(IntPtr pNativeData)
=> throw new NotImplementedException();
}
}

partial class Test
{
[GeneratedDllImport(""DoesNotExist"")]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static partial string Method1([MarshalAs(UnmanagedType.LPStr)]string t);

[GeneratedDllImport(""DoesNotExist"")]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static partial string Method2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NS.MyCustomMarshaler), MarshalCookie=""COOKIE1"")]string t);

[GeneratedDllImport(""DoesNotExist"")]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static partial string Method3([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = ""NS.MyCustomMarshaler"", MarshalCookie=""COOKIE2"")]string t);
}
";

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/Compiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ public static IEnumerable<object[]> CodeSnippetsToCompile()
yield return new[] { CodeSnippets.NestedNamespace };
yield return new[] { CodeSnippets.NestedTypes };
yield return new[] { CodeSnippets.UserDefinedEntryPoint };
yield return new[] { CodeSnippets.AllDllImportNamedArguments };
yield return new[] { CodeSnippets.BasicParametersAndModifiers };
yield return new[] { CodeSnippets.DefaultParameters };
yield return new[] { CodeSnippets.UseCSharpFeaturesForConstants };
yield return new[] { CodeSnippets.MarshalAsAttributeOnTypes };
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Ancillary.Interop\Ancillary.Interop.csproj" />
<ProjectReference Include="..\DllImportGenerator\DllImportGenerator.csproj" />
</ItemGroup>

Expand Down
22 changes: 20 additions & 2 deletions DllImportGenerator/DllImportGenerator.Test/TestUtils.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Xunit;

namespace DllImportGenerator.Test
Expand Down Expand Up @@ -34,10 +36,26 @@ public static void AssertPreSourceGeneratorCompilation(Compilation comp)
/// <param name="outputKind">Output type</param>
/// <returns>The resulting compilation</returns>
public static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
=> CSharpCompilation.Create("compilation",
{
var mdRefs = new List<MetadataReference>();

// Include the assembly containing the new attribute and all of its references.
// [TODO] Remove once the attribute has been added to the BCL
var attrAssem = typeof(GeneratedDllImportAttribute).GetTypeInfo().Assembly;
mdRefs.Add(MetadataReference.CreateFromFile(attrAssem.Location));
foreach (var assemName in attrAssem.GetReferencedAssemblies())
{
var assemRef = Assembly.Load(assemName);
mdRefs.Add(MetadataReference.CreateFromFile(assemRef.Location));
}

// Add a CoreLib reference
mdRefs.Add(MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location));
return CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
mdRefs,
new CSharpCompilationOptions(outputKind));
}

/// <summary>
/// Run the supplied generators on the compilation.
Expand Down
8 changes: 7 additions & 1 deletion DllImportGenerator/DllImportGenerator.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator", "DllIm
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator.Test", "DllImportGenerator.Test\DllImportGenerator.Test.csproj", "{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{E478EE77-E072-4A42-B453-EBFDA7728717}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "Demo\Demo.csproj", "{E478EE77-E072-4A42-B453-EBFDA7728717}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ancillary.Interop", "Ancillary.Interop\Ancillary.Interop.csproj", "{E59F0B6A-1137-4179-A91D-33464A775DEB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -27,6 +29,10 @@ Global
{E478EE77-E072-4A42-B453-EBFDA7728717}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Release|Any CPU.Build.0 = Release|Any CPU
{E59F0B6A-1137-4179-A91D-33464A775DEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E59F0B6A-1137-4179-A91D-33464A775DEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E59F0B6A-1137-4179-A91D-33464A775DEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E59F0B6A-1137-4179-A91D-33464A775DEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Loading