ReactOS  0.4.14-dev-822-g065afd9
printdlg.c
Go to the documentation of this file.
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  * Copyright 2010 Vitaly Perov
9  *
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.
14  *
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.
19  *
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
23  */
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winspool.h"
39 #include "winerror.h"
40 #include "objbase.h"
41 #include "commdlg.h"
42 
43 #include "wine/debug.h"
44 
45 #include "dlgs.h"
46 #include "cderr.h"
47 #include "cdlg.h"
48 
50 
51 /* Yes these constants are the same, but we're just copying win98 */
52 #define UPDOWN_ID 0x270f
53 #define MAX_COPIES 9999
54 
55 /* This PRINTDLGA internal structure stores
56  * pointers to several throughout useful structures.
57  */
58 
59 typedef struct
60 {
66  HICON hCollateIcon; /* PrintDlg only */
67  HICON hNoCollateIcon; /* PrintDlg only */
68  HICON hPortraitIcon; /* PrintSetupDlg only */
69  HICON hLandscapeIcon; /* PrintSetupDlg only */
71 } PRINT_PTRA;
72 
73 typedef struct
74 {
80  HICON hCollateIcon; /* PrintDlg only */
81  HICON hNoCollateIcon; /* PrintDlg only */
82  HICON hPortraitIcon; /* PrintSetupDlg only */
83  HICON hLandscapeIcon; /* PrintSetupDlg only */
85 } PRINT_PTRW;
86 
87 /* Debugging info */
88 struct pd_flags
89 {
92 };
93 
94 static const struct pd_flags psd_flags[] = {
95  {PSD_MINMARGINS,"PSD_MINMARGINS"},
96  {PSD_MARGINS,"PSD_MARGINS"},
97  {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"},
98  {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"},
99  {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"},
100  {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"},
101  {PSD_NOWARNING,"PSD_NOWARNING"},
102  {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"},
103  {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"},
104  {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"},
105  {PSD_SHOWHELP,"PSD_SHOWHELP"},
106  {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"},
107  {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"},
108  {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"},
109  {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"},
110  {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"},
111  {-1, NULL}
112 };
113 
114 static const struct pd_flags pd_flags[] = {
115  {PD_SELECTION, "PD_SELECTION "},
116  {PD_PAGENUMS, "PD_PAGENUMS "},
117  {PD_NOSELECTION, "PD_NOSELECTION "},
118  {PD_NOPAGENUMS, "PD_NOPAGENUMS "},
119  {PD_COLLATE, "PD_COLLATE "},
120  {PD_PRINTTOFILE, "PD_PRINTTOFILE "},
121  {PD_PRINTSETUP, "PD_PRINTSETUP "},
122  {PD_NOWARNING, "PD_NOWARNING "},
123  {PD_RETURNDC, "PD_RETURNDC "},
124  {PD_RETURNIC, "PD_RETURNIC "},
125  {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "},
126  {PD_SHOWHELP, "PD_SHOWHELP "},
127  {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "},
128  {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "},
129  {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "},
130  {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "},
131  {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "},
132  {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "},
133  {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "},
134  {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "},
135  {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "},
136  {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "},
137  {-1, NULL}
138 };
139 /* address of wndproc for subclassed Static control */
142 /* the text of the fake document to render for the Page Setup dialog */
144 static const WCHAR pd32_collateW[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 };
145 static const WCHAR pd32_nocollateW[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 };
146 static const WCHAR pd32_portraitW[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 };
147 static const WCHAR pd32_landscapeW[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 };
148 static const WCHAR printdlg_prop[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0};
149 static const WCHAR pagesetupdlg_prop[] = { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E',
150  'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 };
151 
152 
154 {
155  LPWSTR ret;
156  DWORD len;
157 
158  if(!p) return NULL;
159  len = (lstrlenW(p) + 1) * sizeof(WCHAR);
160  ret = HeapAlloc(GetProcessHeap(), 0, len);
161  memcpy(ret, p, len);
162  return ret;
163 }
164 
165 /***********************************************************************
166  * get_driver_info [internal]
167  *
168  * get DRIVER_INFO_3W for the current printer handle,
169  * alloc the buffer, when needed
170  */
172 {
173  DRIVER_INFO_3W *di3 = NULL;
174  DWORD needed = 0;
175  BOOL res;
176 
177  res = GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
178  if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
179  di3 = HeapAlloc(GetProcessHeap(), 0, needed);
180  res = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)di3, needed, &needed);
181  }
182 
183  if (res)
184  return di3;
185 
186  TRACE("GetPrinterDriverW failed with %u\n", GetLastError());
187  HeapFree(GetProcessHeap(), 0, di3);
188  return NULL;
189 }
190 
192 {
193  DRIVER_INFO_3A *di3 = NULL;
194  DWORD needed = 0;
195  BOOL res;
196 
197  res = GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
198  if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
199  di3 = HeapAlloc(GetProcessHeap(), 0, needed);
200  res = GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)di3, needed, &needed);
201  }
202 
203  if (res)
204  return di3;
205 
206  TRACE("GetPrinterDriverA failed with %u\n", GetLastError());
207  HeapFree(GetProcessHeap(), 0, di3);
208  return NULL;
209 }
210 
211 
212 /***********************************************************************
213  * get_printer_info [internal]
214  *
215  * get PRINTER_INFO_2W for the current printer handle,
216  * alloc the buffer, when needed
217  */
219 {
220  PRINTER_INFO_2W *pi2 = NULL;
221  DWORD needed = 0;
222  BOOL res;
223 
224  res = GetPrinterW(hprn, 2, NULL, 0, &needed);
225  if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
226  pi2 = HeapAlloc(GetProcessHeap(), 0, needed);
227  res = GetPrinterW(hprn, 2, (LPBYTE)pi2, needed, &needed);
228  }
229 
230  if (res)
231  return pi2;
232 
233  TRACE("GetPrinterW failed with %u\n", GetLastError());
234  HeapFree(GetProcessHeap(), 0, pi2);
235  return NULL;
236 }
237 
239 {
240  PRINTER_INFO_2A *pi2 = NULL;
241  DWORD needed = 0;
242  BOOL res;
243 
244  res = GetPrinterA(hprn, 2, NULL, 0, &needed);
245  if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
246  pi2 = HeapAlloc(GetProcessHeap(), 0, needed);
247  res = GetPrinterA(hprn, 2, (LPBYTE)pi2, needed, &needed);
248  }
249 
250  if (res)
251  return pi2;
252 
253  TRACE("GetPrinterA failed with %u\n", GetLastError());
254  HeapFree(GetProcessHeap(), 0, pi2);
255  return NULL;
256 }
257 
258 
259 /***********************************************************************
260  * update_devmode_handle [internal]
261  *
262  * update a devmode handle for the given DEVMODE, alloc the buffer, when needed
263  */
265 {
266  SIZE_T size = GlobalSize(hdm);
267  LPVOID ptr;
268 
269  /* Increase / alloc the global memory block, when needed */
270  if ((dm->dmSize + dm->dmDriverExtra) > size) {
271  if (hdm)
272  hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0);
273  else
274  hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra);
275  }
276 
277  if (hdm) {
278  ptr = GlobalLock(hdm);
279  if (ptr) {
280  memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra);
281  GlobalUnlock(hdm);
282  }
283  else
284  {
285  GlobalFree(hdm);
286  hdm = NULL;
287  }
288  }
289  return hdm;
290 }
291 
293 {
294  SIZE_T size = GlobalSize(hdm);
295  LPVOID ptr;
296 
297  /* Increase / alloc the global memory block, when needed */
298  if ((dm->dmSize + dm->dmDriverExtra) > size) {
299  if (hdm)
300  hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0);
301  else
302  hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra);
303  }
304 
305  if (hdm) {
306  ptr = GlobalLock(hdm);
307  if (ptr) {
308  memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra);
309  GlobalUnlock(hdm);
310  }
311  else
312  {
313  GlobalFree(hdm);
314  hdm = NULL;
315  }
316  }
317  return hdm;
318 }
319 
320 /***********************************************************
321  * convert_to_devmodeA
322  *
323  * Creates an ansi copy of supplied devmode
324  */
326 {
327  DEVMODEA *dmA;
328  DWORD size;
329 
330  if (!dmW) return NULL;
331  size = dmW->dmSize - CCHDEVICENAME -
332  ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
333 
334  dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
335  if (!dmA) return NULL;
336 
339 
340  if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize)
341  {
342  memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
343  dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
344  }
345  else
346  {
347  memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
348  FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
351 
352  memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
353  }
354 
355  dmA->dmSize = size;
356  memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
357  return dmA;
358 }
359 
360 /***********************************************************************
361  * PRINTDLG_OpenDefaultPrinter
362  *
363  * Returns a winspool printer handle to the default printer in *hprn
364  * Caller must call ClosePrinter on the handle
365  *
366  * Returns TRUE on success else FALSE
367  */
369 {
370  WCHAR buf[260];
372  BOOL res;
374  return FALSE;
375  res = OpenPrinterW(buf, hprn, NULL);
376  if (!res)
377  WARN("Could not open printer %s\n", debugstr_w(buf));
378  return res;
379 }
380 
381 /***********************************************************************
382  * PRINTDLG_SetUpPrinterListCombo
383  *
384  * Initializes printer list combox.
385  * hDlg: HWND of dialog
386  * id: Control id of combo
387  * name: Name of printer to select
388  *
389  * Initializes combo with list of available printers. Selects printer 'name'
390  * If name is NULL or does not exist select the default printer.
391  *
392  * Returns number of printers added to list.
393  */
395 {
396  DWORD needed, num;
397  INT i;
399  EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
400  pi = HeapAlloc(GetProcessHeap(), 0, needed);
401  EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
402  &num);
403 
404  SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0);
405 
406  for(i = 0; i < num; i++) {
407  SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0,
408  (LPARAM)pi[i].pPrinterName );
409  }
410  HeapFree(GetProcessHeap(), 0, pi);
411  if(!name ||
412  (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1,
413  (LPARAM)name)) == CB_ERR) {
414 
415  char buf[260];
417  if (name != NULL)
418  WARN("Can't find %s in printer list so trying to find default\n",
419  debugstr_a(name));
421  return num;
423  if(i == CB_ERR)
424  FIXME("Can't find default printer in printer list\n");
425  }
426  SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0);
427  return num;
428 }
429 
431 {
432  DWORD needed, num;
433  INT i;
435  EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
436  pi = HeapAlloc(GetProcessHeap(), 0, needed);
437  EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
438  &num);
439 
440  for(i = 0; i < num; i++) {
441  SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0,
442  (LPARAM)pi[i].pPrinterName );
443  }
444  HeapFree(GetProcessHeap(), 0, pi);
445  if(!name ||
446  (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1,
447  (LPARAM)name)) == CB_ERR) {
448  WCHAR buf[260];
450  if (name != NULL)
451  WARN("Can't find %s in printer list so trying to find default\n",
452  debugstr_w(name));
454  return num;
456  if(i == CB_ERR)
457  TRACE("Can't find default printer in printer list\n");
458  }
459  SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0);
460  return num;
461 }
462 
463 /***********************************************************************
464  * PRINTDLG_CreateDevNames [internal]
465  *
466  *
467  * creates a DevNames structure.
468  *
469  * (NB. when we handle unicode the offsets will be in wchars).
470  */
471 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName,
472  const char* DeviceName, const char* OutputPort)
473 {
474  long size;
475  char* pDevNamesSpace;
476  char* pTempPtr;
477  LPDEVNAMES lpDevNames;
478  char buf[260];
480  const char *p;
481 
482  p = strrchr( DeviceDriverName, '\\' );
483  if (p) DeviceDriverName = p + 1;
484 
485  size = strlen(DeviceDriverName) + 1
486  + strlen(DeviceName) + 1
487  + strlen(OutputPort) + 1
488  + sizeof(DEVNAMES);
489 
490  if(*hmem)
491  *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
492  else
493  *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
494  if (*hmem == 0)
495  return FALSE;
496 
497  pDevNamesSpace = GlobalLock(*hmem);
498  lpDevNames = (LPDEVNAMES) pDevNamesSpace;
499 
500  pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
501  strcpy(pTempPtr, DeviceDriverName);
502  lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
503 
504  pTempPtr += strlen(DeviceDriverName) + 1;
505  strcpy(pTempPtr, DeviceName);
506  lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
507 
508  pTempPtr += strlen(DeviceName) + 1;
509  strcpy(pTempPtr, OutputPort);
510  lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
511 
513  lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
514  GlobalUnlock(*hmem);
515  return TRUE;
516 }
517 
518 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName,
519  LPCWSTR DeviceName, LPCWSTR OutputPort)
520 {
521  long size;
522  LPWSTR pDevNamesSpace;
523  LPWSTR pTempPtr;
524  LPDEVNAMES lpDevNames;
525  WCHAR bufW[260];
526  DWORD dwBufLen = ARRAY_SIZE(bufW);
527  const WCHAR *p;
528 
529  p = wcsrchr( DeviceDriverName, '\\' );
530  if (p) DeviceDriverName = p + 1;
531 
532  size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2
533  + sizeof(WCHAR)*lstrlenW(DeviceName) + 2
534  + sizeof(WCHAR)*lstrlenW(OutputPort) + 2
535  + sizeof(DEVNAMES);
536 
537  if(*hmem)
538  *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
539  else
540  *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
541  if (*hmem == 0)
542  return FALSE;
543 
544  pDevNamesSpace = GlobalLock(*hmem);
545  lpDevNames = (LPDEVNAMES) pDevNamesSpace;
546 
547  pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1);
548  lstrcpyW(pTempPtr, DeviceDriverName);
549  lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
550 
551  pTempPtr += lstrlenW(DeviceDriverName) + 1;
552  lstrcpyW(pTempPtr, DeviceName);
553  lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
554 
555  pTempPtr += lstrlenW(DeviceName) + 1;
556  lstrcpyW(pTempPtr, OutputPort);
557  lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
558 
560  lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0;
561  GlobalUnlock(*hmem);
562  return TRUE;
563 }
564 
565 /***********************************************************************
566  * PRINTDLG_UpdatePrintDlg [internal]
567  *
568  *
569  * updates the PrintDlg structure for return values.
570  *
571  * RETURNS
572  * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
573  * TRUE if successful.
574  */
576  PRINT_PTRA* PrintStructures)
577 {
578  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
579  PDEVMODEA lpdm = PrintStructures->lpDevMode;
580  LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
581 
582 
583  if(!lpdm) {
584  FIXME("No lpdm ptr?\n");
585  return FALSE;
586  }
587 
588 
589  if(!(lppd->Flags & PD_PRINTSETUP)) {
590  /* check whether nFromPage and nToPage are within range defined by
591  * nMinPage and nMaxPage
592  */
593  if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
594  WORD nToPage;
595  WORD nFromPage;
596  BOOL translated;
597  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
598  nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
599 
600  /* if no ToPage value is entered, use the FromPage value */
601  if(!translated) nToPage = nFromPage;
602 
603  if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
604  nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
605  WCHAR resourcestr[256];
606  WCHAR resultstr[256];
608  wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
609  LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255);
610  MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING);
611  return FALSE;
612  }
613  lppd->nFromPage = nFromPage;
614  lppd->nToPage = nToPage;
615  lppd->Flags |= PD_PAGENUMS;
616  }
617  else
618  lppd->Flags &= ~PD_PAGENUMS;
619 
620  if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
621  lppd->Flags |= PD_SELECTION;
622  else
623  lppd->Flags &= ~PD_SELECTION;
624 
625  if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
626  static char file[] = "FILE:";
627  lppd->Flags |= PD_PRINTTOFILE;
628  pi->pPortName = file;
629  }
630 
631  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
632  FIXME("Collate lppd not yet implemented as output\n");
633  }
634 
635  /* set PD_Collate and nCopies */
636  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
637  /* The application doesn't support multiple copies or collate...
638  */
639  lppd->Flags &= ~PD_COLLATE;
640  lppd->nCopies = 1;
641  /* if the printer driver supports it... store info there
642  * otherwise no collate & multiple copies !
643  */
644  if (lpdm->dmFields & DM_COLLATE)
645  lpdm->dmCollate =
646  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
647  if (lpdm->dmFields & DM_COPIES)
648  lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
649  } else {
650  /* Application is responsible for multiple copies */
651  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
652  lppd->Flags |= PD_COLLATE;
653  else
654  lppd->Flags &= ~PD_COLLATE;
655  lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
656  /* multiple copies already included in the document. Driver must print only one copy */
657  lpdm->u1.s1.dmCopies = 1;
658  }
659 
660  /* Print quality, PrintDlg16 */
661  if(GetDlgItem(hDlg, cmb1))
662  {
663  HWND hQuality = GetDlgItem(hDlg, cmb1);
664  int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0);
665 
666  if(Sel != CB_ERR)
667  {
668  LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0);
670  lpdm->u1.s1.dmPrintQuality = LOWORD(dpi);
671  lpdm->dmYResolution = HIWORD(dpi);
672  }
673  }
674  }
675  return TRUE;
676 }
677 
679  PRINT_PTRW* PrintStructures)
680 {
681  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
682  PDEVMODEW lpdm = PrintStructures->lpDevMode;
683  LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo;
684 
685 
686  if(!lpdm) {
687  FIXME("No lpdm ptr?\n");
688  return FALSE;
689  }
690 
691 
692  if(!(lppd->Flags & PD_PRINTSETUP)) {
693  /* check whether nFromPage and nToPage are within range defined by
694  * nMinPage and nMaxPage
695  */
696  if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
697  WORD nToPage;
698  WORD nFromPage;
699  BOOL translated;
700  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
701  nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
702 
703  /* if no ToPage value is entered, use the FromPage value */
704  if(!translated) nToPage = nFromPage;
705 
706  if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
707  nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
708  WCHAR resourcestr[256];
709  WCHAR resultstr[256];
710  DWORD_PTR args[2];
712  resourcestr, 255);
713  args[0] = lppd->nMinPage;
714  args[1] = lppd->nMaxPage;
716  resourcestr, 0, 0, resultstr,
717  ARRAY_SIZE(resultstr),
718  (__ms_va_list*)args);
720  resourcestr, 255);
721  MessageBoxW(hDlg, resultstr, resourcestr,
723  return FALSE;
724  }
725  lppd->nFromPage = nFromPage;
726  lppd->nToPage = nToPage;
727  lppd->Flags |= PD_PAGENUMS;
728  }
729  else
730  lppd->Flags &= ~PD_PAGENUMS;
731 
732  if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
733  lppd->Flags |= PD_SELECTION;
734  else
735  lppd->Flags &= ~PD_SELECTION;
736 
737  if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
738  static WCHAR file[] = {'F','I','L','E',':',0};
739  lppd->Flags |= PD_PRINTTOFILE;
740  pi->pPortName = file;
741  }
742 
743  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
744  FIXME("Collate lppd not yet implemented as output\n");
745  }
746 
747  /* set PD_Collate and nCopies */
748  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
749  /* The application doesn't support multiple copies or collate...
750  */
751  lppd->Flags &= ~PD_COLLATE;
752  lppd->nCopies = 1;
753  /* if the printer driver supports it... store info there
754  * otherwise no collate & multiple copies !
755  */
756  if (lpdm->dmFields & DM_COLLATE)
757  lpdm->dmCollate =
758  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
759  if (lpdm->dmFields & DM_COPIES)
760  lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
761  } else {
762  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
763  lppd->Flags |= PD_COLLATE;
764  else
765  lppd->Flags &= ~PD_COLLATE;
766  lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
767  }
768  }
769  return TRUE;
770 }
771 
772 /************************************************************************
773  * PRINTDLG_SetUpPaperComboBox
774  *
775  * Initialize either the papersize or inputslot combos of the Printer Setup
776  * dialog. We store the associated word (eg DMPAPER_A4) as the item data.
777  * We also try to re-select the old selection.
778  */
780  int nIDComboBox,
781  char* PrinterName,
782  char* PortName,
783  LPDEVMODEA dm)
784 {
785  int i;
786  int NrOfEntries;
787  char* Names;
788  WORD* Words;
789  DWORD Sel, old_Sel;
790  WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
791  int NamesSize;
792  int fwCapability_Names;
793  int fwCapability_Words;
794 
795  TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox);
796 
797  /* query the dialog box for the current selected value */
798  Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
799  if(Sel != CB_ERR) {
800  /* we enter here only if a different printer is selected after
801  * the Print Setup dialog is opened. The current settings are
802  * stored into the newly selected printer.
803  */
804  oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA,
805  Sel, 0);
806  if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
807  oldWord = 0; /* There's no point in trying to keep custom
808  paper / bin sizes across printers */
809  }
810 
811  if (dm)
812  newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
813 
814  if (nIDComboBox == cmb2) {
815  NamesSize = 64;
816  fwCapability_Names = DC_PAPERNAMES;
817  fwCapability_Words = DC_PAPERS;
818  } else {
819  nIDComboBox = cmb3;
820  NamesSize = 24;
821  fwCapability_Names = DC_BINNAMES;
822  fwCapability_Words = DC_BINS;
823  }
824 
825  NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
826  fwCapability_Names, NULL, dm);
827  if (NrOfEntries == 0)
828  WARN("no Name Entries found!\n");
829  else if (NrOfEntries < 0)
830  return FALSE;
831 
832  if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
833  != NrOfEntries) {
834  ERR("Number of caps is different\n");
835  NrOfEntries = 0;
836  }
837 
838  Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize);
839  Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
840  DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Names, Names, dm);
841  NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
842  fwCapability_Words, (LPSTR)Words, dm);
843 
844  /* reset any current content in the combobox */
845  SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
846 
847  /* store new content */
848  for (i = 0; i < NrOfEntries; i++) {
849  DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
850  (LPARAM)(&Names[i*NamesSize]) );
851  SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
852  Words[i]);
853  }
854 
855  /* Look for old selection or the new default.
856  Can't do this is previous loop since item order will change as more items are added */
857  Sel = 0;
858  old_Sel = NrOfEntries;
859  for (i = 0; i < NrOfEntries; i++) {
860  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
861  oldWord) {
862  old_Sel = i;
863  break;
864  }
865  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
866  Sel = i;
867  }
868 
869  if(old_Sel < NrOfEntries)
870  {
871  if (dm)
872  {
873  if(nIDComboBox == cmb2)
874  dm->u1.s1.dmPaperSize = oldWord;
875  else
876  dm->u1.s1.dmDefaultSource = oldWord;
877  }
878  Sel = old_Sel;
879  }
880 
881  SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
882 
883  HeapFree(GetProcessHeap(),0,Words);
885  return TRUE;
886 }
887 
889  int nIDComboBox,
890  const WCHAR* PrinterName,
891  const WCHAR* PortName,
892  LPDEVMODEW dm)
893 {
894  int i;
895  int NrOfEntries;
896  WCHAR* Names;
897  WORD* Words;
898  DWORD Sel, old_Sel;
899  WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
900  int NamesSize;
901  int fwCapability_Names;
902  int fwCapability_Words;
903 
904  TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox);
905 
906  /* query the dialog box for the current selected value */
907  Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
908  if(Sel != CB_ERR) {
909  /* we enter here only if a different printer is selected after
910  * the Print Setup dialog is opened. The current settings are
911  * stored into the newly selected printer.
912  */
913  oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA,
914  Sel, 0);
915 
916  if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
917  oldWord = 0; /* There's no point in trying to keep custom
918  paper / bin sizes across printers */
919  }
920 
921  if (dm)
922  newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
923 
924  if (nIDComboBox == cmb2) {
925  NamesSize = 64;
926  fwCapability_Names = DC_PAPERNAMES;
927  fwCapability_Words = DC_PAPERS;
928  } else {
929  nIDComboBox = cmb3;
930  NamesSize = 24;
931  fwCapability_Names = DC_BINNAMES;
932  fwCapability_Words = DC_BINS;
933  }
934 
935  NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
936  fwCapability_Names, NULL, dm);
937  if (NrOfEntries == 0)
938  WARN("no Name Entries found!\n");
939  else if (NrOfEntries < 0)
940  return FALSE;
941 
942  if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm)
943  != NrOfEntries) {
944  ERR("Number of caps is different\n");
945  NrOfEntries = 0;
946  }
947 
948  Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize);
949  Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
950  DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Names, Names, dm);
951  NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
952  fwCapability_Words, Words, dm);
953 
954  /* reset any current content in the combobox */
955  SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
956 
957  /* store new content */
958  for (i = 0; i < NrOfEntries; i++) {
959  DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0,
960  (LPARAM)(&Names[i*NamesSize]) );
961  SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
962  Words[i]);
963  }
964 
965  /* Look for old selection or the new default.
966  Can't do this is previous loop since item order will change as more items are added */
967  Sel = 0;
968  old_Sel = NrOfEntries;
969  for (i = 0; i < NrOfEntries; i++) {
970  if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
971  oldWord) {
972  old_Sel = i;
973  break;
974  }
975  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
976  Sel = i;
977  }
978 
979  if(old_Sel < NrOfEntries)
980  {
981  if (dm)
982  {
983  if(nIDComboBox == cmb2)
984  dm->u1.s1.dmPaperSize = oldWord;
985  else
986  dm->u1.s1.dmDefaultSource = oldWord;
987  }
988  Sel = old_Sel;
989  }
990 
991  SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
992 
993  HeapFree(GetProcessHeap(),0,Words);
995  return TRUE;
996 }
997 
998 
999 /***********************************************************************
1000  * PRINTDLG_UpdatePrinterInfoTexts [internal]
1001  */
1003 {
1004  char StatusMsg[256];
1005  char ResourceString[256];
1006  int i;
1007 
1008  /* Status Message */
1009  StatusMsg[0]='\0';
1010 
1011  /* add all status messages */
1012  for (i = 0; i < 25; i++) {
1013  if (pi->Status & (1<<i)) {
1015  ResourceString, 255);
1016  strcat(StatusMsg,ResourceString);
1017  }
1018  }
1019  /* append "ready" */
1020  /* FIXME: status==ready must only be appended if really so.
1021  but how to detect? */
1023  ResourceString, 255);
1024  strcat(StatusMsg,ResourceString);
1025  SetDlgItemTextA(hDlg, stc12, StatusMsg);
1026 
1027  /* set all other printer info texts */
1028  SetDlgItemTextA(hDlg, stc11, pi->pDriverName);
1029 
1030  if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1031  SetDlgItemTextA(hDlg, stc14, pi->pLocation);
1032  else
1033  SetDlgItemTextA(hDlg, stc14, pi->pPortName);
1034  SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : "");
1035  return;
1036 }
1037 
1039 {
1040  WCHAR StatusMsg[256];
1041  WCHAR ResourceString[256];
1042  static const WCHAR emptyW[] = {0};
1043  int i;
1044 
1045  /* Status Message */
1046  StatusMsg[0]='\0';
1047 
1048  /* add all status messages */
1049  for (i = 0; i < 25; i++) {
1050  if (pi->Status & (1<<i)) {
1052  ResourceString, 255);
1053  lstrcatW(StatusMsg,ResourceString);
1054  }
1055  }
1056  /* append "ready" */
1057  /* FIXME: status==ready must only be appended if really so.
1058  but how to detect? */
1060  ResourceString, 255);
1061  lstrcatW(StatusMsg,ResourceString);
1062  SetDlgItemTextW(hDlg, stc12, StatusMsg);
1063 
1064  /* set all other printer info texts */
1065  SetDlgItemTextW(hDlg, stc11, pi->pDriverName);
1066  if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1067  SetDlgItemTextW(hDlg, stc14, pi->pLocation);
1068  else
1069  SetDlgItemTextW(hDlg, stc14, pi->pPortName);
1070  SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW);
1071 }
1072 
1073 
1074 /*******************************************************************
1075  *
1076  * PRINTDLG_ChangePrinter
1077  *
1078  */
1079 static BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, PRINT_PTRA *PrintStructures)
1080 {
1081  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1082  LPDEVMODEA lpdm = NULL;
1083  LONG dmSize;
1084  DWORD needed;
1085  HANDLE hprn;
1086 
1087  HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1088  HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1089  if(!OpenPrinterA(name, &hprn, NULL)) {
1090  ERR("Can't open printer %s\n", name);
1091  return FALSE;
1092  }
1093  GetPrinterA(hprn, 2, NULL, 0, &needed);
1094  PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1095  GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1096  &needed);
1097  GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
1098  PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1099  if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1100  needed, &needed)) {
1101  ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName);
1102  return FALSE;
1103  }
1104  ClosePrinter(hprn);
1105 
1106  PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo);
1107 
1108  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1109  PrintStructures->lpDevMode = NULL;
1110 
1111  dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0);
1112  if(dmSize == -1) {
1113  ERR("DocumentProperties fails on %s\n", debugstr_a(name));
1114  return FALSE;
1115  }
1116  PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1117  dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL,
1118  DM_OUT_BUFFER);
1119  if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1120  !lstrcmpA( (LPSTR) lpdm->dmDeviceName,
1121  (LPSTR) PrintStructures->lpDevMode->dmDeviceName)) {
1122  /* Supplied devicemode matches current printer so try to use it */
1123  DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm,
1125  }
1126  if(lpdm)
1127  GlobalUnlock(lppd->hDevMode);
1128 
1129  lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */
1130 
1131  if(!(lppd->Flags & PD_PRINTSETUP)) {
1132  /* Print range (All/Range/Selection) */
1133  if(lppd->nFromPage != 0xffff)
1134  SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1135  if(lppd->nToPage != 0xffff)
1136  SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1137 
1138  CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */
1139  if (lppd->Flags & PD_NOSELECTION)
1140  EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1141  else
1142  if (lppd->Flags & PD_SELECTION)
1143  CheckRadioButton(hDlg, rad1, rad3, rad2);
1144  if (lppd->Flags & PD_NOPAGENUMS) {
1145  EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1147  EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1149  EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1150  } else {
1151  if (lppd->Flags & PD_PAGENUMS)
1152  CheckRadioButton(hDlg, rad1, rad3, rad3);
1153  }
1154 
1155  /* Collate pages
1156  *
1157  * FIXME: The ico3 is not displayed for some reason. I don't know why.
1158  */
1159  if (lppd->Flags & PD_COLLATE) {
1161  (LPARAM)PrintStructures->hCollateIcon);
1162  CheckDlgButton(hDlg, chx2, 1);
1163  } else {
1165  (LPARAM)PrintStructures->hNoCollateIcon);
1166  CheckDlgButton(hDlg, chx2, 0);
1167  }
1168 
1169  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1170  /* if printer doesn't support it: no Collate */
1171  if (!(lpdm->dmFields & DM_COLLATE)) {
1172  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1173  EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1174  }
1175  }
1176 
1177  /* nCopies */
1178  {
1179  INT copies;
1180  if (lppd->hDevMode == 0)
1181  copies = lppd->nCopies;
1182  else
1183  copies = lpdm->u1.s1.dmCopies;
1184  if(copies == 0) copies = 1;
1185  else if(copies < 0) copies = MAX_COPIES;
1186  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1187  }
1188 
1189  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1190  /* if printer doesn't support it: no nCopies */
1191  if (!(lpdm->dmFields & DM_COPIES)) {
1192  EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1193  EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1194  }
1195  }
1196 
1197  /* print to file */
1198  CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1199  if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1200  EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1201  if (lppd->Flags & PD_HIDEPRINTTOFILE)
1202  ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1203 
1204  /* Fill print quality combo, PrintDlg16 */
1205  if(GetDlgItem(hDlg, cmb1))
1206  {
1207  DWORD numResolutions = DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName,
1208  PrintStructures->lpPrinterInfo->pPortName,
1209  DC_ENUMRESOLUTIONS, NULL, lpdm);
1210 
1211  if(numResolutions != -1)
1212  {
1213  HWND hQuality = GetDlgItem(hDlg, cmb1);
1214  LONG* Resolutions;
1215  char buf[255];
1216  DWORD i;
1217  int dpiX, dpiY;
1218  HDC hPrinterDC = CreateDCA(PrintStructures->lpPrinterInfo->pDriverName,
1219  PrintStructures->lpPrinterInfo->pPrinterName,
1220  0, lpdm);
1221 
1222  Resolutions = HeapAlloc(GetProcessHeap(), 0, numResolutions*sizeof(LONG)*2);
1224  PrintStructures->lpPrinterInfo->pPortName,
1225  DC_ENUMRESOLUTIONS, (LPSTR)Resolutions, lpdm);
1226 
1227  dpiX = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
1228  dpiY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
1229  DeleteDC(hPrinterDC);
1230 
1231  SendMessageA(hQuality, CB_RESETCONTENT, 0, 0);
1232  for(i = 0; i < (numResolutions * 2); i += 2)
1233  {
1234  BOOL IsDefault = FALSE;
1235  LRESULT Index;
1236 
1237  if(Resolutions[i] == Resolutions[i+1])
1238  {
1239  if(dpiX == Resolutions[i])
1240  IsDefault = TRUE;
1241  sprintf(buf, "%d dpi", Resolutions[i]);
1242  } else
1243  {
1244  if(dpiX == Resolutions[i] && dpiY == Resolutions[i+1])
1245  IsDefault = TRUE;
1246  sprintf(buf, "%d dpi x %d dpi", Resolutions[i], Resolutions[i+1]);
1247  }
1248 
1249  Index = SendMessageA(hQuality, CB_ADDSTRING, 0, (LPARAM)buf);
1250 
1251  if(IsDefault)
1252  SendMessageA(hQuality, CB_SETCURSEL, Index, 0);
1253 
1254  SendMessageA(hQuality, CB_SETITEMDATA, Index, MAKELONG(dpiX,dpiY));
1255  }
1256  HeapFree(GetProcessHeap(), 0, Resolutions);
1257  }
1258  }
1259  } else { /* PD_PRINTSETUP */
1260  BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1261 
1263  PrintStructures->lpPrinterInfo->pPrinterName,
1264  PrintStructures->lpPrinterInfo->pPortName,
1265  lpdm);
1267  PrintStructures->lpPrinterInfo->pPrinterName,
1268  PrintStructures->lpPrinterInfo->pPortName,
1269  lpdm);
1270  CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1272  (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1273  PrintStructures->hLandscapeIcon));
1274 
1275  }
1276 
1277  /* help button */
1278  if ((lppd->Flags & PD_SHOWHELP)==0) {
1279  /* hide if PD_SHOWHELP not specified */
1281  }
1282  return TRUE;
1283 }
1284 
1286  PRINT_PTRW *PrintStructures)
1287 {
1288  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1289  LPDEVMODEW lpdm = NULL;
1290  LONG dmSize;
1291  DWORD needed;
1292  HANDLE hprn;
1293 
1294  HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1295  HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1296  if(!OpenPrinterW(name, &hprn, NULL)) {
1297  ERR("Can't open printer %s\n", debugstr_w(name));
1298  return FALSE;
1299  }
1300  GetPrinterW(hprn, 2, NULL, 0, &needed);
1301  PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1302  GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1303  &needed);
1304  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
1305  PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1306  if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1307  needed, &needed)) {
1308  ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName));
1309  return FALSE;
1310  }
1311  ClosePrinter(hprn);
1312 
1313  PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo);
1314 
1315  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1316  PrintStructures->lpDevMode = NULL;
1317 
1318  dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
1319  if(dmSize == -1) {
1320  ERR("DocumentProperties fails on %s\n", debugstr_w(name));
1321  return FALSE;
1322  }
1323  PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1324  dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL,
1325  DM_OUT_BUFFER);
1326  if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1327  !lstrcmpW(lpdm->dmDeviceName,
1328  PrintStructures->lpDevMode->dmDeviceName)) {
1329  /* Supplied devicemode matches current printer so try to use it */
1330  DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm,
1332  }
1333  if(lpdm)
1334  GlobalUnlock(lppd->hDevMode);
1335 
1336  lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */
1337 
1338  if(!(lppd->Flags & PD_PRINTSETUP)) {
1339  /* Print range (All/Range/Selection) */
1340  if(lppd->nFromPage != 0xffff)
1341  SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1342  if(lppd->nToPage != 0xffff)
1343  SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1344 
1345  CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */
1346  if (lppd->Flags & PD_NOSELECTION)
1347  EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1348  else
1349  if (lppd->Flags & PD_SELECTION)
1350  CheckRadioButton(hDlg, rad1, rad3, rad2);
1351  if (lppd->Flags & PD_NOPAGENUMS) {
1352  EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1354  EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1356  EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1357  } else {
1358  if (lppd->Flags & PD_PAGENUMS)
1359  CheckRadioButton(hDlg, rad1, rad3, rad3);
1360  }
1361 
1362  /* Collate pages
1363  *
1364  * FIXME: The ico3 is not displayed for some reason. I don't know why.
1365  */
1366  if (lppd->Flags & PD_COLLATE) {
1368  (LPARAM)PrintStructures->hCollateIcon);
1369  CheckDlgButton(hDlg, chx2, 1);
1370  } else {
1372  (LPARAM)PrintStructures->hNoCollateIcon);
1373  CheckDlgButton(hDlg, chx2, 0);
1374  }
1375 
1376  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1377  /* if printer doesn't support it: no Collate */
1378  if (!(lpdm->dmFields & DM_COLLATE)) {
1379  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1380  EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1381  }
1382  }
1383 
1384  /* nCopies */
1385  {
1386  INT copies;
1387  if (lppd->hDevMode == 0)
1388  copies = lppd->nCopies;
1389  else
1390  copies = lpdm->u1.s1.dmCopies;
1391  if(copies == 0) copies = 1;
1392  else if(copies < 0) copies = MAX_COPIES;
1393  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1394  }
1395 
1396  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1397  /* if printer doesn't support it: no nCopies */
1398  if (!(lpdm->dmFields & DM_COPIES)) {
1399  EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1400  EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1401  }
1402  }
1403 
1404  /* print to file */
1405  CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1406  if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1407  EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1408  if (lppd->Flags & PD_HIDEPRINTTOFILE)
1409  ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1410 
1411  } else { /* PD_PRINTSETUP */
1412  BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1413 
1415  PrintStructures->lpPrinterInfo->pPrinterName,
1416  PrintStructures->lpPrinterInfo->pPortName,
1417  lpdm);
1419  PrintStructures->lpPrinterInfo->pPrinterName,
1420  PrintStructures->lpPrinterInfo->pPortName,
1421  lpdm);
1422  CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1424  (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1425  PrintStructures->hLandscapeIcon));
1426 
1427  }
1428 
1429  /* help button */
1430  if ((lppd->Flags & PD_SHOWHELP)==0) {
1431  /* hide if PD_SHOWHELP not specified */
1433  }
1434  return TRUE;
1435 }
1436 
1437  /***********************************************************************
1438  * check_printer_setup [internal]
1439  */
1441 {
1442  DWORD needed,num;
1443  WCHAR resourcestr[256],resultstr[256];
1444 
1445  EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
1446  if(needed == 0)
1447  {
1448  EnumPrintersW(PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &num);
1449  }
1450  if(needed > 0)
1451  return TRUE;
1452  else
1453  {
1455  LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,resourcestr, 255);
1456  MessageBoxW(hDlg, resultstr, resourcestr,MB_OK | MB_ICONWARNING);
1457  return FALSE;
1458  }
1459 }
1460 
1461 /***********************************************************************
1462  * PRINTDLG_WMInitDialog [internal]
1463  */
1465  PRINT_PTRA* PrintStructures)
1466 {
1467  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1468  DEVNAMES *pdn;
1469  DEVMODEA *pdm;
1470  char *name = NULL;
1471  UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1472 
1473  /* load Collate ICONs */
1474  /* We load these with LoadImage because they are not a standard
1475  size and we don't want them rescaled */
1476  PrintStructures->hCollateIcon =
1477  LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0);
1478  PrintStructures->hNoCollateIcon =
1479  LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0);
1480 
1481  /* These can be done with LoadIcon */
1482  PrintStructures->hPortraitIcon =
1483  LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT");
1484  PrintStructures->hLandscapeIcon =
1485  LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE");
1486 
1487  /* display the collate/no_collate icon */
1489  (LPARAM)PrintStructures->hNoCollateIcon);
1490 
1491  if(PrintStructures->hCollateIcon == 0 ||
1492  PrintStructures->hNoCollateIcon == 0 ||
1493  PrintStructures->hPortraitIcon == 0 ||
1494  PrintStructures->hLandscapeIcon == 0) {
1495  ERR("no icon in resource file\n");
1497  EndDialog(hDlg, FALSE);
1498  }
1499 
1500  /*
1501  * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1502  * must be registered and the Help button must be shown.
1503  */
1504  if (lppd->Flags & PD_SHOWHELP) {
1505  if((PrintStructures->HelpMessageID =
1508  return FALSE;
1509  }
1510  } else
1511  PrintStructures->HelpMessageID = 0;
1512 
1513  if(!(lppd->Flags &PD_PRINTSETUP)) {
1514  PrintStructures->hwndUpDown =
1517  UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1519  GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1520  }
1521 
1522  /* FIXME: I allow more freedom than either Win95 or WinNT,
1523  * which do not agree on what errors should be thrown or not
1524  * in case nToPage or nFromPage is out-of-range.
1525  */
1526  if (lppd->nMaxPage < lppd->nMinPage)
1527  lppd->nMaxPage = lppd->nMinPage;
1528  if (lppd->nMinPage == lppd->nMaxPage)
1529  lppd->Flags |= PD_NOPAGENUMS;
1530  if (lppd->nToPage < lppd->nMinPage)
1531  lppd->nToPage = lppd->nMinPage;
1532  if (lppd->nToPage > lppd->nMaxPage)
1533  lppd->nToPage = lppd->nMaxPage;
1534  if (lppd->nFromPage < lppd->nMinPage)
1535  lppd->nFromPage = lppd->nMinPage;
1536  if (lppd->nFromPage > lppd->nMaxPage)
1537  lppd->nFromPage = lppd->nMaxPage;
1538 
1539  /* if we have the combo box, fill it */
1540  if (GetDlgItem(hDlg,comboID)) {
1541  /* Fill Combobox
1542  */
1543  pdn = GlobalLock(lppd->hDevNames);
1544  pdm = GlobalLock(lppd->hDevMode);
1545  if(pdn)
1546  name = (char*)pdn + pdn->wDeviceOffset;
1547  else if(pdm)
1548  name = (char*)pdm->dmDeviceName;
1549  PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name);
1550  if(pdm) GlobalUnlock(lppd->hDevMode);
1551  if(pdn) GlobalUnlock(lppd->hDevNames);
1552 
1553  /* Now find selected printer and update rest of dlg */
1554  name = HeapAlloc(GetProcessHeap(),0,256);
1555  if (GetDlgItemTextA(hDlg, comboID, name, 255))
1556  PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1558  } else {
1559  /* else use default printer */
1560  char name[200];
1563 
1564  if (ret)
1565  PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1566  else
1567  FIXME("No default printer found, expect problems!\n");
1568  }
1569  return TRUE;
1570 }
1571 
1573  PRINT_PTRW* PrintStructures)
1574 {
1575  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1576  DEVNAMES *pdn;
1577  DEVMODEW *pdm;
1578  WCHAR *name = NULL;
1579  UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1580 
1581  /* load Collate ICONs */
1582  /* We load these with LoadImage because they are not a standard
1583  size and we don't want them rescaled */
1584  PrintStructures->hCollateIcon =
1586  PrintStructures->hNoCollateIcon =
1588 
1589  /* These can be done with LoadIcon */
1590  PrintStructures->hPortraitIcon =
1592  PrintStructures->hLandscapeIcon =
1594 
1595  /* display the collate/no_collate icon */
1597  (LPARAM)PrintStructures->hNoCollateIcon);
1598 
1599  if(PrintStructures->hCollateIcon == 0 ||
1600  PrintStructures->hNoCollateIcon == 0 ||
1601  PrintStructures->hPortraitIcon == 0 ||
1602  PrintStructures->hLandscapeIcon == 0) {
1603  ERR("no icon in resource file\n");
1605  EndDialog(hDlg, FALSE);
1606  }
1607 
1608  /*
1609  * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1610  * must be registered and the Help button must be shown.
1611  */
1612  if (lppd->Flags & PD_SHOWHELP) {
1613  if((PrintStructures->HelpMessageID =
1616  return FALSE;
1617  }
1618  } else
1619  PrintStructures->HelpMessageID = 0;
1620 
1621  if(!(lppd->Flags &PD_PRINTSETUP)) {
1622  PrintStructures->hwndUpDown =
1625  UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1627  GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1628  }
1629 
1630  /* FIXME: I allow more freedom than either Win95 or WinNT,
1631  * which do not agree to what errors should be thrown or not
1632  * in case nToPage or nFromPage is out-of-range.
1633  */
1634  if (lppd->nMaxPage < lppd->nMinPage)
1635  lppd->nMaxPage = lppd->nMinPage;
1636  if (lppd->nMinPage == lppd->nMaxPage)
1637  lppd->Flags |= PD_NOPAGENUMS;
1638  if (lppd->nToPage < lppd->nMinPage)
1639  lppd->nToPage = lppd->nMinPage;
1640  if (lppd->nToPage > lppd->nMaxPage)
1641  lppd->nToPage = lppd->nMaxPage;
1642  if (lppd->nFromPage < lppd->nMinPage)
1643  lppd->nFromPage = lppd->nMinPage;
1644  if (lppd->nFromPage > lppd->nMaxPage)
1645  lppd->nFromPage = lppd->nMaxPage;
1646 
1647  /* if we have the combo box, fill it */
1648  if (GetDlgItem(hDlg,comboID)) {
1649  /* Fill Combobox
1650  */
1651  pdn = GlobalLock(lppd->hDevNames);
1652  pdm = GlobalLock(lppd->hDevMode);
1653  if(pdn)
1654  name = (WCHAR*)pdn + pdn->wDeviceOffset;
1655  else if(pdm)
1656  name = pdm->dmDeviceName;
1657  PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name);
1658  if(pdm) GlobalUnlock(lppd->hDevMode);
1659  if(pdn) GlobalUnlock(lppd->hDevNames);
1660 
1661  /* Now find selected printer and update rest of dlg */
1662  /* ansi is ok here */
1663  name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR));
1664  if (GetDlgItemTextW(hDlg, comboID, name, 255))
1665  PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1667  } else {
1668  /* else use default printer */
1669  WCHAR name[200];
1672 
1673  if (ret)
1674  PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1675  else
1676  FIXME("No default printer found, expect problems!\n");
1677  }
1678  return TRUE;
1679 }
1680 
1681 /***********************************************************************
1682  * PRINTDLG_WMCommand [internal]
1683  */
1685  PRINT_PTRA* PrintStructures)
1686 {
1687  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1688  UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1689  LPDEVMODEA lpdm = PrintStructures->lpDevMode;
1690 
1691  switch (LOWORD(wParam)) {
1692  case IDOK:
1693  TRACE(" OK button was hit\n");
1694  if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) {
1695  FIXME("Update printdlg was not successful!\n");
1696  return(FALSE);
1697  }
1698  EndDialog(hDlg, TRUE);
1699  return(TRUE);
1700 
1701  case IDCANCEL:
1702  TRACE(" CANCEL button was hit\n");
1703  EndDialog(hDlg, FALSE);
1704  return(FALSE);
1705 
1706  case pshHelp:
1707  TRACE(" HELP button was hit\n");
1708  SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID,
1709  (WPARAM) hDlg, (LPARAM) lppd);
1710  break;
1711 
1712  case chx2: /* collate pages checkbox */
1713  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1715  (LPARAM)PrintStructures->hCollateIcon);
1716  else
1718  (LPARAM)PrintStructures->hNoCollateIcon);
1719  break;
1720  case edt1: /* from page nr editbox */
1721  case edt2: /* to page nr editbox */
1722  if (HIWORD(wParam)==EN_CHANGE) {
1723  WORD nToPage;
1724  WORD nFromPage;
1725  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1726  nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1727  if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1728  CheckRadioButton(hDlg, rad1, rad3, rad3);
1729  }
1730  break;
1731 
1732  case edt3:
1733  if(HIWORD(wParam) == EN_CHANGE) {
1734  INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1735  if(copies <= 1)
1736  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1737  else
1738  EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1739  }
1740  break;
1741 
1742  case psh2: /* Properties button */
1743  {
1744  HANDLE hPrinter;
1745  char PrinterName[256];
1746 
1747  GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255);
1748  if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) {
1749  FIXME(" Call to OpenPrinter did not succeed!\n");
1750  break;
1751  }
1752  DocumentPropertiesA(hDlg, hPrinter, PrinterName,
1753  PrintStructures->lpDevMode,
1754  PrintStructures->lpDevMode,
1756  ClosePrinter(hPrinter);
1757  break;
1758  }
1759 
1760  case rad1: /* Paperorientation */
1761  if (lppd->Flags & PD_PRINTSETUP)
1762  {
1763  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1765  (LPARAM)(PrintStructures->hPortraitIcon));
1766  }
1767  break;
1768 
1769  case rad2: /* Paperorientation */
1770  if (lppd->Flags & PD_PRINTSETUP)
1771  {
1772  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1774  (LPARAM)(PrintStructures->hLandscapeIcon));
1775  }
1776  break;
1777 
1778  case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT16 */
1779  if (PrinterComboID != LOWORD(wParam)) {
1780  break;
1781  }
1782  /* FALLTHROUGH */
1783  case cmb4: /* Printer combobox */
1784  if (HIWORD(wParam)==CBN_SELCHANGE) {
1785  char *PrinterName;
1788  PrinterName = HeapAlloc(GetProcessHeap(),0,length+1);
1789  SendDlgItemMessageA(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1790  PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures);
1791  HeapFree(GetProcessHeap(),0,PrinterName);
1792  }
1793  break;
1794 
1795  case cmb2: /* Papersize */
1796  {
1797  DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1798  if(Sel != CB_ERR) {
1799  lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2,
1801  Sel, 0);
1802  GetDlgItemTextA(hDlg, cmb2, (char *)lpdm->dmFormName, CCHFORMNAME);
1803  }
1804  }
1805  break;
1806 
1807  case cmb3: /* Bin */
1808  {
1809  DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1810  if(Sel != CB_ERR)
1811  lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3,
1812  CB_GETITEMDATA, Sel,
1813  0);
1814  }
1815  break;
1816  }
1817  if(lppd->Flags & PD_PRINTSETUP) {
1818  switch (LOWORD(wParam)) {
1819  case rad1: /* orientation */
1820  case rad2:
1821  if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1822  if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
1823  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1825  (LPARAM)PrintStructures->hPortraitIcon);
1827  (LPARAM)PrintStructures->hPortraitIcon);
1828  }
1829  } else {
1830  if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
1831  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1833  (LPARAM)PrintStructures->hLandscapeIcon);
1835  (LPARAM)PrintStructures->hLandscapeIcon);
1836  }
1837  }
1838  break;
1839  }
1840  }
1841  return FALSE;
1842 }
1843 
1845  PRINT_PTRW* PrintStructures)
1846 {
1847  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1848  UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1849  LPDEVMODEW lpdm = PrintStructures->lpDevMode;
1850 
1851  switch (LOWORD(wParam)) {
1852  case IDOK:
1853  TRACE(" OK button was hit\n");
1854  if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) {
1855  FIXME("Update printdlg was not successful!\n");
1856  return(FALSE);
1857  }
1858  EndDialog(hDlg, TRUE);
1859  return(TRUE);
1860 
1861  case IDCANCEL:
1862  TRACE(" CANCEL button was hit\n");
1863  EndDialog(hDlg, FALSE);
1864  return(FALSE);
1865 
1866  case pshHelp:
1867  TRACE(" HELP button was hit\n");
1868  SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID,
1869  (WPARAM) hDlg, (LPARAM) lppd);
1870  break;
1871 
1872  case chx2: /* collate pages checkbox */
1873  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1875  (LPARAM)PrintStructures->hCollateIcon);
1876  else
1878  (LPARAM)PrintStructures->hNoCollateIcon);
1879  break;
1880  case edt1: /* from page nr editbox */
1881  case edt2: /* to page nr editbox */
1882  if (HIWORD(wParam)==EN_CHANGE) {
1883  WORD nToPage;
1884  WORD nFromPage;
1885  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1886  nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1887  if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1888  CheckRadioButton(hDlg, rad1, rad3, rad3);
1889  }
1890  break;
1891 
1892  case edt3:
1893  if(HIWORD(wParam) == EN_CHANGE) {
1894  INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1895  if(copies <= 1)
1896  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1897  else
1898  EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1899  }
1900  break;
1901 
1902  case psh2: /* Properties button */
1903  {
1904  HANDLE hPrinter;
1905  WCHAR PrinterName[256];
1906 
1907  if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break;
1908  if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) {
1909  FIXME(" Call to OpenPrinter did not succeed!\n");
1910  break;
1911  }
1912  DocumentPropertiesW(hDlg, hPrinter, PrinterName,
1913  PrintStructures->lpDevMode,
1914  PrintStructures->lpDevMode,
1916  ClosePrinter(hPrinter);
1917  break;
1918  }
1919 
1920  case rad1: /* Paperorientation */
1921  if (lppd->Flags & PD_PRINTSETUP)
1922  {
1923  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1925  (LPARAM)(PrintStructures->hPortraitIcon));
1926  }
1927  break;
1928 
1929  case rad2: /* Paperorientation */
1930  if (lppd->Flags & PD_PRINTSETUP)
1931  {
1932  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1934  (LPARAM)(PrintStructures->hLandscapeIcon));
1935  }
1936  break;
1937 
1938  case cmb1: /* Printer Combobox in PRINT SETUP */
1939  /* FALLTHROUGH */
1940  case cmb4: /* Printer combobox */
1941  if (HIWORD(wParam)==CBN_SELCHANGE) {
1942  WCHAR *PrinterName;
1945 
1946  PrinterName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
1947  SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1948  PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures);
1949  HeapFree(GetProcessHeap(),0,PrinterName);
1950  }
1951  break;
1952 
1953  case cmb2: /* Papersize */
1954  {
1955  DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1956  if(Sel != CB_ERR) {
1957  lpdm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2,
1959  Sel, 0);
1960  GetDlgItemTextW(hDlg, cmb2, lpdm->dmFormName, CCHFORMNAME);
1961  }
1962  }
1963  break;
1964 
1965  case cmb3: /* Bin */
1966  {
1967  DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1968  if(Sel != CB_ERR)
1969  lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3,
1970  CB_GETITEMDATA, Sel,
1971  0);
1972  }
1973  break;
1974  }
1975  if(lppd->Flags & PD_PRINTSETUP) {
1976  switch (LOWORD(wParam)) {
1977  case rad1: /* orientation */
1978  case rad2:
1979  if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1980  if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
1981  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1983  (LPARAM)PrintStructures->hPortraitIcon);
1985  (LPARAM)PrintStructures->hPortraitIcon);
1986  }
1987  } else {
1988  if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
1989  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1991  (LPARAM)PrintStructures->hLandscapeIcon);
1993  (LPARAM)PrintStructures->hLandscapeIcon);
1994  }
1995  }
1996  break;
1997  }
1998  }
1999  return FALSE;
2000 }
2001 
2002 /***********************************************************************
2003  * PrintDlgProcA [internal]
2004  */
2006  LPARAM lParam)
2007 {
2008  PRINT_PTRA* PrintStructures;
2009  INT_PTR res = FALSE;
2010 
2011  if (uMsg!=WM_INITDIALOG) {
2012  PrintStructures = GetPropW(hDlg, printdlg_prop);
2013  if (!PrintStructures)
2014  return FALSE;
2015  } else {
2016  PrintStructures = (PRINT_PTRA*) lParam;
2017  SetPropW(hDlg, printdlg_prop, PrintStructures);
2018  if(!check_printer_setup(hDlg))
2019  {
2020  EndDialog(hDlg,FALSE);
2021  return FALSE;
2022  }
2023  res = PRINTDLG_WMInitDialog(hDlg, PrintStructures);
2024 
2025  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2026  res = PrintStructures->lpPrintDlg->lpfnPrintHook(
2027  hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg
2028  );
2029  return res;
2030  }
2031 
2032  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2033  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam,
2034  lParam);
2035  if(res) return res;
2036  }
2037 
2038  switch (uMsg) {
2039  case WM_COMMAND:
2040  return PRINTDLG_WMCommandA(hDlg, wParam, PrintStructures);
2041 
2042  case WM_DESTROY:
2043  DestroyIcon(PrintStructures->hCollateIcon);
2044  DestroyIcon(PrintStructures->hNoCollateIcon);
2045  DestroyIcon(PrintStructures->hPortraitIcon);
2046  DestroyIcon(PrintStructures->hLandscapeIcon);
2047  if(PrintStructures->hwndUpDown)
2048  DestroyWindow(PrintStructures->hwndUpDown);
2049  return FALSE;
2050  }
2051  return res;
2052 }
2053 
2055  LPARAM lParam)
2056 {
2057  PRINT_PTRW* PrintStructures;
2058  INT_PTR res = FALSE;
2059 
2060  if (uMsg!=WM_INITDIALOG) {
2061  PrintStructures = GetPropW(hDlg, printdlg_prop);
2062  if (!PrintStructures)
2063  return FALSE;
2064  } else {
2065  PrintStructures = (PRINT_PTRW*) lParam;
2066  SetPropW(hDlg, printdlg_prop, PrintStructures);
2067  if(!check_printer_setup(hDlg))
2068  {
2069  EndDialog(hDlg,FALSE);
2070  return FALSE;
2071  }
2072  res = PRINTDLG_WMInitDialogW(hDlg, PrintStructures);
2073 
2074  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2075  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg);
2076  return res;
2077  }
2078 
2079  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2080  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam);
2081  if(res) return res;
2082  }
2083 
2084  switch (uMsg) {
2085  case WM_COMMAND:
2086  return PRINTDLG_WMCommandW(hDlg, wParam, PrintStructures);
2087 
2088  case WM_DESTROY:
2089  DestroyIcon(PrintStructures->hCollateIcon);
2090  DestroyIcon(PrintStructures->hNoCollateIcon);
2091  DestroyIcon(PrintStructures->hPortraitIcon);
2092  DestroyIcon(PrintStructures->hLandscapeIcon);
2093  if(PrintStructures->hwndUpDown)
2094  DestroyWindow(PrintStructures->hwndUpDown);
2095  return FALSE;
2096  }
2097  return res;
2098 }
2099 
2100 /************************************************************
2101  *
2102  * PRINTDLG_GetDlgTemplate
2103  *
2104  */
2106 {
2107  HRSRC hResInfo;
2108  HGLOBAL hDlgTmpl;
2109 
2110  if (lppd->Flags & PD_PRINTSETUP) {
2111  if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2112  hDlgTmpl = lppd->hSetupTemplate;
2113  } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2114  hResInfo = FindResourceA(lppd->hInstance,
2116  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2117  } else {
2118  hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP",
2119  (LPSTR)RT_DIALOG);
2120  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2121  }
2122  } else {
2123  if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2124  hDlgTmpl = lppd->hPrintTemplate;
2125  } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2126  hResInfo = FindResourceA(lppd->hInstance,
2127  lppd->lpPrintTemplateName,
2128  (LPSTR)RT_DIALOG);
2129  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2130  } else {
2131  hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32",
2132  (LPSTR)RT_DIALOG);
2133  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2134  }
2135  }
2136  return hDlgTmpl;
2137 }
2138 
2140 {
2141  HRSRC hResInfo;
2142  HGLOBAL hDlgTmpl;
2143  static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0};
2144  static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0};
2145 
2146  if (lppd->Flags & PD_PRINTSETUP) {
2147  if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2148  hDlgTmpl = lppd->hSetupTemplate;
2149  } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2150  hResInfo = FindResourceW(lppd->hInstance,
2152  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2153  } else {
2154  hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG);
2155  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2156  }
2157  } else {
2158  if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2159  hDlgTmpl = lppd->hPrintTemplate;
2160  } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2161  hResInfo = FindResourceW(lppd->hInstance,
2162  lppd->lpPrintTemplateName,
2163  (LPWSTR)RT_DIALOG);
2164  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2165  } else {
2166  hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG);
2167  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2168  }
2169  }
2170  return hDlgTmpl;
2171 }
2172 
2173 /***********************************************************************
2174  *
2175  * PRINTDLG_CreateDC
2176  *
2177  */
2179 {
2180  DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2181  DEVMODEA *pdm = GlobalLock(lppd->hDevMode);
2182 
2183  if(lppd->Flags & PD_RETURNDC) {
2184  lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset,
2185  (char*)pdn + pdn->wDeviceOffset,
2186  (char*)pdn + pdn->wOutputOffset,
2187  pdm );
2188  } else if(lppd->Flags & PD_RETURNIC) {
2189  lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset,
2190  (char*)pdn + pdn->wDeviceOffset,
2191  (char*)pdn + pdn->wOutputOffset,
2192  pdm );
2193  }
2194  GlobalUnlock(lppd->hDevNames);
2195  GlobalUnlock(lppd->hDevMode);
2196  return lppd->hDC != NULL;
2197 }
2198 
2200 {
2201  DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2202  DEVMODEW *pdm = GlobalLock(lppd->hDevMode);
2203 
2204  if(lppd->Flags & PD_RETURNDC) {
2205  lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset,
2206  (WCHAR*)pdn + pdn->wDeviceOffset,
2207  (WCHAR*)pdn + pdn->wOutputOffset,
2208  pdm );
2209  } else if(lppd->Flags & PD_RETURNIC) {
2210  lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset,
2211  (WCHAR*)pdn + pdn->wDeviceOffset,
2212  (WCHAR*)pdn + pdn->wOutputOffset,
2213  pdm );
2214  }
2215  GlobalUnlock(lppd->hDevNames);
2216  GlobalUnlock(lppd->hDevMode);
2217  return lppd->hDC != NULL;
2218 }
2219 
2220 /***********************************************************************
2221  * PrintDlgA (COMDLG32.@)
2222  *
2223  * Displays the PRINT dialog box, which enables the user to specify
2224  * specific properties of the print job.
2225  *
2226  * PARAMS
2227  * lppd [IO] ptr to PRINTDLG32 struct
2228  *
2229  * RETURNS
2230  * nonzero if the user pressed the OK button
2231  * zero if the user cancelled the window or an error occurred
2232  *
2233  * BUGS
2234  * PrintDlg:
2235  * * The Collate Icons do not display, even though they are in the code.
2236  * * The Properties Button(s) should call DocumentPropertiesA().
2237  */
2238 
2240 {
2241  BOOL bRet = FALSE;
2242  LPVOID ptr;
2243  HINSTANCE hInst;
2244 
2245  if (!lppd)
2246  {
2248  return FALSE;
2249  }
2250 
2251  if(TRACE_ON(commdlg)) {
2252  char flagstr[1000] = "";
2253  const struct pd_flags *pflag = pd_flags;
2254  for( ; pflag->name; pflag++) {
2255  if(lppd->Flags & pflag->flag)
2256  strcat(flagstr, pflag->name);
2257  }
2258  TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2259  "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2260  "flags %08x (%s)\n",
2261  lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2262  lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2263  lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2264  }
2265 
2266  if(lppd->lStructSize != sizeof(PRINTDLGA)) {
2267  WARN("structure size failure!!!\n");
2269  return FALSE;
2270  }
2271 
2272  if(lppd->Flags & PD_RETURNDEFAULT) {
2274  DRIVER_INFO_3A *dbuf;
2275  HANDLE hprn;
2276  DWORD needed;
2277 
2278  if(lppd->hDevMode || lppd->hDevNames) {
2279  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2281  return FALSE;
2282  }
2283  if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2284  WARN("Can't find default printer\n");
2286  return FALSE;
2287  }
2288 
2289  GetPrinterA(hprn, 2, NULL, 0, &needed);
2290  pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2291  GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2292 
2293  GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
2294  dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2295  if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2296  ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2297  GetLastError(),pbuf->pPrinterName);
2298  HeapFree(GetProcessHeap(), 0, dbuf);
2299  HeapFree(GetProcessHeap(), 0, pbuf);
2301  return FALSE;
2302  }
2303  ClosePrinter(hprn);
2304 
2306  dbuf->pDriverPath,
2307  pbuf->pPrinterName,
2308  pbuf->pPortName);
2309  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2310  pbuf->pDevMode->dmDriverExtra);
2311  ptr = GlobalLock(lppd->hDevMode);
2312  memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2313  pbuf->pDevMode->dmDriverExtra);
2314  GlobalUnlock(lppd->hDevMode);
2315  HeapFree(GetProcessHeap(), 0, pbuf);
2316  HeapFree(GetProcessHeap(), 0, dbuf);
2317  bRet = TRUE;
2318  } else {
2319  HGLOBAL hDlgTmpl;
2320  PRINT_PTRA *PrintStructures;
2321 
2322  /* load Dialog resources,
2323  * depending on Flags indicates Print32 or Print32_setup dialog
2324  */
2325  hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd);
2326  if (!hDlgTmpl) {
2328  return FALSE;
2329  }
2330  ptr = LockResource( hDlgTmpl );
2331  if (!ptr) {
2333  return FALSE;
2334  }
2335 
2336  PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2337  sizeof(PRINT_PTRA));
2338  PrintStructures->lpPrintDlg = lppd;
2339 
2340  /* and create & process the dialog .
2341  * -1 is failure, 0 is broken hwnd, everything else is ok.
2342  */
2345  bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner,
2346  PrintDlgProcA,
2347  (LPARAM)PrintStructures));
2348 
2349  if(bRet) {
2350  DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2351  PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo;
2352  DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo;
2353 
2354  if (lppd->hDevMode == 0) {
2355  TRACE(" No hDevMode yet... Need to create my own\n");
2357  lpdm->dmSize + lpdm->dmDriverExtra);
2358  } else {
2359  lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2360  lpdm->dmSize + lpdm->dmDriverExtra,
2361  GMEM_MOVEABLE);
2362  }
2363  lpdmReturn = GlobalLock(lppd->hDevMode);
2364  memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2365 
2367  di->pDriverPath,
2368  pi->pPrinterName,
2369  pi->pPortName
2370  );
2371  GlobalUnlock(lppd->hDevMode);
2372  }
2373  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2374  HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2375  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2376  HeapFree(GetProcessHeap(), 0, PrintStructures);
2377  }
2378  if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2379  bRet = PRINTDLG_CreateDCA(lppd);
2380 
2381  TRACE("exit! (%d)\n", bRet);
2382  return bRet;
2383 }
2384 
2385 /***********************************************************************
2386  * PrintDlgW (COMDLG32.@)
2387  *
2388  * See PrintDlgA.
2389  */
2391 {
2392  BOOL bRet = FALSE;
2393  LPVOID ptr;
2394  HINSTANCE hInst;
2395 
2396  if (!lppd)
2397  {
2399  return FALSE;
2400  }
2401 
2402  if(TRACE_ON(commdlg)) {
2403  char flagstr[1000] = "";
2404  const struct pd_flags *pflag = pd_flags;
2405  for( ; pflag->name; pflag++) {
2406  if(lppd->Flags & pflag->flag)
2407  strcat(flagstr, pflag->name);
2408  }
2409  TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2410  "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2411  "flags %08x (%s)\n",
2412  lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2413  lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2414  lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2415  }
2416 
2417  if(lppd->lStructSize != sizeof(PRINTDLGW)) {
2418  WARN("structure size failure!!!\n");
2420  return FALSE;
2421  }
2422 
2423  if(lppd->Flags & PD_RETURNDEFAULT) {
2425  DRIVER_INFO_3W *dbuf;
2426  HANDLE hprn;
2427  DWORD needed;
2428 
2429  if(lppd->hDevMode || lppd->hDevNames) {
2430  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2432  return FALSE;
2433  }
2434  if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2435  WARN("Can't find default printer\n");
2437  return FALSE;
2438  }
2439 
2440  GetPrinterW(hprn, 2, NULL, 0, &needed);
2441  pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2442  GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2443 
2444  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
2445  dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2446  if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2447  ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2448  GetLastError(),debugstr_w(pbuf->pPrinterName));
2449  HeapFree(GetProcessHeap(), 0, dbuf);
2450  HeapFree(GetProcessHeap(), 0, pbuf);
2452  return FALSE;
2453  }
2454  ClosePrinter(hprn);
2455 
2457  dbuf->pDriverPath,
2458  pbuf->pPrinterName,
2459  pbuf->pPortName);
2460  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2461  pbuf->pDevMode->dmDriverExtra);
2462  ptr = GlobalLock(lppd->hDevMode);
2463  memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2464  pbuf->pDevMode->dmDriverExtra);
2465  GlobalUnlock(lppd->hDevMode);
2466  HeapFree(GetProcessHeap(), 0, pbuf);
2467  HeapFree(GetProcessHeap(), 0, dbuf);
2468  bRet = TRUE;
2469  } else {
2470  HGLOBAL hDlgTmpl;
2471  PRINT_PTRW *PrintStructures;
2472 
2473  /* load Dialog resources,
2474  * depending on Flags indicates Print32 or Print32_setup dialog
2475  */
2476  hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd);
2477  if (!hDlgTmpl) {
2479  return FALSE;
2480  }
2481  ptr = LockResource( hDlgTmpl );
2482  if (!ptr) {
2484  return FALSE;
2485  }
2486 
2487  PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2488  sizeof(PRINT_PTRW));
2489  PrintStructures->lpPrintDlg = lppd;
2490 
2491  /* and create & process the dialog .
2492  * -1 is failure, 0 is broken hwnd, everything else is ok.
2493  */
2496  bRet = (0<DialogBoxIndirectParamW(hInst, ptr, lppd->hwndOwner,
2497  PrintDlgProcW,
2498  (LPARAM)PrintStructures));
2499 
2500  if(bRet) {
2501  DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2502  PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo;
2503  DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo;
2504 
2505  if (lppd->hDevMode == 0) {
2506  TRACE(" No hDevMode yet... Need to create my own\n");
2508  lpdm->dmSize + lpdm->dmDriverExtra);
2509  } else {
2510  WORD locks;
2511  if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) {
2512  WARN("hDevMode has %d locks on it. Unlocking it now\n", locks);
2513  while(locks--) {
2514  GlobalUnlock(lppd->hDevMode);
2515  TRACE("Now got %d locks\n", locks);
2516  }
2517  }
2518  lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2519  lpdm->dmSize + lpdm->dmDriverExtra,
2520  GMEM_MOVEABLE);
2521  }
2522  lpdmReturn = GlobalLock(lppd->hDevMode);
2523  memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2524 
2525  if (lppd->hDevNames != 0) {
2526  WORD locks;
2527  if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) {
2528  WARN("hDevNames has %d locks on it. Unlocking it now\n", locks);
2529  while(locks--)
2530  GlobalUnlock(lppd->hDevNames);
2531  }
2532  }
2534  di->pDriverPath,
2535  pi->pPrinterName,
2536  pi->pPortName
2537  );
2538  GlobalUnlock(lppd->hDevMode);
2539  }
2540  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2541  HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2542  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2543  HeapFree(GetProcessHeap(), 0, PrintStructures);
2544  }
2545  if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2546  bRet = PRINTDLG_CreateDCW(lppd);
2547 
2548  TRACE("exit! (%d)\n", bRet);
2549  return bRet;
2550 }
2551 
2552 /***********************************************************************
2553  *
2554  * PageSetupDlg
2555  * rad1 - portrait
2556  * rad2 - landscape
2557  * cmb1 - printer select (not in standard dialog template)
2558  * cmb2 - paper size
2559  * cmb3 - source (tray?)
2560  * edt4 - border left
2561  * edt5 - border top
2562  * edt6 - border right
2563  * edt7 - border bottom
2564  * psh3 - "Printer..."
2565  */
2566 
2567 typedef struct
2568 {
2570  union
2571  {
2574  } u;
2575  HWND hDlg; /* Page Setup dialog handle */
2576  RECT rtDrawRect; /* Drawing rect for page */
2577 } pagesetup_data;
2578 
2580 {
2581  return data->u.dlgw->Flags;
2582 }
2583 
2584 static inline BOOL is_metric(const pagesetup_data *data)
2585 {
2587 }
2588 
2590 {
2591  if (is_metric(data))
2592  return 10 * size;
2593  else
2594  return 10 * size * 100 / 254;
2595 }
2596 
2598 {
2599  if (is_metric(data))
2600  return size * 254 / 100;
2601  else
2602  return size;
2603 }
2604 
2606 {
2607  static WCHAR sep;
2608 
2609  if(!sep)
2610  {
2611  WCHAR buf[] = {'.', 0};
2613  sep = buf[0];
2614  }
2615  return sep;
2616 }
2617 
2618 static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout)
2619 {
2620  static const WCHAR integer_fmt[] = {'%','d',0};
2621  static const WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0};
2622  static const WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0};
2623 
2624  /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */
2625 
2626  if (is_metric(data))
2627  {
2628  if(size % 100)
2629  wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100);
2630  else
2631  wsprintfW(strout, integer_fmt, size / 100);
2632  }
2633  else
2634  {
2635  if(size % 1000)
2636  wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000);
2637  else
2638  wsprintfW(strout, integer_fmt, size / 1000);
2639 
2640  }
2641 }
2642 
2643 static inline BOOL is_default_metric(void)
2644 {
2645  DWORD system;
2646  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER,
2647  (LPWSTR)&system, sizeof(system));
2648  return system == 0;
2649 }
2650 
2651 /**********************************************
2652  * rotate_rect
2653  * Cyclically permute the four members of rc
2654  * If sense is TRUE l -> t -> r -> b
2655  * otherwise l <- t <- r <- b
2656  */
2657 static inline void rotate_rect(RECT *rc, BOOL sense)
2658 {
2659  INT tmp;
2660  if(sense)
2661  {
2662  tmp = rc->bottom;
2663  rc->bottom = rc->right;
2664  rc->right = rc->top;
2665  rc->top = rc->left;
2666  rc->left = tmp;
2667  }
2668  else
2669  {
2670  tmp = rc->left;
2671  rc->left = rc->top;
2672  rc->top = rc->right;
2673  rc->right = rc->bottom;
2674  rc->bottom = tmp;
2675  }
2676 }
2677 
2679 {
2680  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2681 
2682  assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE);
2683 
2684  if(data->unicode)
2685  dm->u1.s1.dmOrientation = orient;
2686  else
2687  {
2688  DEVMODEA *dmA = (DEVMODEA *)dm;
2689  dmA->u1.s1.dmOrientation = orient;
2690  }
2691  GlobalUnlock(data->u.dlgw->hDevMode);
2692 }
2693 
2695 {
2696  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2697  WORD orient;
2698 
2699  if(data->unicode)
2700  orient = dm->u1.s1.dmOrientation;
2701  else
2702  {
2703  DEVMODEA *dmA = (DEVMODEA *)dm;
2704  orient = dmA->u1.s1.dmOrientation;
2705  }
2706  GlobalUnlock(data->u.dlgw->hDevMode);
2707  return orient;
2708 }
2709 
2711 {
2712  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2713 
2714  if(data->unicode)
2715  dm->u1.s1.dmPaperSize = paper;
2716  else
2717  {
2718  DEVMODEA *dmA = (DEVMODEA *)dm;
2719  dmA->u1.s1.dmPaperSize = paper;
2720  }
2721  GlobalUnlock(data->u.dlgw->hDevMode);
2722 }
2723 
2725 {
2726  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2727  WORD paper;
2728 
2729  if(data->unicode)
2730  paper = dm->u1.s1.dmPaperSize;
2731  else
2732  {
2733  DEVMODEA *dmA = (DEVMODEA *)dm;
2734  paper = dmA->u1.s1.dmPaperSize;
2735  }
2736  GlobalUnlock(data->u.dlgw->hDevMode);
2737  return paper;
2738 }
2739 
2741 {
2742  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2743 
2744  if(data->unicode)
2745  dm->u1.s1.dmDefaultSource = source;
2746  else
2747  {
2748  DEVMODEA *dmA = (DEVMODEA *)dm;
2749  dmA->u1.s1.dmDefaultSource = source;
2750  }
2751  GlobalUnlock(data->u.dlgw->hDevMode);
2752 }
2753 
2754 typedef enum
2755 {
2759 } devnames_name;
2760 
2761 
2763 {
2764  switch(which)
2765  {
2766  case devnames_driver_name: return dn->wDriverOffset;
2767  case devnames_device_name: return dn->wDeviceOffset;
2768  case devnames_output_name: return dn->wOutputOffset;
2769  }
2770  ERR("Shouldn't be here\n");
2771  return 0;
2772 }
2773 
2775 {
2776  DEVNAMES *dn;
2777  WCHAR *name;
2778 
2779  dn = GlobalLock(data->u.dlgw->hDevNames);
2780  if(data->unicode)
2781  name = strdupW((WCHAR *)dn + get_devname_offset(dn, which));
2782  else
2783  {
2784  int len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, NULL, 0);
2785  name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2786  MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, name, len);
2787  }
2788  GlobalUnlock(data->u.dlgw->hDevNames);
2789  return name;
2790 }
2791 
2793 {
2795 }
2796 
2798 {
2800 }
2801 
2803 {
2805 }
2806 
2808 {
2809  HeapFree(GetProcessHeap(), 0, name);
2810 }
2811 
2813 {
2814  DEVNAMES *dn;
2815  WCHAR def[256];
2816  DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len;
2817 
2818  if(data->unicode)
2819  {
2820  drv_len = (lstrlenW(drv) + 1) * sizeof(WCHAR);
2821  dev_len = (lstrlenW(devname) + 1) * sizeof(WCHAR);
2822  port_len = (lstrlenW(port) + 1) * sizeof(WCHAR);
2823  }
2824  else
2825  {
2826  drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL);
2827  dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL);
2828  port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL);
2829  }
2830  len += drv_len + dev_len + port_len;
2831 
2832  if(data->u.dlgw->hDevNames)
2833  data->u.dlgw->hDevNames = GlobalReAlloc(data->u.dlgw->hDevNames, len, GMEM_MOVEABLE);
2834  else
2835  data->u.dlgw->hDevNames = GlobalAlloc(GMEM_MOVEABLE, len);
2836 
2837  dn = GlobalLock(data->u.dlgw->hDevNames);
2838 
2839  if(data->unicode)
2840  {
2841  WCHAR *ptr = (WCHAR *)(dn + 1);
2842  len = sizeof(DEVNAMES) / sizeof(WCHAR);
2843  dn->wDriverOffset = len;
2844  lstrcpyW(ptr, drv);
2845  ptr += drv_len / sizeof(WCHAR);
2846  len += drv_len / sizeof(WCHAR);
2847  dn->wDeviceOffset = len;
2848  lstrcpyW(ptr, devname);
2849  ptr += dev_len / sizeof(WCHAR);
2850  len += dev_len / sizeof(WCHAR);
2851  dn->wOutputOffset = len;
2852  lstrcpyW(ptr, port);
2853  }
2854  else
2855  {
2856  char *ptr = (char *)(dn + 1);
2857  len = sizeof(DEVNAMES);
2858  dn->wDriverOffset = len;
2859  WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL);
2860  ptr += drv_len;
2861  len += drv_len;
2862  dn->wDeviceOffset = len;
2863  WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL);
2864  ptr += dev_len;
2865  len += dev_len;
2866  dn->wOutputOffset = len;
2867  WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL);
2868  }
2869 
2870  dn->wDefault = 0;
2871  len = ARRAY_SIZE(def);
2872  GetDefaultPrinterW(def, &len);
2873  if(!lstrcmpW(def, devname))
2874  dn->wDefault = 1;
2875 
2876  GlobalUnlock(data->u.dlgw->hDevNames);
2877 }
2878 
2880 {
2881  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2882  DEVMODEW *ret;
2883 
2884  if(data->unicode)
2885  {
2886  /* We make a copy even in the unicode case because the ptr
2887  may get passed back to us in pagesetup_set_devmode. */
2888  ret = HeapAlloc(GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra);
2889  memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra);
2890  }
2891  else
2893 
2894  GlobalUnlock(data->u.dlgw->hDevMode);
2895  return ret;
2896 }
2897 
2899 {
2900  HeapFree(GetProcessHeap(), 0, dm);
2901 }
2902 
2904 {
2905  DEVMODEA *dmA = NULL;
2906  void *src, *dst;
2907  DWORD size;
2908 
2909  if(data->unicode)
2910  {
2911  size = dm->dmSize + dm->dmDriverExtra;
2912  src = dm;
2913  }
2914  else
2915  {
2916  dmA = convert_to_devmodeA(dm);
2917  size = dmA->dmSize + dmA->dmDriverExtra;
2918  src = dmA;
2919  }
2920 
2921  if(data->u.dlgw->hDevMode)
2922  data->u.dlgw->hDevMode = GlobalReAlloc(data->u.dlgw->hDevMode, size,
2923  GMEM_MOVEABLE);
2924  else
2925  data->u.dlgw->hDevMode = GlobalAlloc(GMEM_MOVEABLE, size);
2926 
2927  dst = GlobalLock(data->u.dlgw->hDevMode);
2928  memcpy(dst, src, size);
2929  GlobalUnlock(data->u.dlgw->hDevMode);
2930  HeapFree(GetProcessHeap(), 0, dmA);
2931 }
2932 
2934 {
2935  return &data->u.dlgw->ptPaperSize;
2936 }
2937 
2939 {
2940  return &data->u.dlgw->rtMargin;
2941 }
2942 
2943 typedef enum
2944 {
2947 } hook_type;
2948 
2950 {
2951  switch(which)
2952  {
2953  case page_setup_hook: return data->u.dlgw->lpfnPageSetupHook;
2954  case page_paint_hook: return data->u.dlgw->lpfnPagePaintHook;
2955  }
2956  return NULL;
2957 }
2958 
2959 /* This should only be used in calls to hook procs so we return the ptr
2960  already cast to LPARAM */
2962 {
2963  return (LPARAM)data->u.dlgw;
2964 }
2965 
2966 static inline void swap_point(POINT *pt)
2967 {
2968  LONG tmp = pt->x;
2969  pt->x = pt->y;
2970  pt->y = tmp;
2971 }
2972 
2974 {
2975  DEVMODEW *dm;
2976  LPWSTR devname, portname;
2977  int i, num;
2978  WORD *words = NULL, paperword;
2979  POINT *points = NULL;
2980  BOOL retval = FALSE;
2981 
2983  devname = pagesetup_get_devname(data);
2984  portname = pagesetup_get_portname(data);
2985 
2986  num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm);
2987  if (num <= 0)
2988  {
2989  FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname));
2990  goto end;
2991  }
2992 
2993  words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD));
2994  points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT));
2995 
2996  if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm))
2997  {
2998  FIXME("Number of returned words is not %d\n", num);
2999  goto end;
3000  }
3001 
3002  if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm))
3003  {
3004  FIXME("Number of returned sizes is not %d\n", num);
3005  goto end;
3006  }
3007 
3008  paperword = pagesetup_get_papersize(data);
3009 
3010  for (i = 0; i < num; i++)
3011  if (words[i] == paperword)
3012  break;
3013 
3014  if (i == num)
3015  {
3016  FIXME("Papersize %d not found in list?\n", paperword);
3017  goto end;
3018  }
3019 
3020  /* this is _10ths_ of a millimeter */
3023 
3026 
3027  retval = TRUE;
3028 
3029 end:
3030  HeapFree(GetProcessHeap(), 0, words);
3032  pagesetup_release_a_devname(data, portname);
3035 
3036  return retval;
3037 }
3038 
3039 /**********************************************************************************************
3040  * pagesetup_change_printer
3041  *
3042  * Redefines hDevMode and hDevNames HANDLES and initialises it.
3043  *
3044  */
3046 {
3047  HANDLE hprn;
3048  DWORD needed;
3049  PRINTER_INFO_2W *prn_info = NULL;
3050  DRIVER_INFO_3W *drv_info = NULL;
3051  DEVMODEW *dm = NULL;
3052  BOOL retval = FALSE;
3053 
3054  if(!OpenPrinterW(name, &hprn, NULL))
3055  {
3056  ERR("Can't open printer %s\n", debugstr_w(name));
3057  goto end;
3058  }
3059 
3060  GetPrinterW(hprn, 2, NULL, 0, &needed);
3061  prn_info = HeapAlloc(GetProcessHeap(), 0, needed);
3062  GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed);
3063  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
3064  drv_info = HeapAlloc(GetProcessHeap(), 0, needed);
3065  if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed))
3066  {
3067  ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName));
3068  goto end;
3069  }
3070  ClosePrinter(hprn);
3071 
3072  needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
3073  if(needed == -1)
3074  {
3075  ERR("DocumentProperties fails on %s\n", debugstr_w(name));
3076  goto end;
3077  }
3078 
3079  dm = HeapAlloc(GetProcessHeap(), 0, needed);
3081 
3083  pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName,
3084  prn_info->pPortName);
3085 
3086  retval = TRUE;
3087 end:
3088  HeapFree(GetProcessHeap(), 0, dm);
3089  HeapFree(GetProcessHeap(), 0, prn_info);
3090  HeapFree(GetProcessHeap(), 0, drv_info);
3091  return retval;
3092 }
3093 
3094 /****************************************************************************************
3095  * pagesetup_init_combos
3096  *
3097  * Fills Printers, Paper and Source combos
3098  *
3099  */
3101 {
3102  DEVMODEW *dm;
3103  LPWSTR devname, portname;
3104 
3106  devname = pagesetup_get_devname(data);
3107  portname = pagesetup_get_portname(data);
3108 
3109  PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname);
3110  PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm);
3111  PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm);
3112 
3113  pagesetup_release_a_devname(data, portname);
3116 }
3117 
3118 
3119 /****************************************************************************************
3120  * pagesetup_change_printer_dialog
3121  *
3122  * Pops up another dialog that lets the user pick another printer.
3123  *
3124  * For now we display the PrintDlg, this should display a striped down version of it.
3125  */
3127 {
3128  PRINTDLGW prnt;
3129  LPWSTR drvname, devname, portname;
3130  DEVMODEW *tmp_dm, *dm;
3131 
3132  memset(&prnt, 0, sizeof(prnt));
3133  prnt.lStructSize = sizeof(prnt);
3134  prnt.Flags = 0;
3135  prnt.hwndOwner = hDlg;
3136 
3137  drvname = pagesetup_get_drvname(data);
3138  devname = pagesetup_get_devname(data);
3139  portname = pagesetup_get_portname(data);
3140  prnt.hDevNames = 0;
3141  PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname);
3142  pagesetup_release_a_devname(data, portname);
3145 
3146  tmp_dm = pagesetup_get_devmode(data);
3147  prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3148  dm = GlobalLock(prnt.hDevMode);
3149  memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3150  GlobalUnlock(prnt.hDevMode);
3152 
3153  if (PrintDlgW(&prnt))
3154  {
3155  DEVMODEW *dm = GlobalLock(prnt.hDevMode);
3156  DEVNAMES *dn = GlobalLock(prnt.hDevNames);
3157 
3159  (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset);
3161  GlobalUnlock(prnt.hDevNames);
3162  GlobalUnlock(prnt.hDevMode);
3163  pagesetup_init_combos(hDlg, data);
3164  }
3165 
3166  GlobalFree(prnt.hDevMode);
3167  GlobalFree(prnt.hDevNames);
3168 
3169 }
3170 
3171 /******************************************************************************************
3172  * pagesetup_change_preview
3173  *
3174  * Changes paper preview size / position
3175  *
3176  */
3178 {
3179  LONG width, height, x, y;
3180  RECT tmp;
3181  const int shadow = 4;
3182 
3184  {
3185  width = data->rtDrawRect.right - data->rtDrawRect.left;
3187  }
3188  else
3189  {
3190  height = data->rtDrawRect.bottom - data->rtDrawRect.top;
3192  }
3193  x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2;
3194  y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2;
3195  TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n",
3196  wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height);
3197 
3198  MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE);
3199  MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE);
3200  MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE);
3201 
3202  tmp = data->rtDrawRect;
3203  tmp.right += shadow;
3204  tmp.bottom += shadow;
3205  InvalidateRect(data->hDlg, &tmp, TRUE);
3206 }
3207 
3208 static inline LONG *element_from_margin_id(RECT *rc, WORD id)
3209 {
3210  switch(id)
3211  {
3212  case edt4: return &rc->left;
3213  case edt5: return &rc->top;
3214  case edt6: return &rc->right;
3215  case edt7: return &rc->bottom;
3216  }
3217  return NULL;
3218 }
3219 
3220 static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id)
3221 {
3222  WCHAR str[100];
3223  WORD idx;
3224 
3225  for(idx = edt4; idx <= edt7; idx++)
3226  {
3227  if(id == 0 || id == idx)
3228  {
3230  SetDlgItemTextW(hDlg, idx, str);
3231  }
3232  }
3233 }
3234 
3236 {
3237  switch (msg)
3238  {
3239  case EN_CHANGE:
3240  {
3241  WCHAR buf[10];
3242  LONG val = 0;
3244 
3245  if (GetDlgItemTextW(hDlg, id, buf, ARRAY_SIZE(buf)) != 0)
3246  {
3247  WCHAR *end;
3248  WCHAR decimal = get_decimal_sep();
3249 
3250  val = wcstol(buf, &end, 10);
3251  if(end != buf || *end == decimal)
3252  {
3253  int mult = is_metric(data) ? 100 : 1000;
3254  val *= mult;
3255  if(*end == decimal)
3256  {
3257  while(mult > 1)
3258  {
3259  end++;
3260  mult /= 10;
3261  if(iswdigit(*end))
3262  val += (*end - '0') * mult;
3263  else
3264  break;
3265  }
3266  }
3267  }
3268  }
3269  *value = val;
3270  return;
3271  }
3272 
3273  case EN_KILLFOCUS:
3274  update_margin_edits(hDlg, data, id);
3275  return;
3276  }
3277 }
3278 
3280 {
3281  WCHAR title[256];
3282 
3284  title, ARRAY_SIZE(title)))
3285  SetDlgItemTextW(hDlg, grp4, title);
3286 }
3287 
3289 {
3291  CheckRadioButton(hDlg, rad1, rad2, rad2);
3292  else
3293  CheckRadioButton(hDlg, rad1, rad2, rad1);
3294 }
3295 
3296 /****************************************************************************************
3297  * pagesetup_printer_properties
3298  *
3299  * Handle invocation of the 'Properties' button (not present in the default template).
3300  */
3302 {
3303  HANDLE hprn;
3304  LPWSTR devname;
3305  DEVMODEW *dm;
3306  LRESULT count;
3307  int i;
3308 
3309  devname = pagesetup_get_devname(data);
3310 
3311  if (!OpenPrinterW(devname, &hprn, NULL))
3312  {
3313  FIXME("Call to OpenPrinter did not succeed!\n");
3315  return;
3316  }
3317 
3319  DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
3323  ClosePrinter(hprn);
3324 
3325  /* Changing paper */
3328 
3329  /* Changing paper preview */
3331 
3332  /* Selecting paper in combo */
3333  count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0);
3334  if(count != CB_ERR)
3335  {
3336  WORD paperword = pagesetup_get_papersize(data);
3337  for(i = 0; i < count; i++)
3338  {
3339  if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) {
3340  SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0);
3341  break;
3342  }
3343  }
3344  }
3345 }
3346 
3347 /********************************************************************************
3348  * pagesetup_wm_command
3349  * process WM_COMMAND message for PageSetupDlg
3350  *
3351  * PARAMS
3352  * hDlg [in] Main dialog HANDLE
3353  * wParam [in] WM_COMMAND wParam
3354  * lParam [in] WM_COMMAND lParam
3355  * pda [in/out] ptr to PageSetupDataA
3356  */
3357 
3359 {
3360  WORD msg = HIWORD(wParam);
3361  WORD id = LOWORD(wParam);
3362 
3363  TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n",
3365  switch (id) {
3366  case IDOK:
3367  EndDialog(hDlg, TRUE);
3368  return TRUE ;
3369 
3370  case IDCANCEL:
3371  EndDialog(hDlg, FALSE);
3372  return FALSE ;
3373 
3374  case psh3: /* Printer... */
3376  return TRUE;
3377 
3378  case rad1: /* Portrait */
3379  case rad2: /* Landscape */
3382  {
3386  update_margin_edits(hDlg, data, 0);
3388  }
3389  break;
3390  case cmb1: /* Printer combo */
3391  if(msg == CBN_SELCHANGE)
3392  {
3393  WCHAR *name;
3394  INT index = SendDlgItemMessageW(hDlg, id, CB_GETCURSEL, 0, 0);
3396  name = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
3399  pagesetup_init_combos(hDlg, data);
3401  }
3402  break;
3403  case cmb2: /* Paper combo */
3404  if(msg == CBN_SELCHANGE)
3405  {
3406  DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA,
3407  SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0);
3408  if (paperword != CB_ERR)
3409  {
3410  pagesetup_set_papersize(data, paperword);
3413  } else
3414  FIXME("could not get dialog text for papersize cmbbox?\n");
3415  }
3416  break;
3417  case cmb3: /* Paper Source */
3418  if(msg == CBN_SELCHANGE)
3419  {
3421  SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0);
3423  }
3424  break;
3425  case psh2: /* Printer Properties button */
3427  break;
3428  case edt4:
3429  case edt5:
3430  case edt6:
3431  case edt7:
3432  margin_edit_notification(hDlg, data, msg, id);
3433  break;
3434  }
3436  return FALSE;
3437 }
3438 
3439 /***********************************************************************
3440  * default_page_paint_hook
3441  * Default hook paint procedure that receives WM_PSD_* messages from the dialog box
3442  * whenever the sample page is redrawn.
3443  */
3445  const pagesetup_data *data)
3446 {
3447  LPRECT lprc = (LPRECT) lParam;
3448  HDC hdc = (HDC) wParam;
3449  HPEN hpen, holdpen;
3450  LOGFONTW lf;
3451  HFONT hfont, holdfont;
3452  INT oldbkmode;
3453  TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER);
3454  /* Call user paint hook if enable */
3456  if (pagesetup_get_hook(data, page_paint_hook)(hwndDlg, uMsg, wParam, lParam))
3457  return TRUE;
3458 
3459  switch (uMsg) {
3460  /* LPPAGESETUPDLG in lParam */
3461  case WM_PSD_PAGESETUPDLG:
3462  /* Inform about the sample page rectangle */
3463  case WM_PSD_FULLPAGERECT:
3464  /* Inform about the margin rectangle */
3465  case WM_PSD_MINMARGINRECT:
3466  return FALSE;
3467 
3468  /* Draw dashed rectangle showing margins */
3469  case WM_PSD_MARGINRECT:
3471  holdpen = SelectObject(hdc, hpen);
3473  DeleteObject(SelectObject(hdc, holdpen));
3474  return TRUE;
3475  /* Draw the fake document */
3476  case WM_PSD_GREEKTEXTRECT:
3477  /* select a nice scalable font, because we want the text really small */
3478  SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
3479  lf.lfHeight = 6; /* value chosen based on visual effect */
3480  hfont = CreateFontIndirectW(&lf);
3481  holdfont = SelectObject(hdc, hfont);
3482 
3483  /* if text not loaded, then do so now */
3484  if (wszFakeDocumentText[0] == '\0')
3489 
3490  oldbkmode = SetBkMode(hdc, TRANSPARENT);
3492  SetBkMode(hdc, oldbkmode);
3493 
3494  DeleteObject(SelectObject(hdc, holdfont));
3495  return TRUE;
3496 
3497  /* Envelope stamp */
3498  case WM_PSD_ENVSTAMPRECT:
3499  /* Return address */
3500  case WM_PSD_YAFULLPAGERECT:
3501  FIXME("envelope/stamp is not implemented\n");
3502  return FALSE;
3503  default:
3504  FIXME("Unknown message %x\n",uMsg);
3505  return FALSE;
3506  }
3507  return TRUE;
3508 }
3509 
3510 /***********************************************************************
3511  * PagePaintProc
3512  * The main paint procedure for the PageSetupDlg function.
3513  * The Page Setup dialog box includes an image of a sample page that shows how
3514  * the user's selections affect the appearance of the printed output.
3515  * The image consists of a rectangle that represents the selected paper
3516  * or envelope type, with a dotted-line rectangle representing
3517  * the current margins, and partial (Greek text) characters
3518  * to show how text looks on the printed page.
3519  *
3520  * The following messages in the order sends to user hook procedure:
3521  * WM_PSD_PAGESETUPDLG Draw the contents of the sample page
3522  * WM_PSD_FULLPAGERECT Inform about the bounding rectangle
3523  * WM_PSD_MINMARGINRECT Inform about the margin rectangle (min margin?)
3524  * WM_PSD_MARGINRECT Draw the margin rectangle
3525  * WM_PSD_GREEKTEXTRECT Draw the Greek text inside the margin rectangle
3526  * If any of first three messages returns TRUE, painting done.
3527  *
3528  * PARAMS:
3529  * hWnd [in] Handle to the Page Setup dialog box
3530  * uMsg [in] Received message
3531  *
3532  * TODO:
3533  * WM_PSD_ENVSTAMPRECT Draw in the envelope-stamp rectangle (for envelopes only)
3534  * WM_PSD_YAFULLPAGERECT Draw the return address portion (for envelopes and other paper sizes)
3535  *
3536  * RETURNS:
3537  * FALSE if all done correctly
3538  *
3539  */
3540 
3541 
3542 static LRESULT CALLBACK
3544 {
3545  PAINTSTRUCT ps;
3546  RECT rcClient, rcMargin;
3547  HPEN hpen, holdpen;
3548  HDC hdc;
3549  HBRUSH hbrush, holdbrush;
3551  int papersize=0, orientation=0; /* FIXME: set these values for the user paint hook */
3552  double scalx, scaly;
3553 
3554  if (uMsg != WM_PAINT)
3556 
3557  /* Processing WM_PAINT message */
3559  if (!data) {
3560  WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3561  return FALSE;
3562  }
3563  if (default_page_paint_hook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation),
3565  return FALSE;
3566 
3567  hdc = BeginPaint(hWnd, &ps);
3568  GetClientRect(hWnd, &rcClient);
3569 
3570  scalx = rcClient.right / (double)pagesetup_get_papersize_pt(data)->x;
3571  scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y;
3572  rcMargin = rcClient;
3573 
3574  rcMargin.left += pagesetup_get_margin_rect(data)->left * scalx;
3575  rcMargin.top += pagesetup_get_margin_rect(data)->top * scaly;
3576  rcMargin.right -= pagesetup_get_margin_rect(data)->right * scalx;
3577  rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly;
3578 
3579  /* if the space is too small then we make sure to not draw anything */
3580  rcMargin.left = min(rcMargin.left, rcMargin.right);
3581  rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3582 
3585  {
3586  /* fill background */
3588  FillRect(hdc, &rcClient, hbrush);
3589  holdbrush = SelectObject(hdc, hbrush);
3590 
3592  holdpen = SelectObject(hdc, hpen);
3593 
3594  /* paint left edge */
3595  MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3596  LineTo(hdc, rcClient.left, rcClient.bottom-1);
3597 
3598  /* paint top edge */
3599  MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3600  LineTo(hdc, rcClient.right, rcClient.top);
3601 
3604 
3605  /* paint right edge */
3606  MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL);
3607  LineTo(hdc, rcClient.right-1, rcClient.bottom);
3608 
3609  /* paint bottom edge */
3610  MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL);
3611  LineTo(hdc, rcClient.right, rcClient.bottom-1);
3612 
3613  DeleteObject(SelectObject(hdc, holdpen));
3614  DeleteObject(SelectObject(hdc, holdbrush));
3615 
3617 
3618  /* give text a bit of a space from the frame */
3619  InflateRect(&rcMargin, -2, -2);
3620 
3621  /* if the space is too small then we make sure to not draw anything */
3622  rcMargin.left = min(rcMargin.left, rcMargin.right);
3623  rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3624 
3626  }
3627 
3628  EndPaint(hWnd, &ps);
3629  return FALSE;
3630 }
3631 
3632 /*******************************************************
3633  * The margin edit controls are subclassed to filter
3634  * anything other than numbers and the decimal separator.
3635  */
3637 {
3638  if (msg == WM_CHAR)
3639  {
3640  WCHAR decimal = get_decimal_sep();
3641  WCHAR wc = (WCHAR)wparam;
3642  if(!iswdigit(wc) && wc != decimal && wc != VK_BACK) return 0;
3643  }
3645 }
3646 
3647 static void subclass_margin_edits(HWND hDlg)
3648 {
3649  int id;
3650  WNDPROC old_proc;
3651 
3652  for(id = edt4; id <= edt7; id++)
3653  {
3655  GWLP_WNDPROC,
3658  }
3659 }
3660 
3661 /***********************************************************************
3662  * pagesetup_dlg_proc
3663  *
3664  * Message handler for PageSetupDlg
3665  */
3667 {
3669  INT_PTR res = FALSE;
3670  HWND hDrawWnd;
3671 
3672  if (uMsg == WM_INITDIALOG) { /*Init dialog*/
3673  data = (pagesetup_data *)lParam;
3674  data->hDlg = hDlg;
3675 
3676  hDrawWnd = GetDlgItem(hDlg, rct1);
3677  TRACE("set property to %p\n", data);
3679  SetPropW(hDrawWnd, pagesetupdlg_prop, data);
3680  GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */
3681  MapWindowPoints( 0, hDlg, (LPPOINT)&data->rtDrawRect, 2 );
3683  hDrawWnd,
3684  GWLP_WNDPROC,
3686 
3687  /* FIXME: Paint hook. Must it be at begin of initialization or at end? */
3688  res = TRUE;
3690  {
3691  if (!pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam,
3693  FIXME("Setup page hook failed?\n");
3694  }
3695 
3696  /* if printer button disabled */
3698  EnableWindow(GetDlgItem(hDlg, psh3), FALSE);
3699  /* if margin edit boxes disabled */
3701  {
3702  EnableWindow(GetDlgItem(hDlg, edt4), FALSE);
3703  EnableWindow(GetDlgItem(hDlg, edt5), FALSE);
3704  EnableWindow(GetDlgItem(hDlg, edt6), FALSE);
3705  EnableWindow(GetDlgItem(hDlg, edt7), FALSE);
3706  }
3707 
3708  /* Set orientation radiobuttons properly */
3710 
3711  /* if orientation disabled */
3713  {
3716  }
3717 
3718  /* We fill them out enabled or not */
3720  {
3721  /* default is 1 inch */
3724  }
3725  update_margin_edits(hDlg, data, 0);
3726  subclass_margin_edits(hDlg);
3728 
3729  /* if paper disabled */
3731  {
3734  }
3735 
3736  /* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */
3737  pagesetup_init_combos(hDlg, data);
3739  pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */
3740 
3741  /* Drawing paper prev */
3743  return TRUE;
3744  } else {
3745  data = GetPropW(hDlg, pagesetupdlg_prop);
3746  if (!data)
3747  {
3748  WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3749  return FALSE;
3750  }
3752  {
3754  if (res) return res;
3755  }
3756  }
3757  switch (uMsg) {
3758  case WM_COMMAND:
3759  return pagesetup_wm_command(hDlg, wParam, lParam, data);
3760  }
3761  return FALSE;
3762 }
3763 
3765 {
3766  WCHAR *name = NULL;
3767  DWORD len = 0;
3768 
3770  if(len)
3771  {
3772  name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3774  }
3775  return name;
3776 }
3777 
3779 {
3780  if(TRACE_ON(commdlg))
3781  {
3782  char flagstr[1000] = "";
3783  const struct pd_flags *pflag = psd_flags;
3784  for( ; pflag->name; pflag++)
3785  {
3786  if(pagesetup_get_flags(data) & pflag->flag)
3787  {
3788  strcat(flagstr, pflag->name);
3789  strcat(flagstr, "|");
3790  }
3791  }
3792  TRACE("%s: (%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
3793  "hinst %p, flags %08x (%s)\n",
3794  data->unicode ? "unicode" : "ansi",
3795  data->u.dlgw, data->u.dlgw->hwndOwner, data->u.dlgw->hDevMode,
3796  data->u.dlgw->hDevNames, data->u.dlgw->hInstance,
3797  pagesetup_get_flags(data), flagstr);
3798  }
3799 }
3800 
3802 {
3803  HRSRC res;
3804  HGLOBAL tmpl_handle;
3805 
3807  {
3808  tmpl_handle = data->u.dlgw->hPageSetupTemplate;
3809  }
3811  {
3812  if(data->unicode)
3813  res = FindResourceW(data->u.dlgw->hInstance,
3814  data->u.dlgw->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG);
3815  else
3816  res = FindResourceA(data->u.dlga->hInstance,
3817  data->u.dlga->lpPageSetupTemplateName, (LPSTR)RT_DIALOG);
3818  tmpl_handle = LoadResource(data->u.dlgw->hInstance, res);
3819  }
3820  else
3821  {
3823  (LPWSTR)RT_DIALOG);
3824  tmpl_handle = LoadResource(COMDLG32_hInstance, res);
3825  }
3826  return LockResource(tmpl_handle);
3827 }
3828 
3830 {
3831  BOOL ret;
3832  void *tmpl;
3833 
3835  {
3837  return FALSE;
3838  }
3839 
3841 
3842  if(data->u.dlgw->lStructSize != sizeof(PAGESETUPDLGW))
3843  {
3845  return FALSE;
3846  }
3847 
3850  {
3852  return FALSE;
3853  }
3854 
3856  data->u.dlgw->Flags |= is_default_metric() ?
3858 
3859  if (!data->u.dlgw->hDevMode || !data->u.dlgw->hDevNames)
3860  {
3861  WCHAR *def = get_default_printer();
3862  if(!def)
3863  {
3865  {
3866  WCHAR errstr[256];
3868  MessageBoxW(data->u.dlgw->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR);
3869  }
3871  return FALSE;
3872  }
3874  HeapFree(GetProcessHeap(), 0, def);
3875  }
3876 
3878  {
3880  return TRUE;
3881  }
3882 
3883  tmpl = pagesetup_get_template(data);
3884 
3885  ret = DialogBoxIndirectParamW(data->u.dlgw->hInstance, tmpl,
3886  data->u.dlgw->hwndOwner,
3888  return ret;
3889 }
3890 
3891 /***********************************************************************
3892  * PageSetupDlgA (COMDLG32.@)
3893  *
3894  * Displays the PAGE SETUP dialog box, which enables the user to specify
3895  * specific properties of a printed page such as
3896  * size, source, orientation and the width of the page margins.
3897  *
3898  * PARAMS
3899  * setupdlg [IO] PAGESETUPDLGA struct
3900  *
3901  * RETURNS
3902  * TRUE if the user pressed the OK button
3903  * FALSE if the user cancelled the window or an error occurred
3904  *
3905  * NOTES
3906  * The values of hDevMode and hDevNames are filled on output and can be
3907  * changed in PAGESETUPDLG when they are passed in PageSetupDlg.
3908  *
3909  */
3911 {
3913 
3914  data.unicode = FALSE;
3915  data.u.dlga = setupdlg;
3916 
3917  return pagesetup_common(&data);
3918 }
3919 
3920 /***********************************************************************
3921  * PageSetupDlgW (COMDLG32.@)
3922  *
3923  * See PageSetupDlgA.
3924  */
3926 {
3928 
3929  data.unicode = TRUE;
3930  data.u.dlgw = setupdlg;
3931 
3932  return pagesetup_common(&data);
3933 }
3934 
3935 static void pdlgex_to_pdlg(const PRINTDLGEXW *pdlgex, PRINTDLGW *pdlg)
3936 {
3937  pdlg->lStructSize = sizeof(*pdlg);
3938  pdlg->hwndOwner = pdlgex->hwndOwner;
3939  pdlg->hDevMode = pdlgex->hDevMode;
3940  pdlg->hDevNames = pdlgex->hDevNames;
3941  pdlg->hDC = pdlgex->hDC;
3942  pdlg->Flags = pdlgex->Flags;
3943  if ((pdlgex->Flags & PD_NOPAGENUMS) || !pdlgex->nPageRanges || !pdlgex->lpPageRanges)
3944  {
3945  pdlg->nFromPage = 0;
3946  pdlg->nToPage = 65534;
3947  }
3948  else
3949  {
3950  pdlg->nFromPage = pdlgex->lpPageRanges[0].nFromPage;
3951  pdlg->nToPage = pdlgex->lpPageRanges[0].nToPage;
3952  }
3953  pdlg->nMinPage = pdlgex->nMinPage;
3954  pdlg->nMaxPage = pdlgex->nMaxPage;
3955  pdlg->nCopies = pdlgex->nCopies;
3956  pdlg->hInstance = pdlgex->hInstance;
3957  pdlg->lCustData = 0;
3958  pdlg->lpfnPrintHook = NULL;
3959  pdlg->lpfnSetupHook = NULL;
3960  pdlg->lpPrintTemplateName = pdlgex->lpPrintTemplateName;
3961  pdlg->lpSetupTemplateName = NULL;
3962  pdlg->hPrintTemplate = NULL;
3963  pdlg->hSetupTemplate = NULL;
3964 }
3965 
3966 /* Only copy fields that are supposed to be changed. */
3967 static void pdlg_to_pdlgex(const PRINTDLGW *pdlg, PRINTDLGEXW *pdlgex)
3968 {
3969  pdlgex->hDevMode = pdlg->hDevMode;
3970  pdlgex->hDevNames = pdlg->hDevNames;
3971  pdlgex->hDC = pdlg->hDC;
3972  if (!(pdlgex->Flags & PD_NOPAGENUMS) && pdlgex->nPageRanges && pdlgex->lpPageRanges)
3973  {
3974  pdlgex->lpPageRanges[0].nFromPage = pdlg->nFromPage;
3975  pdlgex->lpPageRanges[0].nToPage = pdlg->nToPage;
3976  }
3977  pdlgex->nMinPage = pdlg->nMinPage;
3978  pdlgex->nMaxPage = pdlg->nMaxPage;
3979  pdlgex->nCopies = pdlg->nCopies;
3980 }
3981 
3983 {
3984  IPrintDialogCallback *callback;
3986 };
3987 
3989 {
3990  if (msg == WM_INITDIALOG)
3991  {
3992  PRINTDLGW *pd = (PRINTDLGW *)lp;
3993  struct callback_data *cb = (struct callback_data *)pd->lCustData;
3994 
3995  if (cb->callback)
3996  {
3997  cb->callback->lpVtbl->SelectionChange(cb->callback);
3998  cb->callback->lpVtbl->InitDone(cb->callback);
3999  }
4000  }
4001  else
4002  {
4003 /* FIXME: store interface pointer somewhere in window properties and call it
4004  HRESULT hres;
4005  cb->callback->lpVtbl->HandleMessage(cb->callback, hwnd, msg, wp, lp, &hres);
4006 */
4007  }
4008 
4009  return 0;
4010 }
4011 
4012 /***********************************************************************
4013  * PrintDlgExA (COMDLG32.@)
4014  *
4015  * See PrintDlgExW.
4016  *
4017  * BUGS
4018  * Only a Stub
4019  *
4020  */
4021 HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd)
4022 {
4024  DRIVER_INFO_3A *dbuf;
4025  DEVMODEA *dm;
4026  HRESULT hr = S_OK;
4027  HANDLE hprn;
4028 
4029  if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA)))
4030  return E_INVALIDARG;
4031 
4032  if (!IsWindow(lppd->hwndOwner))
4033  return E_HANDLE;
4034 
4035  if (lppd->nStartPage != START_PAGE_GENERAL)
4036  {
4037  if (!lppd->nPropertyPages)
4038  return E_INVALIDARG;
4039 
4040  FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages);
4041  }
4042 
4043  /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */
4044  if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges))
4045  {
4046  return E_INVALIDARG;
4047  }
4048 
4049  if (lppd->Flags & PD_RETURNDEFAULT)
4050  {
4051  if (lppd->hDevMode || lppd->hDevNames)
4052  {
4053  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
4055  return E_INVALIDARG;
4056  }
4057  if (!PRINTDLG_OpenDefaultPrinter(&hprn))
4058  {
4059  WARN("Can't find default printer\n");
4061  return E_FAIL;
4062  }
4063 
4064  pbuf = get_printer_infoA(hprn);
4065  if (!pbuf)
4066  {
4067  ClosePrinter(hprn);
4068  return E_FAIL;
4069  }
4070 
4071  dbuf = get_driver_infoA(hprn);
4072  if (!dbuf)
4073  {
4074  HeapFree(GetProcessHeap(), 0, pbuf);
4076  ClosePrinter(hprn);
4077  return E_FAIL;
4078  }
4079  dm = pbuf->pDevMode;
4080  }
4081  else
4082  {
4083  PRINTDLGA pdlg;
4084  struct callback_data cb_data = { 0 };
4085 
4086  FIXME("(%p) semi-stub\n", lppd);
4087 
4088  if (lppd->lpCallback)
4089  {
4090  IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback);
4091  IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object);
4092  }
4093 
4094  /*
4095  * PRINTDLGEXA/W and PRINTDLGA/W layout is the same for A and W variants.
4096  */
4097  pdlgex_to_pdlg((const PRINTDLGEXW *)lppd, (PRINTDLGW *)&pdlg);
4098  pdlg.Flags |= PD_ENABLEPRINTHOOK;
4100  pdlg.lCustData = (LPARAM)&cb_data;
4101 
4102  if (PrintDlgA(&pdlg))
4103  {
4104  pdlg_to_pdlgex((const PRINTDLGW *)&pdlg, (PRINTDLGEXW *)lppd);
4105  lppd->dwResultAction = PD_RESULT_PRINT;
4106  }
4107  else
4108  lppd->dwResultAction = PD_RESULT_CANCEL;
4109 
4110  if (cb_data.callback)
4111  cb_data.callback->lpVtbl->Release(cb_data.callback);
4112  if (cb_data.object)
4113  cb_data.object->lpVtbl->Release(cb_data.object);
4114 
4115  return S_OK;
4116  }
4117 
4118  ClosePrinter(hprn);
4119 
4120  PRINTDLG_CreateDevNames(&(lppd->hDevNames), dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName);
4121  if (!lppd->hDevNames)
4122  hr = E_FAIL;
4123 
4124  lppd->hDevMode = update_devmode_handleA(lppd->hDevMode, dm);
4125  if (hr == S_OK && lppd->hDevMode) {
4126  if (lppd->Flags & PD_RETURNDC) {
4127  lppd->hDC = CreateDCA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4128  if (!lppd->hDC)
4129  hr = E_FAIL;
4130  }
4131  else if (lppd->Flags & PD_RETURNIC) {
4132  lppd->hDC = CreateICA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4133  if (!lppd->hDC)
4134  hr = E_FAIL;
4135  }
4136  }
4137  else
4138  hr = E_FAIL;
4139 
4140  HeapFree(GetProcessHeap(), 0, pbuf);
4141  HeapFree(GetProcessHeap(), 0, dbuf);
4142 
4143  return hr;