From 85ad2500ac68b141a9ac8a1508d3e79b47830356 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 3 May 2026 11:10:54 +0500 Subject: [PATCH 1/4] Added a test project for WPF control loading. --- ...ddIn.Tasks.IntegrationTests.TestTarget.sln | 14 +++++++++- .../SDKWPF/Commands.cs | 28 +++++++++++++++++++ .../SDKWPF/SDKWPF.csproj | 27 ++++++++++++++++++ .../SDKWPF/Window1.xaml | 13 +++++++++ .../SDKWPF/Window1.xaml.cs | 27 ++++++++++++++++++ .../WPFControl/UserControl1.xaml | 17 +++++++++++ .../WPFControl/UserControl1.xaml.cs | 28 +++++++++++++++++++ .../WPFControl/WPFControl.csproj | 12 ++++++++ 8 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Commands.cs create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml.cs create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml.cs create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln index bda8dfb8..8a499514 100644 --- a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.3.11312.210 d18.3 +VisualStudioVersion = 18.3.11312.210 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SingleDnaFileDefaultSuffix", "SingleDnaFileDefaultSuffix\SingleDnaFileDefaultSuffix.csproj", "{69CFC6E4-EAF6-416A-B462-B586DC3E051D}" EndProject @@ -144,6 +144,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOTPackNativeInclude", "AOT EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartupHooks", "StartupHooks\StartupHooks.csproj", "{35B162DF-CC46-D126-0741-39D09EB547CE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFControl", "WPFControl\WPFControl.csproj", "{90D59EA8-A127-5441-891E-610F278807BE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDKWPF", "SDKWPF\SDKWPF.csproj", "{E34415DC-1220-D742-33A1-6F7BEB3A49CD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -430,6 +434,14 @@ Global {35B162DF-CC46-D126-0741-39D09EB547CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {35B162DF-CC46-D126-0741-39D09EB547CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {35B162DF-CC46-D126-0741-39D09EB547CE}.Release|Any CPU.Build.0 = Release|Any CPU + {90D59EA8-A127-5441-891E-610F278807BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90D59EA8-A127-5441-891E-610F278807BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90D59EA8-A127-5441-891E-610F278807BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90D59EA8-A127-5441-891E-610F278807BE}.Release|Any CPU.Build.0 = Release|Any CPU + {E34415DC-1220-D742-33A1-6F7BEB3A49CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E34415DC-1220-D742-33A1-6F7BEB3A49CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E34415DC-1220-D742-33A1-6F7BEB3A49CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E34415DC-1220-D742-33A1-6F7BEB3A49CD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Commands.cs b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Commands.cs new file mode 100644 index 00000000..f15ec3c9 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Commands.cs @@ -0,0 +1,28 @@ +using ExcelDna.Integration; +using System; +using System.Windows; + +namespace SDKWPF +{ + public class Commands + { + [ExcelCommand(MenuText = "OpenWindow")] + public static void OpenWindow() + { + try + { + ShowWindow(); + } + catch (Exception e) + { + MessageBox.Show(e.ToString()); + } + } + + private static void ShowWindow() + { + Window1 window1 = new Window1(); + window1.ShowDialog(); + } + } +} diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj new file mode 100644 index 00000000..2347337a --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj @@ -0,0 +1,27 @@ + + + + net472;net8.0-windows + True + True + + + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.Integration.dll + + + + + + ..\..\.exceldna.addin\tools\net462\ExcelDna.Integration.dll + + + + + + + + + + \ No newline at end of file diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml new file mode 100644 index 00000000..f94776b1 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml @@ -0,0 +1,13 @@ + + + + + diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml.cs b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml.cs new file mode 100644 index 00000000..bdbca905 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/Window1.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace SDKWPF +{ + /// + /// Interaction logic for Window1.xaml + /// + public partial class Window1 : Window + { + public Window1() + { + InitializeComponent(); + } + } +} diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml new file mode 100644 index 00000000..89064a57 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml @@ -0,0 +1,17 @@ + + + + + diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml.cs b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml.cs new file mode 100644 index 00000000..9eef76bb --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/UserControl1.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace WPFControl +{ + /// + /// Interaction logic for UserControl1.xaml + /// + public partial class UserControl1 : UserControl + { + public UserControl1() + { + InitializeComponent(); + } + } +} diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj new file mode 100644 index 00000000..909ae6cf --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj @@ -0,0 +1,12 @@ + + + + net472;net8.0-windows + true + + + + + + + From 2d5264bd8970c1ab392bc05e40f5093b020d8be5 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 3 May 2026 12:55:54 +0500 Subject: [PATCH 2/4] Added control dlls to output in the test project. --- .../SDKWPF/SDKWPF.csproj | 11 +++++++++++ .../WPFControl/WPFControl.csproj | 2 ++ 2 files changed, 13 insertions(+) diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj index 2347337a..9a11f83f 100644 --- a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/SDKWPF/SDKWPF.csproj @@ -4,6 +4,17 @@ net472;net8.0-windows True True + + true + + + + + WPFControl.dll; + ControlzEx.dll; + MahApps.Metro.dll; + Microsoft.Xaml.Behaviors.dll + diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj index 909ae6cf..a6ec1681 100644 --- a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/WPFControl/WPFControl.csproj @@ -3,6 +3,8 @@ net472;net8.0-windows true + + true From 7addd89e84117e5ab64cd856fd7f027eae78dee9 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 3 May 2026 22:18:36 +0500 Subject: [PATCH 3/4] Added .dll loading from .xll path. --- Source/ExcelDna.ManagedHost/AddInInitialize.cs | 1 + Source/ExcelDna.ManagedHost/AssemblyManager.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Source/ExcelDna.ManagedHost/AddInInitialize.cs b/Source/ExcelDna.ManagedHost/AddInInitialize.cs index 495ec16e..045c5902 100644 --- a/Source/ExcelDna.ManagedHost/AddInInitialize.cs +++ b/Source/ExcelDna.ManagedHost/AddInInitialize.cs @@ -45,6 +45,7 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, string tempDirPath = Marshal.PtrToStringUni((IntPtr)pTempDirPath); _alc = new ExcelDnaAssemblyLoadContext(pathXll, disableAssemblyContextUnload == 0); AssemblyManager.Initialize((IntPtr)hModuleXll, pathXll, _alc, Path.Combine(tempDirPath, "ExcelDna.ManagedHost")); + AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => AssemblyManager.AppDomainAssemblyResolve(args.Name); var loaderAssembly = _alc.LoadFromAssemblyName(new AssemblyName("ExcelDna.Loader")); var xlAddInType = loaderAssembly.GetType("ExcelDna.Loader.XlAddIn"); var initOK = (bool)xlAddInType.InvokeMember("Initialize", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, diff --git a/Source/ExcelDna.ManagedHost/AssemblyManager.cs b/Source/ExcelDna.ManagedHost/AssemblyManager.cs index 4f700b9a..723d5ec8 100644 --- a/Source/ExcelDna.ManagedHost/AssemblyManager.cs +++ b/Source/ExcelDna.ManagedHost/AssemblyManager.cs @@ -161,6 +161,21 @@ internal static string NativeLibraryResolve(string unmanagedDllName) #endif } +#if NETCOREAPP && !AOT_COMPATIBLE + [MethodImpl(MethodImplOptions.Synchronized)] + internal static Assembly AppDomainAssemblyResolve(string assemblyName) + { + string dllFileName = new AssemblyName(assemblyName).Name + ".dll"; + { + string dllPath = Path.Combine(Path.GetDirectoryName(pathXll), dllFileName); + if (File.Exists(dllPath)) + return Assembly.LoadFrom(dllPath); + } + + return null; + } +#endif + internal static Assembly LoadFromAssemblyPath(string assemblyPath) { #if NETCOREAPP From fc42c0305ca69dbd64ecc8ef45ba5eb322256f31 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 3 May 2026 22:46:32 +0500 Subject: [PATCH 4/4] Added domain .dll loading from resources. --- .../ExcelDna.ManagedHost/AssemblyManager.cs | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/Source/ExcelDna.ManagedHost/AssemblyManager.cs b/Source/ExcelDna.ManagedHost/AssemblyManager.cs index 723d5ec8..c57462a1 100644 --- a/Source/ExcelDna.ManagedHost/AssemblyManager.cs +++ b/Source/ExcelDna.ManagedHost/AssemblyManager.cs @@ -136,18 +136,49 @@ internal static Assembly AssemblyResolve(AssemblyName assemblyName, bool logMiss internal static string NativeLibraryResolve(string unmanagedDllName) { #if NETCOREAPP - byte[] dllBytes = GetResourceBytes(unmanagedDllName.ToUpperInvariant(), 5); + return ExtractDllResource(unmanagedDllName, unmanagedDllName, 5); +#else + return null; +#endif + } + +#if NETCOREAPP && !AOT_COMPATIBLE + [MethodImpl(MethodImplOptions.Synchronized)] + internal static Assembly AppDomainAssemblyResolve(string assemblyName) + { + string dllFileNameWithoutExtension = new AssemblyName(assemblyName).Name; + string dllFileName = dllFileNameWithoutExtension + ".dll"; + { + string dllPath = Path.Combine(Path.GetDirectoryName(pathXll), dllFileName); + if (File.Exists(dllPath)) + return Assembly.LoadFrom(dllPath); + } + { + string dllPath = ExtractDllResource(dllFileNameWithoutExtension, dllFileName, 0); + if (File.Exists(dllPath)) + return Assembly.LoadFrom(dllPath); + } + + return null; + } +#endif + +#if NETCOREAPP + [MethodImpl(MethodImplOptions.Synchronized)] + private static string ExtractDllResource(string resourceName, string dllName, int type) + { + byte[] dllBytes = GetResourceBytes(resourceName.ToUpperInvariant(), type); if (dllBytes == null) return null; - string dllPath = Path.Combine(tempDirPath, unmanagedDllName); + string dllPath = Path.Combine(tempDirPath, dllName); if (!File.Exists(dllPath)) { Directory.CreateDirectory(tempDirPath); File.WriteAllBytes(dllPath, dllBytes); } - byte[] pdbBytes = GetResourceBytes(unmanagedDllName.ToUpperInvariant(), 4); + byte[] pdbBytes = GetResourceBytes(resourceName.ToUpperInvariant(), 4); if (pdbBytes != null) { string pdbPath = Path.ChangeExtension(dllPath, "pdb"); @@ -156,23 +187,6 @@ internal static string NativeLibraryResolve(string unmanagedDllName) } return dllPath; -#else - return null; -#endif - } - -#if NETCOREAPP && !AOT_COMPATIBLE - [MethodImpl(MethodImplOptions.Synchronized)] - internal static Assembly AppDomainAssemblyResolve(string assemblyName) - { - string dllFileName = new AssemblyName(assemblyName).Name + ".dll"; - { - string dllPath = Path.Combine(Path.GetDirectoryName(pathXll), dllFileName); - if (File.Exists(dllPath)) - return Assembly.LoadFrom(dllPath); - } - - return null; } #endif