67079518faa2fa45fc5cc12e43b532cecf034ade
[mono.git] / mcs / class / System.Drawing / System.Drawing.Printing / PrintingServicesUnix.cs
1 //
2 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Author:
24 //
25 //      Jordi Mas i Hernandez, jordimash@gmail.com
26 //
27
28 using System.Runtime.InteropServices;
29 using System.Collections;
30 using System.Drawing.Printing;
31 using System.ComponentModel;
32 using System.Drawing.Imaging;
33 using System.Text;
34 using System.IO;
35
36 namespace System.Drawing.Printing
37 {
38         internal class PrintingServicesUnix : PrintingServices
39         {
40                 private Hashtable doc_info = new Hashtable ();
41                 private bool cups_installed;
42                 private string printer_name;
43                 private bool is_printer_valid;
44
45                 internal PrintingServicesUnix ()
46                 {
47                         CheckCupsInstalled ();
48                 }
49
50                 private void CheckCupsInstalled ()
51                 {
52                         try {
53                                 cupsGetDefault ();
54                         }
55                         catch (DllNotFoundException) {
56                                 Console.WriteLine("libcups not found. To have printing support, you need cups installed");
57                                 cups_installed = false;
58                                 return;
59                         }
60
61                         cups_installed = true;
62                 }
63                 
64                 internal override bool IsPrinterValid(string printer, bool force)
65                 {
66                         if (!cups_installed || printer == null | printer == String.Empty)
67                                 return false;
68
69                         if (!force && this.printer_name != null && String.Intern(this.printer_name).Equals(printer))
70                                 return is_printer_valid;
71
72                         IntPtr ptr = cupsGetPPD (printer);
73                         string ppd_filename = Marshal.PtrToStringAnsi (ptr);
74                         is_printer_valid = ppd_filename != null;
75                         this.printer_name = printer; 
76                         return is_printer_valid;
77                 }
78
79                 // Methods
80                 internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
81                 {
82                         IntPtr ptr, ppd_handle, ptr_opt, ptr_choice;
83                         string ppd_filename;
84                         PPD_FILE ppd;
85                         PPD_OPTION option;
86                         PPD_CHOICE choice;                      
87
88                         if (cups_installed == false || (printer == null) || (printer == String.Empty))
89                                 return;
90                 
91                         ptr = cupsGetPPD (printer);
92                         ppd_filename = Marshal.PtrToStringAnsi (ptr);
93                         ppd_handle = ppdOpenFile (ppd_filename);
94                         //Console.WriteLine ("File: {0}", ppd_filename);
95
96                         ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
97                         settings.landscape_angle = ppd.landscape;
98                         settings.supports_color = (ppd.color_device == 0) ? false : true;
99
100                         // Default paper source
101                         ptr_opt = ppdFindOption (ppd_handle, "InputSlot"); 
102                         if (ptr_opt != IntPtr.Zero) {
103                                 option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
104                                 ptr_choice = option.choices;
105                                 for (int c = 0; c < option.num_choices; c++) {
106                                         choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
107                                         ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
108                                         if (choice.choice == option.defchoice) {
109                                                 foreach (PaperSource paper_source in settings.PaperSources) {
110                                                         if (paper_source.SourceName ==  choice.text) {
111                                                                 settings.DefaultPageSettings.PaperSource = paper_source;
112                                                                 break;
113                                                         }
114                                                 }
115                                                 break;
116                                         }
117                                 }
118                         }
119                         
120                         // Default paper size
121                         ptr_opt = ppdFindOption (ppd_handle, "PageSize"); 
122                         if (ptr_opt != IntPtr.Zero) {
123                                 option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
124                                 ptr_choice = option.choices;
125                                 for (int c = 0; c < option.num_choices; c++) {
126                                         choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
127                                         ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
128                                         if (choice.choice == option.defchoice) {
129                                                 foreach (PaperSize paper_size in settings.PaperSizes) {
130                                                         if (paper_size.PaperName == choice.text) {
131                                                                 settings.DefaultPageSettings.PaperSize = paper_size;
132                                                                 break;
133                                                         }
134                                                 }
135                                                 break;
136                                         }
137                                 }
138                         }
139                         
140                         ppdClose (ppd_handle);
141                 }
142
143                 internal override void LoadPrinterResolutions (string printer, PrinterSettings settings)
144                 {
145                         settings.PrinterResolutions.Clear ();
146                         LoadDefaultResolutions (settings.PrinterResolutions);
147                 }
148
149                 internal override void LoadPrinterPaperSizes (string printer, PrinterSettings settings)
150                 {
151                         IntPtr ptr, ppd_handle;
152                         string ppd_filename, real_name;
153                         PPD_FILE ppd;
154                         PPD_SIZE size;
155                         PaperSize ps;
156
157                         settings.PaperSizes.Clear ();
158
159                         ptr = cupsGetPPD (printer);
160                         ppd_filename = Marshal.PtrToStringAnsi (ptr);
161                         ppd_handle = ppdOpenFile (ppd_filename);
162
163                         ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
164                         ptr = ppd.sizes;
165                         float w, h;
166                         for (int i = 0; i < ppd.num_sizes; i++) {
167                                 size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE));
168                                 real_name = GetPaperSizeName (ppd_handle, size.name);
169                                 ptr = new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (size));
170                                 w = size.width * 100 / 72;
171                                 h = size.length * 100 / 72;
172                                 ps = new PaperSize (real_name, (int) w, (int) h);
173                                 ps.SetKind (GetPaperKind ((int) w, (int) h));
174                                 settings.PaperSizes.Add (ps);
175                         }
176
177                         ppdClose (ppd_handle);
178                 }               
179                 
180                 internal override void LoadPrinterPaperSources (string printer, PrinterSettings settings)
181                 {
182                         IntPtr ptr, ppd_handle, ptr_opt, ptr_choice;
183                         string ppd_filename;
184                         PPD_OPTION option;
185                         PPD_CHOICE choice;
186
187                         if (cups_installed == false || (printer == null) || (printer == String.Empty))
188                                 return;
189
190                         ptr = cupsGetPPD (printer);
191                         ppd_filename = Marshal.PtrToStringAnsi (ptr);
192                         ppd_handle = ppdOpenFile (ppd_filename);
193
194                         ptr_opt = ppdFindOption (ppd_handle, "InputSlot"); 
195
196                         if (ptr_opt == IntPtr.Zero) {
197                                 ppdClose (ppd_handle);
198                                 return; 
199                         }
200                         
201                         option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
202                         //Console.WriteLine (" OPTION  key:{0} def:{1} text: {2}", option.keyword, option.defchoice, option.text);
203
204                         ptr_choice = option.choices;
205                         for (int c = 0; c < option.num_choices; c++) {
206                                 choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
207                                 ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
208                                 //Console.WriteLine ("       choice:{0} - text: {1}", choice.choice, choice.text);
209                                 settings.PaperSources.Add (new PaperSource (choice.text, PaperSourceKind.Custom));                                      
210                         }
211                         ppdClose (ppd_handle);
212                 }
213
214                 internal override bool StartPage (GraphicsPrinter gr)
215                 {
216                         return true;
217                 }
218
219                 internal override bool EndPage (GraphicsPrinter gr)
220                 {
221                         GdipGetPostScriptSavePage (gr.Hdc);
222                         return true;
223                 }
224
225                 string tmpfile;
226
227                 internal override bool EndDoc (GraphicsPrinter gr)
228                 {
229                         DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
230
231                         gr.Graphics.Dispose (); // Dispose object to force surface finish
232
233                         IntPtr options;
234                         int options_count = GetCupsOptions (doc.settings, doc.default_page_settings, out options);
235
236                         cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, options_count, options);
237                         cupsFreeOptions (options_count, options);
238                         doc_info.Remove (gr.Hdc);
239                         if (tmpfile != null) {
240                                 try { File.Delete (tmpfile); }
241                                 catch { }
242                         }
243                         return true;
244                 }
245
246                 internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
247                 {
248                         DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
249                         doc.title = doc_name;
250                         return true;
251                 }
252
253                 // Unfortunately, PrinterSettings and PageSettings couldn't be referencing each other,
254                 // thus we need to pass them separately
255                 internal override IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
256                 {
257                         IntPtr graphics = IntPtr.Zero;
258                         string name;
259                         if (!settings.PrintToFile) {
260                                 StringBuilder sb = new StringBuilder (1024);
261                                 int length = sb.Capacity;
262                                 cupsTempFile (sb, length);
263                                 name = sb.ToString ();
264                                 tmpfile = name;
265                         }
266                         else
267                                 name = settings.PrintFileName;
268
269                         GdipGetPostScriptGraphicsContext (name,
270                                 default_page_settings.PaperSize.Width / 100 * 72,
271                                 default_page_settings.PaperSize.Height / 100 * 72, 
272                                 // Harcoded dpy's
273                                 300, 300, ref graphics);
274
275                         DOCINFO doc = new DOCINFO ();
276                         doc.filename = name.ToString();
277                         doc.settings = settings;
278                         doc.default_page_settings = default_page_settings;
279                         doc_info.Add (graphics, doc);
280
281                         return graphics;
282                 }
283
284                 internal int GetCupsOptions (PrinterSettings printer_settings, PageSettings page_settings, out IntPtr options)
285                 {
286                         options = IntPtr.Zero;
287
288                         PaperSize size = page_settings.PaperSize;
289                         int width = size.Width * 72 / 100;
290                         int height = size.Height * 72 / 100;
291
292                         string options_string =
293                                 "copies=" + printer_settings.Copies + " " + 
294                                 "Collate=" + printer_settings.Collate + " " +
295                                 "ColorModel=" + (page_settings.Color ? "Color" : "Black") + " " +
296                                 "PageSize=" + String.Format ("Custom.{0}x{1}", width, height);
297
298                         return cupsParseOptions (options_string, 0, ref options);
299                 }
300
301                 // Properties
302
303                 internal override PrinterSettings.StringCollection InstalledPrinters {
304                         get {
305                                 int n_printers;
306                                 IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer;
307                                 string str;
308                                 PrinterSettings.StringCollection col = new PrinterSettings.StringCollection (new string[] {});
309
310                                 if (cups_installed == false)
311                                         return col;
312
313                                 n_printers = cupsGetDests (ref dests);
314
315                                 ptr_printers = dests;
316                                 for (int i = 0; i < n_printers; i++) {
317                                         ptr_printer = (IntPtr) Marshal.ReadInt32 (ptr_printers);
318                                         str = Marshal.PtrToStringAnsi (ptr_printer);
319                                         Marshal.FreeHGlobal (ptr_printer);
320                                         ptr_printers = new IntPtr (ptr_printers.ToInt64 () + 20 /*size of CUPS_DEST*/);
321                                         col.Add (str);
322                                 }
323                                 Marshal.FreeHGlobal (dests);
324                                 return col;
325                         }
326                 }
327
328                 internal override string DefaultPrinter {
329                         get {
330                                 IntPtr str;
331
332                                 if (cups_installed == false)
333                                         return string.Empty;
334
335                                 str = cupsGetDefault ();
336                                 return Marshal.PtrToStringAnsi (str);
337                         }
338                 }
339
340                 // Private functions
341
342                 private string GetPaperSizeName (IntPtr ppd, string name)
343                 {
344                         string rslt = name;
345                         PPD_OPTION option;
346                         PPD_CHOICE choice;
347                         IntPtr ptr_opt, ptr_choice;
348                         
349                         ptr_opt = ppdFindOption (ppd, "PageSize"); 
350
351                         if (ptr_opt == IntPtr.Zero) {
352                                 return rslt;    
353                         }
354                         
355                         option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
356
357                         ptr_choice = option.choices;
358                         for (int c = 0; c < option.num_choices; c++) {
359                                 choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
360                                 ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
361                                 if (name.Equals (choice.choice)) {
362                                         // Special case for custom size (cups returns NULL for it)
363                                         if (name == "Custom" && choice.text == null)
364                                                 rslt = "Custom";
365                                         else
366                                                 rslt = choice.text;
367
368                                         break;
369                                 }
370                         }
371                         return rslt;
372                 }
373
374                 private PaperKind GetPaperKind (int width, int height)
375                 {
376                         if (width == 827 && height == 1169)
377                                 return PaperKind.A4;
378                         if (width == 583 && height == 827)
379                                 return PaperKind.A5;
380                         if (width == 717 && height == 1012)
381                                 return PaperKind.B5;
382                         if (width == 693 && height == 984)
383                                 return PaperKind.B5Envelope;
384                         if (width == 638 && height == 902)
385                                 return PaperKind.C5Envelope;
386                         if (width == 449 && height == 638)
387                                 return PaperKind.C6Envelope;
388                         if (width == 1700 && height == 2200)
389                                 return PaperKind.CSheet;
390                         if (width == 433 && height == 866)
391                                 return PaperKind.DLEnvelope;
392                         if (width == 2200 && height == 3400)
393                                 return PaperKind.DSheet;
394                         if (width == 3400 && height == 4400)
395                                 return PaperKind.ESheet;
396                         if (width == 725 && height == 1050)
397                                 return PaperKind.Executive;
398                         if (width == 850 && height == 1300)
399                                 return PaperKind.Folio;
400                         if (width == 850 && height == 1200)
401                                 return PaperKind.GermanStandardFanfold;
402                         if (width == 1700 && height == 1100)
403                                 return PaperKind.Ledger;
404                         if (width == 850 && height == 1400)
405                                 return PaperKind.Legal;
406                         if (width == 927 && height == 1500)
407                                 return PaperKind.LegalExtra;
408                         if (width == 850 && height == 1100)
409                                 return PaperKind.Letter;
410                         if (width == 927 && height == 1200)
411                                 return PaperKind.LetterExtra;
412                         if (width == 850 && height == 1269)
413                                 return PaperKind.LetterPlus;
414                         if (width == 387 && height == 750)
415                                 return PaperKind.MonarchEnvelope;
416                         if (width == 387 && height == 887)
417                                 return PaperKind.Number9Envelope;
418                         if (width == 413 && height == 950)
419                                 return PaperKind.Number10Envelope;
420                         if (width == 450 && height == 1037)
421                                 return PaperKind.Number11Envelope;
422                         if (width == 475 && height == 1100)
423                                 return PaperKind.Number12Envelope;
424                         if (width == 500 && height == 1150)
425                                 return PaperKind.Number14Envelope;
426                         if (width == 363 && height == 650)
427                                 return PaperKind.PersonalEnvelope;
428                         if (width == 1000 && height == 1100)
429                                 return PaperKind.Standard10x11;
430                         if (width == 1000 && height == 1400)
431                                 return PaperKind.Standard10x14;
432                         if (width == 1100 && height == 1700)
433                                 return PaperKind.Standard11x17;
434                         if (width == 1200 && height == 1100)
435                                 return PaperKind.Standard12x11;
436                         if (width == 1500 && height == 1100)
437                                 return PaperKind.Standard15x11;
438                         if (width == 900 && height == 1100)
439                                 return PaperKind.Standard9x11;
440                         if (width == 550 && height == 850)
441                                 return PaperKind.Statement;
442                         if (width == 1100 && height == 1700)
443                                 return PaperKind.Tabloid;
444                         if (width == 1487 && height == 1100)
445                                 return PaperKind.USStandardFanfold;
446
447                         return PaperKind.Custom;
448                 }
449
450                 internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment)
451                 {                       
452                         int printers, state = -1;
453                         CUPS_DESTS cups_dests;
454                         CUPS_OPTIONS options;
455                         string str;
456                         IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer, ptr_options;
457                         
458                         if (cups_installed == false)
459                                 return;
460
461                         printers = cupsGetDests (ref dests);
462
463                         ptr_printers = dests;
464                         for (int i = 0; i < printers; i++) {
465                                 cups_dests = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
466                                 str = Marshal.PtrToStringAnsi (cups_dests.name);
467                                 ptr_printers = new IntPtr (ptr_printers.ToInt64 () + 20 /*size of CUPS_DEST*/);
468                                 if (str != printer)
469                                         continue;
470
471                                 ptr_options = cups_dests.options;
472                                 for (int o = 0; o < cups_dests.num_options; o ++) {
473                                         options = (CUPS_OPTIONS) Marshal.PtrToStructure (ptr_options, typeof (CUPS_OPTIONS));
474                                         str = Marshal.PtrToStringAnsi (options.name);                                   
475                                         if (str == "printer-state") {
476                                                 state = Int32.Parse (Marshal.PtrToStringAnsi (options.val));
477                                         } else {
478                                                 if (str == "printer-info")
479                                                         comment = Marshal.PtrToStringAnsi (options.val);
480                                         }
481                                         ptr_options = new IntPtr (ptr_options.ToInt64 () + 8 /*size of CUPS_DEST*/);
482                                 }
483                                 
484                         }
485
486                         Marshal.FreeHGlobal (dests);
487
488                         if (state == 4) {
489                                 status = "Printing";
490                         }
491                         else {
492                                 if (state == 5) {
493                                         status = "Stopped";
494                                 }
495                                 else {
496                                         status =  "Ready";
497                                 }
498                         }                       
499                 }
500
501                 //
502                 // DllImports
503                 //
504
505                 [DllImport("libcups", CharSet=CharSet.Ansi)]
506                 static extern int cupsGetDests (ref IntPtr dests);
507
508                 [DllImport("libcups", CharSet=CharSet.Ansi)]
509                 static extern IntPtr cupsTempFile (StringBuilder sb, int len);
510
511                 [DllImport("libcups", CharSet=CharSet.Ansi)]
512                 static extern IntPtr cupsGetDefault ();
513
514                 [DllImport("libcups", CharSet=CharSet.Ansi)]
515                 static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options);
516
517                 [DllImport("libcups", CharSet=CharSet.Ansi)]
518                 static extern IntPtr cupsGetPPD (string printer);
519
520                 [DllImport("libcups", CharSet=CharSet.Ansi)]
521                 static extern IntPtr ppdOpenFile (string filename);
522
523                 [DllImport("libcups", CharSet=CharSet.Ansi)]
524                 static extern IntPtr ppdFindOption (IntPtr ppd_file, string keyword);
525
526                 [DllImport("libcups")]
527                 static extern void ppdClose (IntPtr ppd);
528
529                 [DllImport ("libcups", CharSet=CharSet.Ansi)]
530                 static extern int cupsParseOptions (string arg, int number_of_options, ref IntPtr options);
531
532                 [DllImport("libcups")]
533                 static extern void cupsFreeOptions (int number_options, IntPtr options);
534
535                 [DllImport("gdiplus.dll", CharSet=CharSet.Ansi)]
536                 static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
537
538                 [DllImport("gdiplus.dll")]
539                 static extern int GdipGetPostScriptSavePage (IntPtr graphics);
540
541
542                 //Struct
543                 public struct DOCINFO
544                 {
545                         public PrinterSettings settings;
546                         public PageSettings default_page_settings;
547                         public string title;
548                         public string filename;
549                 }
550
551                 public struct PPD_SIZE
552                 {
553                         public  int marked;
554                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
555                         public  string name;
556                         public  float width;
557                         public  float length;
558                         public  float left;
559                         public  float bottom;
560                         public  float right;
561                         public  float top;
562                 }
563
564                 public struct PPD_GROUP
565                 {
566                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
567                         public string text;
568                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
569                         public string name;
570                         public int num_options;
571                         public IntPtr options;
572                         public int num_subgroups;
573                         public IntPtr subgrups;
574                 }
575
576                 public struct PPD_OPTION
577                 {
578                         public byte     conflicted;
579                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
580                         public string   keyword;
581                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
582                         public string   defchoice;
583                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
584                         public string   text;
585                         public int      ui;
586                         public int      section;
587                         public float    order;
588                         public int      num_choices;
589                         public IntPtr   choices;
590                 }
591
592                 public struct PPD_CHOICE
593                 {
594                         public byte     marked;
595                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
596                         public string   choice;
597                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
598                         public string   text;
599                         public IntPtr   code;
600                         public IntPtr   option;
601                 }
602
603                 public struct PPD_FILE
604                 {
605                         public int      language_level;
606                         public int      color_device;
607                         public int      variable_sizes;
608                         public int      accurate_screens;
609                         public int      contone_only;
610                         public int      landscape;
611                         public int      model_number;
612                         public int      manual_copies;
613                         public int      throughput;
614                         public int      colorspace;
615                         public IntPtr   patches;
616                         public int      num_emulations;
617                         public IntPtr   emulations;
618                         public IntPtr   jcl_begin;
619                         public IntPtr   jcl_ps;
620                         public IntPtr   jcl_end;
621                         public IntPtr   lang_encoding;
622                         public IntPtr   lang_version;
623                         public IntPtr   modelname;
624                         public IntPtr   ttrasterizer;
625                         public IntPtr   manufacturer;
626                         public IntPtr   product;
627                         public IntPtr   nickname;
628                         public IntPtr   shortnickname;
629                         public int      num_groups;
630                         public IntPtr   groups;
631                         public int      num_sizes;
632                         public IntPtr   sizes;
633
634                         /* There is more data after this that we are not using*/
635                 }
636
637
638                 public struct CUPS_OPTIONS
639                 {
640                         public IntPtr name;
641                         public IntPtr val;
642                 }
643                 
644                 public struct CUPS_DESTS
645                 {
646                         public IntPtr   name;
647                         public IntPtr   instance;
648                         public int      is_default;
649                         public int      num_options;
650                         public IntPtr   options;
651                 }
652         }
653 }
654