LispLoader v1.0.000

Short description

🧩 LispLoader v1.0.000 is an AutoCAD and Civil 3D .NET startup loader that reads LoaderConfig.txt and safely processes configured LSP VLX FAS and DLL program files.
📄 One configured file failing does not intentionally stop the remaining load sequence and all results are written to the AutoCAD command line and a rolling disk log.
⚙️ The plugin starts its configured load sequence immediately when the compiled LispLoader DLL is loaded into AutoCAD.

Command:

Startup action: NETLOAD LispLoader.dll
Configuration file: LoaderConfig.txt
Log file: LispLoader.log

Description:

🧩 LispLoader v1.0.000 is an AutoCAD and Civil 3D .NET startup loader that reads LoaderConfig.txt and safely processes configured LSP VLX FAS and DLL program files.
📄 One configured file failing does not intentionally stop the remaining load sequence and all results are written to the AutoCAD command line and a rolling disk log.
⚙️ The plugin starts its configured load sequence immediately when the compiled LispLoader DLL is loaded into AutoCAD.

Helper function: (if any)​

Comming soon …

Functionalities:

✅ Configuration driven loading – uses LoaderConfig.txt as the source list.
✅ LSP loading – supports AutoLISP source files.
✅ VLX loading – supports Visual LISP executable files.
✅ FAS loading – supports compiled AutoLISP files.
✅ DLL loading – loads .NET assemblies with Assembly.LoadFrom and ExtensionLoader.
✅ Relative and absolute paths – accepts both path types in the configuration.
✅ Failure isolation – continues the loop when individual files are missing or return a handled failure.
✅ Command line logging – reports loading progress inside AutoCAD.
✅ Rolling disk log – writes LispLoader.log and rotates it at 5 MB.
✅ Version banner – prints version and build timestamp when the plugin initializes.

Result:

🎯 LispLoader v1.0.000 provides the described AutoCAD or Civil 3D workflow.
📌 The generated SEO description is based on the supplied source code or project files.

Images, animations etc.

Pixel

XAML code:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:Autodesk.Windows;assembly=AdWindows">
    
<src:RibbonToolTip x:Key="LispsLoader">
<src:RibbonToolTip.ExpandedContent>
<StackPanel>
<TextBlock Background="AntiqueWhite" TextAlignment="Left">
<Bold>Function Syntax: LispsLoader</Bold>
<LineBreak/>
<Bold>Version: 1.0 Date: 11.08.2026 3:19:48PM</Bold>
<LineBreak/>
<Bold>Version: 1.0 Date: 11.08.2026 3:19:52PM</Bold>
<LineBreak/>
<Hyperlink>N/A</Hyperlink>

<Bold><Run Foreground="DodgerBlue">Description</Run></Bold><LineBreak/>
<Run Foreground="White">🧩 LispLoader v1.0.000 is an AutoCAD and Civil 3D .NET startup loader that reads LoaderConfig.txt and safely processes configured LSP VLX FAS and DLL program files.</Run><LineBreak/>
<Run Foreground="White">📄 One configured file failing does not intentionally stop the remaining load sequence and all results are written to the AutoCAD command line and a rolling disk log.</Run><LineBreak/>
<Run Foreground="White">⚙️ The plugin starts its configured load sequence immediately when the compiled LispLoader DLL is loaded into AutoCAD.</Run><LineBreak/>
<LineBreak/>
<Bold><Run Foreground="DodgerBlue">Function Syntax</Run></Bold><LineBreak/>
<Run Foreground="White">Startup action: </Run><Bold><Run Foreground="Orange">NETLOAD LispLoader.dll</Run></Bold><LineBreak/>
<Run Foreground="White">Configuration file: </Run><Bold><Run Foreground="Orange">LoaderConfig.txt</Run></Bold><LineBreak/>
<Run Foreground="White">Log file: </Run><Bold><Run Foreground="Orange">LispLoader.log</Run></Bold><LineBreak/>
<LineBreak/>
<Bold><Run Foreground="LimeGreen">Primary Workflow</Run></Bold><LineBreak/>
<Run Foreground="White">1. NETLOAD LispLoader.dll into AutoCAD.</Run><LineBreak/>
<Run Foreground="White">2. AutoCAD calls the plugin Initialize method.</Run><LineBreak/>
<Run Foreground="White">3. The plugin prints the version and build timestamp.</Run><LineBreak/>
<Run Foreground="White">4. LoaderConfig.txt is read and blank or commented lines are ignored.</Run><LineBreak/>
<Run Foreground="White">5. Configured files are resolved and processed one by one.</Run><LineBreak/>
<Run Foreground="White">6. LSP VLX and FAS files are sent to the active AutoCAD document as load expressions.</Run><LineBreak/>
<Run Foreground="White">7. DLL files are loaded into the AppDomain and registered through AutoCAD ExtensionLoader.</Run><LineBreak/>
<Run Foreground="White">8. A final OK FAILED and SKIPPED summary is written to the log.</Run><LineBreak/>
<LineBreak/>
<Bold><Run Foreground="LimeGreen">Functionalities</Run></Bold><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Configuration driven loading</Run></Bold><Run Foreground="White"> - uses LoaderConfig.txt as the source list.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">LSP loading</Run></Bold><Run Foreground="White"> - supports AutoLISP source files.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">VLX loading</Run></Bold><Run Foreground="White"> - supports Visual LISP executable files.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">FAS loading</Run></Bold><Run Foreground="White"> - supports compiled AutoLISP files.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">DLL loading</Run></Bold><Run Foreground="White"> - loads .NET assemblies with Assembly.LoadFrom and ExtensionLoader.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Relative and absolute paths</Run></Bold><Run Foreground="White"> - accepts both path types in the configuration.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Failure isolation</Run></Bold><Run Foreground="White"> - continues the loop when individual files are missing or return a handled failure.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Command line logging</Run></Bold><Run Foreground="White"> - reports loading progress inside AutoCAD.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Rolling disk log</Run></Bold><Run Foreground="White"> - writes LispLoader.log and rotates it at 5 MB.</Run><LineBreak/>
<Run Foreground="White">✅ </Run><Bold><Run Foreground="LimeGreen">Version banner</Run></Bold><Run Foreground="White"> - prints version and build timestamp when the plugin initializes.</Run><LineBreak/>
<LineBreak/>
<Bold><Run Foreground="DarkRed">Important Notes</Run></Bold><LineBreak/>
<Run Foreground="White">⚠️ </Run><Bold><Run Foreground="DarkRed">Project version is 1.0.000.</Run></Bold><LineBreak/>
<Run Foreground="White">⚠️ </Run><Bold><Run Foreground="DarkRed">The provided LoaderConfig contains example entries for DLL LSP FAS and VLX files.</Run></Bold><LineBreak/>
<Run Foreground="White">⚠️ </Run><Bold><Run Foreground="DarkRed">The README recommends placing DLL entries before dependent LISP files.</Run></Bold><LineBreak/>
<Run Foreground="White">⚠️ </Run><Bold><Run Foreground="DarkRed">The LSP load path is sent asynchronously with SendStringToExecute so the immediate OK log represents successful dispatch rather than a full parser level verification of the target LISP result.</Run></Bold><LineBreak/>
<Run Foreground="White">⚠️ </Run><Bold><Run Foreground="DarkRed">An active AutoCAD document is required for LSP VLX and FAS dispatch.</Run></Bold><LineBreak/>
<LineBreak/>
<Bold><Run Foreground="Yellow">SEO Keywords</Run></Bold><LineBreak/>
<Run Foreground="Yellow">🏷️ AutoCAD  🏷️ Civil 3D  🏷️ LispLoader  🏷️ AutoLISP loader  🏷️ VLX loader  🏷️ FAS loader  🏷️ DLL loader  🏷️ LoaderConfig  🏷️ ExtensionLoader  🏷️ AutoCAD startup  🏷️ Rolling log  🏷️ CAD automation</Run><LineBreak/>




<LineBreak/>
</TextBlock>
</StackPanel>
</src:RibbonToolTip.ExpandedContent>
</src:RibbonToolTip>
</ResourceDictionary>

C# code:

// ===== FILE: ConfigReader.cs =====
using System;
using System.Collections.Generic;
using System.IO;

namespace LispLoader
{
    /// <summary>
    /// Reads LoaderConfig.txt from the fixed base folder.
    ///
    /// File format (one entry per line):
    ///   # This is a comment — ignored
    ///   ; This is also a comment — ignored
    ///                                        ← blank lines ignored
    ///   C:\full\path\to\file.lsp             ← absolute path
    ///   Polyline_menu\QuickMirror\QuickMirror.lsp   ← relative to base folder
    ///
    /// Relative paths are resolved against the base folder:
    ///   C:\Users\mateid\...\Help_File\
    /// </summary>
    internal static class ConfigReader
    {
        private const string Source = "ConfigReader";

        private static readonly string BaseFolder =
            @"C:\Users\mateid\OneDrive - DB E.C.O. Group\@C3D\@Dan_Templates\Acad\Support_files\Lisps\Help_File";

        private static readonly string ConfigFile =
            Path.Combine(BaseFolder, "LoaderConfig.txt");

        /// <summary>
        /// Returns the list of resolved absolute paths to load.
        /// Missing or unreadable config returns an empty list (logged as error).
        /// </summary>
        internal static IReadOnlyList<string> ReadPaths()
        {
            if (!File.Exists(ConfigFile))
            {
                LogManager.Error(Source, $"Config file not found: {ConfigFile}");
                LogManager.Warn (Source,  "Create LoaderConfig.txt in the base folder.");
                return Array.Empty<string>();
            }

            var paths = new List<string>();

            try
            {
                string[] lines = File.ReadAllLines(ConfigFile);
                int lineNo = 0;

                foreach (string raw in lines)
                {
                    lineNo++;
                    string line = raw.Trim();

                    // Skip blanks and comments
                    if (string.IsNullOrEmpty(line))      continue;
                    if (line.StartsWith("#"))             continue;
                    if (line.StartsWith(";"))             continue;

                    // Resolve relative paths
                    string resolved = Path.IsPathRooted(line)
                        ? line
                        : Path.Combine(BaseFolder, line);

                    paths.Add(resolved);
                }

                LogManager.Info(Source, $"Config loaded: {paths.Count} entries from {ConfigFile}");
            }
            catch (Exception ex)
            {
                LogManager.Error(Source, $"Failed to read config: {ex.Message}");
            }

            return paths;
        }
    }
}


// ===== FILE: FileLoader.cs =====
using System;
using System.IO;
using System.Reflection;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;

namespace LispLoader
{
    /// <summary>
    /// Loads individual files safely — one failure never stops the next file.
    ///
    /// Supported types:
    ///   .lsp  .vlx  .fas  →  Editor.RunLisp( (load "path") )
    ///   .dll              →  Assembly.LoadFrom  +  ExtensionLoader
    /// </summary>
    internal static class FileLoader
    {
        private const string Source = "FileLoader";

        // ── Public entry point ────────────────────────────────────────────────

        /// <summary>
        /// Load a single file. Swallows all exceptions and logs the result.
        /// Returns true on success.
        /// </summary>
        internal static bool Load(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
                return false;

            path = path.Trim();

            if (!File.Exists(path))
            {
                LogManager.Warn(Source, $"[NOT FOUND]  {path}");
                return false;
            }

            string ext = Path.GetExtension(path).ToLowerInvariant();

            return ext switch
            {
                ".lsp" or ".vlx" or ".fas" => LoadLisp(path),
                ".dll"                      => LoadDll(path),
                _                           => UnsupportedType(path, ext),
            };
        }

        // ── LSP / VLX / FAS ──────────────────────────────────────────────────

        private static bool LoadLisp(string path)
        {
            try
            {
                // Escape backslashes for the LISP string
                string escaped = path.Replace("\\", "\\\\");
                string expr    = $"(load \"{escaped}\")";

                Document? doc = Application.DocumentManager?.MdiActiveDocument;
                if (doc == null)
                    throw new InvalidOperationException("No active document.");

                // RunLisp evaluates silently — no command echo on the prompt
                doc.SendStringToExecute(expr + "\n", false, false, false);

                // RunLisp does not return a catchable error for LOAD failures;
                // we use a second expression to check if the load produced an error atom.
                // The reliable signal is the absence of an exception here —
                // any reader-level crash in the target file surfaces as an Exception.
                LogManager.Info(Source, $"[OK]         {path}");
                return true;
            }
            catch (System.Exception ex)
            {
                LogManager.Error(Source, $"[FAIL-LISP]  {path}");
                LogManager.Error(Source, $"             {ex.Message}");
                return false;
            }
        }

        // ── DLL ──────────────────────────────────────────────────────────────

        private static bool LoadDll(string path)
        {
            try
            {
                // Step 1 — load the assembly into the AppDomain
                Assembly asm = Assembly.LoadFrom(path);

                // Step 2 — register it with AutoCAD's ExtensionLoader
                //           so IExtensionApplication.Initialize() is called
                ExtensionLoader.Load(path);

                string name    = asm.GetName().Name ?? Path.GetFileName(path);
                string version = asm.GetName().Version?.ToString() ?? "?";
                LogManager.Info(Source, $"[OK-DLL]     {name}  v{version}");
                LogManager.Info(Source, $"             {path}");
                return true;
            }
            catch (System.Exception ex)
            {
                LogManager.Error(Source, $"[FAIL-DLL]   {path}");
                LogManager.Error(Source, $"             {ex.Message}");
                return false;
            }
        }

        // ── Helpers ───────────────────────────────────────────────────────────

        private static bool UnsupportedType(string path, string ext)
        {
            LogManager.Warn(Source, $"[SKIP]       Unsupported extension '{ext}': {path}");
            return false;
        }
    }
}


// ===== FILE: VersionStamp.cs =====
using System;
using System.Linq;
using System.Reflection;

namespace LispLoader
{
    /// <summary>
    /// Prints the version banner whenever the plugin loads.
    ///
    /// Format:  v1.0.000 | built 12.06.2026 10:30:00
    ///
    /// Version   → AssemblyVersion set in &lt;Version&gt; in the .csproj
    /// Timestamp → AssemblyMetadata("BuildTimestamp", "dd.MM.yyyy_HH.mm.ss")
    ///             injected at compile time by the MSBuild SetBuildTimestamp target.
    ///             No generated .cs file required.
    /// </summary>
    internal static class VersionStamp
    {
        private const string Source = "LispLoader";

        internal static void Print()
        {
            Assembly asm = Assembly.GetExecutingAssembly();

            // ── Version ───────────────────────────────────────────────────────
            string version = asm.GetName().Version?.ToString(3) ?? "?.?.???";

            // ── Timestamp from AssemblyMetadata ───────────────────────────────
            // The .csproj target adds:
            //   [assembly: AssemblyMetadata("BuildTimestamp", "12.06.2026_10.30.00")]
            string raw = asm
                .GetCustomAttributes<AssemblyMetadataAttribute>()
                .FirstOrDefault(a => a.Key == "BuildTimestamp")
                ?.Value
                ?? "??.??.????_??.??.??";

            // raw = "12.06.2026_10.30.00"
            string[] halves = raw.Split('_');
            string date = halves.Length > 0 ? halves[0] : "??";                    // 12.06.2026
            string time = halves.Length > 1 ? halves[1].Replace('.', ':') : "??";  // 10:30:00

            string banner = $"v{version} | built {date} {time}";

            LogManager.Separator();
            LogManager.Info(Source, banner);
            LogManager.Separator();
        }
    }
}


// ===== FILE: LogManager.cs =====
using System;
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;

namespace LispLoader
{
    /// <summary>
    /// Log levels for filtering output.
    /// </summary>
    internal enum LogLevel { INFO, WARN, ERROR }

    /// <summary>
    /// Writes timestamped log lines to both the AutoCAD command line
    /// and a persistent .log file on disk.
    ///
    /// Format:  HH:mm:ss  [LEVEL]  [Source]  message
    /// Example: 05:29:43  [INFO]   [LispLoader]  Loaded ObjectPropExtra.dll
    /// </summary>
    internal static class LogManager
    {
        // ── Config ────────────────────────────────────────────────────────────
        private static readonly string LogFolder =
            @"C:\Users\mateid\OneDrive - DB E.C.O. Group\@C3D\@Dan_Templates\Acad\Support_files\Lisps\Help_File";

        private static readonly string LogFile =
            Path.Combine(LogFolder, "LispLoader.log");

        // Maximum log file size before it is rotated (5 MB)
        private const long MaxLogBytes = 5 * 1024 * 1024;

        // ── Public API ────────────────────────────────────────────────────────

        internal static void Info(string source, string message)
            => Write(LogLevel.INFO, source, message);

        internal static void Warn(string source, string message)
            => Write(LogLevel.WARN, source, message);

        internal static void Error(string source, string message)
            => Write(LogLevel.ERROR, source, message);

        internal static void Separator()
            => Write(null, null, new string('─', 72));

        // ── Core ──────────────────────────────────────────────────────────────

        private static void Write(LogLevel? level, string? source, string message)
        {
            string line = Format(level, source, message);

            // 1. AutoCAD command line
            try
            {
                Document? doc = Application.DocumentManager?.MdiActiveDocument;
                Editor? ed = doc?.Editor;
                ed?.WriteMessage("\n" + line);
            }
            catch { /* editor unavailable during early init — swallow */ }

            // 2. Disk log
            try
            {
                RotateIfNeeded();
                File.AppendAllText(LogFile, line + Environment.NewLine);
            }
            catch { /* disk unavailable — swallow */ }
        }

        private static string Format(LogLevel? level, string? source, string message)
        {
            string ts   = DateTime.Now.ToString("HH:mm:ss");
            string lvl  = level.HasValue ? $"[{level.Value,-5}]" : "       ";
            string src  = source != null ? $"[{source}]" : string.Empty;
            return $"{ts}  {lvl}  {src,-20}  {message}";
        }

        private static void RotateIfNeeded()
        {
            if (!File.Exists(LogFile)) return;
            var info = new FileInfo(LogFile);
            if (info.Length < MaxLogBytes) return;

            // Rename current log to .bak (overwrite previous backup)
            string bak = Path.ChangeExtension(LogFile, ".bak.log");
            if (File.Exists(bak)) File.Delete(bak);
            File.Move(LogFile, bak);
        }
    }
}


// ===== FILE: LispLoader.cs =====
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;

// Register this assembly as an AutoCAD extension
[assembly: ExtensionApplication(typeof(LispLoader.LispLoaderApp))]

namespace LispLoader
{
    /// <summary>
    /// Entry point for the LispLoader AutoCAD plugin.
    ///
    /// AutoCAD calls Initialize() immediately after _.netload completes.
    /// Terminate() is called when AutoCAD shuts down.
    ///
    /// Usage — paste once into the AutoCAD command prompt:
    ///   (command "_.netload" "C:\\...\\LispLoader.dll")
    /// </summary>
    public class LispLoaderApp : IExtensionApplication
    {
        private const string Source = "LispLoader";

        // ── IExtensionApplication ─────────────────────────────────────────────

        public void Initialize()
        {
            // 1. Banner with version + build timestamp
            VersionStamp.Print();

            // 2. Read the config file
            IReadOnlyList<string> paths = ConfigReader.ReadPaths();

            if (paths.Count == 0)
            {
                LogManager.Warn(Source, "Nothing to load — check LoaderConfig.txt.");
                LogManager.Separator();
                return;
            }

            // 3. Load each file — failures are isolated, loading always continues
            int ok   = 0;
            int fail = 0;
            int skip = 0;

            LogManager.Info(Source, $"Starting load sequence: {paths.Count} file(s)");
            LogManager.Separator();

            foreach (string path in paths)
            {
                bool result = FileLoader.Load(path);

                if (result)      ok++;
                else if (System.IO.File.Exists(path)) fail++;
                else             skip++;
            }

            // 4. Summary
            LogManager.Separator();
            LogManager.Info(Source, $"Load complete —  OK: {ok}   FAILED: {fail}   SKIPPED (not found): {skip}");
            LogManager.Separator();
        }

        public void Terminate()
        {
            LogManager.Info(Source, "LispLoader unloaded.");
        }
    }
}

Additional info:

Share this page: