using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.ComponentModel; using System.IO; using System.IO.Packaging; using System.Printing; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Documents.Serialization; using System.Windows.Media; using System.Windows.Xps; using System.Windows.Xps.Packaging; using System.Windows.Xps.Serialization; using System.Threading; namespace gsview { public enum PrintStatus_t { PRINT_READY, PRINT_BUSY, PRINT_ERROR }; public enum PrintResult_t { PrintOK, PrintFAILED, PrintCANCELLED, PrintCOMPLETED } public struct PrintParams_t { public int num_pages; public int start_page; public int end_page; public PrintQueue queu; public FixedDocumentSequence fixdoc; public PrintResult_t result; public PrintStatus_t status; }; public class PrintEventArgs : EventArgs { private PrintStatus_t m_status; private PrintResult_t m_result; private int m_percentdone; public PrintStatus_t Status { get { return m_status; } } public PrintResult_t Result { get { return m_result; } } public int Percent { get { return m_percentdone; } } public PrintEventArgs(PrintStatus_t status, PrintResult_t completed, int percent) { m_status = status; m_result = completed; m_percentdone = percent; } } public class gsprintbg { BackgroundWorker m_worker; private XpsDocumentWriter m_docWriter = null; PrintParams_t m_pparams; internal delegate void PrintCallBackMain(object gsObject, PrintEventArgs info); internal event PrintCallBackMain PrintUpdateMain; private void PrintProgressChanged(object sender, ProgressChangedEventArgs e) { /* Callback with progress */ PrintEventArgs info = new PrintEventArgs(m_pparams.status, m_pparams.result, e.ProgressPercentage); if (PrintUpdateMain != null) PrintUpdateMain(this, info); } /* Callback */ private void PrintCompleted(object sender, RunWorkerCompletedEventArgs e) { PrintParams_t Value; PrintEventArgs info; PrintParams_t Params = (PrintParams_t)e.Result; if (e.Cancelled) { info = new PrintEventArgs(PrintStatus_t.PRINT_READY, PrintResult_t.PrintCANCELLED, 100); } else { Value = (PrintParams_t)e.Result; info = new PrintEventArgs(PrintStatus_t.PRINT_READY, PrintResult_t.PrintCOMPLETED, 100); } PrintUpdateMain(this, info); } /* Show std. print dialog */ public PrintDialog GetPrintDialog() { PrintDialog dlg = new PrintDialog(); /* Current page and page ranges is going to require a little work */ dlg.PageRangeSelection = PageRangeSelection.AllPages; //dlg.UserPageRangeEnabled = true; //dlg.CurrentPageEnabled = true; dlg.SelectedPagesEnabled = false; if (dlg.ShowDialog() == true) return dlg; return null; } /* Main print entry point */ private void Print(PrintParams_t pparams) { XpsDocumentWriter docwrite = GetDocWriter(pparams.queu); docwrite.WritingPrintTicketRequired += new WritingPrintTicketRequiredEventHandler(PrintTicket); PrintPages(docwrite, pparams.fixdoc); } /* Send it */ private void PrintPages(XpsDocumentWriter xpsdw, FixedDocumentSequence fixdoc) { m_docWriter = xpsdw; xpsdw.WritingCompleted += new WritingCompletedEventHandler(AsyncCompleted); xpsdw.WritingProgressChanged += new WritingProgressChangedEventHandler(AsyncProgress); xpsdw.WriteAsync(fixdoc); } private void CancelAsync() { /* ick. This does not work in windows 8. causes crash */ /* https://connect.microsoft.com/VisualStudio/feedback/details/778145/xpsdocumentwriter-cancelasync-cause-crash-in-win8 */ m_docWriter.CancelAsync(); } /* Done */ private void AsyncCompleted(object sender, WritingCompletedEventArgs e) { if (e.Cancelled) m_pparams.result = PrintResult_t.PrintCANCELLED; else if (e.Error != null) m_pparams.result = PrintResult_t.PrintFAILED; else m_pparams.result = PrintResult_t.PrintCOMPLETED; m_worker.ReportProgress(100); } /* Do this update with each fixed document (page) that is handled */ private void AsyncProgress(object sender, WritingProgressChangedEventArgs e) { double perc = 100.0 * (double) e.Number / (double) m_pparams.num_pages; m_worker.ReportProgress((int) perc); } /* Print ticket handling. You can customize for PrintTicketLevel at FixedDocumentSequencePrintTicket, FixedDocumentPrintTicket, or FixedPagePrintTicket. We may want to play around with this some */ private void PrintTicket(Object sender, WritingPrintTicketRequiredEventArgs e) { if (e.CurrentPrintTicketLevel == PrintTicketLevel.FixedDocumentSequencePrintTicket) { PrintTicket pts = new PrintTicket(); pts.PageOrientation = PageOrientation.Portrait; e.CurrentPrintTicket = pts; } } /* Create the document write */ private XpsDocumentWriter GetDocWriter(PrintQueue pq) { XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq); return xpsdw; } private void PrintWork(object sender, DoWorkEventArgs e) { PrintParams_t PParams = (PrintParams_t)e.Argument; BackgroundWorker worker = sender as BackgroundWorker; Print(PParams); } public bool IsBusy() { if (m_worker != null) return m_worker.IsBusy; else return false; } public void PrintWorkThread(object data) { PrintParams_t PParams = (PrintParams_t) data; Print(PParams); } public PrintStatus_t StartPrint(PrintParams_t pparams) { try { if (m_worker != null && m_worker.IsBusy) { m_worker.CancelAsync(); return PrintStatus_t.PRINT_BUSY; } if (m_worker == null) { Thread asyncThread = new Thread(PrintWorkThread); asyncThread.SetApartmentState(ApartmentState.STA); asyncThread.Start(pparams); /* m_worker = new BackgroundWorker(); m_worker.WorkerReportsProgress = true; m_worker.WorkerSupportsCancellation = true; m_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(PrintCompleted); m_worker.ProgressChanged += new ProgressChangedEventHandler(PrintProgressChanged); m_worker.DoWork += new DoWorkEventHandler(PrintWork);*/ } ////m_pparams = pparams; //m_worker.RunWorkerAsync(pparams); pparams.status = PrintStatus_t.PRINT_BUSY; return PrintStatus_t.PRINT_READY; } catch (OutOfMemoryException e) { Console.WriteLine("Memory allocation failed during printing\n"); return PrintStatus_t.PRINT_ERROR; } } public void Cancel() { m_worker.CancelAsync(); } } }