.NET NX Journale debuggen

Inhaltsverzeichnis

Hintergrund

Journale1 sind ein beliebtes Mittel um Abläufe in NX zu automatisieren oder individuelle Erweiterungen zu realisieren. Zur Ausführung ist keine Compilierung und keine zusätzliche Lizenz notwendig. Es gibt jedoch auch verschiedene Nachteile. Gelegentlich wird als Nachteil genannt, dass die Fehlersuche mit einem Debugger nicht möglich sei. Das stimmt jedoch so nicht. Über einen kleinen Umweg können auch C# und VB.NET Journale mit Visual Studio oder auch WinDbg debuggt werden. Für umfangreichere Journale oder bei hartnäckigen Fehlern kann sich dieser Aufwand lohnen.

Lösungsansatz

Entscheidend für die Lösung des Problems ist, wie NX .NET Journale ausführt. Das auszuführende Journal wird dabei zunächst unter einem generischen Namen in ein temporäres Verzeichnis kopiert. Diese Kopie wird zur Laufzeit compiliert und anschließend gelöscht. Jetzt lädt NX das entstandene .NET Assembly wie ein reguläres NX Open-Programm. Nach Abarbeitung des Programmes löscht NX das temporäre Verzeichnis samt Inhalt.
Während des Programmlaufs ist mit dem Assembly und der zugehörigen Symboldatei (pdb-Datei) im temporären Verzeichnis fast alles Notwendige für das Debuggen vorhanden. Lediglich der Quellcode, auf den in der Symboldatei verwiesen wird, liegt zur Laufzeit nicht mehr vor.
Unter der Annahme, dass das ursprüngliche Journal von NX tatsächlich unverändert in das temporäre Verzeichnis kopiert wird, kann der Quellcode aus der Originaldatei wieder hergestellt werden. Der Name der Quellcodedatei muss dabei dem Namen des Assemblies entsprechen. Außerdem darf die Kopie erst erstellt werden, wenn das Programm bereits abgearbeitet wird. Nun kann die Quellcodedatei in Visual Studio oder in einem anderen Debugger geöffnet und der Debugger mit dem NX-Prozess verbunden werden.
Ein kurzer Versuch zeigt, dass dieser Ansatz funktioniert, wenn das ursprüngliche Journal Zeilenumbrüche im Unix-Format besitzt (LF). Bei Zeilenumbrüchen im Windows-Format (CR LF) reicht das Kopieren und Umbenennen des Journals nicht aus. Hier stimmt der MD5-Hash, der für den Quellcode im Assembly hinterlegt ist, nicht mit dem der kopierten Datei überein. Ein Anpassen der Zeilenumbrüche in der kopierten Datei führt zum Erfolg.

Umsetzung

Einige für das Debuggen notwendige Schritte können durch das Journal selbst erledigt werden. Diese sind hier in einer kleinen Methode zusammengefasst, die direkt nach dem Start des Journals aufgerufen werden kann.

/// <summary>
/// Prepare debugging of uncompiled journals.
/// </summary>
public static void InitJournalDebug()
{
    string journalPath = Session.GetSession().ExecutingJournal;
    string extension = Path.GetExtension(journalPath);
    Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
    string tmpSourcePath = Path.ChangeExtension(uri.LocalPath, extension);
    using (StreamWriter sw = File.CreateText(tmpSourcePath))
    {
        sw.NewLine = "\n";
        foreach (string line in File.ReadLines(journalPath))
        {
            sw.WriteLine(line);
        }
    }
    UI.GetUI().NXMessageBox.Show("Source File", NXMessageBox.DialogType.Information, string.Format("Source file for debugging:\n{0}", tmpSourcePath));
}

Die Methode kopiert das ursprüngliche Journal, versieht es mit den richtigen Zeilenumbrüchen und benennt es um. Danach wird die Programmausführung mittels eines Dialoges angehalten. Die im Dialog angezeigte Quellcodedatei kann vom Anwender in Visual Studio geöffnet und nach Bedarf mit Breakpoints versehen werden. Abschließend muss der Debugger an den NX-Prozess (ugraf.exe) angehängt und das Programm durch Bestätigen des Dialoges fortgesetzt werden.

Ein minimales Journal könnte also so aussehen:

using NXOpen;
using System;
using System.IO;
using System.Reflection;

public class Journal
{
    /// <summary>
    /// Journal entry point.
    /// </summary>
    /// <param name="args"></param>
    /// <returns></returns>
    public static int Main(string[] args)
    {
        int retValue = 0;
        try
        {
            InitJournalDebug();//Only for debugging, remove in production

            //Do something.
            double result = Foobar(Math.PI, Math.E);
        }
        catch (NXOpen.NXException e)
        {
            UI.GetUI().NXMessageBox.Show("Message", NXMessageBox.DialogType.Error, e.Message);
        }
        return retValue;
    }

    /// <summary>
    /// Prepare debugging of uncompiled journals.
    /// </summary>
    public static void InitJournalDebug()
    {
        string journalPath = Session.GetSession().ExecutingJournal;
        string extension = Path.GetExtension(journalPath);
        Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
        string tmpSourcePath = Path.ChangeExtension(uri.LocalPath, extension);
        using (StreamWriter sw = File.CreateText(tmpSourcePath))
        {
            sw.NewLine = "\n";
            foreach (string line in File.ReadLines(journalPath))
            {
                sw.WriteLine(line);
            }
        }
        UI.GetUI().NXMessageBox.Show("Source File", NXMessageBox.DialogType.Information, string.Format("Source file for debugging:\n{0}", tmpSourcePath));
    }

    /// <summary>
    /// Do something.
    /// </summary>
    /// <param name="foo"></param>
    /// <param name="bar"></param>
    /// <returns></returns>
    public static double Foobar(double foo, double bar)
    {
        double res = foo * bar;
        return res;
    }

    /// <summary>
    /// Unload option.
    /// Without effect for uncompiled journals
    /// </summary>
    /// <param name="arg"></param>
    /// <returns></returns>
    public static int GetUnloadOption(string arg)
    {
        return System.Convert.ToInt32(Session.LibraryUnloadOption.Immediately);
    }
}
Meldungsfenster in NX mit Pfad zum Quelltext.
Anfügen des Debuggers.

Fazit

Es ist möglich, zur Fehleranalyse von uncompilierten Journalen einen Debugger zu verwenden. Das Vorgehen ist ein wenig umständlich, erweitert aber die Einsatzmöglichkeiten dieser Journale, da so auch umfangreichere Fehlersuchen in komplexeren Programmen möglich sind.


  1. Der Begriff Journal wird im erweiterten Sinn häufig auch für NX Open-Programme allgemein verwendet. Hier sind aber ausschließlich in VB.NET oder C# realisierte Programme gemeint, die direkt als Quellcode ausgeführt werden. ↩︎