zplCore.comzplCore.com

ZplVirtualPrinter

public sealed class ZplVirtualPrinter : IAsyncDisposable

Virtual network label printer: a TCP listener (raw port 9100 protocol) that accepts ZPL or EPL jobs, renders them with ZplRenderer / EplRenderer (one per connection, i.e. its own printer memory), raises LabelReceived and optionally writes the images to ZplVirtualPrinter.OutputDirectory.


Chaos printer: ZplVirtualPrinter.Faults simulates printer conditions (paper/ribbon out, head open, over/under temperature, pause, buffer full, out of memory, cutter fault, RFID void) and communication faults (disconnect after n bytes, communication timeout, latency, slow receive, partial writes, power off), set directly or scheduled deterministically (after n labels/bytes/cuts, on a command, after a time, seeded random). They show on the wire like on a Zebra printer: labels stay in the buffer while printing is stopped, ~HS, ~HQES and SGD device.host_status / head.latch report the flags, a full buffer stops reading the socket. Recovery per the ZPL manual: ~PS resumes from pause, ~JA cancels all buffered formats, ~JP cancels the next format and pauses, ~JR resets (buffer cleared, pause off; physical conditions remain until cleared), ~JK cuts in delayed cut mode. Behaviour and manual references: docs-internal/chaos-printer.md.
Host queries ~HS, ~HI, ~HM and ~HQ (ES, SN, OD, PH) are answered from the simulated state; ZplVirtualPrinter.HostQueryHandler overrides them.
Connections are accepted concurrently but their data is processed one connection at a time, like on a Zebra printer with its single print engine ("first come and first served"; a connection that has sent half a format keeps the others waiting until the format is complete, the connection closes or ZplVirtualPrinter.IdleTimeout ends it). ZplVirtualPrinter.ConcurrentConnections restores processing every connection in parallel (load tests).

Constructors

SignatureDescription
# ZplVirtualPrinter(int port = 9100, IPAddress? address = default)port: TCP port (0 = any free port, see ZplVirtualPrinter.Port after ZplVirtualPrinter.Start). · address: Listen address (default: loopback; use IPAddress.Any for the network).

Properties

PropertyTypeDescription
ConcurrentConnections { get; set; }boolProcess the data of all connections in parallel (behaviour of earlier versions, for load tests). Default false: like a Zebra printer, connections are accepted at the same time but served one after the other, first come first served – a connection holds the printer from its first data until it has no incomplete format left (Zebra developer forum: "only one print engine … taken on a first come and first served basis"; PrintSecure guide P1099957: the raw ports allow multiple connections served first come first served, ip.port_single_conn refuses a second one).
Faults { get; }ZplPrinterFaultsPrinter conditions and communication faults (chaos printer).
Firmware { get; set; }string
HonorPauseCount { get; set; }bool^PQ p with o = N pauses the printer after every group of p labels, like a Zebra printer (resume with ~PS). Default false: such jobs print through (behaviour of earlier versions).
HostQueryHandler { get; set; }Func<string, string>Custom host query answers: gets the command (e.g. "~HQES"), returns the response or null for the default.
IdleTimeout { get; set; }TimeSpanCloses a connection without data for this long (default 60 s).
IsRunning { get; }bool
LabelPrintTime { get; set; }TimeSpanTime to print one label (default 0: instantly). With a print time the printer works through its buffer in the background, so ~JA/~JP can cancel labels that have not printed yet and ~HS reports the labels remaining.
MaxJobBytes { get; set; }intUpper bound of buffered unprocessed data per connection (default 64 MB).
MemoryBytes { get; set; }longPrinter memory for downloads (~DG, ~DY, ~DU, ^DF) per connection in bytes; 0 = default of ZplResourceStore.MaxTotalBytes. Reported by ~HM.
Model { get; set; }stringModel reported by ~HI.
OutputDirectory { get; set; }stringWhen set, each rendered label is saved here ("label-yyyyMMdd-HHmmss-n.png").
Port { get; }intThe bound port (valid after ZplVirtualPrinter.Start).
Profile { get; }PrinterProfileThe profile applied with ZplVirtualPrinter.ApplyProfile, null for the generic virtual printer.
ReceiveBufferBytes { get; set; }intReceive buffer: while the formats waiting to print hold this many bytes, the buffer-full flag is set and the printer stops reading (0 = unlimited).
RenderSettings { get; init; }ZplRenderSettingsRender settings used for each new connection (dpi, label size, output format PNG/PDF/..., ZplRenderSettings.CutterInstalled).
RfidSimulator { get; set; }ZplRfidSimulatorRFID tag simulation (default null: off). When set, each label with RFID commands is encoded into a simulated Gen2 tag from ZplRfidSimulator.NextTag; a failed encoding or read-back voids the label like ZplFaultKind.RfidVoid (^RS tries and error handling). ^HV responses are sent to the host. ~RVE / ~RVD report "_+,n_" / "_-,n_" per RFID label with or without simulation.
SerialNumber { get; set; }string
SilentHostStatusOnError { get; set; }boolNo ~HS / device.host_status answer while media out, ribbon out, head open or head over temperature (note in the 2026 ZPL manual, ~HS). Default false: answered with the flags set, as the older manual and the Link-OS SDK expect.
TimeProvider { get; init; }TimeProviderClock of the simulation (default TimeProvider.System): ZplVirtualPrinter.LabelPrintTime, fault timers (ZplFaultTrigger.After, ZplFaultRule.ClearAfter), latency, slow receive and partial writes wait on it. A manual clock (e.g. FakeTimeProvider) makes timed scenarios deterministic in tests.

Methods

Method SignatureReturnsDescription
# ApplyProfile(PrinterProfile profile)ZplVirtualPrinterMakes the virtual printer behave like profile (call before ZplVirtualPrinter.Start): resolution, label width = printhead width, cutter as installed (PrinterProfile.InstalledOptions; cutter mode on a printer without cutter raises a cutter fault), download memory = user RAM + user flash, and the identity answers: ~HI "model,firmware,dots/mm,RAM KB," and SGD getvar device.product_name, appl.name, head.resolution.in_dpi, ezpl.print_width, device.languages, device.unique_id, device.host_identification. An existing ZplVirtualPrinter.HostQueryHandler keeps priority. Values that the profile does not know keep the defaults. See docs-internal/printer-twin.md for which parts of these answers are documented and which are assumptions.
# DisposeAsync()ValueTask
# GetStatus()ZplVirtualPrinterStatusSnapshot of the simulated printer: conditions, buffer, counters and the current ~HS / ~HQES answers.
# Start()void
# StopAsync()Task
# WaitForIdleAsync(TimeSpan timeout)Task<bool>Waits until the buffer is empty and no label is printing (or printing is stopped by a condition); false on timeout.

Events

EventHandler TypeDescription
ErrorEventHandler<Exception>Raised when a connection fails (bad data, renderer errors, IO); the listener keeps running.
JobReceivedEventHandler<VirtualJobEventArgs>
LabelCutEventHandler<VirtualCutEventArgs>The cutter cut after a label (cutter, delayed cut with ~JK, kiosk ^CN, RFID void with ^PQ e).
LabelDroppedEventHandler<VirtualLabelEventArgs>A label was lost (ZplFaultKind.DropLabels): rendered but not printed.
LabelReceivedEventHandler<VirtualLabelEventArgs>