oleaut32: Add a test for loading/saving an empty picture.
[wine] / dlls / wineps.drv / init.c
1 /*
2  *      PostScript driver initialization functions
3  *
4  *      Copyright 1998 Huw D M Davies
5  *      Copyright 2001 Marcus Meissner
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "winreg.h"
35 #include "winnls.h"
36 #include "psdrv.h"
37 #include "winspool.h"
38 #include "wine/library.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
42
43 static const PSDRV_DEVMODE DefaultDevmode =
44 {
45   { /* dmPublic */
46 /* dmDeviceName */      {'W','i','n','e',' ','P','o','s','t','S','c','r','i','p','t',' ','D','r','i','v','e','r',0},
47 /* dmSpecVersion */     0x30a,
48 /* dmDriverVersion */   0x001,
49 /* dmSize */            sizeof(DEVMODEW),
50 /* dmDriverExtra */     sizeof(PSDRV_DEVMODE)-sizeof(DEVMODEW),
51 /* dmFields */          DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE |
52                         DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR |
53                         DM_YRESOLUTION | DM_TTOPTION,
54    { /* u1 */
55      { /* s1 */
56 /* dmOrientation */     DMORIENT_PORTRAIT,
57 /* dmPaperSize */       DMPAPER_LETTER,
58 /* dmPaperLength */     2794,
59 /* dmPaperWidth */      2159,
60 /* dmScale */           100, /* ?? */
61 /* dmCopies */          1,
62 /* dmDefaultSource */   DMBIN_AUTO,
63 /* dmPrintQuality */    0
64      }
65    },
66 /* dmColor */           DMCOLOR_COLOR,
67 /* dmDuplex */          DMDUP_SIMPLEX,
68 /* dmYResolution */     0,
69 /* dmTTOption */        DMTT_SUBDEV,
70 /* dmCollate */         0,
71 /* dmFormName */        {},
72 /* dmUnusedPadding */   0,
73 /* dmBitsPerPel */      0,
74 /* dmPelsWidth */       0,
75 /* dmPelsHeight */      0,
76    { /* u2 */
77 /* dmDisplayFlags */    0
78    },
79 /* dmDisplayFrequency */ 0,
80 /* dmICMMethod */       0,
81 /* dmICMIntent */       0,
82 /* dmMediaType */       0,
83 /* dmDitherType */      0,
84 /* dmReserved1 */       0,
85 /* dmReserved2 */       0,
86 /* dmPanningWidth */    0,
87 /* dmPanningHeight */   0
88   },
89   { /* dmDocPrivate */
90     /* dummy */ 0
91   },
92   { /* dmDrvPrivate */
93     /* numInstalledOptions */ 0
94   }
95 };
96
97 HINSTANCE PSDRV_hInstance = 0;
98 HANDLE PSDRV_Heap = 0;
99
100 static HFONT PSDRV_DefaultFont = 0;
101 static const LOGFONTA DefaultLogFont = {
102     100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
103     DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
104 };
105
106 static const struct gdi_dc_funcs psdrv_funcs;
107
108 /*********************************************************************
109  *           DllMain
110  *
111  * Initializes font metrics and registers driver. wineps dll entry point.
112  *
113  */
114 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
115 {
116     TRACE("(%p, %d, %p)\n", hinst, reason, reserved);
117
118     switch(reason) {
119
120         case DLL_PROCESS_ATTACH:
121             PSDRV_hInstance = hinst;
122             DisableThreadLibraryCalls(hinst);
123
124             PSDRV_Heap = HeapCreate(0, 0x10000, 0);
125             if (PSDRV_Heap == NULL)
126                 return FALSE;
127
128             if (PSDRV_GetFontMetrics() == FALSE) {
129                 HeapDestroy(PSDRV_Heap);
130                 return FALSE;
131             }
132
133             PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
134             if (PSDRV_DefaultFont == NULL) {
135                 HeapDestroy(PSDRV_Heap);
136                 return FALSE;
137             }
138             break;
139
140         case DLL_PROCESS_DETACH:
141
142             DeleteObject( PSDRV_DefaultFont );
143             HeapDestroy( PSDRV_Heap );
144             break;
145     }
146
147     return TRUE;
148 }
149
150 static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev )
151 {
152     PAGESIZE *page;
153     INT width = 0, height = 0;
154
155     if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) {
156         LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) {
157             if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
158                 break;
159         }
160
161         if(&page->entry == &physDev->pi->ppd->PageSizes) {
162             FIXME("Can't find page\n");
163             physDev->ImageableArea.left = 0;
164             physDev->ImageableArea.right = 0;
165             physDev->ImageableArea.bottom = 0;
166             physDev->ImageableArea.top = 0;
167             physDev->PageSize.cx = 0;
168             physDev->PageSize.cy = 0;
169         } else if(page->ImageableArea) {
170           /* physDev sizes in device units; ppd sizes in 1/72" */
171             physDev->ImageableArea.left = page->ImageableArea->llx *
172               physDev->logPixelsX / 72;
173             physDev->ImageableArea.right = page->ImageableArea->urx *
174               physDev->logPixelsX / 72;
175             physDev->ImageableArea.bottom = page->ImageableArea->lly *
176               physDev->logPixelsY / 72;
177             physDev->ImageableArea.top = page->ImageableArea->ury *
178               physDev->logPixelsY / 72;
179             physDev->PageSize.cx = page->PaperDimension->x *
180               physDev->logPixelsX / 72;
181             physDev->PageSize.cy = page->PaperDimension->y *
182               physDev->logPixelsY / 72;
183         } else {
184             physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
185             physDev->ImageableArea.right = physDev->PageSize.cx =
186               page->PaperDimension->x * physDev->logPixelsX / 72;
187             physDev->ImageableArea.top = physDev->PageSize.cy =
188               page->PaperDimension->y * physDev->logPixelsY / 72;
189         }
190     } else if((physDev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) &&
191               (physDev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH)) {
192       /* physDev sizes in device units; Devmode sizes in 1/10 mm */
193         physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
194         physDev->ImageableArea.right = physDev->PageSize.cx =
195           physDev->Devmode->dmPublic.u1.s1.dmPaperWidth *
196           physDev->logPixelsX / 254;
197         physDev->ImageableArea.top = physDev->PageSize.cy =
198           physDev->Devmode->dmPublic.u1.s1.dmPaperLength *
199           physDev->logPixelsY / 254;
200     } else {
201         FIXME("Odd dmFields %x\n", physDev->Devmode->dmPublic.dmFields);
202         physDev->ImageableArea.left = 0;
203         physDev->ImageableArea.right = 0;
204         physDev->ImageableArea.bottom = 0;
205         physDev->ImageableArea.top = 0;
206         physDev->PageSize.cx = 0;
207         physDev->PageSize.cy = 0;
208     }
209
210     TRACE("ImageableArea = %d,%d - %d,%d: PageSize = %dx%d\n",
211           physDev->ImageableArea.left, physDev->ImageableArea.bottom,
212           physDev->ImageableArea.right, physDev->ImageableArea.top,
213           physDev->PageSize.cx, physDev->PageSize.cy);
214
215     /* these are in device units */
216     width = physDev->ImageableArea.right - physDev->ImageableArea.left;
217     height = physDev->ImageableArea.top - physDev->ImageableArea.bottom;
218
219     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) {
220         physDev->horzRes = width;
221         physDev->vertRes = height;
222     } else {
223         physDev->horzRes = height;
224         physDev->vertRes = width;
225     }
226
227     /* these are in mm */
228     physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX;
229     physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY;
230
231     TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
232           "horzRes = %d, vertRes = %d\n",
233           physDev->horzSize, physDev->vertSize,
234           physDev->horzRes, physDev->vertRes);
235 }
236
237 static PSDRV_PDEVICE *create_psdrv_physdev( PRINTERINFO *pi )
238 {
239     PSDRV_PDEVICE *physDev;
240
241     physDev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev) );
242     if (!physDev) return NULL;
243
244     physDev->Devmode = HeapAlloc( GetProcessHeap(), 0, sizeof(PSDRV_DEVMODE) );
245     if (!physDev->Devmode)
246     {
247         HeapFree( GetProcessHeap(), 0, physDev );
248         return NULL;
249     }
250
251     *physDev->Devmode = *pi->Devmode;
252     physDev->pi = pi;
253     physDev->logPixelsX = pi->ppd->DefaultResolution;
254     physDev->logPixelsY = pi->ppd->DefaultResolution;
255     return physDev;
256 }
257
258 /**********************************************************************
259  *           PSDRV_CreateDC
260  */
261 static BOOL PSDRV_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
262                             LPCWSTR output, const DEVMODEW* initData )
263 {
264     PSDRV_PDEVICE *physDev;
265     PRINTERINFO *pi;
266
267     TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device),
268                              debugstr_w(output), initData);
269
270     if (!device) return FALSE;
271     pi = PSDRV_FindPrinterInfo( device );
272     if(!pi) return FALSE;
273
274     if(!pi->Fonts) {
275         RASTERIZER_STATUS status;
276         if(!GetRasterizerCaps(&status, sizeof(status)) ||
277            !(status.wFlags & TT_AVAILABLE) ||
278            !(status.wFlags & TT_ENABLED)) {
279             MESSAGE("Disabling printer %s since it has no builtin fonts and there are no TrueType fonts available.\n",
280                     debugstr_w(device));
281             return FALSE;
282         }
283     }
284
285     if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
286
287     if (output && *output) physDev->job.output = strdupW( output );
288
289     if(initData)
290         PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)initData, pi);
291
292     PSDRV_UpdateDevCaps(physDev);
293     SelectObject( (*pdev)->hdc, PSDRV_DefaultFont );
294     push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
295     return TRUE;
296 }
297
298
299 /**********************************************************************
300  *           PSDRV_CreateCompatibleDC
301  */
302 static BOOL PSDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
303 {
304     HDC hdc = (*pdev)->hdc;
305     PSDRV_PDEVICE *physDev, *orig_dev = get_psdrv_dev( orig );
306     PRINTERINFO *pi = PSDRV_FindPrinterInfo( orig_dev->pi->friendly_name );
307
308     if (!pi) return FALSE;
309     if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
310     PSDRV_MergeDevmodes( physDev->Devmode, orig_dev->Devmode, pi );
311     PSDRV_UpdateDevCaps(physDev);
312     SelectObject( hdc, PSDRV_DefaultFont );
313     push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
314     return TRUE;
315 }
316
317
318
319 /**********************************************************************
320  *           PSDRV_DeleteDC
321  */
322 static BOOL PSDRV_DeleteDC( PHYSDEV dev )
323 {
324     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
325
326     TRACE("\n");
327
328     HeapFree( GetProcessHeap(), 0, physDev->Devmode );
329     HeapFree( GetProcessHeap(), 0, physDev->job.output );
330     HeapFree( GetProcessHeap(), 0, physDev );
331
332     return TRUE;
333 }
334
335
336 /**********************************************************************
337  *           ResetDC   (WINEPS.@)
338  */
339 static HDC PSDRV_ResetDC( PHYSDEV dev, const DEVMODEW *lpInitData )
340 {
341     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
342
343     if (lpInitData)
344     {
345         PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)lpInitData, physDev->pi);
346         PSDRV_UpdateDevCaps(physDev);
347     }
348     return dev->hdc;
349 }
350
351 /***********************************************************************
352  *           GetDeviceCaps    (WINEPS.@)
353  */
354 static INT PSDRV_GetDeviceCaps( PHYSDEV dev, INT cap )
355 {
356     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
357
358     switch(cap)
359     {
360     case DRIVERVERSION:
361         return 0;
362     case TECHNOLOGY:
363         return DT_RASPRINTER;
364     case HORZSIZE:
365         return MulDiv(physDev->horzSize, 100,
366                       physDev->Devmode->dmPublic.u1.s1.dmScale);
367     case VERTSIZE:
368         return MulDiv(physDev->vertSize, 100,
369                       physDev->Devmode->dmPublic.u1.s1.dmScale);
370     case HORZRES:
371     case DESKTOPHORZRES:
372         return physDev->horzRes;
373     case VERTRES:
374     case DESKTOPVERTRES:
375         return physDev->vertRes;
376     case BITSPIXEL:
377         return (physDev->pi->ppd->ColorDevice != CD_False) ? 32 : 1;
378     case PLANES:
379         return 1;
380     case NUMBRUSHES:
381         return -1;
382     case NUMPENS:
383         return 10;
384     case NUMMARKERS:
385         return 0;
386     case NUMFONTS:
387         return 39;
388     case NUMCOLORS:
389         return -1;
390     case PDEVICESIZE:
391         return sizeof(PSDRV_PDEVICE);
392     case CURVECAPS:
393         return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
394                 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
395     case LINECAPS:
396         return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
397                 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
398     case POLYGONALCAPS:
399         return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
400                 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
401     case TEXTCAPS:
402         return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */
403     case CLIPCAPS:
404         return CP_RECTANGLE;
405     case RASTERCAPS:
406         return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV |
407                 RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */
408     /* Are aspect[XY] and logPixels[XY] correct? */
409     /* Need to handle different res in x and y => fix ppd */
410     case ASPECTX:
411     case ASPECTY:
412         return physDev->pi->ppd->DefaultResolution;
413     case ASPECTXY:
414         return (int)hypot( (double)physDev->pi->ppd->DefaultResolution,
415                            (double)physDev->pi->ppd->DefaultResolution );
416     case LOGPIXELSX:
417         return MulDiv(physDev->logPixelsX,
418                       physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
419     case LOGPIXELSY:
420         return MulDiv(physDev->logPixelsY,
421                       physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
422     case SIZEPALETTE:
423         return 0;
424     case NUMRESERVED:
425         return 0;
426     case COLORRES:
427         return 0;
428     case PHYSICALWIDTH:
429         return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
430           physDev->PageSize.cy : physDev->PageSize.cx;
431     case PHYSICALHEIGHT:
432         return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
433           physDev->PageSize.cx : physDev->PageSize.cy;
434     case PHYSICALOFFSETX:
435       if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
436           if(physDev->pi->ppd->LandscapeOrientation == -90)
437               return physDev->PageSize.cy - physDev->ImageableArea.top;
438           else
439               return physDev->ImageableArea.bottom;
440       }
441       return physDev->ImageableArea.left;
442
443     case PHYSICALOFFSETY:
444       if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
445           if(physDev->pi->ppd->LandscapeOrientation == -90)
446               return physDev->PageSize.cx - physDev->ImageableArea.right;
447           else
448               return physDev->ImageableArea.left;
449       }
450       return physDev->PageSize.cy - physDev->ImageableArea.top;
451
452     case SCALINGFACTORX:
453     case SCALINGFACTORY:
454     case VREFRESH:
455     case BLTALIGNMENT:
456         return 0;
457     case SHADEBLENDCAPS:
458         return SB_NONE;
459     default:
460         FIXME("(%p): unsupported capability %d, will return 0\n", dev->hdc, cap );
461         return 0;
462     }
463 }
464
465 static PRINTER_ENUM_VALUESA *load_font_sub_table( HANDLE printer, DWORD *num_entries )
466 {
467     DWORD res, needed, num;
468     PRINTER_ENUM_VALUESA *table = NULL;
469     static const char fontsubkey[] = "PrinterDriverData\\FontSubTable";
470
471     *num_entries = 0;
472
473     res = EnumPrinterDataExA( printer, fontsubkey, NULL, 0, &needed, &num );
474     if (res != ERROR_MORE_DATA) return NULL;
475
476     table = HeapAlloc( PSDRV_Heap, 0, needed );
477     if (!table) return NULL;
478
479     res = EnumPrinterDataExA( printer, fontsubkey, (LPBYTE)table, needed, &needed, &num );
480     if (res != ERROR_SUCCESS)
481     {
482         HeapFree( PSDRV_Heap, 0, table );
483         return NULL;
484     }
485
486     *num_entries = num;
487     return table;
488 }
489
490 static PSDRV_DEVMODE *get_printer_devmode( HANDLE printer )
491 {
492     DWORD needed, dm_size;
493     BOOL res;
494     PRINTER_INFO_9W *info;
495     PSDRV_DEVMODE *dm;
496
497     GetPrinterW( printer, 9, NULL, 0, &needed );
498     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
499
500     info = HeapAlloc( PSDRV_Heap, 0, needed );
501     res = GetPrinterW( printer, 9, (BYTE *)info, needed, &needed );
502     if (!res || !info->pDevMode)
503     {
504         HeapFree( PSDRV_Heap, 0, info );
505         return NULL;
506     }
507
508     /* sanity check the sizes */
509     dm_size = info->pDevMode->dmSize + info->pDevMode->dmDriverExtra;
510     if ((char *)info->pDevMode - (char *)info + dm_size > needed)
511     {
512         HeapFree( PSDRV_Heap, 0, info );
513         return NULL;
514     }
515
516     dm = (PSDRV_DEVMODE*)info;
517     memmove( dm, info->pDevMode, dm_size );
518     return dm;
519 }
520
521 static PSDRV_DEVMODE *get_devmode( HANDLE printer, const WCHAR *name, BOOL *is_default )
522 {
523     PSDRV_DEVMODE *dm = get_printer_devmode( printer );
524
525     *is_default = FALSE;
526
527     if (dm && dm->dmPublic.dmSize + dm->dmPublic.dmDriverExtra >= sizeof(DefaultDevmode))
528     {
529         TRACE( "Retrieved devmode from winspool\n" );
530         return dm;
531     }
532     HeapFree( PSDRV_Heap, 0, dm );
533
534     TRACE( "Using default devmode\n" );
535     dm = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
536     if (dm)
537     {
538         *dm = DefaultDevmode;
539         lstrcpynW( (WCHAR *)dm->dmPublic.dmDeviceName, name, CCHDEVICENAME );
540         *is_default = TRUE;
541     }
542     return dm;
543 }
544
545 static BOOL set_devmode( HANDLE printer, PSDRV_DEVMODE *dm )
546 {
547     PRINTER_INFO_9W info;
548     info.pDevMode = &dm->dmPublic;
549
550     return SetPrinterW( printer, 9, (BYTE *)&info, 0 );
551 }
552
553 static char *get_ppd_filename( HANDLE printer )
554 {
555     DWORD needed;
556     DRIVER_INFO_2W *info;
557     char *unixname;
558
559     GetPrinterDriverW( printer, NULL, 2, NULL, 0, &needed );
560     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
561     info = HeapAlloc( GetProcessHeap(), 0, needed );
562     if (!info) return NULL;
563     GetPrinterDriverW( printer, NULL, 2, (BYTE*)info, needed, &needed );
564     unixname = wine_get_unix_file_name( info->pDataFile );
565     HeapFree( GetProcessHeap(), 0, info );
566
567     return unixname;
568 }
569
570 static struct list printer_list = LIST_INIT( printer_list );
571
572 /**********************************************************************
573  *              PSDRV_FindPrinterInfo
574  */
575 PRINTERINFO *PSDRV_FindPrinterInfo(LPCWSTR name)
576 {
577     DWORD needed, res, dwPaperSize;
578     PRINTERINFO *pi;
579     FONTNAME *font;
580     const AFM *afm;
581     HANDLE hPrinter = 0;
582     char *ppd_filename = NULL, *nameA = NULL;
583     BOOL using_default_devmode = FALSE;
584     int len;
585
586     TRACE("'%s'\n", debugstr_w(name));
587
588     LIST_FOR_EACH_ENTRY( pi, &printer_list, PRINTERINFO, entry )
589     {
590         if (!strcmpW( pi->friendly_name, name ))
591             return pi;
592     }
593
594     pi = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
595     if (pi == NULL) return NULL;
596
597     if (!(pi->friendly_name = HeapAlloc( PSDRV_Heap, 0, (strlenW(name)+1)*sizeof(WCHAR) ))) goto fail;
598     strcpyW( pi->friendly_name, name );
599
600     if (OpenPrinterW( pi->friendly_name, &hPrinter, NULL ) == 0) {
601         ERR ("OpenPrinter failed with code %i\n", GetLastError ());
602         goto fail;
603     }
604
605     len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
606     nameA = HeapAlloc( GetProcessHeap(), 0, len );
607     WideCharToMultiByte( CP_ACP, 0, name, -1, nameA, len, NULL, NULL );
608
609     pi->Devmode = get_devmode( hPrinter, name, &using_default_devmode );
610     if (!pi->Devmode) goto fail;
611
612     ppd_filename = get_ppd_filename( hPrinter );
613     if (!ppd_filename) goto fail;
614
615     pi->ppd = PSDRV_ParsePPD( ppd_filename, hPrinter );
616     if (!pi->ppd)
617     {
618         WARN( "Couldn't parse PPD file '%s'\n", ppd_filename );
619         goto fail;
620     }
621
622     if(using_default_devmode) {
623         DWORD papersize;
624
625         if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER,
626                           (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) {
627             PSDRV_DEVMODE dm;
628             memset(&dm, 0, sizeof(dm));
629             dm.dmPublic.dmFields = DM_PAPERSIZE;
630             dm.dmPublic.u1.s1.dmPaperSize = papersize;
631             PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
632         }
633     }
634
635     if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */
636         PSDRV_DEVMODE dm;
637         memset(&dm, 0, sizeof(dm));
638         dm.dmPublic.dmFields = DM_PAPERSIZE;
639         dm.dmPublic.u1.s1.dmPaperSize = pi->ppd->DefaultPageSize->WinPage;
640         PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
641     }
642
643     /*
644      *  This is a hack.  The default paper size should be read in as part of
645      *  the Devmode structure, but Wine doesn't currently provide a convenient
646      *  way to configure printers.
647      */
648     res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "Paper Size", NULL,
649                             (LPBYTE)&dwPaperSize, sizeof(DWORD), &needed);
650     if (res == ERROR_SUCCESS)
651         pi->Devmode->dmPublic.u1.s1.dmPaperSize = (SHORT) dwPaperSize;
652     else if (res == ERROR_FILE_NOT_FOUND)
653         TRACE ("No 'Paper Size' for printer '%s'\n", debugstr_w(name));
654     else {
655         ERR ("GetPrinterDataA returned %i\n", res);
656         goto fail;
657     }
658
659     /* Duplex is indicated by the setting of the DM_DUPLEX bit in dmFields.
660        WinDuplex == 0 is a special case which means that the ppd has a
661        *DefaultDuplex: NotCapable entry.  In this case we'll try not to confuse
662        apps and set dmDuplex to DMDUP_SIMPLEX but leave the DM_DUPLEX clear.
663        PSDRV_WriteHeader understands this and copes. */
664     pi->Devmode->dmPublic.dmFields &= ~DM_DUPLEX;
665     if(pi->ppd->DefaultDuplex) {
666         pi->Devmode->dmPublic.dmDuplex = pi->ppd->DefaultDuplex->WinDuplex;
667         if(pi->Devmode->dmPublic.dmDuplex != 0)
668             pi->Devmode->dmPublic.dmFields |= DM_DUPLEX;
669         else
670             pi->Devmode->dmPublic.dmDuplex = DMDUP_SIMPLEX;
671     }
672
673     set_devmode( hPrinter, pi->Devmode );
674
675     pi->FontSubTable = load_font_sub_table( hPrinter, &pi->FontSubTableSize );
676
677     LIST_FOR_EACH_ENTRY( font, &pi->ppd->InstalledFonts, FONTNAME, entry )
678     {
679         afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
680         if(!afm) {
681             TRACE( "Couldn't find AFM file for installed printer font '%s' - "
682                     "ignoring\n", font->Name);
683         }
684         else {
685             BOOL added;
686             if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
687                 PSDRV_FreeAFMList(pi->Fonts);
688                 goto fail;
689             }
690         }
691
692     }
693     ClosePrinter( hPrinter );
694     HeapFree( GetProcessHeap(), 0, nameA );
695     HeapFree( GetProcessHeap(), 0, ppd_filename );
696     list_add_head( &printer_list, &pi->entry );
697     return pi;
698
699 fail:
700     if (hPrinter) ClosePrinter( hPrinter );
701     HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
702     HeapFree(PSDRV_Heap, 0, pi->friendly_name);
703     HeapFree(PSDRV_Heap, 0, pi->Devmode);
704     HeapFree(PSDRV_Heap, 0, pi);
705     HeapFree( GetProcessHeap(), 0, nameA );
706     HeapFree( GetProcessHeap(), 0, ppd_filename );
707     return NULL;
708 }
709
710
711 static const struct gdi_dc_funcs psdrv_funcs =
712 {
713     NULL,                               /* pAbortDoc */
714     NULL,                               /* pAbortPath */
715     NULL,                               /* pAlphaBlend */
716     NULL,                               /* pAngleArc */
717     PSDRV_Arc,                          /* pArc */
718     NULL,                               /* pArcTo */
719     NULL,                               /* pBeginPath */
720     NULL,                               /* pBlendImage */
721     PSDRV_Chord,                        /* pChord */
722     NULL,                               /* pCloseFigure */
723     PSDRV_CreateCompatibleDC,           /* pCreateCompatibleDC */
724     PSDRV_CreateDC,                     /* pCreateDC */
725     PSDRV_DeleteDC,                     /* pDeleteDC */
726     NULL,                               /* pDeleteObject */
727     PSDRV_DeviceCapabilities,           /* pDeviceCapabilities */
728     PSDRV_Ellipse,                      /* pEllipse */
729     PSDRV_EndDoc,                       /* pEndDoc */
730     PSDRV_EndPage,                      /* pEndPage */
731     NULL,                               /* pEndPath */
732     PSDRV_EnumFonts,                    /* pEnumFonts */
733     NULL,                               /* pEnumICMProfiles */
734     NULL,                               /* pExcludeClipRect */
735     PSDRV_ExtDeviceMode,                /* pExtDeviceMode */
736     PSDRV_ExtEscape,                    /* pExtEscape */
737     NULL,                               /* pExtFloodFill */
738     NULL,                               /* pExtSelectClipRgn */
739     PSDRV_ExtTextOut,                   /* pExtTextOut */
740     PSDRV_FillPath,                     /* pFillPath */
741     NULL,                               /* pFillRgn */
742     NULL,                               /* pFlattenPath */
743     NULL,                               /* pFontIsLinked */
744     NULL,                               /* pFrameRgn */
745     NULL,                               /* pGdiComment */
746     NULL,                               /* pGdiRealizationInfo */
747     NULL,                               /* pGetBoundsRect */
748     NULL,                               /* pGetCharABCWidths */
749     NULL,                               /* pGetCharABCWidthsI */
750     PSDRV_GetCharWidth,                 /* pGetCharWidth */
751     PSDRV_GetDeviceCaps,                /* pGetDeviceCaps */
752     NULL,                               /* pGetDeviceGammaRamp */
753     NULL,                               /* pGetFontData */
754     NULL,                               /* pGetFontUnicodeRanges */
755     NULL,                               /* pGetGlyphIndices */
756     NULL,                               /* pGetGlyphOutline */
757     NULL,                               /* pGetICMProfile */
758     NULL,                               /* pGetImage */
759     NULL,                               /* pGetKerningPairs */
760     NULL,                               /* pGetNearestColor */
761     NULL,                               /* pGetOutlineTextMetrics */
762     NULL,                               /* pGetPixel */
763     NULL,                               /* pGetSystemPaletteEntries */
764     NULL,                               /* pGetTextCharsetInfo */
765     PSDRV_GetTextExtentExPoint,         /* pGetTextExtentExPoint */
766     NULL,                               /* pGetTextExtentExPointI */
767     NULL,                               /* pGetTextFace */
768     PSDRV_GetTextMetrics,               /* pGetTextMetrics */
769     NULL,                               /* pGradientFill */
770     NULL,                               /* pIntersectClipRect */
771     NULL,                               /* pInvertRgn */
772     PSDRV_LineTo,                       /* pLineTo */
773     NULL,                               /* pModifyWorldTransform */
774     NULL,                               /* pMoveTo */
775     NULL,                               /* pOffsetClipRgn */
776     NULL,                               /* pOffsetViewportOrg */
777     NULL,                               /* pOffsetWindowOrg */
778     PSDRV_PaintRgn,                     /* pPaintRgn */
779     PSDRV_PatBlt,                       /* pPatBlt */
780     PSDRV_Pie,                          /* pPie */
781     PSDRV_PolyBezier,                   /* pPolyBezier */
782     PSDRV_PolyBezierTo,                 /* pPolyBezierTo */
783     NULL,                               /* pPolyDraw */
784     PSDRV_PolyPolygon,                  /* pPolyPolygon */
785     PSDRV_PolyPolyline,                 /* pPolyPolyline */
786     NULL,                               /* pPolygon */
787     NULL,                               /* pPolyline */
788     NULL,                               /* pPolylineTo */
789     PSDRV_PutImage,                     /* pPutImage */
790     NULL,                               /* pRealizeDefaultPalette */
791     NULL,                               /* pRealizePalette */
792     PSDRV_Rectangle,                    /* pRectangle */
793     PSDRV_ResetDC,                      /* pResetDC */
794     NULL,                               /* pRestoreDC */
795     PSDRV_RoundRect,                    /* pRoundRect */
796     NULL,                               /* pSaveDC */
797     NULL,                               /* pScaleViewportExt */
798     NULL,                               /* pScaleWindowExt */
799     NULL,                               /* pSelectBitmap */
800     PSDRV_SelectBrush,                  /* pSelectBrush */
801     NULL,                               /* pSelectClipPath */
802     PSDRV_SelectFont,                   /* pSelectFont */
803     NULL,                               /* pSelectPalette */
804     PSDRV_SelectPen,                    /* pSelectPen */
805     NULL,                               /* pSetArcDirection */
806     PSDRV_SetBkColor,                   /* pSetBkColor */
807     NULL,                               /* pSetBkMode */
808     NULL,                               /* pSetBoundsRect */
809     PSDRV_SetDCBrushColor,              /* pSetDCBrushColor */
810     PSDRV_SetDCPenColor,                /* pSetDCPenColor */
811     NULL,                               /* pSetDIBitsToDevice */
812     NULL,                               /* pSetDeviceClipping */
813     NULL,                               /* pSetDeviceGammaRamp */
814     NULL,                               /* pSetLayout */
815     NULL,                               /* pSetMapMode */
816     NULL,                               /* pSetMapperFlags */
817     PSDRV_SetPixel,                     /* pSetPixel */
818     NULL,                               /* pSetPolyFillMode */
819     NULL,                               /* pSetROP2 */
820     NULL,                               /* pSetRelAbs */
821     NULL,                               /* pSetStretchBltMode */
822     NULL,                               /* pSetTextAlign */
823     NULL,                               /* pSetTextCharacterExtra */
824     PSDRV_SetTextColor,                 /* pSetTextColor */
825     NULL,                               /* pSetTextJustification */
826     NULL,                               /* pSetViewportExt */
827     NULL,                               /* pSetViewportOrg */
828     NULL,                               /* pSetWindowExt */
829     NULL,                               /* pSetWindowOrg */
830     NULL,                               /* pSetWorldTransform */
831     PSDRV_StartDoc,                     /* pStartDoc */
832     PSDRV_StartPage,                    /* pStartPage */
833     NULL,                               /* pStretchBlt */
834     NULL,                               /* pStretchDIBits */
835     PSDRV_StrokeAndFillPath,            /* pStrokeAndFillPath */
836     PSDRV_StrokePath,                   /* pStrokePath */
837     NULL,                               /* pUnrealizePalette */
838     NULL,                               /* pWidenPath */
839     NULL,                               /* wine_get_wgl_driver */
840     GDI_PRIORITY_GRAPHICS_DRV           /* priority */
841 };
842
843
844 /******************************************************************************
845  *      PSDRV_get_gdi_driver
846  */
847 const struct gdi_dc_funcs * CDECL PSDRV_get_gdi_driver( unsigned int version )
848 {
849     if (version != WINE_GDI_DRIVER_VERSION)
850     {
851         ERR( "version mismatch, gdi32 wants %u but wineps has %u\n", version, WINE_GDI_DRIVER_VERSION );
852         return NULL;
853     }
854     return &psdrv_funcs;
855 }