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
14 changes: 10 additions & 4 deletions Source/ExcelDna.Integration/Registration/ParamsRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ static LambdaExpression WrapMethodParams(LambdaExpression functionLambda)
*
*/

int maxArguments = 125; // Constrained by 255 char registration string, take off 3 type chars, use up to 2 chars per param (before we start doing object...) (& also return)
// CONSIDER: Might improve this if we generate the delegate based on the max length...
int maxArguments = NativeAOT.IsActive ? 16 : 125; // Constrained by 255 char registration string, take off 3 type chars, use up to 2 chars per param (before we start doing object...) (& also return)
// CONSIDER: Might improve this if we generate the delegate based on the max length...

var normalParams = functionLambda.Parameters.Take(functionLambda.Parameters.Count() - 1).ToList();
var normalParamCount = normalParams.Count;
Expand Down Expand Up @@ -210,13 +210,19 @@ static LambdaExpression WrapMethodParams(LambdaExpression functionLambda)
if (maxArguments == 125)
{
delegateType = typeof(CustomFunc125<,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>)
.MakeGenericType(allParamTypes.ToArray());
.MakeGenericType(allParamTypes.ToArray());
}
else // if (maxArguments == 29)
else if (maxArguments == 29)
{
delegateType = typeof(CustomFunc29<,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>)
.MakeGenericType(allParamTypes.ToArray());
}
else // if (maxArguments == 16)
{
delegateType = typeof(Func<,,,,,,,,,,,,,,,,>)
.MakeGenericType(allParamTypes.ToArray());
}

return Expression.Lambda(delegateType, blockExpr, allParamExprs);
}
}
Expand Down
23 changes: 18 additions & 5 deletions Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public void Execute(GeneratorExecutionContext context)

string source = """
// <auto-generated/>
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

Expand All @@ -44,7 +47,7 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll,

[ADDINS]

[FUNCTIONS]
[FUNCTIONS]

return ExcelDna.ManagedHost.AddInInitialize.InitializeNativeAOT(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath);
}
Expand All @@ -68,16 +71,26 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll,
source = source.Replace("[ADDINS]", addIns);
}
{
string functions = "List<Type> functionTypes = new List<Type>();\r\n";
string functions = "List<Type> typeRefs = new List<Type>();\r\n";
string methods = "List<MethodInfo> methodRefs = new List<MethodInfo>();\r\n";
foreach (var i in receiver.Functions)
{
functions += $"ExcelDna.Integration.NativeAOT.MethodsForRegistration.Add(typeof({Util.GetFullTypeName(i.ContainingType)}).GetMethod(\"{i.Name}\")!);\r\n";
functions += $"functionTypes.Add(typeof({Util.MethodType(i)}));\r\n";
functions += $"typeRefs.Add(typeof({Util.MethodType(i)}));\r\n";
foreach (var p in i.Parameters)
functions += $"functionTypes.Add(typeof(Func<object, {Util.GetFullTypeName(p.Type)}>));\r\n";
{
functions += $"typeRefs.Add(typeof(Func<object, {Util.GetFullTypeName(p.Type)}>));\r\n";
}

if (i.Parameters.Length > 0 && i.Parameters.Last().IsParams && i.Parameters.Last().Type is IArrayTypeSymbol arrayType)
{
methods += $"methodRefs.Add(typeof(List<{Util.GetFullTypeName(arrayType.ElementType)}>).GetMethod(\"ToArray\")!);\r\n";
functions += $"typeRefs.Add(typeof(Func<{Util.CreateFunc16Args(i)}>));\r\n";
}

functions += "\r\n";
}
source = source.Replace("[FUNCTIONS]", functions);
source = source.Replace("[FUNCTIONS]", functions + methods);
}

context.AddSource($"ExcelDna.SG.NAOT.Init.g.cs", source);
Expand Down
13 changes: 13 additions & 0 deletions Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ public static string MethodType(IMethodSymbol method)
$"Func<{(string.IsNullOrWhiteSpace(parameters) ? null : $"{parameters}, ")}{GetFullTypeName(method.ReturnType)}>";
}

public static string CreateFunc16Args(IMethodSymbol method)
{
List<ITypeSymbol?> allParamTypes = method.Parameters.Take(method.Parameters.Length - 1).Select(p => p.Type).Cast<ITypeSymbol?>().ToList();
var toAdd = 16 - allParamTypes.Count;
for (int i = 0; i < toAdd; i++)
{
allParamTypes.Add(null);
}
allParamTypes.Add(method.ReturnType);

return string.Join(",", allParamTypes.Select(i => i == null ? "object" : GetFullTypeName(i)));
}

private static SymbolDisplayFormat FullNameFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
}
}
11 changes: 11 additions & 0 deletions Source/ExcelDna.sln
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.AddIn.RuntimeTests
{D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} = {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.SourceGenerator.NativeAOT.Tests", "Tests\ExcelDna.SourceGenerator.NativeAOT.Tests\ExcelDna.SourceGenerator.NativeAOT.Tests.csproj", "{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Expand Down Expand Up @@ -292,6 +294,14 @@ Global
{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU
{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.ActiveCfg = Release|Any CPU
{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.Build.0 = Release|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Debug|Win32.ActiveCfg = Debug|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Debug|Win32.Build.0 = Debug|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Debug|x64.ActiveCfg = Debug|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Debug|x64.Build.0 = Debug|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Release|Win32.ActiveCfg = Release|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Release|Win32.Build.0 = Release|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Release|x64.ActiveCfg = Release|Any CPU
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -311,6 +321,7 @@ Global
{7CA501E1-FB74-4903-B34D-EFE513C5B428} = {511CE610-5E55-457F-B818-1522D1A96727}
{151AE960-6320-402D-BDD0-D76DF96F2BD7} = {511CE610-5E55-457F-B818-1522D1A96727}
{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F} = {511CE610-5E55-457F-B818-1522D1A96727}
{D47CC5BF-712E-4FFA-BE52-E783BDCC6D33} = {511CE610-5E55-457F-B818-1522D1A96727}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {69EF43B0-B903-4775-BC81-C7E7E012EDA3}
Expand Down
68 changes: 68 additions & 0 deletions Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,73 @@ public static string NativeRangeAddress(IRange r)
{
return "Native Address: " + r.Get<string>("Address");
}

[ExcelFunction]
public static string NativeEnum(DateTimeKind e)
{
return "Native Enum VAL: " + e.ToString();
}

[ExcelFunction]
public static DateTimeKind NativeEnumReturn(string s)
{
return Enum.Parse<DateTimeKind>(s);
}

[ExcelFunction]
public static string NativeStringArray(string[] s)
{
return "Native StringArray VALS: " + string.Concat(s);
}

[ExcelFunction]
public static string NativeStringArray2D(string[,] s)
{
string result = "";
for (int i = 0; i < s.GetLength(0); i++)
{
for (int j = 0; j < s.GetLength(1); j++)
{
result += s[i, j];
}

result += " ";
}

return $"Native StringArray2D VALS: {result}";
}

[ExcelFunction]
public static string NativeParamsFunc1(
[ExcelArgument(Name = "first.Input", Description = "is a useful start")]
object input,
[ExcelArgument(Description = "is another param start")]
string QtherInpEt,
[ExcelArgument(Name = "Value", Description = "gives the Rest")]
params object[] args)
{
return input + "," + QtherInpEt + ", : " + args.Length;
}

[ExcelFunction]
public static string NativeParamsFunc2(
[ExcelArgument(Name = "first.Input", Description = "is a useful start")]
object input,
[ExcelArgument(Name = "second.Input", Description = "is some more stuff")]
string input2,
[ExcelArgument(Description = "is another param ")]
string QtherInpEt,
[ExcelArgument(Name = "Value", Description = "gives the Rest")]
params object[] args)
{
var content = string.Join(",", args.Select(ValueType => ValueType.ToString()));
return input + "," + input2 + "," + QtherInpEt + ", " + $"[{args.Length}: {content}]";
}

[ExcelFunction]
public static string NativeParamsJoinString(string separator, params string[] values)
{
return String.Join(separator, values);
}
}
}
90 changes: 90 additions & 0 deletions Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,95 @@ public void Range()
functionRange3.Formula = "=NativeRangeAddress((B2,D5:E6))";
Assert.Equal("Native Address: $B$2,$D$5:$E$6", functionRange3.Value.ToString());
}

[ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)]
public void Enum()
{
Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"];
functionRange.Formula = "=NativeEnum(\"Unspecified\")";
Assert.Equal("Native Enum VAL: Unspecified", functionRange.Value.ToString());

functionRange.Formula = "=NativeEnum(\"Local\")";
Assert.Equal("Native Enum VAL: Local", functionRange.Value.ToString());

functionRange.Formula = "=NativeEnum(1)";
Assert.Equal("Native Enum VAL: Utc", functionRange.Value.ToString());
}

[ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)]
public void EnumReturn()
{
Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"];
functionRange.Formula = "=NativeEnumReturn(\"Unspecified\")";
Assert.Equal("Unspecified", functionRange.Value.ToString());

functionRange.Formula = "=NativeEnumReturn(\"Local\")";
Assert.Equal("Local", functionRange.Value.ToString());
}

[ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)]
public void StringArray()
{
Range a1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1:A1"];
a1.Value = "01";

Range a2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A2:A2"];
a2.Value = "2.30";

Range a3 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A3:A3"];
a3.Value = "World";

Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"];
functionRange.Formula = "=NativeStringArray(A1:A3)";

Assert.Equal("Native StringArray VALS: 12.3World", functionRange.Value.ToString());
}

[ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)]
public void StringArray2D()
{
Range a1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1"];
a1.Value = "01";

Range a2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A2"];
a2.Value = "2.30";

Range a3 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A3"];
a3.Value = "Hello";

Range b1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"];
b1.Value = "5";

Range b2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"];
b2.Value = "6.7";

Range b3 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B3"];
b3.Value = "World";

Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"];
functionRange.Formula = "=NativeStringArray2D(A1:B3)";

Assert.Equal("Native StringArray2D VALS: 15 2.36.7 HelloWorld ", functionRange.Value.ToString());
}

[ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)]
public void Params()
{
{
Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"];
functionRange.Formula = "=NativeParamsFunc1(1,\"2\",4,5)";
Assert.Equal("1,2, : 2", functionRange.Value.ToString());
}
{
Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"];
functionRange.Formula = "=NativeParamsFunc2(\"a\",,\"c\",\"d\",,\"f\")";
Assert.Equal("a,,c, [3: d,ExcelDna.Integration.ExcelMissing,f]", functionRange.Value.ToString());
}
{
Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B3"];
functionRange.Formula = "=NativeParamsJoinString(\"//\",\"5\",\"4\",\"3\")";
Assert.Equal("5//4//3", functionRange.Value.ToString());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\ExcelDna.Integration\ExcelDna.Integration.csproj" />
<ProjectReference Include="..\..\ExcelDna.Loader\ExcelDna.Loader.csproj" />
<ProjectReference Include="..\..\ExcelDna.ManagedHost\ExcelDna.ManagedHost.csproj" />
<ProjectReference Include="..\..\ExcelDna.SourceGenerator.NativeAOT\ExcelDna.SourceGenerator.NativeAOT.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
Loading