Printing with XPSDocumentWritter on an Epson printer PrintQueue - c#

We have an application that have a print function that works well on all printers except some products from Epson on Windows 8.
I've manage to make a minimal sample that reproduce the problem.
Call the following method, providing it with the full path to a correct xps file.
private void Print(string xpsFilename)
{
if (string.IsNullOrEmpty(xpsFilename))
{
return;
}
PrintDialog printDialog = new PrintDialog();
printDialog.ShowDialog();
PrintQueue defaultPrintQueue = printDialog.PrintQueue;
try
{
// This is were it seems to fail for some Epson printers: no job in spooler, no print ...
PrintSystemJobInfo xpsPrintJob = defaultPrintQueue.AddJob("Print through 'AddJob' on PrintQueue", xpsFilename, false);
}
catch (PrintJobException printJobException)
{
Console.WriteLine("{0} Could not be added to the print queue.", xpsFilename);
Console.WriteLine(printJobException.Message);
}
catch (Exception exception)
{
Console.WriteLine("{0} Unknown error:", xpsFilename);
Console.WriteLine(exception.Message);
}
}
You will see that if you choose an Epson printer no job will appear in the spooler whereas it will work with any other printer.
Does anyone has an idea why it's not printing (the job does not even appears in the spool) ?
In the real application we do not use xps file but rather use a paginator, but for the sample purpose it's simpler and fail too ...
Thanks for any help.

Related

Microsoft OPOS hangs on Claim after PC restart

I am using 'Microsoft Point of Service for .NET v1.14.' dlls to connect with Posiflex Thermal Printer (PP8800 model).
Code snippet which I am using is also pasted below. I am running this code from WPF application.
But I am facing one strange issue. If printer is powered on and machine on which the printer is connected is restarted, below pasted code is not able to claim the printer and it also does not come out of the Claim() statement. Whereas if I power off the printer and then power it on before running the below code snippet then it is able to claim the printer.
PosExplorer posExplorer = new PosExplorer();
var printerList = posExplorer.GetDevices(DeviceType.PosPrinter);
foreach (DeviceInfo item in printerList)
{
if (item.ServiceObjectName != printerName)
continue;
posPrinter = (PosPrinter)posExplorer.CreateInstance(item);
posPrinter.Open();
posPrinter.PowerNotify = PowerNotification.Enabled;
posPrinter.FlagWhenIdle = true;
posPrinter.StatusUpdateEvent += PosPrinter_StatusUpdateEvent;
posPrinter.DirectIOEvent += PosPrinter_DirectIOEvent;
posPrinter.ErrorEvent += PosPrinter_ErrorEvent;
posPrinter.OutputCompleteEvent += PosPrinter_OutputCompleteEvent;
try
{
posPrinter.Claim(100);
if (posPrinter.Claimed)
{
isPrinterClaimed = true;
}
else
{
isPrinterClaimed = false;
}
}
catch (Exception ex)
{
isPrinterClaimed = false;
}
break;
}
Has anybody faced the same issue while using OPOS libraries?

Check if Adobe Acrobat Reader installed - pdf in WebBrowser control

I have an application that displays a pdf in a webBrowser control, using the following code
webBrowser1.Navigate(filename + "#toolbar=0");
It works perfectly if Adobe Reader is installed
I would like to check if Adobe Acrobat Reader is installed before displaying the window, or at least when trying to display the pdf.
I have adapted the following code from here Check Adobe Reader is installed (C#)?
As mentioned in the comments, unfortunately, it flags uninstalled versions as well.
I have also tried the 64 bit code in the same article but find errors I can't easily resolve and suspect would give the same result anyway as it simmply looks at the registry in a similar way.
using System;
using Microsoft.Win32;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if(null == adobe)
{
var policies = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Policies");
if (null == policies)
return;
adobe = policies.OpenSubKey("Adobe");
}
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
Console.WriteLine("The following version(s) of Acrobat Reader are installed: ");
foreach (string versionNumber in acroReadVersions)
{
Console.WriteLine(versionNumber);
}
}
}
}
}
}
If Adobe pdf Reader is not loaded, a prompt appears to open(in any other installed reader), save the file or cancel.
I would like to be able to intercept this so as to Indicate that Adobe's reader is not available.
I have tried
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
string url = e.Url.ToString();
if (url.StartsWith("res://ieframe.dll/navcancl.htm") && url.EndsWith("pdf"))
{
e.Cancel = true;
MessageBox.Show("Cannot open PDF!");
}
}
at the following https://social.msdn.microsoft.com/Forums/en-US/46aaeecd-5317-462a-ac36-9ebb30ba90e7/load-pdf-file-using-webbrowser-control-in-windows-form-c?forum=csharpgeneral
but found the open, save cancel event precedes the webBrowser1_Navigating.
I would appreciate any help in a reliable solution that will not flag uninstalled versions, or a seperate solution that will stop the open, save, cancel prompt, and allow me to create a message to install the reader
Thanks
The Simple Way is to use try / catch
in the try give the code.
The web browser will give error if there is an error so in the catch then say the user to install adobe reader.
Here is the sample
try
{
//your code goes her
}
catch(Exception ex)
{
if(ex.Message != null)
{
Console.WriteLine("Adobe Reader not Installed");
//this is where you say adobe reader is not installed
}
}

PrintQueue.AddJob hangs when printing to non-xps based printers

I am trying to print an xps document to printers (network printer, some virtual local printers, xps and non xps based) with the following code.
C# Source:
static void Main(string[] args)
{
PrintServer printServer = new PrintServer(#"\\printserver.csez.zohocorpin.com");
foreach (PrintQueue queue in printServer.GetPrintQueues())
{
Console.WriteLine("Printer: {0}, Port: {1}, ShareName: {2}, status: {3}, PrintingIsCancelled: {4}",
queue.Name, queue.QueuePort.Name, queue.ShareName, queue.QueueStatus, queue.PrintingIsCancelled);
Program program = new Program();
Thread printingThread = new Thread(() => program.Print_XPXFile(queue, #"D:\Assist\RemotePrint\Spool\Donalduck.xps"));
// Set the thread that will use PrintQueue.AddJob to single threading.
printingThread.SetApartmentState(ApartmentState.STA);
printingThread.Start();
printingThread.Join();
}
}
public void Print_XPXFile(PrintQueue pQueue, String FilePath)
{
// Create print server and print queue.
bool fastCopy = pQueue.IsXpsDevice;
FileInfo file = new FileInfo(FilePath);
if (!file.Exists)
{
Console.WriteLine("There is no such file.");
}
else
{
Console.WriteLine("Adding {0} to {1} queue. share name : {2}", FilePath, pQueue.Name, pQueue.ShareName);
try
{
// Print the Xps file while providing XPS validation and progress notifications.
PrintSystemJobInfo xpsPrintJob = pQueue.AddJob(file.Name, FilePath, fastCopy);
Console.WriteLine("Done adding.");
}
catch (PrintJobException e)
{
Console.WriteLine("\n\t{0} could not be added to the print queue.", file.Name);
if (e.InnerException.Message == "File contains corrupted data.")
{
Console.WriteLine("\tIt is not a valid XPS file."); // Use the isXPS Conformance Tool to debug it.
}
else
{
Console.WriteLine("\tmessage : {0}", e.InnerException.Message);
}
}
}
}
When printing to Microsoft XPS Document Writer, Microsoft Print to PDF, etc it works fine.
I found that it is working fine with all XPS based printers. I even installed a XPS sample printer driver and added a virtual local printer to confirm this claim and as expected it worked.
For non-xps based printers, it actually gets stuck in the AddJob function. It neither throws any exception, nor it moves to the next statement.
I developed the code based on this msdn resource.
What is the cause and solution?
All thoughts are welcome.
I can't seem to find the problem. But here is a more promising way to print XPS files:
public static void PrintXPSToDefaultPrinter(string FilePath)
{
try
{
// Create the print dialog object and set options
PrintDialog pDialog = new PrintDialog();
pDialog.PageRangeSelection = PageRangeSelection.AllPages;
pDialog.UserPageRangeEnabled = true;
FileInfo file = new FileInfo(FilePath);
XpsDocument xpsDocument = new XpsDocument(FilePath, FileAccess.ReadWrite);
FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();
pDialog.PrintDocument(fixedDocSeq.DocumentPaginator, file.Name);
}
catch (System.IO.IOException ex)
{
Console.WriteLine("The file is being used by some other process.");
}
catch (Exception ex)
{
Console.WriteLine("Exception occured : {0}", ex.Message);
}
}
You should call this in STA mode just like you have used:
static void Main(string[] args)
{
Thread printingThread = new Thread(() => PrintXPSToDefaultPrinter(#"D:\Assist\RemotePrint\Spool\Donalduck.xps"));
printingThread.SetApartmentState(ApartmentState.STA);
printingThread.Start();
}
You can also mention any printqueue u want in the pDialog.PrintQueue property.
Hope this helps. Enjoy man !!!
I, too, got stuck in the AddJob() method. The problem seemed to be more prevalent as Windows 10 platforms became involved.
Breaking the execution in debug, the stack trace showed the STA thread was blocked on a call to
MS.Internal.PrintWin32Thunk.XpsCompatiblePrinter.JobIdentifier.get
and this was further blocking on a low-level WaitOne() on some unknown synchronization object.
Even though details on this problem are thin (this is the only post I have found on the topic), THANKFULLY the accepted solution works extremely well (and I have been trying all kinds of things to print in WPF for years).
AddJob() is fully replaced in all respects. One can even control the PrintTicket more easily through the PrintDialog (to set paper size, orientation, one/two sided printing, etc.)

Xamarin: How to print from Android device to dot matrix printer?

I have the following hardware:
Dot matrix printer: LX 300-II.
Android device with Android version 4.2.2.
Connection type: USB, Wi-FI, Bluetooth.
I have an Android Activity that create an invoice, so I want to print some text on printer. But I can't make it work.
I tried using USBManager with no success. Is there any way to achieve this?
I found a solution. It's the only way to make it works. USBManager cannot access to printer because driver is missing. So I tried with a WI-FI option.
You need some extra hardware here:
Print Server (In this case I tried TL-WPS510-U).
Android Device 4.0.3 or superior
Epson LX-300+II
First of all you must configure your Print Server. I did it following this tutorial.
Now I have the Print Server pointing to my device (acting as Server) and waiting for any printer job.
What I did on my Xamarin.Android project?
Created an instance of a Socket class pointing to the Printer Server ;)
No Epson command needed (Ok some of them). The code is the following:
private async Task SendCommand()
{
await Task.Run (() =>
{
try
{
Socket sock = new Socket("199.1.1.50", 9100);
PrintWriter oStream = new PrintWriter (sock.OutputStream, true);;
OutputStreamWriter outWriter;
oStream.Write(0x1B); //T1
oStream.Write(0x40); //T2 Start Printer
oStream.Print("This is great!!! á é í ó ú ü Ü Ñ ñ");
oStream.Write(0x0C); //release paper
oStream.Write(0x1B); //t1
oStream.Write(0x40); //t2 Finish Printer
oStream.Flush ();
oStream.Close ();
oStream.Dispose();
sock.Close ();
sock.Dispose();
}
catch(SocketException ex)
{
string m = ex.Message;
RunOnUiThread(() => Toast.MakeText(this, m, ToastLength.Long).Show());
}
catch(Exception ex)
{
Toast.MakeText(this, ex.ToString(), ToastLength.Long).Show();
}
});
}
Now is working very fine.

PrintDocument.Print() throws a Win32Exception

I'm getting a strange exception from the following code:
var printDialog = new PrintDialog();
printDialog.ShowDialog();
var printDocument = new PrintDocument { DefaultPageSettings = { Landscape = true, PrinterSettings = new PrinterSettings { PrinterName = printDialog.PrintQueue.Name } } };
var updateResult = new UpdateResult<Image>(UpdateType.Print) { Success = true };
foreach (string location in fileLocation)
{
try
{
_printImage = Image.FromFile(location);
printDocument.PrintPage += PrintRequest;
}
catch (Exception exception)
{
//various error handling code here
}
}
printDocument.Print();
The final line is throwing a Win32Exception with the detail "The handle is invalid", according to the msdn documentation the only exception that should be thrown is printer not found. The exception seems to be to be some sort of driver/non framework exception.
When I select my printer (Lexmark T640, setup to print directly to the printer port) the code prints fine, but selecting either of the other two printers I have access to (another T640, or a dell colour) the code fails.
The other two printers are setup to print through our central print server, but I didn't think this should make any difference.
Can anyone give me any pointers?
Edit: Just tried it with printDialog.PrintQueue.Fullname and the behaviour is no different. Substituting in a garbage printer name throws an InvalidPrinterException as expected, suggesting it has found the printer, but seems to fail.
Try setting the target printer as the default printer (if it isn't already) and see if it still happens
For #Matt's benefit.
I didn't manage to figure out what the issue was in the end, could well be something to do with the configuration of our network but that's out of my hands.
Instead I used a different method, I used CommonDialogClass.ShowPhotoPrintingWizard() which is part of Interop.WIA as below.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms630492%28v=vs.85%29.aspx
This hands over the process to the photo printing wizard and I've not had any issues since.
I got this exception only when printing multiple documents. My solutions was to add
printDocument.Dispose(); after printDocument.Print();.

Categories