Various cosmetic changes.
[wine] / dlls / wineps / init.c
1 /*
2  *      PostScript driver initialization functions
3  *
4  *      Copyright 1998 Huw D M Davies
5  *      Copyright 2001 Marcus Meissner
6  *
7  */
8
9 #include "config.h"
10
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "gdi.h"
15 #include "psdrv.h"
16 #include "debugtools.h"
17 #include "winreg.h"
18 #include "winspool.h"
19 #include "winerror.h"
20
21 #ifdef HAVE_CUPS
22 # include <cups/cups.h>
23 #endif
24
25 DEFAULT_DEBUG_CHANNEL(psdrv);
26
27 static PSDRV_DEVMODEA DefaultDevmode = 
28 {
29   { /* dmPublic */
30 /* dmDeviceName */      "Wine PostScript Driver",
31 /* dmSpecVersion */     0x30a,
32 /* dmDriverVersion */   0x001,
33 /* dmSize */            sizeof(DEVMODEA),
34 /* dmDriverExtra */     0,
35 /* dmFields */          DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE | 
36                         DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR | 
37                         DM_DUPLEX | DM_YRESOLUTION | DM_TTOPTION,
38    { /* u1 */
39      { /* s1 */
40 /* dmOrientation */     DMORIENT_PORTRAIT,
41 /* dmPaperSize */       DMPAPER_A4,
42 /* dmPaperLength */     2969,
43 /* dmPaperWidth */      2101
44      }
45    },
46 /* dmScale */           100, /* ?? */
47 /* dmCopies */          1,
48 /* dmDefaultSource */   DMBIN_AUTO,
49 /* dmPrintQuality */    0,
50 /* dmColor */           DMCOLOR_COLOR,
51 /* dmDuplex */          0,
52 /* dmYResolution */     0,
53 /* dmTTOption */        DMTT_SUBDEV,
54 /* dmCollate */         0,
55 /* dmFormName */        "",
56 /* dmUnusedPadding */   0,
57 /* dmBitsPerPel */      0,
58 /* dmPelsWidth */       0,
59 /* dmPelsHeight */      0,
60 /* dmDisplayFlags */    0,
61 /* dmDisplayFrequency */ 0,
62 /* dmICMMethod */       0,
63 /* dmICMIntent */       0,
64 /* dmMediaType */       0,
65 /* dmDitherType */      0,
66 /* dmReserved1 */       0,
67 /* dmReserved2 */       0,
68 /* dmPanningWidth */    0,
69 /* dmPanningHeight */   0
70   },
71   { /* dmDocPrivate */
72     /* dummy */ 0
73   },
74   { /* dmDrvPrivate */
75     /* numInstalledOptions */ 0 
76   }
77 };
78
79 HANDLE PSDRV_Heap = 0;
80
81 static HANDLE PSDRV_DefaultFont = 0;
82 static LOGFONTA DefaultLogFont = {
83     100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
84     DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
85 };
86
87 /*********************************************************************
88  *           PSDRV_Init
89  *
90  * Initializes font metrics and registers driver. Called from GDI_Init()
91  *
92  */
93 BOOL WINAPI PSDRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
94 {
95     TRACE("(0x%4x, 0x%08lx, %p)\n", hinst, reason, reserved);
96    
97     switch(reason) {
98
99         case DLL_PROCESS_ATTACH:
100
101             PSDRV_Heap = HeapCreate(0, 0x10000, 0);
102             if (PSDRV_Heap == (HANDLE)NULL)
103                 return FALSE;
104
105             if (PSDRV_GetFontMetrics() == FALSE) {
106                 HeapDestroy(PSDRV_Heap);
107                 return FALSE;
108             }
109
110             PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
111             if (PSDRV_DefaultFont == (HANDLE)NULL) {
112                 HeapDestroy(PSDRV_Heap);
113                 return FALSE;
114             }
115             break;
116
117         case DLL_PROCESS_DETACH:
118
119             DeleteObject( PSDRV_DefaultFont );
120             HeapDestroy( PSDRV_Heap );
121             break;
122     }
123  
124     return TRUE;
125 }
126
127
128 /**********************************************************************
129  *           PSDRV_CreateDC
130  */
131 BOOL PSDRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device,
132                      LPCSTR output, const DEVMODEA* initData )
133 {
134     PSDRV_PDEVICE *physDev;
135     PRINTERINFO *pi;
136     PAGESIZE *page;
137     INT width = 0, height = 0;
138
139     /* If no device name was specified, retrieve the device name
140      * from the DEVMODE structure from the DC's physDev.
141      * (See CreateCompatibleDC) */
142     if ( !device && dc->physDev )
143     {
144         physDev = (PSDRV_PDEVICE *)dc->physDev;
145         device = physDev->Devmode->dmPublic.dmDeviceName;
146     }
147     pi = PSDRV_FindPrinterInfo(device);
148         
149     TRACE("(%s %s %s %p)\n", driver, device, output, initData);
150
151     if(!pi) return FALSE;
152
153     if(!pi->Fonts) {
154         MESSAGE("To use WINEPS you need to install some AFM files.\n");
155         return FALSE;
156     }
157
158     physDev = (PSDRV_PDEVICE *)HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
159                                                      sizeof(*physDev) );
160     if (!physDev) return FALSE;
161     dc->physDev = physDev;
162
163     physDev->pi = pi;
164
165     physDev->Devmode = (PSDRV_DEVMODEA *)HeapAlloc( PSDRV_Heap, 0,
166                                                      sizeof(PSDRV_DEVMODEA) );
167     if(!physDev->Devmode) {
168         HeapFree( PSDRV_Heap, 0, physDev );
169         return FALSE;
170     }
171     
172     memcpy( physDev->Devmode, pi->Devmode, sizeof(PSDRV_DEVMODEA) );
173
174     if(initData) {
175         PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)initData, pi);
176     }
177
178     physDev->logPixelsX = physDev->pi->ppd->DefaultResolution;
179     physDev->logPixelsY = physDev->pi->ppd->DefaultResolution;
180
181     for(page = pi->ppd->PageSizes; page; page = page->next) {
182         if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
183             break;
184     }
185
186     if(!page) {
187         FIXME("Can't find page\n");
188         physDev->PageSize.left = 0;
189         physDev->PageSize.right = 0;
190         physDev->PageSize.bottom = 0;
191         physDev->PageSize.top = 0;
192     } else if(page->ImageableArea) {  /* PageSize is in device units */
193         physDev->PageSize.left = page->ImageableArea->llx * physDev->logPixelsX / 72;
194         physDev->PageSize.right = page->ImageableArea->urx * physDev->logPixelsX / 72;
195         physDev->PageSize.bottom = page->ImageableArea->lly * physDev->logPixelsY / 72;
196         physDev->PageSize.top = page->ImageableArea->ury * physDev->logPixelsY / 72;
197     } else {
198         physDev->PageSize.left = physDev->PageSize.bottom = 0;
199         physDev->PageSize.right = page->PaperDimension->x * physDev->logPixelsX / 72;
200         physDev->PageSize.top = page->PaperDimension->y * physDev->logPixelsY / 72;
201     }
202     TRACE("PageSize = (%d,%d - %d,%d)\n",physDev->PageSize.left, physDev->PageSize.bottom, physDev->PageSize.right, physDev->PageSize.top);
203
204     /* these are in device units */
205     width = physDev->PageSize.right - physDev->PageSize.left;
206     height = physDev->PageSize.top - physDev->PageSize.bottom;
207
208     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) {
209         physDev->horzRes = width;
210         physDev->vertRes = height;
211     } else {
212         physDev->horzRes = height;
213         physDev->vertRes = width;
214     }
215
216     /* these are in mm */
217     physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX;
218     physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY;
219
220     TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
221           "horzRes = %d, vertRes = %d\n",
222           physDev->horzSize, physDev->vertSize,
223           physDev->horzRes, physDev->vertRes);
224
225     /* etc */
226
227     dc->hVisRgn = CreateRectRgn(0, 0, physDev->horzRes, physDev->vertRes);
228     dc->hFont = PSDRV_DefaultFont;
229
230     if (!output) output = "LPT1:";  /* HACK */
231     physDev->job.output = HeapAlloc( PSDRV_Heap, 0, strlen(output)+1 );
232     strcpy( physDev->job.output, output );
233     physDev->job.hJob = 0;
234     return TRUE;
235 }
236
237
238 /**********************************************************************
239  *           PSDRV_DeleteDC
240  */
241 BOOL PSDRV_DeleteDC( DC *dc )
242 {
243     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
244     
245     TRACE("\n");
246
247     HeapFree( PSDRV_Heap, 0, physDev->Devmode );
248     HeapFree( PSDRV_Heap, 0, physDev->job.output );
249     HeapFree( PSDRV_Heap, 0, physDev );
250     dc->physDev = NULL;
251
252     return TRUE;
253 }
254
255
256 /***********************************************************************
257  *           get_phys_page_size
258  *
259  * Helper function to compute PHYSICALWIDTH and PHYSICALHEIGHT dev caps.
260  */
261 static void get_phys_page_size( const PSDRV_PDEVICE *pdev, POINT *p )
262 {
263     p->x = p->y = 0;
264
265     if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) != 0 &&
266         pdev->Devmode->dmPublic.u1.s1.dmPaperSize != 0)
267     {
268         PAGESIZE *page = pdev->pi->ppd->PageSizes;
269
270         while (page != NULL)
271         {
272             if (page->WinPage == pdev->Devmode->dmPublic.u1.s1.dmPaperSize)
273                 break;
274             page = page->next;
275         }
276
277         if (page == NULL)
278         {
279             ERR("No entry for papersize %u in PPD file for '%s'\n",
280                 pdev->Devmode->dmPublic.u1.s1.dmPaperSize,
281                 pdev->pi->FriendlyName);
282             return;
283         }
284
285         TRACE("Found '%s' for paper size %u\n", page->FullName,
286               pdev->Devmode->dmPublic.u1.s1.dmPaperSize);
287
288         p->x = page->PaperDimension->x * pdev->logPixelsX / 72;
289         p->y = page->PaperDimension->y * pdev->logPixelsY / 72;
290
291         TRACE("%fx%f PostScript points = %lix%li device units\n",
292               page->PaperDimension->x, page->PaperDimension->y,
293               p->x, p->y);
294     }
295
296     /* These are in tenths of a millimeter */
297     if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH) != 0 &&
298         pdev->Devmode->dmPublic.u1.s1.dmPaperWidth != 0)
299     {
300         p->x = (pdev->Devmode->dmPublic.u1.s1.dmPaperWidth *
301                 pdev->logPixelsX) / 254;
302         TRACE("dmPaperWidth = %li device units\n", p->x);
303     }
304
305     if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) != 0 &&
306         pdev->Devmode->dmPublic.u1.s1.dmPaperLength != 0)
307     {
308         p->y = (pdev->Devmode->dmPublic.u1.s1.dmPaperLength *
309                 pdev->logPixelsY) / 254;
310         TRACE("dmPaperLength = %li device units\n", p->y);
311     }
312
313     if (p->x == 0 || p->y == 0)
314     {
315         ERR("Paper size not properly set for '%s'\n", pdev->pi->FriendlyName);
316         return;
317     }
318
319     if ((pdev->Devmode->dmPublic.dmFields & DM_ORIENTATION) != 0 &&
320         pdev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE)
321     {
322         INT temp = p->y;
323         p->y = p->x;
324         p->x = temp;
325     }
326 }
327
328
329 /***********************************************************************
330  *           GetDeviceCaps    (WINEPS.@)
331  */
332 INT PSDRV_GetDeviceCaps( DC *dc, INT cap )
333 {
334     PSDRV_PDEVICE *physDev = dc->physDev;
335     POINT pt;
336
337     switch(cap)
338     {
339     case DRIVERVERSION:
340         return 0;
341     case TECHNOLOGY:
342         return DT_RASPRINTER;
343     case HORZSIZE:
344         return physDev->horzSize;
345     case VERTSIZE:
346         return physDev->vertSize;
347     case HORZRES:
348         return physDev->horzRes;
349     case VERTRES:
350         return physDev->vertRes;
351     case BITSPIXEL:
352         return (physDev->pi->ppd->ColorDevice ? 8 : 1);
353     case PLANES:
354         return 1;
355     case NUMBRUSHES:
356         return -1;
357     case NUMPENS:
358         return 10;
359     case NUMMARKERS:
360         return 0;
361     case NUMFONTS:
362         return 39;
363     case NUMCOLORS:
364         return (physDev->pi->ppd->ColorDevice ? 256 : -1);
365     case PDEVICESIZE:
366         return sizeof(PSDRV_PDEVICE);
367     case CURVECAPS:
368         return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
369                 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
370     case LINECAPS:
371         return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
372                 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
373     case POLYGONALCAPS:
374         return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
375                 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
376     case TEXTCAPS:
377         return TC_CR_ANY; /* psdrv 0x59f7 */
378     case CLIPCAPS:
379         return CP_RECTANGLE;
380     case RASTERCAPS:
381         return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV |
382                 RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */
383     /* Are aspect[XY] and logPixels[XY] correct? */
384     /* Need to handle different res in x and y => fix ppd */
385     case ASPECTX:
386     case ASPECTY:
387         return physDev->pi->ppd->DefaultResolution;
388     case ASPECTXY:
389         return (int)hypot( (double)physDev->pi->ppd->DefaultResolution,
390                            (double)physDev->pi->ppd->DefaultResolution );
391     case LOGPIXELSX:
392         return physDev->logPixelsX;
393     case LOGPIXELSY:
394         return physDev->logPixelsY;
395     case SIZEPALETTE:
396         return 0;
397     case NUMRESERVED:
398         return 0;
399     case COLORRES:
400         return 0;
401     case PHYSICALWIDTH:
402         get_phys_page_size( physDev, &pt );
403         return pt.x;
404     case PHYSICALHEIGHT:
405         get_phys_page_size( physDev, &pt );
406         return pt.y;
407     case PHYSICALOFFSETX:
408     case PHYSICALOFFSETY:
409     case SCALINGFACTORX:
410     case SCALINGFACTORY:
411     case VREFRESH:
412     case DESKTOPVERTRES:
413     case DESKTOPHORZRES:
414     case BTLALIGNMENT:
415         return 0;
416     default:
417         FIXME("(%04x): unsupported capability %d, will return 0\n", dc->hSelf, cap );
418         return 0;
419     }
420 }
421
422
423 /**********************************************************************
424  *              PSDRV_FindPrinterInfo
425  */
426 PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) 
427 {
428     static PRINTERINFO *PSDRV_PrinterList;
429     DWORD type = REG_BINARY, needed, res, dwPaperSize;
430     PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList;
431     FONTNAME *font;
432     const AFM *afm;
433     HANDLE hPrinter;
434     const char *ppd = NULL;
435     DWORD ppdType;
436     char* ppdFileName = NULL;
437     HKEY hkey;
438
439     TRACE("'%s'\n", name);
440     
441     /*
442      *  If this loop completes, last will point to the 'next' element of the
443      *  final PRINTERINFO in the list
444      */    
445     for( ; pi; last = &pi->next, pi = pi->next)
446         if(!strcmp(pi->FriendlyName, name))
447             return pi;
448
449     pi = *last = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
450     if (pi == NULL)
451         return NULL;
452
453     if (!(pi->FriendlyName = HeapAlloc( PSDRV_Heap, 0, strlen(name)+1 ))) goto fail;
454     strcpy( pi->FriendlyName, name );
455
456     /* Use Get|SetPrinterDataExA instead? */
457     
458     res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
459                             NULL, 0, &needed );
460
461     if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) {
462         pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
463         if (pi->Devmode == NULL)
464             goto cleanup;           
465         memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) );
466         strcpy(pi->Devmode->dmPublic.dmDeviceName,name);
467         DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE,
468                  REG_BINARY, (LPBYTE)&DefaultDevmode, sizeof(DefaultDevmode) );
469
470         /* need to do something here AddPrinter?? */
471     }
472     else {
473         pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed );
474         DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
475                           (LPBYTE)pi->Devmode, needed, &needed);
476     }
477
478     if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) {
479         ERR ("OpenPrinterA failed with code %li\n", GetLastError ());
480         goto cleanup;
481     }
482
483 #ifdef HAVE_CUPS
484     {
485         ppd = cupsGetPPD(name);
486
487         if (ppd) {
488             needed=strlen(ppd)+1;
489             ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed);
490             memcpy(ppdFileName, ppd, needed);
491             ppdType=REG_SZ;
492             res = ERROR_SUCCESS;
493             /* we should unlink() that file later */
494         } else {
495             res = ERROR_FILE_NOT_FOUND;
496             WARN("Did not find ppd for %s\n",name);
497         }
498     }
499 #endif
500
501     if (!ppdFileName) {
502         res = GetPrinterDataA(hPrinter, "PPD File", NULL, NULL, 0, &needed);
503         if ((res==ERROR_SUCCESS) || (res==ERROR_MORE_DATA)) {
504             ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed);
505             res = GetPrinterDataA(hPrinter, "PPD File", &ppdType, ppdFileName, needed, &needed);
506         }
507     }
508     /* Look for a ppd file for this printer in the config file.
509      * First look under that printer's name, and then under 'generic'
510      */
511     if((res != ERROR_SUCCESS) && !RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd", &hkey))
512     {
513         const char* value_name;
514
515         if (RegQueryValueExA(hkey, name, 0, NULL, NULL, &needed) == ERROR_SUCCESS) {
516             value_name=name;
517         } else if (RegQueryValueExA(hkey, "generic", 0, NULL, NULL, &needed) == ERROR_SUCCESS) {
518             value_name="generic";
519         } else {
520             value_name=NULL;
521         }
522         if (value_name) {
523             ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed);
524             RegQueryValueExA(hkey, value_name, 0, &ppdType, ppdFileName, &needed);
525         }
526         RegCloseKey(hkey);
527     }
528
529     if (!ppdFileName) {
530         res = ERROR_FILE_NOT_FOUND;
531         ERR ("Error %li getting PPD file name for printer '%s'\n", res, name);
532         goto closeprinter;
533     } else {
534         res = ERROR_SUCCESS;
535         if (ppdType==REG_EXPAND_SZ) {
536             char* tmp;
537
538             /* Expand environment variable references */
539             needed=ExpandEnvironmentStringsA(ppdFileName,NULL,0);
540             tmp=HeapAlloc(PSDRV_Heap, 0, needed);
541             ExpandEnvironmentStringsA(ppdFileName,tmp,needed);
542             HeapFree(PSDRV_Heap, 0, ppdFileName);
543             ppdFileName=tmp;
544         }
545     }
546
547     pi->ppd = PSDRV_ParsePPD(ppdFileName);
548     if(!pi->ppd) {
549         MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n",
550             ppdFileName);
551         goto closeprinter;
552     }
553
554     /*
555      *  This is a hack.  The default paper size should be read in as part of
556      *  the Devmode structure, but Wine doesn't currently provide a convenient
557      *  way to configure printers.
558      */
559     res = GetPrinterDataA (hPrinter, "Paper Size", NULL, (LPBYTE) &dwPaperSize,
560             sizeof (DWORD), &needed);
561     if (res == ERROR_SUCCESS)
562         pi->Devmode->dmPublic.u1.s1.dmPaperSize = (SHORT) dwPaperSize;
563     else if (res == ERROR_FILE_NOT_FOUND)
564         TRACE ("No 'Paper Size' for printer '%s'\n", name);
565     else {
566         ERR ("GetPrinterDataA returned %li\n", res);
567         goto closeprinter;
568     }
569
570     res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", NULL,
571             0, &needed, &pi->FontSubTableSize);
572     if (res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND) {
573         TRACE ("No 'FontSubTable' for printer '%s'\n", name);
574     }
575     else if (res == ERROR_MORE_DATA) {
576         pi->FontSubTable = HeapAlloc (PSDRV_Heap, 0, needed);
577         if (pi->FontSubTable == NULL) {
578             ERR ("Failed to allocate %li bytes from heap\n", needed);
579             goto closeprinter;
580         }
581
582         res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable",
583                 (LPBYTE) pi->FontSubTable, needed, &needed,
584                 &pi->FontSubTableSize);
585         if (res != ERROR_SUCCESS) {
586             ERR ("EnumPrinterDataExA returned %li\n", res);
587             goto closeprinter;
588         }
589     }
590     else {
591         ERR("EnumPrinterDataExA returned %li\n", res);
592         goto closeprinter;
593     }
594
595     if (ClosePrinter (hPrinter) == 0) {
596         ERR ("ClosePrinter failed with code %li\n", GetLastError ());
597         goto cleanup;
598     }
599
600     pi->next = NULL;
601     pi->Fonts = NULL;
602
603     for(font = pi->ppd->InstalledFonts; font; font = font->next) {
604         afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
605         if(!afm) {
606             TRACE( "Couldn't find AFM file for installed printer font '%s' - "
607                     "ignoring\n", font->Name);
608         }
609         else {
610             BOOL added;
611             if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
612                 PSDRV_FreeAFMList(pi->Fonts);
613                 goto cleanup;
614             }
615         }
616
617     }
618     if (ppd) unlink(ppd);
619     return pi;
620
621 closeprinter:
622     ClosePrinter(hPrinter);
623 cleanup:
624     if (ppdFileName)
625         HeapFree(PSDRV_Heap, 0, ppdFileName);
626     if (pi->FontSubTable)
627         HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
628     if (pi->FriendlyName)
629         HeapFree(PSDRV_Heap, 0, pi->FriendlyName);
630     if (pi->Devmode)
631         HeapFree(PSDRV_Heap, 0, pi->Devmode);
632 fail:
633     HeapFree(PSDRV_Heap, 0, pi);
634     if (ppd) unlink(ppd);
635     *last = NULL;
636     return NULL;
637 }