I am using this C++ code to successfully send a command to a thermal printer (Citizen CT S310II) that is attached via USB:
bool SendPrinterCommand(char* printerName, unsigned char* command, int size)
{
HANDLE printer = NULL;
BOOL result = OpenPrinter((LPSTR)printerName, &printer, NULL);
DOC_INFO_1 doc = { TEXT("PrinterCommand"), 0, TEXT("RAW") };
DWORD jobId = StartDocPrinter(printer, 1, (LPBYTE)&doc);
if (jobId)
{
if (StartPagePrinter(printer))
{
DWORD dwBytesWritten = 0;
if (WritePrinter(printer, command, size, &dwBytesWritten))
{
// read back from the printer
HANDLE printerJob = NULL;
String jobName = printerName + STRING(",Job %d", jobId);
BOOL result = OpenPrinter((LPSTR)jobName.c_str(), &printerJob, NULL);
if (result)
{
const int SIZE = 2048;
char* buffer = new char[SIZE];
DWORD size = 0;
if (ReadPrinter(printerJob, buffer, SIZE, &size))
{
REPORT("received %d bytes from the printer", size);
}
delete[] buffer;
ClosePrinter(printerJob);
}
}
EndPagePrinter(printer);
}
EndDocPrinter(printer);
}
ClosePrinter(printer);
}
To open up an attached cash-drawer I call it like this:
// ESC p m t1 t2
unsigned char command[] = "\33p\0\31\372";
SendPrinterCommand("Citizen CT S310II", command, 5);
This command works fine, and it shows me that sending ESC-sequence commands basically work through WritePrinter()
.
Now I would like to send a command that allows me to check the paper-status of the thermal-printer:
// DLE EOT n
// n=1 Transmit printer status
// n=2 Transmit off-line status
// n=3 Transmit error status
// n=4 Transmit paper roll sensor status
unsigned char command[] = "\20\4\4";
SendPrinterCommand("Citizen CT S310II", command, 3);
This command requires to read back the result. However, while ReadPrinter()
succeeds, it always returns 0 bytes read. From another thread I learned that ReadPrinter()
only works on a HANDLE
to the printer job. Using the HANDLE
of the printer instead made the call to ReadPrinter
fail - so I am certain that this approach is better.
However, I am not sure if sending ESC-commands (other than the open cash-drawer) are even accepted/processed by the thermal printer, because all the commands I know, none had an effect - like line-feed, cutting, etc. So I wonder if that would even work?
However, communicating with the printer directly through the serial port works, and delivers the correct result, demonstrated in this C# code:
var serial = new SerialPort
{
PortName = "COM6",
BaudRate = 9600,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
Handshake = Handshake.None,
};
try
{
serial.Open();
byte[] command = { 16, 4, 4 }; // DLE EOT 4
serial.Write(command, 0, 3);
byte[] buffer = new byte[256];
int bytesRead = serial.Read(buffer, 0, 100);
if (bytesRead > 0 && (buffer[0] & 0x60) != 0)
Log.Information("no paper in printer");
serial.Close();
}
catch (Exception e)
{
Log.Warning("failed to check printer paper status (Error: {0}", e.Message);
}
Question: has anyone successfully sent ESC-commands to a USB-attached printer using WritePrinter()
and received data back using ReadPrinter()
?