//#define PrintDebug // // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Author: // // Jordi Mas i Hernandez, jordimash@gmail.com // using System.Runtime.InteropServices; using System.Collections; using System.Collections.Specialized; using System.Drawing.Printing; using System.ComponentModel; using System.Drawing.Imaging; using System.Text; using System.IO; namespace System.Drawing.Printing { internal class PrintingServicesUnix : PrintingServices { #region Private Fields private static Hashtable doc_info = new Hashtable (); private static bool cups_installed; //private string printer_name; private static Hashtable installed_printers; private static string default_printer = String.Empty; #endregion #region Constructor internal PrintingServicesUnix () { } static PrintingServicesUnix () { installed_printers = new Hashtable (); CheckCupsInstalled (); } #endregion #region Properties internal static PrinterSettings.StringCollection InstalledPrinters { get { LoadPrinters(); PrinterSettings.StringCollection list = new PrinterSettings.StringCollection (new string[] {}); foreach (object key in installed_printers.Keys) { list.Add (key.ToString()); } return list; } } internal override string DefaultPrinter { get { if (installed_printers.Count == 0) LoadPrinters(); return default_printer; } } #endregion #region Methods /// /// Do a cups call to check if it is installed /// private static void CheckCupsInstalled () { try { cupsGetDefault (); } catch (DllNotFoundException) { Console.WriteLine("libcups not found. To have printing support, you need cups installed"); cups_installed = false; return; } cups_installed = true; } /// /// Open the printer's PPD file /// /// Printer name, returned from cupsGetDests private IntPtr OpenPrinter (string printer) { try { IntPtr ptr = cupsGetPPD (printer); string ppd_filename = Marshal.PtrToStringAnsi (ptr); IntPtr ppd_handle = ppdOpenFile (ppd_filename); return ppd_handle; } catch (Exception) { Console.WriteLine ("There was an error opening the printer {0}. Please check your cups installation."); } return IntPtr.Zero; } /// /// Close the printer file /// /// PPD handle private void ClosePrinter (ref IntPtr handle) { try { if (handle != IntPtr.Zero) ppdClose (handle); } finally { handle = IntPtr.Zero; } } private static int OpenDests (ref IntPtr ptr) { try { return cupsGetDests (ref ptr); } catch { ptr = IntPtr.Zero; } return 0; } private static void CloseDests (ref IntPtr ptr, int count) { try { if (ptr != IntPtr.Zero) cupsFreeDests (count, ptr); } finally { ptr = IntPtr.Zero; } } /// /// Checks if a printer has a valid PPD file. Caches the result unless force is true /// /// Does the check disregarding the last cached value if true internal override bool IsPrinterValid(string printer) { if (!cups_installed || printer == null | printer == String.Empty) return false; return installed_printers.Contains (printer); /* if (!force && this.printer_name != null && String.Intern(this.printer_name).Equals(printer)) return is_printer_valid; IntPtr ptr = cupsGetPPD (printer); string ppd_filename = Marshal.PtrToStringAnsi (ptr); is_printer_valid = ppd_filename != null; this.printer_name = printer; return is_printer_valid; */ } /// /// Loads the printer settings and initializes the PrinterSettings and PageSettings fields /// /// Printer name /// PrinterSettings object to initialize internal override void LoadPrinterSettings (string printer, PrinterSettings settings) { if (cups_installed == false || (printer == null) || (printer == String.Empty)) return; if (installed_printers.Count == 0) LoadPrinters (); if (((SysPrn.Printer)installed_printers[printer]).Settings != null) { SysPrn.Printer p = (SysPrn.Printer) installed_printers[printer]; settings.can_duplex = p.Settings.can_duplex; settings.is_plotter = p.Settings.is_plotter; settings.landscape_angle = p.Settings.landscape_angle; settings.maximum_copies = p.Settings.maximum_copies; settings.paper_sizes = p.Settings.paper_sizes; settings.paper_sources = p.Settings.paper_sources; settings.printer_capabilities = p.Settings.printer_capabilities; settings.printer_resolutions = p.Settings.printer_resolutions; settings.supports_color = p.Settings.supports_color; return; } settings.PrinterCapabilities.Clear (); IntPtr dests = IntPtr.Zero, ptr = IntPtr.Zero, ptr_printer, ppd_handle = IntPtr.Zero; string name = String.Empty; CUPS_DESTS printer_dest; PPD_FILE ppd; int ret = 0, cups_dests_size; NameValueCollection options, paper_names, paper_sources; try { ret = OpenDests (ref dests); if (ret == 0) return; cups_dests_size = Marshal.SizeOf (typeof(CUPS_DESTS)); ptr = dests; for (int i = 0; i < ret; i++) { ptr_printer = (IntPtr) Marshal.ReadIntPtr (ptr); if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) { name = printer; break; } ptr = (IntPtr) ((long)ptr + cups_dests_size); } if (!name.Equals(printer)) { return; } ppd_handle = OpenPrinter (printer); if (ppd_handle == IntPtr.Zero) return; printer_dest = (CUPS_DESTS) Marshal.PtrToStructure (ptr, typeof (CUPS_DESTS)); options = new NameValueCollection(); paper_names = new NameValueCollection(); paper_sources = new NameValueCollection(); string defsize; string defsource; LoadPrinterOptions (printer_dest.options, printer_dest.num_options, ppd_handle, options, paper_names, out defsize, paper_sources, out defsource); if (settings.paper_sizes == null) settings.paper_sizes = new PrinterSettings.PaperSizeCollection (new PaperSize [] {}); else settings.paper_sizes.Clear(); if (settings.paper_sources == null) settings.paper_sources = new PrinterSettings.PaperSourceCollection (new PaperSource [] {}); else settings.paper_sources.Clear(); settings.DefaultPageSettings.PaperSource = LoadPrinterPaperSources (settings, defsource, paper_sources); settings.DefaultPageSettings.PaperSize = LoadPrinterPaperSizes (ppd_handle, settings, defsize, paper_names); LoadPrinterResolutionsAndDefault (printer, settings, ppd_handle); ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE)); settings.landscape_angle = ppd.landscape; settings.supports_color = (ppd.color_device == 0) ? false : true; settings.can_duplex = options["Duplex"] != null; ClosePrinter (ref ppd_handle); ((SysPrn.Printer)installed_printers[printer]).Settings = settings; } finally { CloseDests (ref dests, ret); } } /// /// Loads the global options of a printer plus the paper types and trays supported, /// and sets the default paper size and source tray. /// /// The options field of a printer's CUPS_DESTS structure /// The number of options of the printer /// A ppd handle for the printer, returned by ppdOpen /// The list of options /// A list of types of paper (PageSize) /// The default paper size, set by LoadOptionList /// A list of trays(InputSlot) /// The default source tray, set by LoadOptionList private static void LoadPrinterOptions(IntPtr options, int numOptions, IntPtr ppd, NameValueCollection list, NameValueCollection paper_names, out string defsize, NameValueCollection paper_sources, out string defsource) { CUPS_OPTIONS cups_options; string option_name, option_value; int cups_size = Marshal.SizeOf(typeof(CUPS_OPTIONS)); for (int j = 0; j < numOptions; j++) { cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS)); option_name = Marshal.PtrToStringAnsi(cups_options.name); option_value = Marshal.PtrToStringAnsi(cups_options.val); #if PrintDebug Console.WriteLine("{0} = {1}", option_name, option_value); #endif list.Add(option_name, option_value); options = (IntPtr) ((long)options + cups_size); } LoadOptionList (ppd, "PageSize", paper_names, out defsize); LoadOptionList (ppd, "InputSlot", paper_sources, out defsource); } /// /// Loads the global options of a printer. /// /// The options field of a printer's CUPS_DESTS structure /// The number of options of the printer private static NameValueCollection LoadPrinterOptions(IntPtr options, int numOptions) { CUPS_OPTIONS cups_options; string option_name, option_value; int cups_size = Marshal.SizeOf (typeof(CUPS_OPTIONS)); NameValueCollection list = new NameValueCollection (); for (int j = 0; j < numOptions; j++) { cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS)); option_name = Marshal.PtrToStringAnsi (cups_options.name); option_value = Marshal.PtrToStringAnsi (cups_options.val); #if PrintDebug Console.WriteLine("{0} = {1}", option_name, option_value); #endif list.Add (option_name, option_value); options = (IntPtr) ((long)options + cups_size); } return list; } /// /// Loads a printer's options (selection of paper sizes, paper sources, etc) /// and sets the default option from the selected list. /// /// Printer ppd file handle /// Name of the option group to load /// List of loaded options /// The default option from the loaded options list private static void LoadOptionList (IntPtr ppd, string option_name, NameValueCollection list, out string defoption) { IntPtr ptr = IntPtr.Zero; PPD_OPTION ppd_option; PPD_CHOICE choice; int choice_size = Marshal.SizeOf(typeof(PPD_CHOICE)); defoption = null; ptr = ppdFindOption (ppd, option_name); if (ptr != IntPtr.Zero) { ppd_option = (PPD_OPTION) Marshal.PtrToStructure (ptr, typeof (PPD_OPTION)); #if PrintDebug Console.WriteLine (" OPTION key:{0} def:{1} text: {2}", ppd_option.keyword, ppd_option.defchoice, ppd_option.text); #endif defoption = ppd_option.defchoice; ptr = ppd_option.choices; for (int c = 0; c < ppd_option.num_choices; c++) { choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr, typeof (PPD_CHOICE)); list.Add(choice.choice, choice.text); #if PrintDebug Console.WriteLine (" choice:{0} - text: {1}", choice.choice, choice.text); #endif ptr = (IntPtr) ((long)ptr + choice_size); } } } /// /// Loads a printer's available resolutions /// /// Printer name /// PrinterSettings object to fill internal override void LoadPrinterResolutions (string printer, PrinterSettings settings) { IntPtr ppd_handle = OpenPrinter (printer); if (ppd_handle == IntPtr.Zero) return; LoadPrinterResolutionsAndDefault (printer, settings, ppd_handle); ClosePrinter (ref ppd_handle); } /// /// Create a PrinterResolution from a string Resolution that is set in the PPD option. /// An example of Resolution is "600x600dpi" or "600dpi". Returns null if malformed or "Unknown". /// private PrinterResolution ParseResolution (string resolution) { if (String.IsNullOrEmpty (resolution)) return null; int dpiIndex = resolution.IndexOf ("dpi"); if (dpiIndex == -1) { // Resolution is "Unknown" or unparsable return null; } resolution = resolution.Substring (0, dpiIndex); int x_resolution, y_resolution; try { if (resolution.Contains ("x")) { string[] resolutions = resolution.Split (new[] {'x'}); x_resolution = Convert.ToInt32 (resolutions [0]); y_resolution = Convert.ToInt32 (resolutions [1]); } else { x_resolution = Convert.ToInt32 (resolution); y_resolution = x_resolution; } } catch (Exception) { return null; } return new PrinterResolution (x_resolution, y_resolution, PrinterResolutionKind.Custom); } /// /// Loads a printer's paper sizes. Returns the default PaperSize, and fills a list of paper_names for use in dialogues /// /// PPD printer file handle /// PrinterSettings object to fill /// Default paper size, from the global options of the printer /// List of available paper sizes that gets filled private PaperSize LoadPrinterPaperSizes(IntPtr ppd_handle, PrinterSettings settings, string def_size, NameValueCollection paper_names) { IntPtr ptr; string real_name; PPD_FILE ppd; PPD_SIZE size; PaperSize ps; PaperSize defsize = new PaperSize ("A4", 827, 1169, GetPaperKind (827, 1169), true); ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE)); ptr = ppd.sizes; float w, h; for (int i = 0; i < ppd.num_sizes; i++) { size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE)); real_name = paper_names[size.name]; w = size.width * 100 / 72; h = size.length * 100 / 72; PaperKind kind = GetPaperKind ((int) w, (int) h); ps = new PaperSize (real_name, (int) w, (int) h, kind, def_size == kind.ToString ()); ps.SetKind (kind); if (def_size == ps.Kind.ToString ()) defsize = ps; settings.paper_sizes.Add (ps); ptr = (IntPtr) ((long)ptr + Marshal.SizeOf (size)); } return defsize; } /// /// Loads a printer's paper sources (trays). Returns the default PaperSource, and fills a list of paper_sources for use in dialogues /// /// PrinterSettings object to fill /// Default paper source, from the global options of the printer /// List of available paper sizes that gets filled private PaperSource LoadPrinterPaperSources (PrinterSettings settings, string def_source, NameValueCollection paper_sources) { PaperSourceKind kind; PaperSource defsource = null; foreach(string source in paper_sources) { switch (source) { case "Auto": kind = PaperSourceKind.AutomaticFeed; break; case "Standard": kind = PaperSourceKind.AutomaticFeed; break; case "Tray": kind = PaperSourceKind.AutomaticFeed; break; case "Envelope": kind = PaperSourceKind.Envelope; break; case "Manual": kind = PaperSourceKind.Manual; break; default: kind = PaperSourceKind.Custom; break; } settings.paper_sources.Add (new PaperSource (paper_sources[source], kind, def_source == source)); if (def_source == source) defsource = settings.paper_sources[settings.paper_sources.Count-1]; } if (defsource == null && settings.paper_sources.Count > 0) return settings.paper_sources[0]; return defsource; } /// /// Sets the available resolutions and default resolution from a /// printer's PPD file into settings. /// private void LoadPrinterResolutionsAndDefault (string printer, PrinterSettings settings, IntPtr ppd_handle) { if (settings.printer_resolutions == null) settings.printer_resolutions = new PrinterSettings.PrinterResolutionCollection (new PrinterResolution [] {}); else settings.printer_resolutions.Clear (); var printer_resolutions = new NameValueCollection (); string defresolution; LoadOptionList (ppd_handle, "Resolution", printer_resolutions, out defresolution); foreach (var resolution in printer_resolutions.Keys) { var new_resolution = ParseResolution (resolution.ToString ()); settings.PrinterResolutions.Add (new_resolution); } var default_resolution = ParseResolution (defresolution); if (default_resolution == null) default_resolution = ParseResolution ("300dpi"); if (printer_resolutions.Count == 0) settings.PrinterResolutions.Add (default_resolution); settings.DefaultPageSettings.PrinterResolution = default_resolution; } /// /// /// /// private static void LoadPrinters() { installed_printers.Clear (); if (cups_installed == false) return; IntPtr dests = IntPtr.Zero, ptr_printers; CUPS_DESTS printer; int n_printers = 0; int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS)); string name, first, type, status, comment; first = type = status = comment = String.Empty; int state = 0; try { n_printers = OpenDests (ref dests); ptr_printers = dests; for (int i = 0; i < n_printers; i++) { printer = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS)); name = Marshal.PtrToStringAnsi (printer.name); if (printer.is_default == 1) default_printer = name; if (first.Equals (String.Empty)) first = name; NameValueCollection options = LoadPrinterOptions(printer.options, printer.num_options); if (options["printer-state"] != null) state = Int32.Parse(options["printer-state"]); if (options["printer-comment"] != null) comment = options["printer-state"]; switch(state) { case 4: status = "Printing"; break; case 5: status = "Stopped"; break; default: status = "Ready"; break; } installed_printers.Add (name, new SysPrn.Printer (String.Empty, type, status, comment)); ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size); } } finally { CloseDests (ref dests, n_printers); } if (default_printer.Equals (String.Empty)) default_printer = first; } /// /// Gets a printer's settings for use in the print dialogue /// /// /// /// /// /// internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment) { int count = 0, state = -1; bool found = false; CUPS_DESTS cups_dests; IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer; int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS)); if (cups_installed == false) return; try { count = OpenDests (ref dests); if (count == 0) return; ptr_printers = dests; for (int i = 0; i < count; i++) { ptr_printer = (IntPtr) Marshal.ReadIntPtr (ptr_printers); if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) { found = true; break; } ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size); } if (!found) return; cups_dests = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS)); NameValueCollection options = LoadPrinterOptions(cups_dests.options, cups_dests.num_options); if (options["printer-state"] != null) state = Int32.Parse(options["printer-state"]); if (options["printer-comment"] != null) comment = options["printer-state"]; switch(state) { case 4: status = "Printing"; break; case 5: status = "Stopped"; break; default: status = "Ready"; break; } } finally { CloseDests (ref dests, count); } } /// /// Returns the appropriate PaperKind for the width and height /// /// /// private PaperKind GetPaperKind (int width, int height) { if (width == 827 && height == 1169) return PaperKind.A4; if (width == 583 && height == 827) return PaperKind.A5; if (width == 717 && height == 1012) return PaperKind.B5; if (width == 693 && height == 984) return PaperKind.B5Envelope; if (width == 638 && height == 902) return PaperKind.C5Envelope; if (width == 449 && height == 638) return PaperKind.C6Envelope; if (width == 1700 && height == 2200) return PaperKind.CSheet; if (width == 433 && height == 866) return PaperKind.DLEnvelope; if (width == 2200 && height == 3400) return PaperKind.DSheet; if (width == 3400 && height == 4400) return PaperKind.ESheet; if (width == 725 && height == 1050) return PaperKind.Executive; if (width == 850 && height == 1300) return PaperKind.Folio; if (width == 850 && height == 1200) return PaperKind.GermanStandardFanfold; if (width == 1700 && height == 1100) return PaperKind.Ledger; if (width == 850 && height == 1400) return PaperKind.Legal; if (width == 927 && height == 1500) return PaperKind.LegalExtra; if (width == 850 && height == 1100) return PaperKind.Letter; if (width == 927 && height == 1200) return PaperKind.LetterExtra; if (width == 850 && height == 1269) return PaperKind.LetterPlus; if (width == 387 && height == 750) return PaperKind.MonarchEnvelope; if (width == 387 && height == 887) return PaperKind.Number9Envelope; if (width == 413 && height == 950) return PaperKind.Number10Envelope; if (width == 450 && height == 1037) return PaperKind.Number11Envelope; if (width == 475 && height == 1100) return PaperKind.Number12Envelope; if (width == 500 && height == 1150) return PaperKind.Number14Envelope; if (width == 363 && height == 650) return PaperKind.PersonalEnvelope; if (width == 1000 && height == 1100) return PaperKind.Standard10x11; if (width == 1000 && height == 1400) return PaperKind.Standard10x14; if (width == 1100 && height == 1700) return PaperKind.Standard11x17; if (width == 1200 && height == 1100) return PaperKind.Standard12x11; if (width == 1500 && height == 1100) return PaperKind.Standard15x11; if (width == 900 && height == 1100) return PaperKind.Standard9x11; if (width == 550 && height == 850) return PaperKind.Statement; if (width == 1100 && height == 1700) return PaperKind.Tabloid; if (width == 1487 && height == 1100) return PaperKind.USStandardFanfold; return PaperKind.Custom; } #endregion #region Print job methods static string tmpfile; /// /// Gets a pointer to an options list parsed from the printer's current settings, to use when setting up the printing job /// /// /// /// internal static int GetCupsOptions (PrinterSettings printer_settings, PageSettings page_settings, out IntPtr options) { options = IntPtr.Zero; PaperSize size = page_settings.PaperSize; int width = size.Width * 72 / 100; int height = size.Height * 72 / 100; StringBuilder sb = new StringBuilder(); sb.Append( "copies=" + printer_settings.Copies + " " + "Collate=" + printer_settings.Collate + " " + "ColorModel=" + (page_settings.Color ? "Color" : "Black") + " " + "PageSize=" + String.Format ("Custom.{0}x{1}", width, height) + " " + "landscape=" + page_settings.Landscape ); if (printer_settings.CanDuplex) { if (printer_settings.Duplex == Duplex.Simplex) sb.Append(" Duplex=None"); else sb.Append(" Duplex=DuplexNoTumble"); } return cupsParseOptions (sb.ToString(), 0, ref options); } internal static bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file) { DOCINFO doc = (DOCINFO) doc_info[gr.Hdc]; doc.title = doc_name; return true; } internal static bool EndDoc (GraphicsPrinter gr) { DOCINFO doc = (DOCINFO) doc_info[gr.Hdc]; gr.Graphics.Dispose (); // Dispose object to force surface finish IntPtr options; int options_count = GetCupsOptions (doc.settings, doc.default_page_settings, out options); cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, options_count, options); cupsFreeOptions (options_count, options); doc_info.Remove (gr.Hdc); if (tmpfile != null) { try { File.Delete (tmpfile); } catch { } } return true; } internal static bool StartPage (GraphicsPrinter gr) { return true; } internal static bool EndPage (GraphicsPrinter gr) { GdipGetPostScriptSavePage (gr.Hdc); return true; } // Unfortunately, PrinterSettings and PageSettings couldn't be referencing each other, // thus we need to pass them separately internal static IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings) { IntPtr graphics = IntPtr.Zero; string name; if (!settings.PrintToFile) { StringBuilder sb = new StringBuilder (1024); int length = sb.Capacity; cupsTempFile (sb, length); name = sb.ToString (); tmpfile = name; } else name = settings.PrintFileName; PaperSize psize = default_page_settings.PaperSize; int width, height; if (default_page_settings.Landscape) { // Swap in case of landscape width = psize.Height; height = psize.Width; } else { width = psize.Width; height = psize.Height; } GdipGetPostScriptGraphicsContext (name, width * 72 / 100, height * 72 / 100, default_page_settings.PrinterResolution.X, default_page_settings.PrinterResolution.Y, ref graphics); DOCINFO doc = new DOCINFO (); doc.filename = name; doc.settings = settings; doc.default_page_settings = default_page_settings; doc_info.Add (graphics, doc); return graphics; } #endregion #region DllImports [DllImport("libcups", CharSet=CharSet.Ansi)] static extern int cupsGetDests (ref IntPtr dests); // [DllImport("libcups", CharSet=CharSet.Ansi)] // static extern void cupsGetDest (string name, string instance, int num_dests, ref IntPtr dests); [DllImport("libcups")] static extern void cupsFreeDests (int num_dests, IntPtr dests); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern IntPtr cupsTempFile (StringBuilder sb, int len); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern IntPtr cupsGetDefault (); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern IntPtr cupsGetPPD (string printer); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern IntPtr ppdOpenFile (string filename); [DllImport("libcups", CharSet=CharSet.Ansi)] static extern IntPtr ppdFindOption (IntPtr ppd_file, string keyword); [DllImport("libcups")] static extern void ppdClose (IntPtr ppd); [DllImport ("libcups", CharSet=CharSet.Ansi)] static extern int cupsParseOptions (string arg, int number_of_options, ref IntPtr options); [DllImport("libcups")] static extern void cupsFreeOptions (int number_options, IntPtr options); [DllImport("gdiplus.dll", CharSet=CharSet.Ansi)] static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics); [DllImport("gdiplus.dll")] static extern int GdipGetPostScriptSavePage (IntPtr graphics); #endregion #region Struct public struct DOCINFO { public PrinterSettings settings; public PageSettings default_page_settings; public string title; public string filename; } public struct PPD_SIZE { public int marked; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)] public string name; public float width; public float length; public float left; public float bottom; public float right; public float top; } public struct PPD_GROUP { [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)] public string text; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)] public string name; public int num_options; public IntPtr options; public int num_subgroups; public IntPtr subgrups; } public struct PPD_OPTION { public byte conflicted; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)] public string keyword; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)] public string defchoice; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)] public string text; public int ui; public int section; public float order; public int num_choices; public IntPtr choices; } public struct PPD_CHOICE { public byte marked; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)] public string choice; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)] public string text; public IntPtr code; public IntPtr option; } public struct PPD_FILE { public int language_level; public int color_device; public int variable_sizes; public int accurate_screens; public int contone_only; public int landscape; public int model_number; public int manual_copies; public int throughput; public int colorspace; public IntPtr patches; public int num_emulations; public IntPtr emulations; public IntPtr jcl_begin; public IntPtr jcl_ps; public IntPtr jcl_end; public IntPtr lang_encoding; public IntPtr lang_version; public IntPtr modelname; public IntPtr ttrasterizer; public IntPtr manufacturer; public IntPtr product; public IntPtr nickname; public IntPtr shortnickname; public int num_groups; public IntPtr groups; public int num_sizes; public IntPtr sizes; /* There is more data after this that we are not using*/ } public struct CUPS_OPTIONS { public IntPtr name; public IntPtr val; } public struct CUPS_DESTS { public IntPtr name; public IntPtr instance; public int is_default; public int num_options; public IntPtr options; } #endregion } class GlobalPrintingServicesUnix : GlobalPrintingServices { internal override PrinterSettings.StringCollection InstalledPrinters { get { return PrintingServicesUnix.InstalledPrinters; } } internal override IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings) { return PrintingServicesUnix.CreateGraphicsContext (settings, default_page_settings); } internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file) { return PrintingServicesUnix.StartDoc (gr, doc_name, output_file); } internal override bool EndDoc (GraphicsPrinter gr) { return PrintingServicesUnix.EndDoc (gr); } internal override bool StartPage (GraphicsPrinter gr) { return PrintingServicesUnix.StartPage (gr); } internal override bool EndPage (GraphicsPrinter gr) { return PrintingServicesUnix.EndPage (gr); } } }