Files

472 lines
18 KiB
C#
Raw Permalink Normal View History

2025-09-04 10:18:07 +08:00
using System;
2025-09-04 09:53:20 +08:00
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
2025-09-04 10:18:07 +08:00
using System.Linq;
2025-09-04 09:53:20 +08:00
using System.Reflection;
2026-01-02 11:14:44 +08:00
using System.Runtime.Serialization.Json;
using System.Text;
2025-09-04 09:53:20 +08:00
using AddInManager.Properties;
namespace AddInManager
{
public class AddinManager
{
public AddinsApplication Applications { get; }
public int AppCount => Applications.Count;
public AddinsCommand Commands { get; }
public int CmdCount => Commands.Count;
public AddinManager()
{
Commands = new AddinsCommand();
Applications = new AddinsApplication();
GetIniFilePaths();
ReadAddinsFromAimIni();
}
public IniFile AimIniFile { get; set; }
public IniFile RevitIniFile { get; set; }
private void GetIniFilePaths()
{
2026-01-02 11:14:44 +08:00
//var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
2026-01-02 09:37:33 +08:00
var appFolder = Path.Combine(folderPath, Resources.AppFolder);
2026-01-02 11:14:44 +08:00
// switch from INI to JSON storage
var iniFilePath = Path.Combine(appFolder, "AimInternal.json");
2026-01-02 09:37:33 +08:00
AimIniFile = new IniFile(iniFilePath);
2026-01-02 11:14:44 +08:00
// If an old INI exists, migrate it to JSON (one-time)
try
{
var oldIniPath = Path.Combine(appFolder, "AimInternal.ini");
if (File.Exists(oldIniPath) && !File.Exists(iniFilePath))
{
var oldIni = new IniFile(oldIniPath);
// populate commands/applications from old INI
Commands.ReadItems(oldIni);
Applications.ReadItems(oldIni);
// save to new JSON store
SaveToPersistentStore(iniFilePath);
// backup old INI
try
{
var backupPath = oldIniPath + ".bak";
File.Copy(oldIniPath, backupPath, true);
FileUtils.SetWriteable(oldIniPath);
File.Delete(oldIniPath);
}
catch (Exception)
{
// ignore backup errors
}
}
}
catch (Exception)
{
// ignore migration errors
}
2025-09-04 09:53:20 +08:00
var currentProcess = Process.GetCurrentProcess();
var fileName = currentProcess.MainModule.FileName;
2026-01-02 09:37:33 +08:00
var revitIniFilePath = fileName.Replace(".exe", ".ini");
RevitIniFile = new IniFile(revitIniFilePath);
2025-09-04 09:53:20 +08:00
}
public void ReadAddinsFromAimIni()
{
2026-01-02 11:14:44 +08:00
// try load from persistent JSON store; if fails, fall back to legacy INI-format reader
if (!LoadFromPersistentStore(AimIniFile.FilePath))
{
Commands.ReadItems(AimIniFile);
Applications.ReadItems(AimIniFile);
}
2025-09-04 09:53:20 +08:00
}
public void RemoveAddin(Addin addin)
{
if (!Commands.RemoveAddIn(addin))
{
Applications.RemoveAddIn(addin);
}
}
public AddinType LoadAddin(string filePath)
{
var addinType = AddinType.Invalid;
if (!File.Exists(filePath))
{
return addinType;
}
Path.GetFileName(filePath);
var assemLoader = new AssemLoader();
2026-01-02 09:37:33 +08:00
List<AddinItem> cmdItems = null;
List<AddinItem> appItems = null;
2025-09-04 09:53:20 +08:00
try
{
assemLoader.HookAssemblyResolve();
var assembly = assemLoader.LoadAddinsToTempFolder(filePath, true);
if (null == assembly)
{
return addinType;
}
2026-01-02 09:37:33 +08:00
cmdItems = Commands.LoadItems(assembly, StaticUtil.m_ecFullName, filePath, AddinType.Command);
appItems = Applications.LoadItems(assembly, StaticUtil.m_eaFullName, filePath, AddinType.Application);
2025-09-04 09:53:20 +08:00
}
catch (Exception)
{
}
finally
{
assemLoader.UnhookAssemblyResolve();
}
2026-01-02 09:37:33 +08:00
if (cmdItems != null && cmdItems.Count > 0)
2025-09-04 09:53:20 +08:00
{
2026-01-02 09:37:33 +08:00
var cmdAddin = new Addin(filePath, cmdItems);
Commands.AddAddIn(cmdAddin);
2025-09-04 09:53:20 +08:00
addinType |= AddinType.Command;
}
2026-01-02 09:37:33 +08:00
if (appItems != null && appItems.Count > 0)
2025-09-04 09:53:20 +08:00
{
2026-01-02 09:37:33 +08:00
var appAddin = new Addin(filePath, appItems);
Applications.AddAddIn(appAddin);
2025-09-04 09:53:20 +08:00
addinType |= AddinType.Application;
}
return addinType;
}
2025-09-04 10:18:07 +08:00
public void SaveToLocal(AddinType addinTypeToSave)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
SaveToLocalManifest(addinTypeToSave);
2025-09-04 09:53:20 +08:00
}
2026-01-02 11:14:44 +08:00
public void SaveToAimIni()
2025-09-04 09:53:20 +08:00
{
2026-01-02 11:14:44 +08:00
// ensure file exists
try
2025-09-04 09:53:20 +08:00
{
2026-01-02 11:14:44 +08:00
if (!File.Exists(AimIniFile.FilePath))
2025-09-04 09:53:20 +08:00
{
2026-01-02 11:14:44 +08:00
new FileInfo(AimIniFile.FilePath).Directory?.Create();
FileUtils.CreateFile(AimIniFile.FilePath);
FileUtils.SetWriteable(AimIniFile.FilePath);
2025-09-04 09:53:20 +08:00
}
}
2026-01-02 11:14:44 +08:00
catch (Exception)
{
// ignore
}
2025-09-04 09:53:20 +08:00
2026-01-02 11:14:44 +08:00
// save to persistent JSON store; if fails, fall back to legacy INI writer
if (!SaveToPersistentStore(AimIniFile.FilePath))
2025-09-04 09:53:20 +08:00
{
2026-01-02 11:14:44 +08:00
Commands.Save(AimIniFile);
Applications.Save(AimIniFile);
2025-09-04 09:53:20 +08:00
}
}
public bool HasItemsToSave()
{
foreach (var addin in Commands.AddinDict.Values)
{
if (addin.Save)
{
return true;
}
}
foreach (var addin2 in Applications.AddinDict.Values)
{
if (addin2.Save)
{
return true;
}
}
return false;
}
2025-09-04 10:18:07 +08:00
public string SaveToAllUserManifest(AddinType addinTypeToSave)
2025-09-04 09:53:20 +08:00
{
var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var currentAddinFolder = Path.Combine(folderPath, $"Autodesk\\Revit\\Addins\\{App.RevitVersion}");
var manifestFile = new ManifestFile(false);
var numCmdAddins = 0;
Addin savedCmdAddin = null;
2025-09-04 10:18:07 +08:00
if (addinTypeToSave == AddinType.Command)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
foreach (var cmdAddin in Commands.AddinDict.Values.Where(a => a.Save))
2025-09-04 09:53:20 +08:00
{
numCmdAddins++;
savedCmdAddin = cmdAddin;
2025-09-04 10:18:07 +08:00
foreach (var addinItem in cmdAddin.ItemList.Where(i => i.Save))
2025-09-04 09:53:20 +08:00
{
manifestFile.Commands.Add(addinItem);
}
}
}
2025-09-04 10:18:07 +08:00
2025-09-04 09:53:20 +08:00
var numAppAddins = 0;
Addin savedAppAddin = null;
2025-09-04 10:18:07 +08:00
if (addinTypeToSave == AddinType.Application)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
foreach (var appAddin in Applications.AddinDict.Values.Where(a => a.Save))
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
numAppAddins++;
2025-09-04 09:53:20 +08:00
savedAppAddin = appAddin;
2025-09-04 10:18:07 +08:00
foreach (var appAddinItem in appAddin.ItemList.Where(i => i.Save))
2025-09-04 09:53:20 +08:00
{
manifestFile.Applications.Add(appAddinItem);
}
}
}
var addinFileName = string.Empty;
string addinFilePath;
if (numCmdAddins <= 1 && numAppAddins <= 1 && numCmdAddins + numAppAddins > 0)
{
if (savedCmdAddin != null)
{
if (savedAppAddin == null || savedCmdAddin.FilePath.Equals(savedAppAddin.FilePath, StringComparison.OrdinalIgnoreCase))
{
addinFileName = Path.GetFileNameWithoutExtension(savedCmdAddin.FilePath);
}
}
else if (savedAppAddin != null && savedCmdAddin == null)
{
addinFileName = Path.GetFileNameWithoutExtension(savedAppAddin.FilePath);
}
if (string.IsNullOrEmpty(addinFileName))
{
return string.Empty;
}
addinFilePath = GetProperFilePath(currentAddinFolder, addinFileName, ".addin");
}
else
{
2026-01-02 11:14:44 +08:00
addinFilePath = GetProperFilePath(currentAddinFolder, addinFileName, ".addin");
2025-09-04 09:53:20 +08:00
}
manifestFile.SaveAs(addinFilePath);
return addinFilePath;
}
2025-09-04 10:18:07 +08:00
public void SaveToLocalManifest(AddinType addinTypeToSave)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
if (addinTypeToSave == AddinType.Command)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
foreach (var cmdKeyValuePair in Commands.AddinDict.Where(kv => kv.Value.Save))
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
var value = cmdKeyValuePair.Value;
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(value.FilePath);
var directoryName = Path.GetDirectoryName(value.FilePath);
var text = Path.Combine(directoryName, $"{fileNameWithoutExtension}.addin");
var manifestFile = new ManifestFile(true);
foreach (var addinItem in value.ItemList.Where(i => i.Save))
2025-09-04 09:53:20 +08:00
{
manifestFile.Commands.Add(addinItem);
}
2025-09-04 10:18:07 +08:00
manifestFile.SaveAs(text);
2025-09-04 09:53:20 +08:00
}
}
2025-09-04 10:18:07 +08:00
if (addinTypeToSave == AddinType.Application)
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
foreach (var appKeyValuePair in Applications.AddinDict.Where(kv => kv.Value.Save))
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
var value2 = appKeyValuePair.Value;
2025-09-04 09:53:20 +08:00
var fileNameWithoutExtension2 = Path.GetFileNameWithoutExtension(value2.FilePath);
var directoryName2 = Path.GetDirectoryName(value2.FilePath);
var text2 = Path.Combine(directoryName2, $"{fileNameWithoutExtension2}.addin");
var manifestFile2 = new ManifestFile(true);
2025-09-04 10:18:07 +08:00
foreach (var addinItem3 in value2.ItemList.Where(i => i.Save))
2025-09-04 09:53:20 +08:00
{
2025-09-04 10:18:07 +08:00
manifestFile2.Applications.Add(addinItem3);
2025-09-04 09:53:20 +08:00
}
manifestFile2.SaveAs(text2);
}
}
}
private static string GetProperFilePath(string folder, string fileNameWithoutExt, string ext)
{
var filePath = string.Empty;
var fileIndex = -1;
do
{
fileIndex++;
var text2 = ((fileIndex <= 0) ? (fileNameWithoutExt + ext) : (fileNameWithoutExt + fileIndex + ext));
filePath = Path.Combine(folder, text2);
}
while (File.Exists(filePath));
return filePath;
}
2026-01-02 11:14:44 +08:00
private bool LoadFromPersistentStore(string filePath)
{
try
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) return false;
using (var fs = File.OpenRead(filePath))
{
var ser = new DataContractJsonSerializer(typeof(PersistentAddinStore));
var obj = ser.ReadObject(fs) as PersistentAddinStore;
if (obj == null) return false;
// reset internal dictionaries
Commands.AddinDict.Clear();
Applications.AddinDict.Clear();
foreach (var p in obj.Commands)
{
var items = new List<AddinItem>();
foreach (var pi in p.Items)
{
var ai = new AddinItem(pi.AssemblyPath ?? string.Empty, pi.ClientId == Guid.Empty ? Guid.NewGuid() : pi.ClientId, pi.FullClassName ?? string.Empty, AddinType.Command, pi.TransactionMode, pi.RegenerationMode, pi.JournalingMode)
{
Name = pi.Name,
Description = pi.Description,
VisibilityMode = pi.VisibilityMode,
Save = pi.Save,
Hidden = pi.Hidden
};
items.Add(ai);
}
var addin = new Addin(p.FilePath ?? string.Empty, items)
{
Save = p.Save,
Hidden = p.Hidden
};
Commands.AddAddIn(addin);
}
foreach (var p in obj.Applications)
{
var items = new List<AddinItem>();
foreach (var pi in p.Items)
{
var ai = new AddinItem(pi.AssemblyPath ?? string.Empty, pi.ClientId == Guid.Empty ? Guid.NewGuid() : pi.ClientId, pi.FullClassName ?? string.Empty, AddinType.Application, pi.TransactionMode, pi.RegenerationMode, pi.JournalingMode)
{
Name = pi.Name,
Description = pi.Description,
VisibilityMode = pi.VisibilityMode,
Save = pi.Save,
Hidden = pi.Hidden
};
items.Add(ai);
}
var addin = new Addin(p.FilePath ?? string.Empty, items)
{
Save = p.Save,
Hidden = p.Hidden
};
Applications.AddAddIn(addin);
}
return true;
}
}
catch (Exception)
{
return false;
}
}
private bool SaveToPersistentStore(string filePath)
{
try
{
var store = new PersistentAddinStore
{
FormatVersion = 1,
RevitVersion = App.RevitVersion,
LastSaved = DateTime.Now
};
foreach (var kv in Commands.AddinDict)
{
var a = kv.Value;
var p = new PersistentAddin
{
FilePath = a.FilePath,
Save = a.Save,
Hidden = a.Hidden
};
foreach (var ai in a.ItemList)
{
var pi = new PersistentAddinItem
{
AddinType = ai.AddinType,
AssemblyPath = ai.AssemblyPath,
AssemblyName = ai.AssemblyName,
ClientId = ai.ClientId,
FullClassName = ai.FullClassName,
Name = ai.Name,
Description = ai.Description,
VisibilityMode = ai.VisibilityMode,
Save = ai.Save,
Hidden = ai.Hidden,
TransactionMode = ai.TransactionMode,
RegenerationMode = ai.RegenerationMode,
JournalingMode = ai.JournalingMode
};
p.Items.Add(pi);
}
store.Commands.Add(p);
}
foreach (var kv in Applications.AddinDict)
{
var a = kv.Value;
var p = new PersistentAddin
{
FilePath = a.FilePath,
Save = a.Save,
Hidden = a.Hidden
};
foreach (var ai in a.ItemList)
{
var pi = new PersistentAddinItem
{
AddinType = ai.AddinType,
AssemblyPath = ai.AssemblyPath,
AssemblyName = ai.AssemblyName,
ClientId = ai.ClientId,
FullClassName = ai.FullClassName,
Name = ai.Name,
Description = ai.Description,
VisibilityMode = ai.VisibilityMode,
Save = ai.Save,
Hidden = ai.Hidden,
TransactionMode = ai.TransactionMode,
RegenerationMode = ai.RegenerationMode,
JournalingMode = ai.JournalingMode
};
p.Items.Add(pi);
}
store.Applications.Add(p);
}
var directory = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) Directory.CreateDirectory(directory);
using (var fs = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
var ser = new DataContractJsonSerializer(typeof(PersistentAddinStore));
ser.WriteObject(fs, store);
}
return true;
}
catch (Exception)
{
return false;
}
}
2025-09-04 09:53:20 +08:00
}
}