wineps: Switch to using a Unicode devmode.
[wine.git] / dlls / wineps.drv / driver.c
blob926daf553ec182b301e9c093650d65416c3131bb
1 /*
2 * Exported functions from the PostScript driver.
4 * [Ext]DeviceMode, DeviceCapabilities, AdvancedSetupDialog.
6 * Will need ExtTextOut for winword6 (urgh!)
8 * Copyright 1998 Huw D M Davies
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
28 #include "config.h"
30 #include <string.h>
32 #include "wine/debug.h"
33 #include "psdrv.h"
35 #include "winuser.h"
36 #include "wine/wingdi16.h"
37 #include "prsht.h"
38 #include "psdlg.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
42 /* convert points to paper size units (10th of a millimeter) */
43 static inline int paper_size_from_points( float size )
45 return size * 254 / 72;
48 /************************************************************************
50 * PSDRV_MergeDevmodes
52 * Updates dm1 with some fields from dm2
55 void PSDRV_MergeDevmodes( PSDRV_DEVMODE *dm1, PSDRV_DEVMODE *dm2, PRINTERINFO *pi )
57 /* some sanity checks here on dm2 */
59 if(dm2->dmPublic.dmFields & DM_ORIENTATION) {
60 dm1->dmPublic.u1.s1.dmOrientation = dm2->dmPublic.u1.s1.dmOrientation;
61 TRACE("Changing orientation to %d (%s)\n",
62 dm1->dmPublic.u1.s1.dmOrientation,
63 dm1->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT ?
64 "Portrait" :
65 (dm1->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE ?
66 "Landscape" : "unknown"));
69 /* NB PaperWidth is always < PaperLength */
70 if(dm2->dmPublic.dmFields & DM_PAPERSIZE) {
71 PAGESIZE *page;
73 LIST_FOR_EACH_ENTRY(page, &pi->ppd->PageSizes, PAGESIZE, entry) {
74 if(page->WinPage == dm2->dmPublic.u1.s1.dmPaperSize)
75 break;
77 if(&page->entry != &pi->ppd->PageSizes ) {
78 dm1->dmPublic.u1.s1.dmPaperSize = dm2->dmPublic.u1.s1.dmPaperSize;
79 dm1->dmPublic.u1.s1.dmPaperWidth = paper_size_from_points( page->PaperDimension->x );
80 dm1->dmPublic.u1.s1.dmPaperLength = paper_size_from_points( page->PaperDimension->y );
81 dm1->dmPublic.dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH);
82 dm1->dmPublic.dmFields |= DM_PAPERSIZE;
83 TRACE("Changing page to %s %d x %d\n", page->FullName,
84 dm1->dmPublic.u1.s1.dmPaperWidth,
85 dm1->dmPublic.u1.s1.dmPaperLength );
86 } else {
87 TRACE("Trying to change to unsupported pagesize %d\n",
88 dm2->dmPublic.u1.s1.dmPaperSize);
90 } else if((dm2->dmPublic.dmFields & DM_PAPERLENGTH) &&
91 (dm2->dmPublic.dmFields & DM_PAPERWIDTH)) {
92 dm1->dmPublic.u1.s1.dmPaperLength = dm2->dmPublic.u1.s1.dmPaperLength;
93 dm1->dmPublic.u1.s1.dmPaperWidth = dm2->dmPublic.u1.s1.dmPaperWidth;
94 TRACE("Changing PaperLength|Width to %dx%d\n",
95 dm2->dmPublic.u1.s1.dmPaperLength,
96 dm2->dmPublic.u1.s1.dmPaperWidth);
97 dm1->dmPublic.dmFields &= ~DM_PAPERSIZE;
98 dm1->dmPublic.dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
99 } else if(dm2->dmPublic.dmFields & (DM_PAPERLENGTH | DM_PAPERWIDTH)) {
100 /* You might think that this would be allowed if dm1 is in custom size
101 mode, but apparently Windows reverts to standard paper mode even in
102 this case */
103 FIXME("Trying to change only paperlength or paperwidth\n");
104 dm1->dmPublic.dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH);
105 dm1->dmPublic.dmFields |= DM_PAPERSIZE;
108 if(dm2->dmPublic.dmFields & DM_SCALE) {
109 dm1->dmPublic.u1.s1.dmScale = dm2->dmPublic.u1.s1.dmScale;
110 TRACE("Changing Scale to %d\n", dm2->dmPublic.u1.s1.dmScale);
113 if(dm2->dmPublic.dmFields & DM_COPIES) {
114 dm1->dmPublic.u1.s1.dmCopies = dm2->dmPublic.u1.s1.dmCopies;
115 TRACE("Changing Copies to %d\n", dm2->dmPublic.u1.s1.dmCopies);
118 if (dm2->dmPublic.dmFields & DM_DEFAULTSOURCE)
120 INPUTSLOT *slot;
122 LIST_FOR_EACH_ENTRY( slot, &pi->ppd->InputSlots, INPUTSLOT, entry )
123 if(slot->WinBin == dm2->dmPublic.u1.s1.dmDefaultSource)
124 break;
126 if (&slot->entry != &pi->ppd->InputSlots)
128 dm1->dmPublic.u1.s1.dmDefaultSource = dm2->dmPublic.u1.s1.dmDefaultSource;
129 TRACE("Changing bin to '%s'\n", slot->FullName);
131 else
132 TRACE("Trying to change to unsupported bin %d\n", dm2->dmPublic.u1.s1.dmDefaultSource);
135 if (dm2->dmPublic.dmFields & DM_DEFAULTSOURCE )
136 dm1->dmPublic.u1.s1.dmDefaultSource = dm2->dmPublic.u1.s1.dmDefaultSource;
137 if (dm2->dmPublic.dmFields & DM_PRINTQUALITY )
138 dm1->dmPublic.u1.s1.dmPrintQuality = dm2->dmPublic.u1.s1.dmPrintQuality;
139 if (dm2->dmPublic.dmFields & DM_COLOR )
140 dm1->dmPublic.dmColor = dm2->dmPublic.dmColor;
141 if (dm2->dmPublic.dmFields & DM_DUPLEX && pi->ppd->DefaultDuplex && pi->ppd->DefaultDuplex->WinDuplex != 0)
142 dm1->dmPublic.dmDuplex = dm2->dmPublic.dmDuplex;
143 if (dm2->dmPublic.dmFields & DM_YRESOLUTION )
144 dm1->dmPublic.dmYResolution = dm2->dmPublic.dmYResolution;
145 if (dm2->dmPublic.dmFields & DM_TTOPTION )
146 dm1->dmPublic.dmTTOption = dm2->dmPublic.dmTTOption;
147 if (dm2->dmPublic.dmFields & DM_COLLATE )
148 dm1->dmPublic.dmCollate = dm2->dmPublic.dmCollate;
149 if (dm2->dmPublic.dmFields & DM_FORMNAME )
150 lstrcpynA((LPSTR)dm1->dmPublic.dmFormName, (LPCSTR)dm2->dmPublic.dmFormName, CCHFORMNAME);
151 if (dm2->dmPublic.dmFields & DM_BITSPERPEL )
152 dm1->dmPublic.dmBitsPerPel = dm2->dmPublic.dmBitsPerPel;
153 if (dm2->dmPublic.dmFields & DM_PELSWIDTH )
154 dm1->dmPublic.dmPelsWidth = dm2->dmPublic.dmPelsWidth;
155 if (dm2->dmPublic.dmFields & DM_PELSHEIGHT )
156 dm1->dmPublic.dmPelsHeight = dm2->dmPublic.dmPelsHeight;
157 if (dm2->dmPublic.dmFields & DM_DISPLAYFLAGS )
158 dm1->dmPublic.u2.dmDisplayFlags = dm2->dmPublic.u2.dmDisplayFlags;
159 if (dm2->dmPublic.dmFields & DM_DISPLAYFREQUENCY )
160 dm1->dmPublic.dmDisplayFrequency = dm2->dmPublic.dmDisplayFrequency;
161 if (dm2->dmPublic.dmFields & DM_POSITION )
162 dm1->dmPublic.u1.s2.dmPosition = dm2->dmPublic.u1.s2.dmPosition;
163 if (dm2->dmPublic.dmFields & DM_LOGPIXELS )
164 dm1->dmPublic.dmLogPixels = dm2->dmPublic.dmLogPixels;
165 if (dm2->dmPublic.dmFields & DM_ICMMETHOD )
166 dm1->dmPublic.dmICMMethod = dm2->dmPublic.dmICMMethod;
167 if (dm2->dmPublic.dmFields & DM_ICMINTENT )
168 dm1->dmPublic.dmICMIntent = dm2->dmPublic.dmICMIntent;
169 if (dm2->dmPublic.dmFields & DM_MEDIATYPE )
170 dm1->dmPublic.dmMediaType = dm2->dmPublic.dmMediaType;
171 if (dm2->dmPublic.dmFields & DM_DITHERTYPE )
172 dm1->dmPublic.dmDitherType = dm2->dmPublic.dmDitherType;
173 if (dm2->dmPublic.dmFields & DM_PANNINGWIDTH )
174 dm1->dmPublic.dmPanningWidth = dm2->dmPublic.dmPanningWidth;
175 if (dm2->dmPublic.dmFields & DM_PANNINGHEIGHT )
176 dm1->dmPublic.dmPanningHeight = dm2->dmPublic.dmPanningHeight;
178 return;
182 typedef struct
184 PRINTERINFO *pi;
185 PSDRV_DEVMODE *dlgdm;
186 } PSDRV_DLGINFO;
188 /****************************************************************
189 * PSDRV_PaperDlgProc
191 * Dialog proc for 'Paper' propsheet
193 static INT_PTR CALLBACK PSDRV_PaperDlgProc(HWND hwnd, UINT msg,
194 WPARAM wParam, LPARAM lParam)
196 PSDRV_DLGINFO *di;
197 int i, Cursel;
198 PAGESIZE *ps;
199 DUPLEX *duplex;
201 switch(msg) {
202 case WM_INITDIALOG:
203 di = (PSDRV_DLGINFO*)((PROPSHEETPAGEA*)lParam)->lParam;
204 SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)di);
206 i = Cursel = 0;
207 LIST_FOR_EACH_ENTRY(ps, &di->pi->ppd->PageSizes, PAGESIZE, entry) {
208 SendDlgItemMessageA(hwnd, IDD_PAPERS, LB_INSERTSTRING, i,
209 (LPARAM)ps->FullName);
210 if(di->pi->Devmode->dmPublic.u1.s1.dmPaperSize == ps->WinPage)
211 Cursel = i;
212 i++;
214 SendDlgItemMessageA(hwnd, IDD_PAPERS, LB_SETCURSEL, Cursel, 0);
216 CheckRadioButton(hwnd, IDD_ORIENT_PORTRAIT, IDD_ORIENT_LANDSCAPE,
217 di->pi->Devmode->dmPublic.u1.s1.dmOrientation ==
218 DMORIENT_PORTRAIT ? IDD_ORIENT_PORTRAIT :
219 IDD_ORIENT_LANDSCAPE);
221 if (list_empty( &di->pi->ppd->Duplexes ))
223 ShowWindow(GetDlgItem(hwnd, IDD_DUPLEX), SW_HIDE);
224 ShowWindow(GetDlgItem(hwnd, IDD_DUPLEX_NAME), SW_HIDE);
226 else
228 i = Cursel = 0;
229 LIST_FOR_EACH_ENTRY( duplex, &di->pi->ppd->Duplexes, DUPLEX, entry )
231 SendDlgItemMessageA(hwnd, IDD_DUPLEX, CB_INSERTSTRING, i,
232 (LPARAM)(duplex->FullName ? duplex->FullName : duplex->Name));
233 if(di->pi->Devmode->dmPublic.dmDuplex == duplex->WinDuplex)
234 Cursel = i;
235 i++;
237 SendDlgItemMessageA(hwnd, IDD_DUPLEX, CB_SETCURSEL, Cursel, 0);
239 break;
241 case WM_COMMAND:
242 di = (PSDRV_DLGINFO *)GetWindowLongPtrW(hwnd, DWLP_USER);
243 switch(LOWORD(wParam)) {
244 case IDD_PAPERS:
245 if(HIWORD(wParam) == LBN_SELCHANGE) {
246 Cursel = SendDlgItemMessageA(hwnd, LOWORD(wParam), LB_GETCURSEL, 0, 0);
247 i = 0;
248 LIST_FOR_EACH_ENTRY(ps, &di->pi->ppd->PageSizes, PAGESIZE, entry) {
249 if(i >= Cursel) break;
250 i++;
252 TRACE("Setting pagesize to item %d Winpage = %d\n", Cursel, ps->WinPage);
253 di->dlgdm->dmPublic.u1.s1.dmPaperSize = ps->WinPage;
254 SendMessageW(GetParent(hwnd), PSM_CHANGED, 0, 0);
256 break;
257 case IDD_ORIENT_PORTRAIT:
258 case IDD_ORIENT_LANDSCAPE:
259 TRACE("Setting orientation to %s\n", wParam == IDD_ORIENT_PORTRAIT ?
260 "portrait" : "landscape");
261 di->dlgdm->dmPublic.u1.s1.dmOrientation = wParam == IDD_ORIENT_PORTRAIT ?
262 DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
263 SendMessageW(GetParent(hwnd), PSM_CHANGED, 0, 0);
264 break;
265 case IDD_DUPLEX:
266 if(HIWORD(wParam) == CBN_SELCHANGE) {
267 Cursel = SendDlgItemMessageA(hwnd, LOWORD(wParam), CB_GETCURSEL, 0, 0);
268 i = 0;
269 LIST_FOR_EACH_ENTRY( duplex, &di->pi->ppd->Duplexes, DUPLEX, entry )
271 if (i >= Cursel) break;
272 i++;
274 TRACE("Setting duplex to item %d Winduplex = %d\n", Cursel, duplex->WinDuplex);
275 di->dlgdm->dmPublic.dmDuplex = duplex->WinDuplex;
276 SendMessageW(GetParent(hwnd), PSM_CHANGED, 0, 0);
278 break;
280 break;
282 case WM_NOTIFY:
284 NMHDR *nmhdr = (NMHDR *)lParam;
285 di = (PSDRV_DLGINFO *)GetWindowLongPtrW(hwnd, DWLP_USER);
286 switch(nmhdr->code) {
287 case PSN_APPLY:
288 *di->pi->Devmode = *di->dlgdm;
289 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
290 return TRUE;
292 default:
293 return FALSE;
295 break;
298 default:
299 return FALSE;
301 return TRUE;
305 static void (WINAPI *pInitCommonControls) (void);
306 static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPage) (LPCPROPSHEETPAGEW);
307 static int (WINAPI *pPropertySheet) (LPCPROPSHEETHEADERW);
309 static PRINTERINFO *PSDRV_FindPrinterInfoA(LPCSTR name)
311 int len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
312 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
313 PRINTERINFO *pi;
315 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
316 pi = PSDRV_FindPrinterInfo( nameW );
317 HeapFree( GetProcessHeap(), 0, nameW );
319 return pi;
322 /***********************************************************
323 * DEVMODEdupWtoA
325 * Creates an ascii copy of supplied devmode on the process heap
327 * Copied from dlls/winspool/info.c until full unicodification
329 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
331 DEVMODEA *dmA;
332 DWORD size;
333 BOOL formname;
334 /* there is no pointer dereference here, if your code checking tool complains it's broken */
335 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
337 if (!dmW) return NULL;
338 formname = (dmW->dmSize > off_formname);
339 size = dmW->dmSize - CCHDEVICENAME - (formname ? CCHFORMNAME : 0);
340 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
341 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1, (LPSTR)dmA->dmDeviceName,
342 CCHDEVICENAME, NULL, NULL );
343 if (!formname)
345 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
346 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR) );
348 else
350 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
351 off_formname - CCHDEVICENAME * sizeof(WCHAR) );
352 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1, (LPSTR)dmA->dmFormName,
353 CCHFORMNAME, NULL, NULL );
354 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
355 (off_formname + CCHFORMNAME * sizeof(WCHAR)) );
357 dmA->dmSize = size;
358 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
359 dmW->dmDriverExtra );
360 return dmA;
363 /******************************************************************
364 * PSDRV_ExtDeviceMode
366 * Retrieves or modifies device-initialization information for the PostScript
367 * driver, or displays a driver-supplied dialog box for configuring the driver.
369 * PARAMETERS
370 * lpszDriver -- Driver name
371 * hwnd -- Parent window for the dialog box
372 * lpdmOutput -- Address of a DEVMODE structure for writing initialization information
373 * lpszDevice -- Device name
374 * lpszPort -- Port name
375 * lpdmInput -- Address of a DEVMODE structure for reading initialization information
376 * lpProfile -- Name of initialization file, defaults to WIN.INI if NULL
377 * wMode -- Operation to perform. Can be a combination if > 0.
378 * (0) -- Returns number of bytes required by DEVMODE structure
379 * DM_UPDATE (1) -- Write current settings to environment and initialization file
380 * DM_COPY (2) -- Write current settings to lpdmOutput
381 * DM_PROMPT (4) -- Presents the driver's modal dialog box (USER.240)
382 * DM_MODIFY (8) -- Changes current settings according to lpdmInput before any other operation
384 * RETURNS
385 * Returns size of DEVMODE structure if wMode is 0. Otherwise, IDOK is returned for success
386 * for both dialog and non-dialog operations. IDCANCEL is returned if the dialog box was cancelled.
387 * A return value less than zero is returned if a non-dialog operation fails.
389 * BUGS
391 * Just returns default devmode at the moment. No use of initialization file.
393 INT PSDRV_ExtDeviceMode(LPSTR lpszDriver, HWND hwnd, LPDEVMODEA lpdmOutput,
394 LPSTR lpszDevice, LPSTR lpszPort, LPDEVMODEA lpdmInput,
395 LPSTR lpszProfile, DWORD dwMode)
397 PRINTERINFO *pi = PSDRV_FindPrinterInfoA(lpszDevice);
398 if(!pi) return -1;
400 TRACE("(Driver=%s, hwnd=%p, devOut=%p, Device='%s', Port='%s', devIn=%p, Profile='%s', Mode=%04x)\n",
401 lpszDriver, hwnd, lpdmOutput, lpszDevice, lpszPort, lpdmInput, debugstr_a(lpszProfile), dwMode);
403 /* If dwMode == 0, return size of DEVMODE structure */
404 if(!dwMode)
405 return pi->Devmode->dmPublic.dmSize + pi->Devmode->dmPublic.dmDriverExtra - CCHDEVICENAME - CCHFORMNAME;
407 /* If DM_MODIFY is set, change settings in accordance with lpdmInput */
408 if((dwMode & DM_MODIFY) && lpdmInput)
410 DEVMODEW *dmW = GdiConvertToDevmodeW( lpdmInput );
411 TRACE("DM_MODIFY set. devIn->dmFields = %08x\n", lpdmInput->dmFields);
412 if (dmW) PSDRV_MergeDevmodes(pi->Devmode, (PSDRV_DEVMODE *)dmW, pi);
413 HeapFree( GetProcessHeap(), 0, dmW );
416 /* If DM_PROMPT is set, present modal dialog box */
417 if(dwMode & DM_PROMPT) {
418 HINSTANCE hinstComctl32;
419 HPROPSHEETPAGE hpsp[1];
420 PROPSHEETPAGEW psp;
421 PROPSHEETHEADERW psh;
422 PSDRV_DLGINFO di;
423 PSDRV_DEVMODE dlgdm;
424 static const WCHAR PAPERW[] = {'P','A','P','E','R','\0'};
425 static const WCHAR SetupW[] = {'S','e','t','u','p','\0'};
427 hinstComctl32 = LoadLibraryA("comctl32.dll");
428 pInitCommonControls = (void*)GetProcAddress(hinstComctl32,
429 "InitCommonControls");
430 pCreatePropertySheetPage = (void*)GetProcAddress(hinstComctl32,
431 "CreatePropertySheetPageW");
432 pPropertySheet = (void*)GetProcAddress(hinstComctl32, "PropertySheetW");
433 memset(&psp,0,sizeof(psp));
434 dlgdm = *pi->Devmode;
435 di.pi = pi;
436 di.dlgdm = &dlgdm;
437 psp.dwSize = sizeof(psp);
438 psp.hInstance = PSDRV_hInstance;
439 psp.u.pszTemplate = PAPERW;
440 psp.u2.pszIcon = NULL;
441 psp.pfnDlgProc = PSDRV_PaperDlgProc;
442 psp.lParam = (LPARAM)&di;
443 hpsp[0] = pCreatePropertySheetPage(&psp);
445 memset(&psh, 0, sizeof(psh));
446 psh.dwSize = sizeof(psh);
447 psh.pszCaption = SetupW;
448 psh.nPages = 1;
449 psh.hwndParent = hwnd;
450 psh.u3.phpage = hpsp;
452 pPropertySheet(&psh);
456 /* If DM_UPDATE is set, should write settings to environment and initialization file */
457 if(dwMode & DM_UPDATE)
458 FIXME("Mode DM_UPDATE. Just do the same as DM_COPY\n");
460 /* If DM_COPY is set, should write settings to lpdmOutput */
461 if((dwMode & DM_COPY) || (dwMode & DM_UPDATE)) {
462 if (lpdmOutput)
464 DEVMODEA *dmA = DEVMODEdupWtoA( &pi->Devmode->dmPublic );
465 if (dmA) memcpy( lpdmOutput, dmA, dmA->dmSize + dmA->dmDriverExtra );
466 HeapFree( GetProcessHeap(), 0, dmA );
468 else
469 FIXME("lpdmOutput is NULL what should we do??\n");
471 return IDOK;
473 /***********************************************************************
474 * PSDRV_DeviceCapabilities
476 * Retrieves the capabilities of a printer device driver.
478 * Parameters
479 * lpszDriver -- printer driver name
480 * lpszDevice -- printer name
481 * lpszPort -- port name
482 * fwCapability -- device capability
483 * lpszOutput -- output buffer
484 * lpDevMode -- device data buffer
486 * Returns
487 * Result depends on the setting of fwCapability. -1 indicates failure.
489 DWORD PSDRV_DeviceCapabilities(LPSTR lpszDriver, LPCSTR lpszDevice, LPCSTR lpszPort,
490 WORD fwCapability, LPSTR lpszOutput, LPDEVMODEA lpDevMode)
492 PRINTERINFO *pi;
493 DEVMODEW *lpdm;
494 DWORD ret;
495 pi = PSDRV_FindPrinterInfoA(lpszDevice);
497 TRACE("%s %s %s, %u, %p, %p\n", debugstr_a(lpszDriver), debugstr_a(lpszDevice),
498 debugstr_a(lpszPort), fwCapability, lpszOutput, lpDevMode);
500 if (!pi) {
501 ERR("no printer info for %s %s, return 0!\n",
502 debugstr_a(lpszDriver), debugstr_a(lpszDevice));
503 return 0;
506 lpdm = &pi->Devmode->dmPublic;
507 if (lpDevMode) lpdm = GdiConvertToDevmodeW( lpDevMode );
509 switch(fwCapability) {
511 case DC_PAPERS:
513 PAGESIZE *ps;
514 WORD *wp = (WORD *)lpszOutput;
515 int i = 0;
517 LIST_FOR_EACH_ENTRY(ps, &pi->ppd->PageSizes, PAGESIZE, entry)
519 TRACE("DC_PAPERS: %u\n", ps->WinPage);
520 i++;
521 if(lpszOutput != NULL)
522 *wp++ = ps->WinPage;
524 ret = i;
525 break;
528 case DC_PAPERSIZE:
530 PAGESIZE *ps;
531 POINT16 *pt = (POINT16 *)lpszOutput;
532 int i = 0;
534 LIST_FOR_EACH_ENTRY(ps, &pi->ppd->PageSizes, PAGESIZE, entry)
536 TRACE("DC_PAPERSIZE: %f x %f\n", ps->PaperDimension->x, ps->PaperDimension->y);
537 i++;
538 if(lpszOutput != NULL) {
539 pt->x = paper_size_from_points( ps->PaperDimension->x );
540 pt->y = paper_size_from_points( ps->PaperDimension->y );
541 pt++;
544 ret = i;
545 break;
548 case DC_PAPERNAMES:
550 PAGESIZE *ps;
551 char *cp = lpszOutput;
552 int i = 0;
554 LIST_FOR_EACH_ENTRY(ps, &pi->ppd->PageSizes, PAGESIZE, entry)
556 TRACE("DC_PAPERNAMES: %s\n", debugstr_a(ps->FullName));
557 i++;
558 if(lpszOutput != NULL) {
559 lstrcpynA(cp, ps->FullName, 64);
560 cp += 64;
563 ret = i;
564 break;
567 case DC_ORIENTATION:
568 ret = pi->ppd->LandscapeOrientation ? pi->ppd->LandscapeOrientation : 90;
569 break;
571 case DC_BINS:
573 INPUTSLOT *slot;
574 WORD *wp = (WORD *)lpszOutput;
575 int i = 0;
577 LIST_FOR_EACH_ENTRY( slot, &pi->ppd->InputSlots, INPUTSLOT, entry )
579 i++;
580 if (lpszOutput != NULL)
581 *wp++ = slot->WinBin;
583 ret = i;
584 break;
587 case DC_BINNAMES:
589 INPUTSLOT *slot;
590 char *cp = lpszOutput;
591 int i = 0;
593 LIST_FOR_EACH_ENTRY( slot, &pi->ppd->InputSlots, INPUTSLOT, entry )
595 i++;
596 if (lpszOutput != NULL)
598 lstrcpynA( cp, slot->FullName, 24 );
599 cp += 24;
602 ret = i;
603 break;
606 case DC_BINADJUST:
607 FIXME("DC_BINADJUST: stub.\n");
608 ret = DCBA_FACEUPNONE;
609 break;
611 case DC_ENUMRESOLUTIONS:
613 LONG *lp = (LONG*)lpszOutput;
615 if(lpszOutput != NULL) {
616 lp[0] = pi->ppd->DefaultResolution;
617 lp[1] = pi->ppd->DefaultResolution;
619 ret = 1;
620 break;
623 /* Windows returns 9999 too */
624 case DC_COPIES:
625 TRACE("DC_COPIES: returning 9999\n");
626 ret = 9999;
627 break;
629 case DC_DRIVER:
630 ret = lpdm->dmDriverVersion;
631 break;
633 case DC_DATATYPE_PRODUCED:
634 FIXME("DATA_TYPE_PRODUCED: stub.\n");
635 ret = -1; /* simulate that the driver supports 'RAW' */
636 break;
638 case DC_DUPLEX:
639 ret = 0;
640 if(pi->ppd->DefaultDuplex && pi->ppd->DefaultDuplex->WinDuplex != 0)
641 ret = 1;
642 TRACE("DC_DUPLEX: returning %d\n", ret);
643 break;
645 case DC_EMF_COMPLIANT:
646 FIXME("DC_EMF_COMPLIANT: stub.\n");
647 ret = -1; /* simulate that the driver do not support EMF */
648 break;
650 case DC_EXTRA:
651 ret = lpdm->dmDriverExtra;
652 break;
654 case DC_FIELDS:
655 ret = lpdm->dmFields;
656 break;
658 case DC_FILEDEPENDENCIES:
659 FIXME("DC_FILEDEPENDENCIES: stub.\n");
660 ret = 0;
661 break;
663 case DC_MAXEXTENT:
665 PAGESIZE *ps;
666 float x = 0, y = 0;
668 LIST_FOR_EACH_ENTRY(ps, &pi->ppd->PageSizes, PAGESIZE, entry)
670 if (ps->PaperDimension->x > x) x = ps->PaperDimension->x;
671 if (ps->PaperDimension->y > y) y = ps->PaperDimension->y;
673 ret = MAKELONG( paper_size_from_points(x), paper_size_from_points(y) );
674 break;
677 case DC_MINEXTENT:
679 PAGESIZE *ps;
680 float x = 1e6, y = 1e6;
682 LIST_FOR_EACH_ENTRY(ps, &pi->ppd->PageSizes, PAGESIZE, entry)
684 if (ps->PaperDimension->x < x) x = ps->PaperDimension->x;
685 if (ps->PaperDimension->y < y) y = ps->PaperDimension->y;
687 ret = MAKELONG( paper_size_from_points(x), paper_size_from_points(y) );
688 break;
691 case DC_SIZE:
692 ret = lpdm->dmSize;
693 break;
695 case DC_TRUETYPE:
696 FIXME("DC_TRUETYPE: stub\n");
697 ret = DCTT_SUBDEV;
698 break;
700 case DC_VERSION:
701 ret = lpdm->dmSpecVersion;
702 break;
704 /* We'll just return false here, very few printers can collate anyway */
705 case DC_COLLATE:
706 TRACE("DC_COLLATE: returning FALSE\n");
707 ret = FALSE;
708 break;
710 /* Printer supports colour printing - 1 if yes, 0 if no (Win2k/XP only) */
711 case DC_COLORDEVICE:
712 ret = (pi->ppd->ColorDevice != CD_False) ? TRUE : FALSE;
713 break;
715 /* Identification number of the printer manufacturer for use with ICM (Win9x only) */
716 case DC_MANUFACTURER:
717 FIXME("DC_MANUFACTURER: stub\n");
718 ret = -1;
719 break;
721 /* Identification number of the printer model for use with ICM (Win9x only) */
722 case DC_MODEL:
723 FIXME("DC_MODEL: stub\n");
724 ret = -1;
725 break;
727 /* Nonzero if the printer supports stapling, zero otherwise (Win2k/XP only) */
728 case DC_STAPLE: /* WINVER >= 0x0500 */
729 FIXME("DC_STAPLE: stub\n");
730 ret = -1;
731 break;
733 /* Returns an array of 64-character string buffers containing the names of the paper forms
734 * available for use, unless pOutput is NULL. The return value is the number of paper forms.
735 * (Win2k/XP only)
737 case DC_MEDIAREADY: /* WINVER >= 0x0500 */
738 FIXME("DC_MEDIAREADY: stub\n");
739 ret = -1;
740 break;
742 /* Returns an array of 64-character string buffers containing the names of the supported
743 * media types, unless pOutput is NULL. The return value is the number of supported.
744 * media types (XP only)
746 case DC_MEDIATYPENAMES: /* WINVER >= 0x0501 */
747 FIXME("DC_MEDIATYPENAMES: stub\n");
748 ret = -1;
749 break;
751 /* Returns an array of DWORD values which represent the supported media types, unless
752 * pOutput is NULL. The return value is the number of supported media types. (XP only)
754 case DC_MEDIATYPES: /* WINVER >= 0x0501 */
755 FIXME("DC_MEDIATYPES: stub\n");
756 ret = -1;
757 break;
759 /* Returns an array of DWORD values, each representing a supported number of document
760 * pages per printed page, unless pOutput is NULL. The return value is the number of
761 * array entries. (Win2k/XP only)
763 case DC_NUP:
764 FIXME("DC_NUP: stub\n");
765 ret = -1;
766 break;
768 /* Returns an array of 32-character string buffers containing a list of printer description
769 * languages supported by the printer, unless pOutput is NULL. The return value is
770 * number of array entries. (Win2k/XP only)
773 case DC_PERSONALITY: /* WINVER >= 0x0500 */
774 FIXME("DC_PERSONALITY: stub\n");
775 ret = -1;
776 break;
778 /* Returns the amount of printer memory in kilobytes. (Win2k/XP only) */
779 case DC_PRINTERMEM: /* WINVER >= 0x0500 */
780 FIXME("DC_PRINTERMEM: stub\n");
781 ret = -1;
782 break;
784 /* Returns the printer's print rate in PRINTRATEUNIT units. (Win2k/XP only) */
785 case DC_PRINTRATE: /* WINVER >= 0x0500 */
786 FIXME("DC_PRINTRATE: stub\n");
787 ret = -1;
788 break;
790 /* Returns the printer's print rate in pages per minute. (Win2k/XP only) */
791 case DC_PRINTRATEPPM: /* WINVER >= 0x0500 */
792 FIXME("DC_PRINTRATEPPM: stub\n");
793 ret = -1;
794 break;
796 /* Returns the printer rate unit used for DC_PRINTRATE, which is one of
797 * PRINTRATEUNIT_{CPS,IPM,LPM,PPM} (Win2k/XP only)
799 case DC_PRINTRATEUNIT: /* WINVER >= 0x0500 */
800 FIXME("DC_PRINTRATEUNIT: stub\n");
801 ret = -1;
802 break;
804 default:
805 FIXME("Unsupported capability %d\n", fwCapability);
806 ret = -1;
809 if (lpDevMode) HeapFree( GetProcessHeap(), 0, lpdm );
810 return ret;
813 #if 0
814 typedef struct {
815 DWORD nPages;
816 DWORD Unknown;
817 HPROPSHEETPAGE hPages[10];
818 } EDMPS;
820 INT PSDRV_ExtDeviceModePropSheet(HWND hwnd, LPSTR lpszDevice, LPSTR lpszPort,
821 LPVOID pPropSheet)
823 EDMPS *ps = pPropSheet;
824 PROPSHEETPAGE psp;
826 psp->dwSize = sizeof(psp);
827 psp->hInstance = 0x1234;
829 ps->nPages = 1;
833 #endif