Streaming a file to a local printer
Streaming a file to a local printer
(OP)
I have an application that creates a file (it happens to be a PDF file, but my problem occurs with .DOCX and .XLSX files). After creating it, it sends it to your default printer. That's where it gets a little crazy.
If the default printer is a system network one, the printer starts immediately after the file is streamed to it. If it is a locally connected printer, the streaming is immediate, but the printer doesn't start up for several minutes.
To test the connectivity of the printer, I can separately open up the PDF with my default PDF reader and print it and it is instantaneous.
Another test I performed is printing via another application that uses the PrintDocument method and it is immediately printed. I don't know where the problem is, but this is my code that performs the streaming:
public static class myPrinters
{
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);
}
private string SendToPrinter ( string strFileName, string strPrinterName )
{
FileInfo f = new FileInfo ( strFileName );
string fullname = f.FullName;
byte[] file = File.ReadAllBytes ( fullname );
// This is my ideal scenario in case the user wants to print to a different printer.
// I have tried with this line commented out and get the same results.
//
myPrinters.SetDefaultPrinter( strPrinterName );
PrintQueue printQueue = LocalPrintServer.GetDefaultPrintQueue();
using (var job = printQueue.AddJob())
using (var stream = job.JobStream)
{
stream.Write ( file, 0, file.Length );
}
Thanks in advance,
Jerry
If the default printer is a system network one, the printer starts immediately after the file is streamed to it. If it is a locally connected printer, the streaming is immediate, but the printer doesn't start up for several minutes.
To test the connectivity of the printer, I can separately open up the PDF with my default PDF reader and print it and it is instantaneous.
Another test I performed is printing via another application that uses the PrintDocument method and it is immediately printed. I don't know where the problem is, but this is my code that performs the streaming:
public static class myPrinters
{
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);
}
private string SendToPrinter ( string strFileName, string strPrinterName )
{
FileInfo f = new FileInfo ( strFileName );
string fullname = f.FullName;
byte[] file = File.ReadAllBytes ( fullname );
// This is my ideal scenario in case the user wants to print to a different printer.
// I have tried with this line commented out and get the same results.
//
myPrinters.SetDefaultPrinter( strPrinterName );
PrintQueue printQueue = LocalPrintServer.GetDefaultPrintQueue();
using (var job = printQueue.AddJob())
using (var stream = job.JobStream)
{
stream.Write ( file, 0, file.Length );
}
Thanks in advance,
Jerry
Jerry Scannell
RE: Streaming a file to a local printer
(In Windows 10, you find this by opening your start screen, typing "Printers," opening "Printers and Scanners," left-clicking on your default printer in the list, go to "Manage" then "Printer properties," then follow the Advanced Tab instruction above.)
Katie
RE: Streaming a file to a local printer
Printers speak a different language than files....
Unless the file is in a printer output file, I wouldn't expect it to work.
For example, if you had a BMP file, you can't just write that BMP out to the printer, the printer wouldn't know it was a BMP file.
You need to load the program as an object, then load the file into the object, then print from the object. You can't just send bytes from assorted files to a printer and have it work, unless it's a pre-formatted for that printer file.
Just my $.02
"What the captain doesn't realize is that we've secretly replaced his Dilithium Crystals with new Folger's Crystals."
--Greg
RE: Streaming a file to a local printer
For the benefit of those who do not have your working code, two of the native subroutines are:
CODE --> c#
Usage example:
CODE --> c#
The full list of relevant native subroutines that you can P/Invoke is documented here: https://msdn.microsoft.com/en-us/library/windows/d...
A potentially easier approach to P/Invoke is the Windows Driver Kit available at https://docs.microsoft.com/en-us/windows-hardware/... with C# Printer demo at https://github.com/Microsoft/Windows-driver-sample... but in my experience the native methods are more performant and more empowering.
The biggest risk I foresee is the Garbage Collector freeing the managed bytes before the unmanaged printer driver has stopped reading them. The WDK should prevent this from happening, but in my experience Microsoft's (other) managed assemblies work better during lab unit tests than they do in the wild. The wild can stress apps with a mix of unexpectedly large data sets and unexpected order/frequency of user commands. When the GC frees something that the native libraries later read, its the assemblies that misbehaved, and its the user interface that gets blamed. Many programmers disagree with me, but I would put faith in the P/Invoke approach because that empowers us to try and fix some unforeseen memory issues.