~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/comdlg32/printdlg.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * COMMDLG - Print Dialog
  3  *
  4  * Copyright 1994 Martin Ayotte
  5  * Copyright 1996 Albrecht Kleine
  6  * Copyright 1999 Klaas van Gend
  7  * Copyright 2000 Huw D M Davies
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 #include <ctype.h>
 24 #include <stdlib.h>
 25 #include <stdarg.h>
 26 #include <stdio.h>
 27 #include <string.h>
 28 
 29 #define NONAMELESSUNION
 30 #define NONAMELESSSTRUCT
 31 #include "windef.h"
 32 #include "winbase.h"
 33 #include "wingdi.h"
 34 #include "winuser.h"
 35 #include "winspool.h"
 36 #include "winerror.h"
 37 
 38 #include "wine/debug.h"
 39 
 40 #include "commdlg.h"
 41 #include "dlgs.h"
 42 #include "cderr.h"
 43 
 44 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
 45 
 46 #include "cdlg.h"
 47 #include "printdlg.h"
 48 
 49 /* Yes these constants are the same, but we're just copying win98 */
 50 #define UPDOWN_ID 0x270f
 51 #define MAX_COPIES 9999
 52 
 53 /* Debugging info */
 54 static const struct pd_flags psd_flags[] = {
 55   {PSD_MINMARGINS,"PSD_MINMARGINS"},
 56   {PSD_MARGINS,"PSD_MARGINS"},
 57   {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"},
 58   {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"},
 59   {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"},
 60   {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"},
 61   {PSD_NOWARNING,"PSD_NOWARNING"},
 62   {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"},
 63   {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"},
 64   {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"},
 65   {PSD_SHOWHELP,"PSD_SHOWHELP"},
 66   {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"},
 67   {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"},
 68   {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"},
 69   {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"},
 70   {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"},
 71   {-1, NULL}
 72 };
 73 
 74 /* address of wndproc for subclassed Static control */
 75 static WNDPROC lpfnStaticWndProc;
 76 /* the text of the fake document to render for the Page Setup dialog */
 77 static WCHAR wszFakeDocumentText[1024];
 78 
 79 /***********************************************************************
 80  *    PRINTDLG_OpenDefaultPrinter
 81  *
 82  * Returns a winspool printer handle to the default printer in *hprn
 83  * Caller must call ClosePrinter on the handle
 84  *
 85  * Returns TRUE on success else FALSE
 86  */
 87 BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn)
 88 {
 89     WCHAR buf[260];
 90     DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]);
 91     BOOL res;
 92     if(!GetDefaultPrinterW(buf, &dwBufLen))
 93         return FALSE;
 94     res = OpenPrinterW(buf, hprn, NULL);
 95     if (!res)
 96         WARN("Could not open printer %s\n", debugstr_w(buf));
 97     return res;
 98 }
 99 
100 /***********************************************************************
101  *    PRINTDLG_SetUpPrinterListCombo
102  *
103  * Initializes printer list combox.
104  * hDlg:  HWND of dialog
105  * id:    Control id of combo
106  * name:  Name of printer to select
107  *
108  * Initializes combo with list of available printers.  Selects printer 'name'
109  * If name is NULL or does not exist select the default printer.
110  *
111  * Returns number of printers added to list.
112  */
113 INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name)
114 {
115     DWORD needed, num;
116     INT i;
117     LPPRINTER_INFO_2A pi;
118     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
119     pi = HeapAlloc(GetProcessHeap(), 0, needed);
120     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
121                   &num);
122 
123     SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0);
124     
125     for(i = 0; i < num; i++) {
126         SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0,
127                             (LPARAM)pi[i].pPrinterName );
128     }
129     HeapFree(GetProcessHeap(), 0, pi);
130     if(!name ||
131        (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1,
132                                 (LPARAM)name)) == CB_ERR) {
133 
134         char buf[260];
135         DWORD dwBufLen = sizeof(buf);
136         if (name != NULL)
137             WARN("Can't find %s in printer list so trying to find default\n",
138                 debugstr_a(name));
139         if(!GetDefaultPrinterA(buf, &dwBufLen))
140             return num;
141         i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
142         if(i == CB_ERR)
143             FIXME("Can't find default printer in printer list\n");
144     }
145     SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0);
146     return num;
147 }
148 
149 static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name)
150 {
151     DWORD needed, num;
152     INT i;
153     LPPRINTER_INFO_2W pi;
154     EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
155     pi = HeapAlloc(GetProcessHeap(), 0, needed);
156     EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
157                   &num);
158 
159     for(i = 0; i < num; i++) {
160         SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0,
161                             (LPARAM)pi[i].pPrinterName );
162     }
163     HeapFree(GetProcessHeap(), 0, pi);
164     if(!name ||
165        (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1,
166                                 (LPARAM)name)) == CB_ERR) {
167         WCHAR buf[260];
168         DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]);
169         if (name != NULL)
170             WARN("Can't find %s in printer list so trying to find default\n",
171                 debugstr_w(name));
172         if(!GetDefaultPrinterW(buf, &dwBufLen))
173             return num;
174         i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
175         if(i == CB_ERR)
176             TRACE("Can't find default printer in printer list\n");
177     }
178     SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0);
179     return num;
180 }
181 
182 /***********************************************************************
183  *             PRINTDLG_CreateDevNames          [internal]
184  *
185  *
186  *   creates a DevNames structure.
187  *
188  *  (NB. when we handle unicode the offsets will be in wchars).
189  */
190 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName,
191                                     const char* DeviceName, const char* OutputPort)
192 {
193     long size;
194     char*   pDevNamesSpace;
195     char*   pTempPtr;
196     LPDEVNAMES lpDevNames;
197     char buf[260];
198     DWORD dwBufLen = sizeof(buf);
199 
200     size = strlen(DeviceDriverName) + 1
201             + strlen(DeviceName) + 1
202             + strlen(OutputPort) + 1
203             + sizeof(DEVNAMES);
204 
205     if(*hmem)
206         *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
207     else
208         *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
209     if (*hmem == 0)
210         return FALSE;
211 
212     pDevNamesSpace = GlobalLock(*hmem);
213     lpDevNames = (LPDEVNAMES) pDevNamesSpace;
214 
215     pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
216     strcpy(pTempPtr, DeviceDriverName);
217     lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
218 
219     pTempPtr += strlen(DeviceDriverName) + 1;
220     strcpy(pTempPtr, DeviceName);
221     lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
222 
223     pTempPtr += strlen(DeviceName) + 1;
224     strcpy(pTempPtr, OutputPort);
225     lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
226 
227     GetDefaultPrinterA(buf, &dwBufLen);
228     lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
229     GlobalUnlock(*hmem);
230     return TRUE;
231 }
232 
233 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName,
234                                     LPCWSTR DeviceName, LPCWSTR OutputPort)
235 {
236     long size;
237     LPWSTR   pDevNamesSpace;
238     LPWSTR   pTempPtr;
239     LPDEVNAMES lpDevNames;
240     WCHAR bufW[260];
241     DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR);
242 
243     size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2
244             + sizeof(WCHAR)*lstrlenW(DeviceName) + 2
245             + sizeof(WCHAR)*lstrlenW(OutputPort) + 2
246             + sizeof(DEVNAMES);
247 
248     if(*hmem)
249         *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
250     else
251         *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
252     if (*hmem == 0)
253         return FALSE;
254 
255     pDevNamesSpace = GlobalLock(*hmem);
256     lpDevNames = (LPDEVNAMES) pDevNamesSpace;
257 
258     pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1);
259     lstrcpyW(pTempPtr, DeviceDriverName);
260     lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
261 
262     pTempPtr += lstrlenW(DeviceDriverName) + 1;
263     lstrcpyW(pTempPtr, DeviceName);
264     lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
265 
266     pTempPtr += lstrlenW(DeviceName) + 1;
267     lstrcpyW(pTempPtr, OutputPort);
268     lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
269 
270     GetDefaultPrinterW(bufW, &dwBufLen);
271     lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0;
272     GlobalUnlock(*hmem);
273     return TRUE;
274 }
275 
276 /***********************************************************************
277  *             PRINTDLG_UpdatePrintDlg          [internal]
278  *
279  *
280  *   updates the PrintDlg structure for return values.
281  *
282  * RETURNS
283  *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
284  *   TRUE  if successful.
285  */
286 static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg,
287                                     PRINT_PTRA* PrintStructures)
288 {
289     LPPRINTDLGA       lppd = PrintStructures->lpPrintDlg;
290     PDEVMODEA         lpdm = PrintStructures->lpDevMode;
291     LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
292 
293 
294     if(!lpdm) {
295         FIXME("No lpdm ptr?\n");
296         return FALSE;
297     }
298 
299 
300     if(!(lppd->Flags & PD_PRINTSETUP)) {
301         /* check whether nFromPage and nToPage are within range defined by
302          * nMinPage and nMaxPage
303          */
304         if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
305             WORD nToPage;
306             WORD nFromPage;
307             nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
308             nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
309             if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
310                 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
311                 WCHAR resourcestr[256];
312                 WCHAR resultstr[256];
313                 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, resourcestr, 255);
314                 wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
315                 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255);
316                 MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING);
317                 return FALSE;
318             }
319             lppd->nFromPage = nFromPage;
320             lppd->nToPage   = nToPage;
321             lppd->Flags |= PD_PAGENUMS;
322         }
323         else
324             lppd->Flags &= ~PD_PAGENUMS;
325 
326         if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
327             lppd->Flags |= PD_SELECTION;
328         else
329             lppd->Flags &= ~PD_SELECTION;
330 
331         if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
332             static char file[] = "FILE:";
333             lppd->Flags |= PD_PRINTTOFILE;
334             pi->pPortName = file;
335         }
336 
337         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
338             FIXME("Collate lppd not yet implemented as output\n");
339         }
340 
341         /* set PD_Collate and nCopies */
342         if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
343           /*  The application doesn't support multiple copies or collate...
344            */
345             lppd->Flags &= ~PD_COLLATE;
346             lppd->nCopies = 1;
347           /* if the printer driver supports it... store info there
348            * otherwise no collate & multiple copies !
349            */
350             if (lpdm->dmFields & DM_COLLATE)
351                 lpdm->dmCollate =
352                   (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
353             if (lpdm->dmFields & DM_COPIES)
354                 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
355         } else {
356             /* Application is responsible for multiple copies */
357             if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
358                 lppd->Flags |= PD_COLLATE;
359             else
360                lppd->Flags &= ~PD_COLLATE;
361             lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
362             /* multiple copies already included in the document. Driver must print only one copy */
363             lpdm->u1.s1.dmCopies = 1;
364         }
365 
366         /* Print quality, PrintDlg16 */
367         if(GetDlgItem(hDlg, cmb1))
368         {
369             HWND hQuality = GetDlgItem(hDlg, cmb1);
370             int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0);
371 
372             if(Sel != CB_ERR)
373             {
374                 LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0);
375                 lpdm->dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
376                 lpdm->u1.s1.dmPrintQuality = LOWORD(dpi);
377                 lpdm->dmYResolution = HIWORD(dpi);
378             }
379         }
380     }
381     return TRUE;
382 }
383 
384 static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg,
385                                     PRINT_PTRW* PrintStructures)
386 {
387     LPPRINTDLGW       lppd = PrintStructures->lpPrintDlg;
388     PDEVMODEW         lpdm = PrintStructures->lpDevMode;
389     LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo;
390 
391 
392     if(!lpdm) {
393         FIXME("No lpdm ptr?\n");
394         return FALSE;
395     }
396 
397 
398     if(!(lppd->Flags & PD_PRINTSETUP)) {
399         /* check whether nFromPage and nToPage are within range defined by
400          * nMinPage and nMaxPage
401          */
402         if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
403             WORD nToPage;
404             WORD nFromPage;
405             nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
406             nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
407             if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
408                 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
409                 WCHAR resourcestr[256];
410                 WCHAR resultstr[256];
411                 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE,
412                             resourcestr, 255);
413                 wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
414                 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,
415                             resourcestr, 255);
416                 MessageBoxW(hDlg, resultstr, resourcestr,
417                             MB_OK | MB_ICONWARNING);
418                 return FALSE;
419             }
420             lppd->nFromPage = nFromPage;
421             lppd->nToPage   = nToPage;
422             lppd->Flags |= PD_PAGENUMS;
423         }
424         else
425             lppd->Flags &= ~PD_PAGENUMS;
426 
427         if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
428             lppd->Flags |= PD_SELECTION;
429         else
430             lppd->Flags &= ~PD_SELECTION;
431 
432         if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
433             static WCHAR file[] = {'F','I','L','E',':',0};
434             lppd->Flags |= PD_PRINTTOFILE;
435             pi->pPortName = file;
436         }
437 
438         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
439             FIXME("Collate lppd not yet implemented as output\n");
440         }
441 
442         /* set PD_Collate and nCopies */
443         if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
444           /*  The application doesn't support multiple copies or collate...
445            */
446             lppd->Flags &= ~PD_COLLATE;
447             lppd->nCopies = 1;
448           /* if the printer driver supports it... store info there
449            * otherwise no collate & multiple copies !
450            */
451             if (lpdm->dmFields & DM_COLLATE)
452                 lpdm->dmCollate =
453                   (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
454             if (lpdm->dmFields & DM_COPIES)
455                 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
456         } else {
457             if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
458                 lppd->Flags |= PD_COLLATE;
459             else
460                lppd->Flags &= ~PD_COLLATE;
461             lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
462         }
463     }
464     return TRUE;
465 }
466 
467 static BOOL PRINTDLG_PaperSizeA(
468         PRINTDLGA       *pdlga,const WORD PaperSize,LPPOINT size
469 ) {
470     DEVNAMES    *dn;
471     DEVMODEA    *dm;
472     LPSTR       devname,portname;
473     int         i;
474     INT         NrOfEntries,ret;
475     WORD        *Words = NULL;
476     POINT       *points = NULL;
477     BOOL        retval = FALSE;
478 
479     dn = GlobalLock(pdlga->hDevNames);
480     dm = GlobalLock(pdlga->hDevMode);
481     devname     = ((char*)dn)+dn->wDeviceOffset;
482     portname    = ((char*)dn)+dn->wOutputOffset;
483 
484 
485     NrOfEntries = DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,NULL,dm);
486     if (!NrOfEntries) {
487         FIXME("No papernames found for %s/%s\n",devname,portname);
488         goto out;
489     }
490     if (NrOfEntries == -1) {
491         ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n");
492         goto out;
493     }
494 
495     Words = HeapAlloc(GetProcessHeap(),0,NrOfEntries*sizeof(WORD));
496     if (NrOfEntries != (ret=DeviceCapabilitiesA(devname,portname,DC_PAPERS,(LPSTR)Words,dm))) {
497         FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret);
498         goto out;
499     }
500     for (i=0;i<NrOfEntries;i++)
501         if (Words[i] == PaperSize)
502             break;
503     if (i == NrOfEntries) {
504         FIXME("Papersize %d not found in list?\n",PaperSize);
505         goto out;
506     }
507     points = HeapAlloc(GetProcessHeap(),0,sizeof(points[0])*NrOfEntries);
508     if (NrOfEntries!=(ret=DeviceCapabilitiesA(devname,portname,DC_PAPERSIZE,(LPSTR)points,dm))) {
509         FIXME("Number of returned sizes %d is not %d?\n",NrOfEntries,ret);
510         goto out;
511     }
512     /* this is _10ths_ of a millimeter */
513     size->x=points[i].x;
514     size->y=points[i].y;
515     retval = TRUE;
516 out:
517     GlobalUnlock(pdlga->hDevNames);
518     GlobalUnlock(pdlga->hDevMode);
519     HeapFree(GetProcessHeap(),0,Words);
520     HeapFree(GetProcessHeap(),0,points);
521     return retval;
522 }
523 
524 static BOOL PRINTDLG_PaperSizeW(
525         PRINTDLGW       *pdlga,const WCHAR *PaperSize,LPPOINT size
526 ) {
527     DEVNAMES    *dn;
528     DEVMODEW    *dm;
529     LPWSTR      devname,portname;
530     int         i;
531     INT         NrOfEntries,ret;
532     WCHAR       *Names = NULL;
533     POINT       *points = NULL;
534     BOOL        retval = FALSE;
535 
536     dn = GlobalLock(pdlga->hDevNames);
537     dm = GlobalLock(pdlga->hDevMode);
538     devname     = ((WCHAR*)dn)+dn->wDeviceOffset;
539     portname    = ((WCHAR*)dn)+dn->wOutputOffset;
540 
541 
542     NrOfEntries = DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,NULL,dm);
543     if (!NrOfEntries) {
544         FIXME("No papernames found for %s/%s\n",debugstr_w(devname),debugstr_w(portname));
545         goto out;
546     }
547     if (NrOfEntries == -1) {
548         ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n");
549         goto out;
550     }
551 
552     Names = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*NrOfEntries*64);
553     if (NrOfEntries != (ret=DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,Names,dm))) {
554         FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret);
555         goto out;
556     }
557     for (i=0;i<NrOfEntries;i++)
558         if (!lstrcmpW(PaperSize,Names+(64*i)))
559             break;
560     if (i==NrOfEntries) {
561         FIXME("Papersize %s not found in list?\n",debugstr_w(PaperSize));
562         goto out;
563     }
564     points = HeapAlloc(GetProcessHeap(),0,sizeof(points[0])*NrOfEntries);
565     if (NrOfEntries!=(ret=DeviceCapabilitiesW(devname,portname,DC_PAPERSIZE,(LPWSTR)points,dm))) {
566         FIXME("Number of returned sizes %d is not %d?\n",NrOfEntries,ret);
567         goto out;
568     }
569     /* this is _10ths_ of a millimeter */
570     size->x=points[i].x;
571     size->y=points[i].y;
572     retval = TRUE;
573 out:
574     GlobalUnlock(pdlga->hDevNames);
575     GlobalUnlock(pdlga->hDevMode);
576     HeapFree(GetProcessHeap(),0,Names);
577     HeapFree(GetProcessHeap(),0,points);
578     return retval;
579 }
580 
581 
582 /************************************************************************
583  * PRINTDLG_SetUpPaperComboBox
584  *
585  * Initialize either the papersize or inputslot combos of the Printer Setup
586  * dialog.  We store the associated word (eg DMPAPER_A4) as the item data.
587  * We also try to re-select the old selection.
588  */
589 static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg,
590                                         int   nIDComboBox,
591                                         char* PrinterName,
592                                         char* PortName,
593                                         LPDEVMODEA dm)
594 {
595     int     i;
596     int     NrOfEntries;
597     char*   Names;
598     WORD*   Words;
599     DWORD   Sel;
600     WORD    oldWord = 0;
601     int     NamesSize;
602     int     fwCapability_Names;
603     int     fwCapability_Words;
604 
605     TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox);
606 
607     /* query the dialog box for the current selected value */
608     Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
609     if(Sel != CB_ERR) {
610         /* we enter here only if a different printer is selected after
611          * the Print Setup dialog is opened. The current settings are
612          * stored into the newly selected printer.
613          */
614         oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA,
615                                       Sel, 0);
616         if (dm) {
617             if (nIDComboBox == cmb2)
618                 dm->u1.s1.dmPaperSize = oldWord;
619             else
620                 dm->u1.s1.dmDefaultSource = oldWord;
621         }
622     }
623     else {
624         /* we enter here only when the Print setup dialog is initially
625          * opened. In this case the settings are restored from when
626          * the dialog was last closed.
627          */
628         if (dm) {
629             if (nIDComboBox == cmb2)
630                 oldWord = dm->u1.s1.dmPaperSize;
631             else
632                 oldWord = dm->u1.s1.dmDefaultSource;
633         }
634     }
635 
636     if (nIDComboBox == cmb2) {
637          NamesSize          = 64;
638          fwCapability_Names = DC_PAPERNAMES;
639          fwCapability_Words = DC_PAPERS;
640     } else {
641          nIDComboBox        = cmb3;
642          NamesSize          = 24;
643          fwCapability_Names = DC_BINNAMES;
644          fwCapability_Words = DC_BINS;
645     }
646 
647     /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the
648      * paper settings. As Wine doesn't allow VXDs, this results in a crash.
649      */
650     WARN(" if your printer driver uses VXDs, expect a crash now!\n");
651     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
652                                       fwCapability_Names, NULL, dm);
653     if (NrOfEntries == 0)
654          WARN("no Name Entries found!\n");
655     else if (NrOfEntries < 0)
656          return FALSE;
657 
658     if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
659        != NrOfEntries) {
660         ERR("Number of caps is different\n");
661         NrOfEntries = 0;
662     }
663 
664     Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize);
665     Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
666     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
667                                       fwCapability_Names, Names, dm);
668     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
669                                       fwCapability_Words, (LPSTR)Words, dm);
670 
671     /* reset any current content in the combobox */
672     SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
673 
674     /* store new content */
675     for (i = 0; i < NrOfEntries; i++) {
676         DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
677                                         (LPARAM)(&Names[i*NamesSize]) );
678         SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
679                             Words[i]);
680     }
681 
682     /* Look for old selection - can't do this is previous loop since
683        item order will change as more items are added */
684     Sel = 0;
685     for (i = 0; i < NrOfEntries; i++) {
686         if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
687            oldWord) {
688             Sel = i;
689             break;
690         }
691     }
692     SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
693 
694     HeapFree(GetProcessHeap(),0,Words);
695     HeapFree(GetProcessHeap(),0,Names);
696     return TRUE;
697 }
698 
699 static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg,
700                                         int   nIDComboBox,
701                                         const WCHAR* PrinterName,
702                                         const WCHAR* PortName,
703                                         LPDEVMODEW dm)
704 {
705     int     i;
706     int     NrOfEntries;
707     WCHAR*  Names;
708     WORD*   Words;
709     DWORD   Sel;
710     WORD    oldWord = 0;
711     int     NamesSize;
712     int     fwCapability_Names;
713     int     fwCapability_Words;
714 
715     TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox);
716 
717     /* query the dialog box for the current selected value */
718     Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
719     if(Sel != CB_ERR) {
720         /* we enter here only if a different printer is selected after
721          * the Print Setup dialog is opened. The current settings are
722          * stored into the newly selected printer.
723          */
724         oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA,
725                                       Sel, 0);
726         if (dm) {
727             if (nIDComboBox == cmb2)
728                 dm->u1.s1.dmPaperSize = oldWord;
729             else
730                 dm->u1.s1.dmDefaultSource = oldWord;
731         }
732     }
733     else {
734         /* we enter here only when the Print setup dialog is initially
735          * opened. In this case the settings are restored from when
736          * the dialog was last closed.
737          */
738         if (dm) {
739             if (nIDComboBox == cmb2)
740                 oldWord = dm->u1.s1.dmPaperSize;
741             else
742                 oldWord = dm->u1.s1.dmDefaultSource;
743         }
744     }
745 
746     if (nIDComboBox == cmb2) {
747          NamesSize          = 64;
748          fwCapability_Names = DC_PAPERNAMES;
749          fwCapability_Words = DC_PAPERS;
750     } else {
751          nIDComboBox        = cmb3;
752          NamesSize          = 24;
753          fwCapability_Names = DC_BINNAMES;
754          fwCapability_Words = DC_BINS;
755     }
756 
757     /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the
758      * paper settings. As Wine doesn't allow VXDs, this results in a crash.
759      */
760     WARN(" if your printer driver uses VXDs, expect a crash now!\n");
761     NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
762                                       fwCapability_Names, NULL, dm);
763     if (NrOfEntries == 0)
764          WARN("no Name Entries found!\n");
765     else if (NrOfEntries < 0)
766          return FALSE;
767 
768     if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm)
769        != NrOfEntries) {
770         ERR("Number of caps is different\n");
771         NrOfEntries = 0;
772     }
773 
774     Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize);
775     Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
776     NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
777                                       fwCapability_Names, Names, dm);
778     NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
779                                       fwCapability_Words, (LPWSTR)Words, dm);
780 
781     /* reset any current content in the combobox */
782     SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
783 
784     /* store new content */
785     for (i = 0; i < NrOfEntries; i++) {
786         DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0,
787                                         (LPARAM)(&Names[i*NamesSize]) );
788         SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
789                             Words[i]);
790     }
791 
792     /* Look for old selection - can't do this is previous loop since
793        item order will change as more items are added */
794     Sel = 0;
795     for (i = 0; i < NrOfEntries; i++) {
796         if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
797            oldWord) {
798             Sel = i;
799             break;
800         }
801     }
802     SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
803 
804     HeapFree(GetProcessHeap(),0,Words);
805     HeapFree(GetProcessHeap(),0,Names);
806     return TRUE;
807 }
808 
809 
810 /***********************************************************************
811  *               PRINTDLG_UpdatePrinterInfoTexts               [internal]
812  */
813 static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, const PRINTER_INFO_2A *pi)
814 {
815     char   StatusMsg[256];
816     char   ResourceString[256];
817     int    i;
818 
819     /* Status Message */
820     StatusMsg[0]='\0';
821 
822     /* add all status messages */
823     for (i = 0; i < 25; i++) {
824         if (pi->Status & (1<<i)) {
825             LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
826                         ResourceString, 255);
827             strcat(StatusMsg,ResourceString);
828         }
829     }
830     /* append "ready" */
831     /* FIXME: status==ready must only be appended if really so.
832               but how to detect? */
833     LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
834                 ResourceString, 255);
835     strcat(StatusMsg,ResourceString);
836     SetDlgItemTextA(hDlg, stc12, StatusMsg);
837 
838     /* set all other printer info texts */
839     SetDlgItemTextA(hDlg, stc11, pi->pDriverName);
840     
841     if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
842         SetDlgItemTextA(hDlg, stc14, pi->pLocation);
843     else
844         SetDlgItemTextA(hDlg, stc14, pi->pPortName);
845     SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : "");
846     return;
847 }
848 
849 static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, const PRINTER_INFO_2W *pi)
850 {
851     WCHAR   StatusMsg[256];
852     WCHAR   ResourceString[256];
853     static const WCHAR emptyW[] = {0};
854     int    i;
855 
856     /* Status Message */
857     StatusMsg[0]='\0';
858 
859     /* add all status messages */
860     for (i = 0; i < 25; i++) {
861         if (pi->Status & (1<<i)) {
862             LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
863                         ResourceString, 255);
864             lstrcatW(StatusMsg,ResourceString);
865         }
866     }
867     /* append "ready" */
868     /* FIXME: status==ready must only be appended if really so.
869               but how to detect? */
870     LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
871                 ResourceString, 255);
872     lstrcatW(StatusMsg,ResourceString);
873     SetDlgItemTextW(hDlg, stc12, StatusMsg);
874 
875     /* set all other printer info texts */
876     SetDlgItemTextW(hDlg, stc11, pi->pDriverName);
877     if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
878         SetDlgItemTextW(hDlg, stc14, pi->pLocation);
879     else
880         SetDlgItemTextW(hDlg, stc14, pi->pPortName);
881     SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW);
882 }
883 
884 
885 /*******************************************************************
886  *
887  *                 PRINTDLG_ChangePrinter
888  *
889  */
890 BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name,
891                                    PRINT_PTRA *PrintStructures)
892 {
893     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
894     LPDEVMODEA lpdm = NULL;
895     LONG dmSize;
896     DWORD needed;
897     HANDLE hprn;
898 
899     HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
900     HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
901     if(!OpenPrinterA(name, &hprn, NULL)) {
902         ERR("Can't open printer %s\n", name);
903         return FALSE;
904     }
905     GetPrinterA(hprn, 2, NULL, 0, &needed);
906     PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
907