Um List & Label in einem Windows Docker Image ausführen zu können, gibt es ein paar nützliche Tipps & Tricks wie auch Hinweise, die berücksichtigt werden müssten.
Hinweis: Die folgenden Tipps und Tricks beziehen sich auf die Verwendung einer .NET Anwendung - gelten davon aber unabhängig auf für andere Programmierumgebungen wie C++, VCL etc.
Printerless: Kein Drucker(-treiber) verfügbar
In Windows Docker-Images existiert kein nutzbarer Druckertreiber, sodass List & Label im sogenannten Printerless-Mode arbeiten muss - siehe auch List & Label ohne Druckertreiber verwenden (Printerless). Diese Tatsache wird in der Regel von List & Label unter Docker automatisch erkannt und der Modus entsprechend gesetzt. Er kann aber auch explizit über die Eigenschaft Printerless aktiviert werden:
...
LL.Printerless = true;
...
Durch den Printerless-Mode können geringfügige Abweichungen bei der Ausrichtung und Positionierung von Texten entstehen - siehe auch Printerless-Modus: Auswirkungen und Optionen bei der Ausgabe von Texten. Über die Option LlOption.VirtualDeviceScalingOptions kann Einfluss auf die Textausgaben genommen werden - Beispiel:
...
LL.Core.LlSetOption(LlOption.VirtualDeviceScalingOptions, 600);
...
Wichtig: Beachten Sie in diesem Zusammenhang unbedingt den Punkt Fehlende Schriftarten in Windows Docker-Images in diesem Artikel.
Protokollierung
Da in einem Docker-Image das Debwin4-Tool nicht zur Verfügung steht um so bequem wie in einer einfachen Windows Desktop Anwendung die Logausgaben von List & Label aufzuzeichnen, muss die Protokollierung in eine Datei umgeleitet werden. Hierzu stehen die beiden Eigenschaften Debug und DebugLogFilePath zur Verfügung:
...
LL.DebugLogFilePath = logfilePath;
LL.Debug = LlDebug.Enabled | LlDebug.LogToFile;
...
Weitere wichtige Debug-Flags können zusätzlich LlDebug.ObjectStates und LlDebug.ForceSysinfo sein.
Fehlende Schriftarten in Windows Docker-Images
Es gibt nur wenige Windows Docker-Images, bei denen wie gewohnt sämtliche Fonts enthalten sind und für die Ausgabe verwendet werden können. In Server-Core Images steht meist nur die Schriftart Lucon zur Verfügung. Dadurch können aber Ausgaben im Reporting die Verdana, Tahoma, Segoi UI etc. verwenden nicht zufriedenstellend dargestellt werden - siehe auch Fehlende Fonts in den Windows Server Core Docker-Images nachinstallieren.
Ab List & Label in der Version 30 können die Schriftarten direkt über den Designer in die Projektdateien eingebettet werden und ein Nachinstallieren der Schriftarten auf dem Docker-Image ist nicht mehr erforderlich. Frühere Versionen von List & Label müssen jedoch wie hier beschrieben vorgehen.
Für frühere List & Label Version oder wenn die Schriftarten nicht in den Projektdateien eingebettet sind, ist es essentiell wichtig, dass die fehlenden Schriftarten nicht nur auf dem Docker-Image durch einfaches Kopieren bereitgestellt werden - Auszug aus dem Dockerfile:
...
WORKDIR /src
#Copy the fonts to docker
COPY ["/fonts/", "/fonts/"]
...
Die kopierten Schriftarten müssen auch dem ausführenden Prozess mitgeteilt werden - noch bevor das List & Label Objekt erzeugt wird! - was zur Laufzeit über die Windows API AddFontResource() umgesetzt werden kann:
internal static class NativeMethods
{
[DllImport("gdi32.dll")]
internal static extern int AddFontResource
(
string lpFilename
);
}
// ...
string[] files = Directory.GetFiles(Path.Combine(appPath, "Fonts"));
foreach(string fileName in files)
{
NativeMethods.AddFontResource(fileName);
}
Hinweis: Bitte beim Kopieren und Bereitstellen der Schriftarten im Docker-Image ggf. die entsprechenden Lizenzbestimmungen des Herstellers für die Schriftarten berücksichtigen.
Unterschiedliche Maßsysteme
Die Druckvorlagen werden bereits im Vorfeld auf einem lokalen Windows-System über den Designer oder den Web Report Designer erstellt, wobei die lokalen Windows-Region Einstellungen berücksichtigt werden. Doch die bereitgestellten Windows Docker-Images basieren alle auf en-US und es kommt daher inch/Zoll als Maßsystem zum Einsatz.
Wenn nun aber das lokale Windows-System für das Erstellen der Druckvorlagen im Designer ein de-DE System ist und mm/Millimeter als Maßeinheit verwendet und die Druckvorlage in einem Docker-Image mit en-US verwendet wird, kann es zu unerwarteten Endlosschleifen und fehlerhaften Darstellungen im Bericht kommen, da en-US im Standard mit inch/Zoll anstelle von mm/Millimeter rechnet - siehe auch Verwendung von List & Label Druckvorlagen unter gemischten Maßsystemen. Daher sollte man bei der Verwendung für Positions- und Dimensionsangaben mit Formeln von Objekten im Designer die Designer-Funktion UnitFromSCM verwenden. Über die Eigenschaft Unit kann das Maßsystem vom List & Label bestimmt werden:
...
LL.Unit = LlUnits.Millimeter_1_1000;
...
.NET Grundgerüst:
Zusammengefasst eignet sich mit den obigen Informationen das folgende Code-Snippet als gute Ausgangslage:
internal static class NativeMethods
{
[DllImport("gdi32.dll")]
internal static extern int AddFontResource
(
string lpFilename
);
}
// ...
// installing fonts to current process
string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string[] files = Directory.GetFiles(Path.Combine(appPath, "Fonts"));
foreach (string fileName in files)
NativeMethods.AddFontResource(fileName);
using (ListLabel LL = new ListLabel())
{
//LL.LicensingInfo = "";
// define printerless-mode
LL.Printerless = true;
// define scaling value for text rendering
LL.Core.LlSetOption(LlOption.VirtualDeviceScalingOptions, 600);
// define path for logfile and delete old one
string logfilePath = Path.Combine(appPath, "debug.log");
if (File.Exists(logfilePath))
File.Delete(logfilePath);
// enable debnugging into logfile with helpful options
LL.DebugLogFilePath = logfilePath;
LL.Debug = LlDebug.Enabled | LlDebug.LogToFile |
LlDebug.ObjectStates | LlDebug.ForceSysinfo;
// define the measurement system
LL.Unit = LlUnits.Millimeter_1_1000;
// define additional options, the dada source,
// project-file/repository, export parameters etc.
string profectFile = Path.Combine(appPath, "myProject.lst");
string exportFile = Path.Combine(appPath, "export.ll");
ExportConfiguration exportPreview =
new ExportConfiguration(LlExportTarget.Preview, exportFile, profectFile);
LL.Export(exportPreview);
}
...