diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eadfab..6590fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.4.1] / 2025-09-18 +### Features +- Create `Revit.DesignApplication` with `DesignApplication` to load correct assembly version in the bundle. (#7) +### Updates +- Use `DesignApplication` to load correct assembly version in the bundle. +- Add `ApplicationInitialized` event to test. + ## [1.4.0] / 2025-08-27 ### Features - Support Bundle multiple versions of Revit using `DesignAutomationLoadVersion`. (#7) @@ -40,6 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - First Release [vNext]: ../../compare/1.0.0...HEAD +[1.4.1]: ../../compare/1.4.0...1.4.1 [1.4.0]: ../../compare/1.3.1...1.4.0 [1.3.1]: ../../compare/1.3.0...1.3.1 [1.3.0]: ../../compare/1.2.0...1.3.0 diff --git a/DesignAutomationConsole/Bundle/RevitAddin.DA.Tester.bundle.zip b/DesignAutomationConsole/Bundle/RevitAddin.DA.Tester.bundle.zip index aaf4471..049c058 100644 Binary files a/DesignAutomationConsole/Bundle/RevitAddin.DA.Tester.bundle.zip and b/DesignAutomationConsole/Bundle/RevitAddin.DA.Tester.bundle.zip differ diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..a5caae5 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + 1.4.1 + + \ No newline at end of file diff --git a/Revit.DesignApplication/DesignApplication.cs b/Revit.DesignApplication/DesignApplication.cs new file mode 100644 index 0000000..a91b5ab --- /dev/null +++ b/Revit.DesignApplication/DesignApplication.cs @@ -0,0 +1,74 @@ +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.DB; +using DesignAutomationFramework; +using System; + +namespace Revit.DesignApplication +{ + public abstract class DesignApplication : IExternalDBApplication, IDesignAutomation + { + public ControlledApplication Application { get; private set; } + public abstract void OnStartup(); + public abstract void OnShutdown(); + public abstract bool Execute(Application application, string filePath, Document document); + + private IExternalDBApplication designApplication; + public ExternalDBApplicationResult OnStartup(ControlledApplication application) + { + this.Application = application; + + designApplication = DesignApplicationLoader.LoadVersion(this); + + if (designApplication is IExternalDBApplication) + { + return designApplication.OnStartup(application); + } + + Console.WriteLine("----------------------------------------"); + Console.WriteLine($"FullName: \t{this.GetType().Assembly.FullName}"); + Console.WriteLine($"AddInName: \t{this.Application.ActiveAddInId?.GetAddInName()}"); + Console.WriteLine("----------------------------------------"); + + OnStartup(); + DesignAutomationBridge.DesignAutomationReadyEvent += DesignAutomationReadyEvent; + + return ExternalDBApplicationResult.Succeeded; + } + + public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + { + this.Application = application; + + if (designApplication is IExternalDBApplication) + { + try + { + return designApplication.OnShutdown(application); + } + finally + { + DesignApplicationLoader.Dispose(); + } + } + + OnShutdown(); + DesignAutomationBridge.DesignAutomationReadyEvent -= DesignAutomationReadyEvent; + + return ExternalDBApplicationResult.Succeeded; + } + + + private void DesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e) + { + DesignAutomationBridge.DesignAutomationReadyEvent -= DesignAutomationReadyEvent; + + var data = e.DesignAutomationData; + + Console.WriteLine("--------------------------------------------------"); + Console.WriteLine($"RevitApp: {data.RevitApp} \tFilePath: {data.FilePath} \tRevitDoc: {data.RevitDoc} \tAddInName:{data.RevitApp.ActiveAddInId?.GetAddInName()}"); + Console.WriteLine("--------------------------------------------------"); + + e.Succeeded = Execute(data.RevitApp, data.FilePath, data.RevitDoc); + } + } +} \ No newline at end of file diff --git a/Revit.DesignApplication/DesignApplicationLoader.cs b/Revit.DesignApplication/DesignApplicationLoader.cs new file mode 100644 index 0000000..b9e1ebc --- /dev/null +++ b/Revit.DesignApplication/DesignApplicationLoader.cs @@ -0,0 +1,87 @@ +using Autodesk.Revit.DB; +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Versioning; + +namespace Revit.DesignApplication +{ + internal static class DesignApplicationLoader + { + private static Assembly loadAssembly; + public static IExternalDBApplication LoadVersion(T designApplication) where T : DesignApplication + { + var type = designApplication.GetType(); + + var similar = AppDomain.CurrentDomain.GetAssemblies().Where(e => e.FullName == type.Assembly.FullName); + if (similar.Count() >= 2) + { + return null; + } + + var location = type.Assembly.Location; + var revitAssemblyReference = type.Assembly.GetReferencedAssemblies().FirstOrDefault(e => e.Name.Equals("RevitAPI")); + var revitAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(e => e.GetName().Name.Equals("RevitAPI")); + + var revitReferenceVersion = revitAssemblyReference.Version.Major + 2000; + var revitVersion = revitAssembly.GetName().Version.Major + 2000; + + Console.WriteLine("--------------------------------------------------"); + Console.WriteLine($"DesignApplicationLoader: \t{revitVersion} -> {revitReferenceVersion}"); + + for (int version = revitVersion; version > revitReferenceVersion; version--) + { + var directory = Path.GetDirectoryName(location); + var directoryVersionRevit = Path.Combine(directory, "..", version.ToString()); + var fileName = Path.Combine(directoryVersionRevit, Path.GetFileName(location)); + + //Console.WriteLine($"DesignApplicationLoader Try: \t{version}"); + + if (File.Exists(fileName)) + { + fileName = new FileInfo(fileName).FullName; + Console.WriteLine($"DesignApplicationLoader File Exists: \t{fileName}"); + Console.WriteLine($"DesignApplicationLoader Version: \t{version}"); + Console.WriteLine($"DesignApplicationLoader LoadFile: \t{Path.GetFileName(fileName)}"); + AppDomain.CurrentDomain.AssemblyResolve += LoadAssemblyResolve; + loadAssembly = Assembly.LoadFile(fileName); + break; + } + } + + Console.WriteLine("----------------------------------------"); + + if (loadAssembly is not null) + { + var loadType = loadAssembly.GetType(type.FullName); + + Console.WriteLine($"DesignApplicationLoader Type: {loadType}"); + Console.WriteLine($"DesignApplicationLoader FrameworkName: \t{loadType.Assembly.GetCustomAttribute()?.FrameworkName}"); + Console.WriteLine("----------------------------------------"); + + return Activator.CreateInstance(loadType) as IExternalDBApplication; + } + + return null; + } + + private static Assembly LoadAssemblyResolve(object sender, ResolveEventArgs args) + { + var assemblyName = new AssemblyName(args.Name); + var assemblyPath = Path.Combine(Path.GetDirectoryName(loadAssembly.Location), assemblyName.Name + ".dll"); + if (File.Exists(assemblyPath)) + { + var folderName = Path.GetFileName(Path.GetDirectoryName(assemblyPath)); + Console.WriteLine($"AssemblyResolve LoadFile: {folderName}\\{assemblyName.Name + ".dll"}"); + return Assembly.LoadFile(assemblyPath); + } + return null; + } + + public static void Dispose() + { + AppDomain.CurrentDomain.AssemblyResolve -= LoadAssemblyResolve; + } + } +} \ No newline at end of file diff --git a/RevitAddin.DA.Tester/Revit/IDesignAutomation.cs b/Revit.DesignApplication/IDesignAutomation.cs similarity index 84% rename from RevitAddin.DA.Tester/Revit/IDesignAutomation.cs rename to Revit.DesignApplication/IDesignAutomation.cs index cfb523a..e8df580 100644 --- a/RevitAddin.DA.Tester/Revit/IDesignAutomation.cs +++ b/Revit.DesignApplication/IDesignAutomation.cs @@ -1,7 +1,7 @@ using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.DB; -namespace RevitAddin.DA.Tester.Revit +namespace Revit.DesignApplication { public interface IDesignAutomation { diff --git a/Revit.DesignApplication/Revit.DesignApplication.csproj b/Revit.DesignApplication/Revit.DesignApplication.csproj new file mode 100644 index 0000000..c860d9c --- /dev/null +++ b/Revit.DesignApplication/Revit.DesignApplication.csproj @@ -0,0 +1,66 @@ + + + + Library + latest + + + + + net47;net48;net8.0-windows + true + None + + + + + 2017 + + + + + 2019 + + + + + 2021 + + + + + 2025 + + + + + + + true + true + false + + + + + true + bin\Release\$(RevitVersion) + REVIT$(RevitVersion) + MSB3052 + None + + + + + true + bin\Debug\ + DEBUG;TRACE;REVIT$(RevitVersion) + Full + + + + + + + + diff --git a/RevitAddin.DA.Tester.sln b/RevitAddin.DA.Tester.sln index 2e956d8..81427e3 100644 --- a/RevitAddin.DA.Tester.sln +++ b/RevitAddin.DA.Tester.sln @@ -10,12 +10,15 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{64A2F0FA-4270-45D5-B9DB-3561832ADA42}" ProjectSection(SolutionItems) = preProject CHANGELOG.md = CHANGELOG.md + Directory.Build.props = Directory.Build.props LICENSE = LICENSE README.md = README.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesignAutomationConsole", "DesignAutomationConsole\DesignAutomationConsole.csproj", "{7F41BE81-4EFB-4FAC-8563-B5EDAEA9F44B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Revit.DesignApplication", "Revit.DesignApplication\Revit.DesignApplication.csproj", "{0966B1C7-6ECE-44D0-A71B-7C26EB598BFF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,6 +35,10 @@ Global {7F41BE81-4EFB-4FAC-8563-B5EDAEA9F44B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F41BE81-4EFB-4FAC-8563-B5EDAEA9F44B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F41BE81-4EFB-4FAC-8563-B5EDAEA9F44B}.Release|Any CPU.Build.0 = Release|Any CPU + {0966B1C7-6ECE-44D0-A71B-7C26EB598BFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0966B1C7-6ECE-44D0-A71B-7C26EB598BFF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0966B1C7-6ECE-44D0-A71B-7C26EB598BFF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0966B1C7-6ECE-44D0-A71B-7C26EB598BFF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RevitAddin.DA.Tester/Revit/App.cs b/RevitAddin.DA.Tester/Revit/App.cs index e1bf6f9..cf6c552 100644 --- a/RevitAddin.DA.Tester/Revit/App.cs +++ b/RevitAddin.DA.Tester/Revit/App.cs @@ -1,31 +1,39 @@ using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.DB; +using Revit.DesignApplication; using RevitAddin.DA.Tester.Services; using System; namespace RevitAddin.DA.Tester.Revit { - public class App : IExternalDBApplication + public class App : DesignApplication { - IDisposable designAutomation; - public ExternalDBApplicationResult OnStartup(ControlledApplication application) + public static string AddInName { get; set; } = "none"; + public override void OnStartup() { Console.WriteLine("----------------------------------------"); Console.WriteLine($"FullName: \t{this.GetType().Assembly.FullName}"); Console.WriteLine("----------------------------------------"); Console.WriteLine($"Location: {this.GetType().Assembly.Location}"); Console.WriteLine("----------------------------------------"); - Console.WriteLine($"AddInName: \t{application.ActiveAddInId?.GetAddInName()}"); + Console.WriteLine($"AddInName: \t{Application.ActiveAddInId?.GetAddInName()}"); Console.WriteLine("----------------------------------------"); + Application.ApplicationInitialized += Application_ApplicationInitialized; + } - designAutomation = new DesignAutomationLoadVersion(); - return ExternalDBApplicationResult.Succeeded; + private void Application_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e) + { + var application = (Application)sender; + AddInName = application.ActiveAddInId?.GetAddInName(); } - public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + public override void OnShutdown() + { + + } + public override bool Execute(Application application, string filePath, Document document) { - designAutomation?.Dispose(); - return ExternalDBApplicationResult.Succeeded; + return new DesignAutomationController().Execute(application, filePath, document); } } } \ No newline at end of file diff --git a/RevitAddin.DA.Tester/Revit/DesignAutomation.cs b/RevitAddin.DA.Tester/Revit/DesignAutomation.cs deleted file mode 100644 index 34f6473..0000000 --- a/RevitAddin.DA.Tester/Revit/DesignAutomation.cs +++ /dev/null @@ -1,77 +0,0 @@ -using DesignAutomationFramework; -using System; -using System.Linq; - -namespace RevitAddin.DA.Tester.Revit -{ - public class DesignAutomation : DesignAutomation where T : IDesignAutomation - { - public DesignAutomation() : base(Activator.CreateInstance(typeof(T))) - { - - } - public DesignAutomation(T instance) : base(instance) - { - - } - } - - public class DesignAutomation : IDisposable - { - private readonly object instance; - - public DesignAutomation(Type type) - { - this.instance = Activator.CreateInstance(type); - Initialize(); - } - - public DesignAutomation(object instance) - { - this.instance = instance; - Initialize(); - } - - public virtual void Initialize() - { - Console.WriteLine($"{nameof(DesignAutomation)} Initialize: \t{instance}"); - DesignAutomationBridge.DesignAutomationReadyEvent += DesignAutomationReadyEvent; - } - - public void Dispose() - { - Console.WriteLine($"{nameof(DesignAutomation)} Dispose: \t{instance}"); - DesignAutomationBridge.DesignAutomationReadyEvent -= DesignAutomationReadyEvent; - } - - private void DesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e) - { - DesignAutomationBridge.DesignAutomationReadyEvent -= DesignAutomationReadyEvent; - - var data = e.DesignAutomationData; - - Console.WriteLine("--------------------------------------------------"); - Console.WriteLine($"RevitApp: {data.RevitApp} FilePath: {data.FilePath} RevitDoc: {data.RevitDoc}"); - Console.WriteLine("--------------------------------------------------"); - - try - { - var method = instance.GetType().GetMethods() - .Where(e => e.Name.Equals(nameof(IDesignAutomation.Execute))) - .FirstOrDefault(e => e.GetParameters().Count() == 3); - - Console.WriteLine($"Invoke: {method}"); - - var result = method.Invoke(instance, new object[] { data.RevitApp, data.FilePath, data.RevitDoc }); - - if (result is bool resultBool) - e.Succeeded = resultBool; - } - catch (Exception ex) - { - Console.WriteLine($"{nameof(DesignAutomation)} Invoke Exception: \t{ex.Message}"); - throw; - } - } - } -} \ No newline at end of file diff --git a/RevitAddin.DA.Tester/Revit/DesignAutomationLoadVersion.cs b/RevitAddin.DA.Tester/Revit/DesignAutomationLoadVersion.cs deleted file mode 100644 index 1d68b7d..0000000 --- a/RevitAddin.DA.Tester/Revit/DesignAutomationLoadVersion.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Versioning; - -namespace RevitAddin.DA.Tester.Revit -{ - public class DesignAutomationLoadVersion : DesignAutomationLoadVersion where T : IDesignAutomation - { - public DesignAutomationLoadVersion() : base(typeof(T)) - { - - } - } - - public class DesignAutomationLoadVersion : IDisposable - { - readonly IDisposable designAutomation; - readonly Assembly loadAssembly; - - public DesignAutomationLoadVersion(Type type) - { - var location = type.Assembly.Location; - var revitAssemblyReference = type.Assembly.GetReferencedAssemblies().FirstOrDefault(e => e.Name.Equals("RevitAPI")); - var revitAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(e => e.GetName().Name.Equals("RevitAPI")); - - var revitReferenceVersion = revitAssemblyReference.Version.Major + 2000; - var revitVersion = revitAssembly.GetName().Version.Major + 2000; - - Console.WriteLine($"DesignAutomationLoadVersion: \t{revitVersion} -> {revitReferenceVersion}"); - - for (int version = revitVersion; version > revitReferenceVersion; version--) - { - var directory = System.IO.Path.GetDirectoryName(location); - var directoryVersionRevit = System.IO.Path.Combine(directory, "..", version.ToString()); - var fileName = System.IO.Path.Combine(directoryVersionRevit, System.IO.Path.GetFileName(location)); - - Console.WriteLine($"DesignAutomationLoadVersion Try: \t{version}"); - - if (File.Exists(fileName)) - { - fileName = new FileInfo(fileName).FullName; - Console.WriteLine($"DesignAutomationLoadVersion File Exists: \t{fileName}"); - Console.WriteLine($"DesignAutomationLoadVersion Version: \t{version}"); - Console.WriteLine($"DesignAutomationLoadVersion LoadFile: \t{Path.GetFileName(fileName)}"); - AppDomain.CurrentDomain.AssemblyResolve += LoadAssemblyResolve; - loadAssembly = Assembly.LoadFile(fileName); - type = loadAssembly.GetType(type.FullName); - break; - } - } - - Console.WriteLine("----------------------------------------"); - Console.WriteLine($"DesignAutomationLoadVersion Type: {type}"); - Console.WriteLine($"DesignAutomationLoadVersion FrameworkName: \t{type.Assembly.GetCustomAttribute()?.FrameworkName}"); - designAutomation = new DesignAutomation(type); - } - - private Assembly LoadAssemblyResolve(object sender, ResolveEventArgs args) - { - var assemblyName = new AssemblyName(args.Name); - var assemblyPath = Path.Combine(Path.GetDirectoryName(loadAssembly.Location), assemblyName.Name + ".dll"); - if (File.Exists(assemblyPath)) - { - var folderName = Path.GetFileName(Path.GetDirectoryName(assemblyPath)); - Console.WriteLine($"AssemblyResolve LoadFile: {folderName}\\{assemblyName.Name + ".dll"}"); - return Assembly.LoadFile(assemblyPath); - } - return null; - } - - public void Dispose() - { - designAutomation?.Dispose(); - AppDomain.CurrentDomain.AssemblyResolve -= LoadAssemblyResolve; - } - } -} \ No newline at end of file diff --git a/RevitAddin.DA.Tester/RevitAddin.DA.Tester.csproj b/RevitAddin.DA.Tester/RevitAddin.DA.Tester.csproj index 9c0a625..291ea40 100644 --- a/RevitAddin.DA.Tester/RevitAddin.DA.Tester.csproj +++ b/RevitAddin.DA.Tester/RevitAddin.DA.Tester.csproj @@ -75,7 +75,6 @@ RevitAddin.DA.Tester - 1.4.0 {7C324916-9F8D-43B0-B226-DA67D2504393} @@ -132,6 +131,10 @@ + + + + True diff --git a/RevitAddin.DA.Tester/Services/DesignAutomationController.cs b/RevitAddin.DA.Tester/Services/DesignAutomationController.cs index b05bf10..cb66a9c 100644 --- a/RevitAddin.DA.Tester/Services/DesignAutomationController.cs +++ b/RevitAddin.DA.Tester/Services/DesignAutomationController.cs @@ -9,7 +9,7 @@ namespace RevitAddin.DA.Tester.Services { - public class DesignAutomationController : IDesignAutomation + public class DesignAutomationController { public bool Execute(Application application, string filePath = null, Document document = null) { @@ -39,6 +39,7 @@ public bool Execute(Application application, string filePath = null, Document do } Console.WriteLine($"UI:\t{UI.IsValid()}"); + Console.WriteLine($"App.AddInName:\t{App.AddInName}"); Console.WriteLine("----------------------------------------"); Console.WriteLine($"Shape:\t{typeof(ricaun.Revit.DB.Shape.Colors).Assembly}"); Console.WriteLine($"Shape Location:\t{typeof(ricaun.Revit.DB.Shape.Colors).Assembly.Location}");