Drucken und PDF-Ausgabe in Windows-Geschäftsanwendungen — System.Drawing.Printing, WPF und Berichtsbibliotheken richtig einsetzen
· Go Komura · CSharp, .NET, WinForms, WPF, Drucken, PDF, Berichte, Windows-Entwicklung, Technische Beratung
Drucken in Windows-Geschäftsanwendungen ist nicht einfach mit „etwas in PrintDocument zeichnen und fertig“ erledigt. Seitenumbrüche greifen nicht, Ränder verrutschen, Vorschau und tatsächlicher Ausdruck unterscheiden sich oder ein PDF soll erzeugt werden, obwohl ein Druckdialog dazwischentritt — solche Probleme entstehen meist, wenn die Implementierung beginnt, bevor der Druckmechanismus richtig verstanden ist.
Dieser Beitrag ordnet vier Optionen nach ihren Anforderungen ein: System.Drawing.Printing für WinForms, FlowDocument und FixedDocument für WPF, Bibliotheken zur PDF-Ausgabe sowie Berichte über Excel oder Word.
1. Zuerst das Fazit
- Für einfache Listen oder die Weiterverwendung vorhandener WinForms-Bausteine reicht
PrintDocumentaus. Der Seitenumbruch funktioniert so, dass dasPrintPage-Ereignis wiederholt aufgerufen wird, bisHasMorePagesden Wertfalsehat. Wird das übersehen, erscheinen ab der zweiten Seite keine weiteren Ausgaben.12 - Die DPI beim Drucken sind nicht dieselben wie auf dem Bildschirm.
PageSettings.PrinterResolutionsteht für die Auflösung des Druckers. Ränder bestehen aus zwei Ebenen:PageSettings.HardMarginXundHardMarginY, dem physisch nicht bedruckbaren Bereich des Druckers, sowieMargins, dem von der Anwendung festgelegten logischen Rand. Werden Bildschirmkoordinaten unverändert zum Drucken verwendet, verschiebt dieses Zusammenspiel aus DPI und Koordinatensystem das Layout.345 - Unter WPF bestehen die Standarddruckpfade von Windows aus einem GDI- und einem XPS-Pfad. WPF-Anwendungen verwenden grundsätzlich den XPS-Pfad; für Drucker ohne XPSDrv-Unterstützung wird automatisch in das GDI-Format umgewandelt.67
- WPF-Dokumente folgen mit
FlowDocumentundFixedDocumentunterschiedlichen Entwürfen.FlowDocumentpriorisiert Lesbarkeit und layoutet je nach Fenstergröße und Auflösung neu;FixedDocumentpriorisiert die getreue Darstellung auf Anzeige- und Druckgeräten.89 - Papier und Fach werden in WPF mit
PrintDialogsowiePrintTicketundPrintQueuefestgelegt. Vor dem Drucken sollten Sie die Einstellung mitPrintQueue.MergeAndValidatePrintTicketgegen die tatsächlichen Fähigkeiten des Druckers prüfen und zusammenführen.1011 - Microsoft Print to PDF ist ein Druckertreiber für interaktive Bedienung. Er ist Teil der standardmäßig vorhandenen Druckwarteschlange und des Treiberpakets und zeigt grundsätzlich bei jedem Vorgang einen Dialog zur Wahl des Speicherorts. Für unbeaufsichtigte Batch-Verarbeitung ist er daher ungeeignet.12
- Office-COM-Automatisierung aus Servern oder Diensten wird von Microsoft offiziell weder unterstützt noch empfohlen. Office wurde für einen interaktiven Desktop und ein Benutzerprofil entwickelt; in unbeaufsichtigten, nicht interaktiven Umgebungen kann es instabil werden oder Deadlocks verursachen.13
- Windows-Dienste laufen in Sitzung 0. Sie können deshalb keine Dialoge anzeigen und dürfen sich auch nicht auf den mit einer Benutzersitzung verknüpften Standarddrucker verlassen. Berücksichtigen Sie diese Grenze von Beginn an, wenn Sie einen dauerhaft laufenden Prozess mit Druckfunktion planen.14
- Werden GDI-Objekte, also Handles, im Langzeitbetrieb nicht freigegeben, erreicht der Prozess sein Limit und kann abstürzen. Das Limit ist ein endlicher Wert, der sich über
GDIProcessHandleQuotain der Registrierung anpassen lässt; unbegrenzt können diese Objekte nicht angelegt werden.15
Entscheidungstabelle — Anforderung × Mittel
| Anforderung | Geeignetes Mittel | Grund |
|---|---|---|
| Einfache Listen oder wenige Belege aus WinForms drucken | PrintDocument |
Nur Standardklassen sind nötig; vorhandene GDI+-Zeichenlogik lässt sich direkt weiterverwenden |
| Berichte mit vielen Linien, mehreren Papierformaten oder komplexem Layout | Berichtsbibliothek oder festes Layout mit FixedDocument |
Koordinatenberechnung, Seitenumbrüche und japanischer Schriftsatz sind in Eigenentwicklung aufwendig |
| Große Batch-Druckläufe, nachts ohne Bedienung | Programmgesteuertes PrintDocument.Print() oder direkte Ausgabe an XpsDocumentWriter |
Der Ablauf muss ohne jeden Dialog enden und soll nicht vom Standarddrucker abhängen |
| Nur PDF speichern, ohne zu drucken | PDF direkt mit einer PDF-Bibliothek erzeugen | Kein Druckdialog, kein Standarddrucker und kein Zustand des Spoolers sind erforderlich |
| Vorschau ist zwingend, interne Freigabe wichtig | PrintPreviewDialog für WinForms, DocumentViewer für WPF |
Die Standardoberfläche zur Prüfung vor dem Drucken ist direkt nutzbar |
| Vorhandene Excel-Vorlage weiterverwenden | Direkte Erzeugung mit Open XML SDK oder begrenzte COM-Automatisierung | Bestehende Assets können weitergenutzt werden; COM-Automatisierung in dauerhaft laufenden Diensten vermeiden |
Im Folgenden betrachten wir die einzelnen Punkte genauer.
2. Das Nötigste zur Druckarchitektur von Windows
Die Druckarchitektur von Windows besteht aus dem Druckspooler und den Treibern für die einzelnen Drucker. Eine Anwendung ruft nur geräteunabhängige Funktionen auf und kann so Druckaufträge an ganz unterschiedliche Ziele wie Laserdrucker, Vektorplotter, Rasterdrucker oder Fax senden.16
Es gibt im Wesentlichen zwei Druckpfade.
- GDI-Druckpfad. Wenn eine Win32-GDI-Anwendung druckt, spult die GDI-Grafik-Engine ihre Zeichenanweisungen als EMF, Enhanced Metafile, oder rendert gemeinsam mit dem Druckertreiber direkt ein druckbares Bild und übergibt es an den Spooler. Traditionelle WinForms-Anwendungen verwenden diesen Weg.166
- XPS-Druckpfad. Dieser Weg ist für Druckertreiber auf Basis von XPS, XML Paper Specification, vorgesehen. WPF-Anwendungen verwenden ihn grundsätzlich und senden ein XPS-Dokument an den Spooler. Unterstützt der Zieldrucker keinen XPSDrv-Treiber, wird die Ausgabe vor dem Versand automatisch in GDI umgewandelt.67
Warum unterscheiden sich Bildschirm und Ausdruck? Der häufigste Grund ist eine Verwechslung der DPI. Die Grafik auf dem Bildschirm arbeitet gewöhnlich mit etwa 96 DPI, während die Drucker-Grafik mit der in PageSettings.PrinterResolution bestimmten und oft deutlich höheren Auflösung von ungefähr 600 DPI arbeitet.3 Werden für den Bildschirm berechnete Pixelkoordinaten direkt an die Drucker-Grafik übergeben, wird die Ausgabe viel kleiner gezeichnet, oder je nach Auflösungseinstellung auch größer als beabsichtigt. Legen Sie Druckkoordinaten deshalb immer in Hundertstel Zoll oder in realen Maßen wie Millimeter und Zoll an und nicht abhängig von der Auflösung der Grafik.
Ein weiterer leicht übersehener Punkt ist der physisch nicht bedruckbare Bereich des Druckers. Viele Drucker können einige Millimeter vom Papierrand entfernt nicht drucken. Diese physische Grenze lässt sich über PageSettings.HardMarginX und HardMarginY auslesen; die offizielle Dokumentation beschreibt sie als die vom Drucker festgelegten physischen Ränder.4 Die von der Anwendung gesetzten logischen Ränder sind PageSettings.Margins, standardmäßig je ein Zoll auf allen Seiten. Selbst wenn sie auf null gesetzt werden, kann nicht innerhalb des Hard Margin gedruckt werden.5 Fehler wie „Der Rand ist null, aber der Ausdruck wird abgeschnitten oder verschoben“ beruhen oft darauf, dass diese Hard Margins nicht berücksichtigt werden.
3. WinForms: praktische Arbeit mit System.Drawing.Printing
Der WinForms-Druck wird um die Komponente PrintDocument herum aufgebaut. Der grundlegende Ablauf lautet: ein PrintDocument erstellen, PrinterSettings und DefaultPageSettings festlegen, im Ereignis PrintPage tatsächlich zeichnen und den Druck mit der Methode Print() starten.1
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
public sealed class ReportPrinter
{
// Zu druckende Daten. Es wird von einer Belegposition pro Zeile ausgegangen.
private readonly IReadOnlyList<string> _lines;
private int _lineIndex;
public ReportPrinter(IReadOnlyList<string> lines) => _lines = lines;
public void Print(string printerName)
{
using var document = new PrintDocument();
document.DocumentName = "Bestellpositionen";
if (!string.IsNullOrEmpty(printerName))
{
document.PrinterSettings.PrinterName = printerName;
}
// Bei einem unbekannten Druckernamen ergibt die Prüfung hier false (nicht zur Erkennung eines Offlinezustands geeignet).
if (!document.PrinterSettings.IsValid)
{
throw new InvalidOperationException(
$"Der angegebene Drucker wurde nicht gefunden: {printerName}");
}
_lineIndex = 0;
document.PrintPage += Document_PrintPage;
document.Print();
}
private void Document_PrintPage(object? sender, PrintPageEventArgs e)
{
// MarginBounds ist der unter Berücksichtigung der logischen Ränder (Margins) verfügbare Zeichenbereich.
// PageBounds umfasst das gesamte Papier; selbst beim Zeichnen innerhalb des Hardwarerands kann Inhalt abgeschnitten werden.
using var font = new Font("Segoe UI", 10);
float lineHeight = font.GetHeight(e.Graphics);
float y = e.MarginBounds.Top;
while (_lineIndex < _lines.Count)
{
if (y + lineHeight > e.MarginBounds.Bottom)
{
// Diese Seite ist fertig. Da weitere Daten folgen, geht es auf der nächsten Seite weiter.
e.HasMorePages = true;
return;
}
e.Graphics.DrawString(_lines[_lineIndex], font, Brushes.Black,
e.MarginBounds.Left, y);
y += lineHeight;
_lineIndex++;
}
// Alle Zeilen sind gezeichnet; dies ist die letzte Seite.
e.HasMorePages = false;
}
}
Ein typisches Fehlerbild bei „Die zweite Seite erscheint nicht“ ist, HasMorePages nicht ausdrücklich auf false zurückzusetzen, obwohl der Standardwert false ist, oder die Verzweigung so falsch zu schreiben, dass sie stets mit false endet. Das Ereignis PrintPage wird wiederholt aufgerufen, bis diese Eigenschaft false ist. Prüfen Sie daher ausdrücklich, ob noch zu zeichnende Zeilen vorhanden sind, bevor Sie den Wert setzen.12 Sollen je Seite unterschiedliche Einstellungen wie Papierformat oder Ausrichtung gelten, können Sie neben PrintPage auch das Ereignis QueryPageSettings verwenden.
Ein typisches Fehlerbild bei „Der Rand verschiebt sich“ entsteht, wenn Koordinaten anhand von e.Graphics.VisibleClipBounds oder e.PageBounds aufgebaut und MarginBounds, der Bereich unter Berücksichtigung der logischen Ränder, sowie HardMarginX und HardMarginY, die physischen Grenzen des Druckers, ignoriert werden.4 Besonders leicht bleibt das unbemerkt, wenn der Drucker auf dem Entwicklungsrechner nur einen kleinen Hard Margin besitzt, beim Kunden aber ein anderes Modell mit größerem Hard Margin eingesetzt wird und dadurch Linien oder Felder abgeschnitten erscheinen. Der Drucktest auf mehreren Geräten ist ein oft übersehener Entwicklungsschritt.
Für eine Vorschau verwenden Sie PrintPreviewDialog und weisen dessen Eigenschaft Document einfach dasselbe PrintDocument zu; die Logik des PrintPage-Ereignisses kann unverändert wiederverwendet werden.1 Soll die Ausgabe entsprechend der Druckerauflösung umgeschaltet werden, ermitteln Sie die Optionen über PrinterSettings.PrinterResolutions und setzen sie in PageSettings.PrinterResolution.3
4. WPF: FlowDocument, FixedDocument und PrintDialog
Unter WPF entscheidet die Art des Dokuments darüber, ob FlowDocument oder FixedDocument den Schwerpunkt bildet.
FlowDocument. Dieses Dokument priorisiert Lesbarkeit und passt seinen Inhalt dynamisch an Laufzeitwerte wie Fenstergröße und Schriftkonfiguration an. Suche, Seiteneinteilung und Wechsel des Anzeigemodus gehören zu den Standardfunktionen.8FixedDocument. Dieses WYSIWYG-Dokument priorisiert Genauigkeit; die Anwendung kontrolliert sein Layout vollständig. Es passt, wenn die Darstellung auf Anzeige- und Druckgeräten sehr genau wiedergegeben werden muss.9
Für interne Berichte, bei denen ein gut lesbarer Textfluss Vorrang hat, ist FlowDocument der Ausgangspunkt. Für Belege oder Etiketten, bei denen die Position von Linien und Feldern pixelgenau feststehen soll, ist FixedDocument die Grundentscheidung.
Der grundlegende Druck erfolgt mit System.Windows.Controls.PrintDialog. Diese Klasse ist speziell für WPF und nicht dasselbe wie System.Windows.Forms.PrintDialog.10
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
public static class FlowDocumentPrinter
{
public static void Print(FlowDocument document, string jobName)
{
var printDialog = new PrintDialog();
// Nur drucken, wenn der Benutzer OK gewählt hat.
if (printDialog.ShowDialog() != true)
{
return;
}
// Da FlowDocument für Anzeige und Druck unterschiedliche Annahmen zur Seitengröße verwendet,
// Seitengröße und Ränder des Druckinhalts an den bedruckbaren Bereich des Druckers anpassen.
var paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
paginator.PageSize = new Size(
printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
printDialog.PrintDocument(paginator, jobName);
}
}
Sollen Papierformat, Papierfach oder Duplexdruck detailliert vorgegeben werden, verwenden Sie PrintQueue sowie PrintTicket und PrintCapabilities. PrintTicket beschreibt den Druckauftrag, PrintCapabilities die tatsächlich vom Drucker unterstützten Funktionen. Die vorgegebenen Einstellungen sollten mit PrintQueue.MergeAndValidatePrintTicket zuerst mit gültigen druckerspezifischen Werten zusammengeführt und geprüft werden.711
using System.Linq;
using System.Printing;
public static class DuplexPrintTicketBuilder
{
public static PrintTicket BuildDuplexTicket(PrintQueue printQueue)
{
PrintCapabilities capabilities = printQueue.GetPrintCapabilities();
// Vorab prüfen, ob der Drucker Duplexdruck (Bindung an der langen Kante) unterstützt.
bool supportsDuplex = capabilities.DuplexingCapability
.Contains(Duplexing.TwoSidedLongEdge);
var requestedTicket = new PrintTicket();
if (supportsDuplex)
{
requestedTicket.Duplexing = Duplexing.TwoSidedLongEdge;
}
// Mit dem Standard-PrintTicket des Benutzers nur die Duplexdruckanforderung zusammenführen.
// Nicht unterstützte Einstellungen werden automatisch durch gültige Werte ersetzt.
ValidationResult result = printQueue.MergeAndValidatePrintTicket(
printQueue.UserPrintTicket, requestedTicket);
return result.ValidatedPrintTicket;
}
}
Wird ein Bericht mit festem Layout als FixedDocument aufgebaut und direkt über den XPS-Druckpfad gesendet, fügt XpsDocumentWriter mit den Methoden Write oder WriteAsync den Auftrag in die PrintQueue ein. Unterstützt der Zieldrucker XPSDrv nicht, wird intern automatisch in GDI umgewandelt; der aufrufende Code muss den Pfad nicht eigens behandeln.7
5. Optionen für die PDF-Ausgabe
Die Anforderung „als PDF ausgeben“ führt je nachdem, welche der folgenden drei Bedeutungen gemeint ist, zu einer anderen Architektur:
- Als Erweiterung des Druckens genügt es, wenn der Benutzer das Speichern als PDF manuell auswählt.
- Die Anwendung soll über einen Druckdialog ein PDF erzeugen.
- Sie soll überhaupt nicht drucken, sondern in einem unbeaufsichtigten Batchlauf nur PDF-Dateien in großer Menge erzeugen.
Microsoft Print to PDF ist für 1 und 2 gedacht. Die seit Windows 10 standardmäßig vorhandene Funktion besteht aus Druckwarteschlange und Treiberpaket und erscheint der druckenden Anwendung als einer der normalen Drucker.12 Ihr Funktionsprinzip ist jedoch interaktiv: Bei jedem Druckvorgang wird nach Speicherort und Dateinamen gefragt. Offiziell gibt es Steuerungsmöglichkeiten nur auf Ebene der Druckwarteschlange und des betreffenden Treiberpakets, das ein Administrator aus einem Image entfernen kann.12 Für Fall 3 — eine unbeaufsichtigte große Batch-Verarbeitung, die still einen festgelegten Dateipfad als PDF schreibt — ist diese Architektur nicht geeignet. Verwenden Sie dafür eine Bibliothek, die PDF direkt erzeugt, ohne die Druckpipeline zu durchlaufen.
Bei der Auswahl einer PDF-Bibliothek sollten Sie die eigenen Anforderungen vor einer Produktempfehlung entlang der folgenden Kriterien ordnen.
| Kriterium | Zu prüfen |
|---|---|
| Lizenz | Open Source, etwa MIT/Apache oder GPL/AGPL, oder kommerzielle Lizenz. Wenn die eigene Anwendung extern verteilt oder verkauft wird, anhand der Primärquellen — Lizenztext und offizielle Seite des Anbieters — prüfen, ob Offenlegungspflichten, Bedingungen für Weitergabe und kommerzielle Nutzung zur eigenen Vertriebsform passen |
| Umgang mit japanischen Schriften | Unterstützt die Bibliothek Teilmengen-Einbettung japanischer Schriften? Kann die PDF die Schrift selbst enthalten, damit ohne installierte Schrift keine Zeichen beschädigt werden? Werden bei Bedarf vertikaler Satz und Variantenzeichen, IVS, unterstützt? |
| Funktionen für Berichte | Vorlagenbasierte Berichtsdefinition, Barcodes und 2D-Codes, elektronische Signaturen, PDF/A für Langzeitarchivierung und die Übertragbarkeit eines vorhandenen Papierlayouts |
| Abhängigkeiten und Laufzeitumgebung | Funktioniert sie auch auf Servern ohne GUI oder in Containern? Gibt es Abhängigkeiten von nativen Bibliotheken? Gibt es erprobte Nutzung unter .NET Core oder modernem .NET, nicht nur .NET Framework? |
| Leistung | Speicherverbrauch bei vielen Seiten oder Aufträgen in Batch-Erzeugung sowie Verhalten bei paralleler Erzeugung |
Lizenzbedingungen können sich je nach Produkt und Version ändern. Treffen Sie die Auswahl daher erst, nachdem Sie die offizielle Dokumentation des Anbieters und den eigentlichen Lizenztext geprüft haben. Dieser Beitrag empfiehlt keine bestimmte Bibliothek oder kein bestimmtes Produkt, sondern nennt nur die Vergleichskriterien.
6. Berichte über Excel oder Word als weitere Option
Gibt es bereits Berichte, die mit einer Excel-Vorlage betrieben werden, ist es manchmal realistischer, vorhandene Assets weiterzuverwenden, als sie von Grund auf neu zu erstellen. Grundsätzlich gibt es zwei Wege:
- xlsx/docx mit Open XML SDK oder ähnlichen Werkzeugen direkt erzeugen und bearbeiten. Dabei wird keine ausführbare Excel- oder Word-Anwendung gestartet; das Dateiformat, ZIP plus XML, wird direkt gelesen und geschrieben. Das läuft auch auf Servern stabil und eignet sich gut dafür, Linien und Formatierung der Vorlage beizubehalten und nur Werte einzusetzen. Näheres erläutert Wie man Excel-Berichte erstellt — COM, Open XML und Vorlagen.
- Mit Excel COM Interop die tatsächliche
Excel.Applicationsteuern. Diese Variante wird gewählt, wenn vorhandene Excel-Arbeitsmappen mit Makros oder komplexer Neuberechnung unverändert weiterverwendet werden sollen. Dabei bleiben durch nicht freigegebene COM-Referenzen leichtEXCEL.EXE-Prozesse zurück; Gegenmaßnahmen und Entscheidungskriterien behandelt Wenn EXCEL.EXE bei der Excel-Steuerung aus C# zurückbleibt.
Entscheidend ist hier, dass Microsoft Office-COM-Automatisierung auf der Serverseite oder in einem Windows-Dienst ausdrücklich als nicht empfohlen und nicht unterstützt bezeichnet. Office-Anwendungen sind für einen interaktiven Desktop und ein angemeldetes Benutzerprofil entworfen; in unbeaufsichtigten, nicht interaktiven Umgebungen können sie instabil werden oder Deadlocks verursachen.13 Auch lizenzrechtlich ist die Bereitstellung von Office-Funktionen für Clients über serverseitige Automatisierung in einer üblichen EULA nicht vorgesehen.13
Soll die Berichtsausgabe in einen dauerhaft laufenden Dienst oder einen Batchjob eingebaut werden, ist es daher sicherer, auch bei Weiterverwendung einer Excel-Vorlage keine Excel.exe zur Laufzeit über COM Interop zu starten, sondern auf eine direkte Dateierzeugung mit Open XML SDK oder ähnlichen Werkzeugen zu setzen. Ist COM Interop unvermeidlich, sollte die Anwendung als dauerhaft laufende Anwendung in einer interaktiv angemeldeten Benutzersitzung gestaltet werden — nicht als Dienst.
7. Praktische Fallstricke
Drucken aus Windows-Diensten und Sitzung 0
Anfragen, Druckverarbeitung in einen dauerhaft laufenden Dienst einzubauen, sind nicht selten. Windows-Dienste laufen jedoch in Sitzung 0. Seit Windows Vista ist Sitzung 0 ausschließlich für Prozesse reserviert, die weder zu einem Dienst noch zu einem interaktiven Benutzer gehören, und vom interaktiven Benutzer getrennt.14 Dadurch sieht der Benutzer einen Dialog nicht, selbst wenn der Dienst ihn anzeigt; Code, der auf eine Benutzereingabe wartet, etwa auf das Schließen eines Druckdialogs, wirkt dann wie aufgehängt.14
Ein weiterer praktischer Stolperstein ist die Sichtbarkeit von Netzwerkdruckern und benutzerspezifisch zugeordneten Druckern. Ein Netzwerkdrucker, den ein Benutzer nach der Anmeldung verbunden hat, ist häufig an dessen interaktive Sitzung gebunden und erscheint aus einer anderen Sitzung, also aus dem Prozesskontext eines Dienstes in Sitzung 0, nicht auf dieselbe Weise. Bei einem dauerhaft laufenden Prozess mit Druckfunktion muss von Anfang an geklärt sein: Welches Konto und welche Sitzung sehen welchen Drucker? Den Gesamtzusammenhang der Sitzungsisolation erläutert Windows-Sitzungsisolation verstehen — Sitzung 0, RDP und parallele Benutzer; Grundlagen der Implementierung und des Betriebs eines Dienstes behandelt Windows-Dienste erstellen und betreiben.
Verhalten ohne Drucker oder bei Offline-Druckern
Wird in PrinterSettings.PrinterName ein nicht vorhandener Drucker angegeben oder läuft die Anwendung in einer Umgebung ohne festgelegten Standarddrucker, treten beim Druckversuch Fehler oder Ausnahmen auf. Mindestens zwei Dinge sollten eingeplant werden: vorab mit PrinterSettings.IsValid prüfen und für Druckfehler Wiederholungen sowie Benachrichtigungen vorsehen. Ist ein Netzwerkdrucker vorübergehend offline, kann ein Auftrag zwar im Spooler liegen, die tatsächliche Ausgabe aber stehen bleiben. Beenden Sie die Betrachtung daher nicht mit „Senden war erfolgreich“, sondern erwägen Sie bei Bedarf auch eine Prüfung des Auftragsstatus.
Risiko der Abhängigkeit vom Standarddrucker
Eine Implementierung, die PrinterSettings.PrinterName nicht ausdrücklich festlegt und sich immer auf den „Standarddrucker“ verlässt, wird mit zunehmender Betriebsdauer riskanter. Ändert ein Benutzer seinen Standarddrucker oder nimmt ein Notebook an einen anderen Ort mit, kann sich die Ausgabe ungewollt auf einen anderen Drucker richten. Für geschäftskritische Berichte sollte der Name des Zielgeräts in einer Konfigurationsdatei oder in den Anwendungseinstellungen ausdrücklich gespeichert werden, damit Änderungen am Standarddrucker die Ausgabe nicht beeinflussen.
GDI-Handle-Leaks im Langzeitbetrieb
Werden GDI- oder GDI+-Ressourcen wie Graphics, Font, Brush und Pen im Druckcode nicht zuverlässig über using oder Dispose() freigegeben, können nach langer Laufzeit die Handles für GDI-Objekte erschöpft sein und Zeichen-APIs beginnen zu fehlschlagen. Diese Handles besitzen pro Prozess ein Standardlimit und sind eine endliche Ressource; der Registrierungswert GDIProcessHandleQuota kann das Limit im Bereich von 256 bis 65.536 verändern.15 Gerade bei dauerhaft laufenden Anwendungen, die oft drucken, werden solche Lecks leicht zu Fehlern, die erst in der Produktionsumgebung sichtbar werden. Konkrete Untersuchung und Eingrenzung von Handle-Leaks erklärt Untersuchung eines Langzeit-Crashs einer Industriekamera — Handle-Leaks.
Verwandte Artikel
- Wie man Excel-Berichte erstellt — COM, Open XML und Vorlagen
- Wenn EXCEL.EXE bei der Excel-Steuerung aus C# zurückbleibt — COM-Referenzen richtig freigeben und Alternativen abwägen
- Windows-Dienste erstellen und betreiben — Abgrenzung zum Aufgabenplaner bis zur Umwandlung von BackgroundService in einen Dienst
- Windows-Sitzungsisolation verstehen — Sitzung 0, RDP und parallele Benutzer
- Untersuchung eines Langzeit-Crashs einer Industriekamera — Handle-Leaks
Verwandte Beratungsbereiche
Komura Soft LLC berät zur Gestaltung von Druck- und Berichtsausgabefunktionen in Windows-Geschäftsanwendungen, zur Modernisierung von Berichten unter Weiterverwendung vorhandener Excel-Assets und zur Architektur von Druck- und Ausgabefunktionen aus dauerhaft laufenden Diensten.
Referenzen
-
Microsoft Learn, PrintDocument Class. Zur Rolle von
PrintDocument—DocumentNameundPrinterSettingssetzen und mitPrint()den Druck beginnen — sowie zum Hinweis, dass WPF für das Drucken den NamespaceSystem.Printingverwenden sollte. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, PrintPageEventArgs.HasMorePages Property. Dazu, dass der Standardwert
falseist und dasPrintPage-Ereignis wiederholt eintritt, bis diese Eigenschaftfalsewird. ↩ ↩2 -
Microsoft Learn, PageSettings.PrinterResolution Property. Dazu, dass die Standardauflösung einer Seite die Standardauflösung des Druckers ist und dass
PrinterSettings.PrinterResolutionsdie wählbaren Auflösungen liefert. ↩ ↩2 ↩3 -
Microsoft Learn, PageSettings.HardMarginX Property. Dazu, dass der Hard Margin den vom Drucker vorgegebenen physischen Rand darstellt. ↩ ↩2 ↩3
-
Microsoft Learn, PageSettings.Margins Property. Dazu, dass die Standardränder einer Seite auf allen vier Seiten je ein Zoll betragen und der druckbare Bereich im Ereignis
PrintPagezusammen mit der EigenschaftBoundsberechnet werden kann. ↩ ↩2 -
Microsoft Learn, Windows Print Path Overview. Dazu, dass Windows zwei wesentliche Druckpfade hat: den GDI-Pfad aus Win32-Anwendungen und den XPS-Pfad aus WPF-Anwendungen oder der XPS Print API. ↩ ↩2 ↩3
-
Microsoft Learn, Printing documents overview. Dazu, dass WPF den XPS-Druckpfad nutzt, zu einfachem Druck mit
PrintDialog, erweitertem Druck überPrintTicket,PrintCapabilities,PrintQueueundXpsDocumentWritersowie zur automatischen GDI-Umwandlung für Drucker ohne XPSDrv. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Flow Document Overview. Dazu, dass
FlowDocumentseine Inhalte anhand von Laufzeitwerten wie Fenstergröße und Auflösung neu layoutet und die Lesbarkeit priorisiert. ↩ ↩2 -
Microsoft Learn, FixedDocument Class. Dazu, dass
FixedDocumentals WYSIWYG-Entwurf eine getreue Darstellung auf Anzeige- und Druckgeräten priorisiert und einen anderen Gestaltungsansatz alsFlowDocumentverfolgt. ↩ ↩2 -
Microsoft Learn, PrintDialog Class. Dazu, dass
System.Windows.Controls.PrintDialogPrintTicketundPrintQueueanhand von Benutzereingaben konfiguriert und eine andere Klasse alsSystem.Windows.Forms.PrintDialogist. ↩ ↩2 -
Microsoft Learn, How to: Validate and Merge PrintTickets. Zum Prüfen der Druckerfähigkeiten über
PrintQueue.GetPrintCapabilitiesund zum Zusammenführen und Validieren der angeforderten Einstellungen mitMergeAndValidatePrintTicketin ein druckerspezifisches gültigesPrintTicket. ↩ ↩2 -
Microsoft Learn, RemoveMPDW. Dazu, dass Microsoft Print to PDF eine standardmäßig installierte optionale Funktion ist und auf Ebene von Druckwarteschlange und Treiberpaket konfiguriert oder entfernt wird. ↩ ↩2 ↩3
-
Microsoft Support, Considerations for server-side Automation of Office. Dazu, dass Microsoft Office-Automatisierung aus unbeaufsichtigten, nicht interaktiven Clientanwendungen einschließlich ASP, ASP.NET, DCOM und NT-Diensten weder empfiehlt noch unterstützt und dass Office für interaktiven Desktop und Benutzerprofil konzipiert ist. ↩ ↩2 ↩3
-
Microsoft Learn, Service Changes for Windows Vista - Session 0 Isolation. Dazu, dass Sitzung 0 seit Windows Vista ausschließlich für Anwendungen ohne Bezug zu Diensten oder interaktiven Benutzern reserviert ist und Dienste deshalb Dialoge nicht mehr direkt anzeigen können. ↩ ↩2 ↩3
-
Microsoft Learn, GDI Objects. Dazu, dass GDI-Objekt-Handles je Prozess ein Standardlimit besitzen und dieses über den Registrierungswert
GDIProcessHandleQuotazwischen 256 und 65.536 angepasst werden kann. ↩ ↩2 -
Microsoft Learn, Introduction to printing. Zur Zusammensetzung der Windows-Druckarchitektur aus Spooler und Druckertreibern sowie dazu, dass Zeichenanweisungen von Win32-GDI-Anwendungen als EMF gespult werden. ↩ ↩2
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Mit PerfView und dotnet-trace die Ursache von „langsam“ finden — Praxis-Einstieg in die .NET-Performanceanalyse
Wenn eine Geschäftsanwendung langsam ist, die CPU auslastet oder gelegentlich einfriert: Welches Werkzeug zeigt was? Dieser Beitrag ordne...
Nicht nur appsettings.json ── Praxisleitfaden für die Konfigurationsverwaltung in Windows-Geschäftsanwendungen (Umgebungen, Geheimnisse und Speicherorte)
Ein praxisnaher Leitfaden zur Konfigurationsverwaltung in Windows-Geschäftsanwendungen: Schichtung von appsettings.json, Einsatz von ICon...
Einführung in Windows-Ereignisprotokoll und ETW ── Protokolle von Geschäftsanwendungen in die Standardmechanismen des Betriebssystems einordnen
Verlassen Sie sich bei den Protokollen einer Windows-Geschäftsanwendung nur auf Dateien? Ereignisprotokoll und ETW bilden eine eigene Ebe...
Google Ads mit kleinem Budget im B2B ── Planung und wöchentliche Routine für Ergebnisse mit einigen Zehntausend Yen im Monat
Ein Praxisleitfaden für B2B-Unternehmen, die Google Ads mit einigen Zehntausend Yen monatlich beginnen möchten. Er behandelt durchschnitt...
Bei Suchen nach Ortsnamen sichtbar werden — Praxisleitfaden für lokales SEO für kleine und mittlere Unternehmen (Gebietsseiten und Google Unternehmensprofil)
Ihre Firma erscheint nicht bei einer Suche nach „Ortsname + Branche“? Dieser Beitrag ordnet für kleine und mittlere Unternehmen die sinnv...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
UI-Threading und Timer
WPF-/WinForms-UI-Thread, asynchrone Abläufe, Dispatcher und Timer-Entscheidungen.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Die Planung und Implementierung von Druck- und PDF-Ausgabefunktionen für Geschäftsanwendungen gehören zum Beratungsbereich für Windows-Anwendungsentwicklung.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Sollte ich mit PrintDocument oder mit WPF drucken?
- Für eine WinForms-Oberfläche ist PrintDocument, für WPF FlowDocument oder FixedDocument die naheliegende Wahl. Technologien müssen nicht gemischt werden; praktisch entscheidet das UI-Framework der bestehenden Anwendung. Bei einem neuen WPF-Projekt sollten Sie früh festlegen, ob der Bericht in erster Linie fließenden Text oder ein festes Layout braucht. Dann ist klar, ob FlowDocument oder FixedDocument die Grundlage bildet.
- Lohnt sich der Kauf einer Berichtsbibliothek?
- Bei komplexen Berichten mit vielen Linien, mehreren Papierformaten, eingebetteten japanischen Schriften oder vertikalem Satz kann die Einführung einer Berichtsbibliothek günstiger sein als eine aufwendige Eigenentwicklung mit GDI+ oder WPF. Für eine einfache A4-Übersicht reicht eine eigene Umsetzung mit PrintDocument oder FixedDocument oft aus. Schätzen Sie daher zuerst die Komplexität der Anforderungen ab.
- Kann ich nur PDF erzeugen und gar nicht drucken?
- Ja, das ist oft sinnvoll. PDF ist nur ein Ausgabeformat. Die direkte Erzeugung mit einer PDF-Bibliothek, die weder Druckdialog noch Standarddrucker benötigt, passt besonders gut zu Batch-Verarbeitung und Automatisierung. Microsoft Print to PDF ist ein Treiber für interaktive Nutzung und nicht für unbeaufsichtigte PDF-Erzeugung gedacht.
- Lassen sich auch Etiketten- oder Bondrucker unterstützen?
- Ja, allerdings nicht immer als bloße Erweiterung von PrintDocument oder FixedDocument. Viele Etikettendrucker besitzen eine eigene Befehlssprache oder ein SDK und werden häufig außerhalb des Standarddruckpfads von Windows angesteuert. Prüfen Sie zunächst, ob das Zielgerät wie ein normaler Windows-Drucker arbeitet oder eine Steuerung über ein spezielles SDK erfordert.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.
Öffentliche Links