ReactOS  0.4.15-dev-5097-g328cc41
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 #ifdef __REACTOS__
464 static const CHAR cDriverName[] = "winspool";
465 static const WCHAR wDriverName[] = L"winspool";
466 #endif
467 
468 /***********************************************************************
469  * PRINTDLG_CreateDevNames [internal]
470  *
471  *
472  * creates a DevNames structure.
473  *
474  * (NB. when we handle unicode the offsets will be in wchars).
475  */
476 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName,
477  const char* DeviceName, const char* OutputPort)
478 {
479  long size;
480  char* pDevNamesSpace;
481  char* pTempPtr;
482  LPDEVNAMES lpDevNames;
483  char buf[260];
485  const char *p;
486 
487  p = strrchr( DeviceDriverName, '\\' );
488  if (p) DeviceDriverName = p + 1;
489 #ifndef __REACTOS__
490  size = strlen(DeviceDriverName) + 1
491 #else
492  size = strlen(cDriverName) + 1
493 #endif
494  + strlen(DeviceName) + 1
495  + strlen(OutputPort) + 1
496  + sizeof(DEVNAMES);
497 
498  if(*hmem)
499  *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
500  else
501  *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
502  if (*hmem == 0)
503  return FALSE;
504 
505  pDevNamesSpace = GlobalLock(*hmem);
506  lpDevNames = (LPDEVNAMES) pDevNamesSpace;
507 
508  pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
509 #ifndef __REACTOS__
510  strcpy(pTempPtr, DeviceDriverName);
511 #else
512  strcpy(pTempPtr, cDriverName);
513 #endif
514  lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
515 
516  pTempPtr += strlen(DeviceDriverName) + 1;
517  strcpy(pTempPtr, DeviceName);
518  lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
519 
520  pTempPtr += strlen(DeviceName) + 1;
521  strcpy(pTempPtr, OutputPort);
522  lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
523 
525  lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
526  GlobalUnlock(*hmem);
527  return TRUE;
528 }
529 
530 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName,
531  LPCWSTR DeviceName, LPCWSTR OutputPort)
532 {
533  long size;
534  LPWSTR pDevNamesSpace;
535  LPWSTR pTempPtr;
536  LPDEVNAMES lpDevNames;
537  WCHAR bufW[260];
538  DWORD dwBufLen = ARRAY_SIZE(bufW);
539  const WCHAR *p;
540 
541  p = wcsrchr( DeviceDriverName, '\\' );
542  if (p) DeviceDriverName = p + 1;
543 #ifndef __REACTOS__
544  size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2
545 #else
546  size = sizeof(WCHAR)*lstrlenW(wDriverName) + 2
547 #endif
548  + sizeof(WCHAR)*lstrlenW(DeviceName) + 2
549  + sizeof(WCHAR)*lstrlenW(OutputPort) + 2
550  + sizeof(DEVNAMES);
551 
552  if(*hmem)
553  *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
554  else
555  *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
556  if (*hmem == 0)
557  return FALSE;
558 
559  pDevNamesSpace = GlobalLock(*hmem);
560  lpDevNames = (LPDEVNAMES) pDevNamesSpace;
561 
562  pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1);
563 #ifndef __REACTOS__
564  lstrcpyW(pTempPtr, DeviceDriverName);
565 #else
566  lstrcpyW(pTempPtr, wDriverName);
567 #endif
568  lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
569 
570  pTempPtr += lstrlenW(DeviceDriverName) + 1;
571  lstrcpyW(pTempPtr, DeviceName);
572  lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
573 
574  pTempPtr += lstrlenW(DeviceName) + 1;
575  lstrcpyW(pTempPtr, OutputPort);
576  lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
577 
579  lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0;
580  GlobalUnlock(*hmem);
581  return TRUE;
582 }
583 
584 /***********************************************************************
585  * PRINTDLG_UpdatePrintDlg [internal]
586  *
587  *
588  * updates the PrintDlg structure for return values.
589  *
590  * RETURNS
591  * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
592  * TRUE if successful.
593  */
595  PRINT_PTRA* PrintStructures)
596 {
597  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
598  PDEVMODEA lpdm = PrintStructures->lpDevMode;
599  LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
600 
601 
602  if(!lpdm) {
603  FIXME("No lpdm ptr?\n");
604  return FALSE;
605  }
606 
607 
608  if(!(lppd->Flags & PD_PRINTSETUP)) {
609  /* check whether nFromPage and nToPage are within range defined by
610  * nMinPage and nMaxPage
611  */
612  if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
613  WORD nToPage;
614  WORD nFromPage;
615  BOOL translated;
616  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
617  nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
618 
619  /* if no ToPage value is entered, use the FromPage value */
620  if(!translated) nToPage = nFromPage;
621 
622  if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
623  nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
624  WCHAR resourcestr[256];
625  WCHAR resultstr[256];
627  wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
628  LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255);
629  MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING);
630  return FALSE;
631  }
632  lppd->nFromPage = nFromPage;
633  lppd->nToPage = nToPage;
634  lppd->Flags |= PD_PAGENUMS;
635  }
636  else
637  lppd->Flags &= ~PD_PAGENUMS;
638 
639  if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
640  lppd->Flags |= PD_SELECTION;
641  else
642  lppd->Flags &= ~PD_SELECTION;
643 
644  if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
645  static char file[] = "FILE:";
646  lppd->Flags |= PD_PRINTTOFILE;
647  pi->pPortName = file;
648  }
649 
650  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
651  FIXME("Collate lppd not yet implemented as output\n");
652  }
653 
654  /* set PD_Collate and nCopies */
655  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
656  /* The application doesn't support multiple copies or collate...
657  */
658  lppd->Flags &= ~PD_COLLATE;
659  lppd->nCopies = 1;
660  /* if the printer driver supports it... store info there
661  * otherwise no collate & multiple copies !
662  */
663  if (lpdm->dmFields & DM_COLLATE)
664  lpdm->dmCollate =
665  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
666  if (lpdm->dmFields & DM_COPIES)
667  lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
668  } else {
669  /* Application is responsible for multiple copies */
670  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
671  lppd->Flags |= PD_COLLATE;
672  else
673  lppd->Flags &= ~PD_COLLATE;
674  lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
675  /* multiple copies already included in the document. Driver must print only one copy */
676  lpdm->u1.s1.dmCopies = 1;
677  }
678 
679  /* Print quality, PrintDlg16 */
680  if(GetDlgItem(hDlg, cmb1))
681  {
682  HWND hQuality = GetDlgItem(hDlg, cmb1);
683  int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0);
684 
685  if(Sel != CB_ERR)
686  {
687  LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0);
689  lpdm->u1.s1.dmPrintQuality = LOWORD(dpi);
690  lpdm->dmYResolution = HIWORD(dpi);
691  }
692  }
693  }
694  return TRUE;
695 }
696 
698  PRINT_PTRW* PrintStructures)
699 {
700  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
701  PDEVMODEW lpdm = PrintStructures->lpDevMode;
702  LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo;
703 
704 
705  if(!lpdm) {
706  FIXME("No lpdm ptr?\n");
707  return FALSE;
708  }
709 
710 
711  if(!(lppd->Flags & PD_PRINTSETUP)) {
712  /* check whether nFromPage and nToPage are within range defined by
713  * nMinPage and nMaxPage
714  */
715  if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
716  WORD nToPage;
717  WORD nFromPage;
718  BOOL translated;
719  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
720  nToPage = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
721 
722  /* if no ToPage value is entered, use the FromPage value */
723  if(!translated) nToPage = nFromPage;
724 
725  if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
726  nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
727  WCHAR resourcestr[256];
728  WCHAR resultstr[256];
729  DWORD_PTR args[2];
731  resourcestr, 255);
732  args[0] = lppd->nMinPage;
733  args[1] = lppd->nMaxPage;
735  resourcestr, 0, 0, resultstr,
736  ARRAY_SIZE(resultstr),
737  (__ms_va_list*)args);
739  resourcestr, 255);
740  MessageBoxW(hDlg, resultstr, resourcestr,
742  return FALSE;
743  }
744  lppd->nFromPage = nFromPage;
745  lppd->nToPage = nToPage;
746  lppd->Flags |= PD_PAGENUMS;
747  }
748  else
749  lppd->Flags &= ~PD_PAGENUMS;
750 
751  if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
752  lppd->Flags |= PD_SELECTION;
753  else
754  lppd->Flags &= ~PD_SELECTION;
755 
756  if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
757  static WCHAR file[] = {'F','I','L','E',':',0};
758  lppd->Flags |= PD_PRINTTOFILE;
759  pi->pPortName = file;
760  }
761 
762  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
763  FIXME("Collate lppd not yet implemented as output\n");
764  }
765 
766  /* set PD_Collate and nCopies */
767  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
768  /* The application doesn't support multiple copies or collate...
769  */
770  lppd->Flags &= ~PD_COLLATE;
771  lppd->nCopies = 1;
772  /* if the printer driver supports it... store info there
773  * otherwise no collate & multiple copies !
774  */
775  if (lpdm->dmFields & DM_COLLATE)
776  lpdm->dmCollate =
777  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
778  if (lpdm->dmFields & DM_COPIES)
779  lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
780  } else {
781  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
782  lppd->Flags |= PD_COLLATE;
783  else
784  lppd->Flags &= ~PD_COLLATE;
785  lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
786  }
787  }
788  return TRUE;
789 }
790 
791 /************************************************************************
792  * PRINTDLG_SetUpPaperComboBox
793  *
794  * Initialize either the papersize or inputslot combos of the Printer Setup
795  * dialog. We store the associated word (eg DMPAPER_A4) as the item data.
796  * We also try to re-select the old selection.
797  */
799  int nIDComboBox,
800  char* PrinterName,
801  char* PortName,
802  LPDEVMODEA dm)
803 {
804  int i;
805  int NrOfEntries;
806  char* Names;
807  WORD* Words;
808  DWORD Sel, old_Sel;
809  WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
810  int NamesSize;
811  int fwCapability_Names;
812  int fwCapability_Words;
813 
814  TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox);
815 
816  /* query the dialog box for the current selected value */
817  Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
818  if(Sel != CB_ERR) {
819  /* we enter here only if a different printer is selected after
820  * the Print Setup dialog is opened. The current settings are
821  * stored into the newly selected printer.
822  */
823  oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA,
824  Sel, 0);
825  if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
826  oldWord = 0; /* There's no point in trying to keep custom
827  paper / bin sizes across printers */
828  }
829 
830  if (dm)
831  newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
832 
833  if (nIDComboBox == cmb2) {
834  NamesSize = 64;
835  fwCapability_Names = DC_PAPERNAMES;
836  fwCapability_Words = DC_PAPERS;
837  } else {
838  nIDComboBox = cmb3;
839  NamesSize = 24;
840  fwCapability_Names = DC_BINNAMES;
841  fwCapability_Words = DC_BINS;
842  }
843 
844  NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
845  fwCapability_Names, NULL, dm);
846  if (NrOfEntries == 0)
847  WARN("no Name Entries found!\n");
848  else if (NrOfEntries < 0)
849  return FALSE;
850 
851  if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
852  != NrOfEntries) {
853  ERR("Number of caps is different\n");
854  NrOfEntries = 0;
855  }
856 
857  Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize);
858  Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
859  DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Names, Names, dm);
860  NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
861  fwCapability_Words, (LPSTR)Words, dm);
862 
863  /* reset any current content in the combobox */
864  SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
865 
866  /* store new content */
867  for (i = 0; i < NrOfEntries; i++) {
868  DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
869  (LPARAM)(&Names[i*NamesSize]) );
870  SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
871  Words[i]);
872  }
873 
874  /* Look for old selection or the new default.
875  Can't do this is previous loop since item order will change as more items are added */
876  Sel = 0;
877  old_Sel = NrOfEntries;
878  for (i = 0; i < NrOfEntries; i++) {
879  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
880  oldWord) {
881  old_Sel = i;
882  break;
883  }
884  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
885  Sel = i;
886  }
887 
888  if(old_Sel < NrOfEntries)
889  {
890  if (dm)
891  {
892  if(nIDComboBox == cmb2)
893  dm->u1.s1.dmPaperSize = oldWord;
894  else
895  dm->u1.s1.dmDefaultSource = oldWord;
896  }
897  Sel = old_Sel;
898  }
899 
900  SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
901 
902  HeapFree(GetProcessHeap(),0,Words);
904  return TRUE;
905 }
906 
908  int nIDComboBox,
909  const WCHAR* PrinterName,
910  const WCHAR* PortName,
911  LPDEVMODEW dm)
912 {
913  int i;
914  int NrOfEntries;
915  WCHAR* Names;
916  WORD* Words;
917  DWORD Sel, old_Sel;
918  WORD oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
919  int NamesSize;
920  int fwCapability_Names;
921  int fwCapability_Words;
922 
923  TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox);
924 
925  /* query the dialog box for the current selected value */
926  Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
927  if(Sel != CB_ERR) {
928  /* we enter here only if a different printer is selected after
929  * the Print Setup dialog is opened. The current settings are
930  * stored into the newly selected printer.
931  */
932  oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA,
933  Sel, 0);
934 
935  if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
936  oldWord = 0; /* There's no point in trying to keep custom
937  paper / bin sizes across printers */
938  }
939 
940  if (dm)
941  newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
942 
943  if (nIDComboBox == cmb2) {
944  NamesSize = 64;
945  fwCapability_Names = DC_PAPERNAMES;
946  fwCapability_Words = DC_PAPERS;
947  } else {
948  nIDComboBox = cmb3;
949  NamesSize = 24;
950  fwCapability_Names = DC_BINNAMES;
951  fwCapability_Words = DC_BINS;
952  }
953 
954  NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
955  fwCapability_Names, NULL, dm);
956  if (NrOfEntries == 0)
957  WARN("no Name Entries found!\n");
958  else if (NrOfEntries < 0)
959  return FALSE;
960 
961  if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm)
962  != NrOfEntries) {
963  ERR("Number of caps is different\n");
964  NrOfEntries = 0;
965  }
966 
967  Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize);
968  Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
969  DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Names, Names, dm);
970  NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
971  fwCapability_Words, Words, dm);
972 
973  /* reset any current content in the combobox */
974  SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
975 
976  /* store new content */
977  for (i = 0; i < NrOfEntries; i++) {
978  DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0,
979  (LPARAM)(&Names[i*NamesSize]) );
980  SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
981  Words[i]);
982  }
983 
984  /* Look for old selection or the new default.
985  Can't do this is previous loop since item order will change as more items are added */
986  Sel = 0;
987  old_Sel = NrOfEntries;
988  for (i = 0; i < NrOfEntries; i++) {
989  if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
990  oldWord) {
991  old_Sel = i;
992  break;
993  }
994  if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
995  Sel = i;
996  }
997 
998  if(old_Sel < NrOfEntries)
999  {
1000  if (dm)
1001  {
1002  if(nIDComboBox == cmb2)
1003  dm->u1.s1.dmPaperSize = oldWord;
1004  else
1005  dm->u1.s1.dmDefaultSource = oldWord;
1006  }
1007  Sel = old_Sel;
1008  }
1009 
1010  SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
1011 
1012  HeapFree(GetProcessHeap(),0,Words);
1014  return TRUE;
1015 }
1016 
1017 
1018 /***********************************************************************
1019  * PRINTDLG_UpdatePrinterInfoTexts [internal]
1020  */
1022 {
1023  char StatusMsg[256];
1024  char ResourceString[256];
1025  int i;
1026 
1027  /* Status Message */
1028  StatusMsg[0]='\0';
1029 
1030  /* add all status messages */
1031  for (i = 0; i < 25; i++) {
1032  if (pi->Status & (1<<i)) {
1034  ResourceString, 255);
1035  strcat(StatusMsg,ResourceString);
1036  }
1037  }
1038  /* append "ready" */
1039  /* FIXME: status==ready must only be appended if really so.
1040  but how to detect? */
1042  ResourceString, 255);
1043  strcat(StatusMsg,ResourceString);
1044  SetDlgItemTextA(hDlg, stc12, StatusMsg);
1045 
1046  /* set all other printer info texts */
1047  SetDlgItemTextA(hDlg, stc11, pi->pDriverName);
1048 
1049  if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1050  SetDlgItemTextA(hDlg, stc14, pi->pLocation);
1051  else
1052  SetDlgItemTextA(hDlg, stc14, pi->pPortName);
1053  SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : "");
1054  return;
1055 }
1056 
1058 {
1059  WCHAR StatusMsg[256];
1060  WCHAR ResourceString[256];
1061  static const WCHAR emptyW[] = {0};
1062  int i;
1063 
1064  /* Status Message */
1065  StatusMsg[0]='\0';
1066 
1067  /* add all status messages */
1068  for (i = 0; i < 25; i++) {
1069  if (pi->Status & (1<<i)) {
1071  ResourceString, 255);
1072  lstrcatW(StatusMsg,ResourceString);
1073  }
1074  }
1075  /* append "ready" */
1076  /* FIXME: status==ready must only be appended if really so.
1077  but how to detect? */
1079  ResourceString, 255);
1080  lstrcatW(StatusMsg,ResourceString);
1081  SetDlgItemTextW(hDlg, stc12, StatusMsg);
1082 
1083  /* set all other printer info texts */
1084  SetDlgItemTextW(hDlg, stc11, pi->pDriverName);
1085  if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1086  SetDlgItemTextW(hDlg, stc14, pi->pLocation);
1087  else
1088  SetDlgItemTextW(hDlg, stc14, pi->pPortName);
1089  SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW);
1090 }
1091 
1092 
1093 /*******************************************************************
1094  *
1095  * PRINTDLG_ChangePrinter
1096  *
1097  */
1098 static BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, PRINT_PTRA *PrintStructures)
1099 {
1100  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1101  LPDEVMODEA lpdm = NULL;
1102  LONG dmSize;
1103  DWORD needed;
1104  HANDLE hprn;
1105 
1106  HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1107  HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1108  if(!OpenPrinterA(name, &hprn, NULL)) {
1109  ERR("Can't open printer %s\n", name);
1110  return FALSE;
1111  }
1112  GetPrinterA(hprn, 2, NULL, 0, &needed);
1113  PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1114  GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1115  &needed);
1116  GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
1117  PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1118  if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1119  needed, &needed)) {
1120  ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName);
1121  return FALSE;
1122  }
1123  ClosePrinter(hprn);
1124 
1125  PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo);
1126 
1127  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1128  PrintStructures->lpDevMode = NULL;
1129 
1130  dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0);
1131  if(dmSize == -1) {
1132  ERR("DocumentProperties fails on %s\n", debugstr_a(name));
1133  return FALSE;
1134  }
1135  PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1136  dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL,
1137  DM_OUT_BUFFER);
1138  if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1139  !lstrcmpA( (LPSTR) lpdm->dmDeviceName,
1140  (LPSTR) PrintStructures->lpDevMode->dmDeviceName)) {
1141  /* Supplied devicemode matches current printer so try to use it */
1142  DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm,
1144  }
1145  if(lpdm)
1146  GlobalUnlock(lppd->hDevMode);
1147 
1148  lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */
1149 
1150  if(!(lppd->Flags & PD_PRINTSETUP)) {
1151  /* Print range (All/Range/Selection) */
1152  if(lppd->nFromPage != 0xffff)
1153  SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1154  if(lppd->nToPage != 0xffff)
1155  SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1156 
1157  CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */
1158  if (lppd->Flags & PD_NOSELECTION)
1159  EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1160  else
1161  if (lppd->Flags & PD_SELECTION)
1162  CheckRadioButton(hDlg, rad1, rad3, rad2);
1163  if (lppd->Flags & PD_NOPAGENUMS) {
1164  EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1166  EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1168  EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1169  } else {
1170  if (lppd->Flags & PD_PAGENUMS)
1171  CheckRadioButton(hDlg, rad1, rad3, rad3);
1172  }
1173 
1174  /* Collate pages */
1175  if (lppd->Flags & PD_COLLATE) {
1177  (LPARAM)PrintStructures->hCollateIcon);
1178  CheckDlgButton(hDlg, chx2, 1);
1179  } else {
1181  (LPARAM)PrintStructures->hNoCollateIcon);
1182  CheckDlgButton(hDlg, chx2, 0);
1183  }
1184 
1185  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1186  /* if printer doesn't support it: no Collate */
1187  if (!(lpdm->dmFields & DM_COLLATE)) {
1188  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1189  EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1190  }
1191  }
1192 
1193  /* nCopies */
1194  {
1195  INT copies;
1196  if (lppd->hDevMode == 0)
1197  copies = lppd->nCopies;
1198  else
1199  copies = lpdm->u1.s1.dmCopies;
1200  if(copies == 0) copies = 1;
1201  else if(copies < 0) copies = MAX_COPIES;
1202  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1203  }
1204 
1205  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1206  /* if printer doesn't support it: no nCopies */
1207  if (!(lpdm->dmFields & DM_COPIES)) {
1208  EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1209  EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1210  }
1211  }
1212 
1213  /* print to file */
1214  CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1215  if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1216  EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1217  if (lppd->Flags & PD_HIDEPRINTTOFILE)
1218  ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1219 
1220  /* Fill print quality combo, PrintDlg16 */
1221  if(GetDlgItem(hDlg, cmb1))
1222  {
1223  DWORD numResolutions = DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName,
1224  PrintStructures->lpPrinterInfo->pPortName,
1225  DC_ENUMRESOLUTIONS, NULL, lpdm);
1226 
1227  if(numResolutions != -1)
1228  {
1229  HWND hQuality = GetDlgItem(hDlg, cmb1);
1230  LONG* Resolutions;
1231  char buf[255];
1232  DWORD i;
1233  int dpiX, dpiY;
1234  HDC hPrinterDC = CreateDCA(PrintStructures->lpPrinterInfo->pDriverName,
1235  PrintStructures->lpPrinterInfo->pPrinterName,
1236  0, lpdm);
1237 
1238  Resolutions = HeapAlloc(GetProcessHeap(), 0, numResolutions*sizeof(LONG)*2);
1240  PrintStructures->lpPrinterInfo->pPortName,
1241  DC_ENUMRESOLUTIONS, (LPSTR)Resolutions, lpdm);
1242 
1243  dpiX = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
1244  dpiY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
1245  DeleteDC(hPrinterDC);
1246 
1247  SendMessageA(hQuality, CB_RESETCONTENT, 0, 0);
1248  for(i = 0; i < (numResolutions * 2); i += 2)
1249  {
1250  BOOL IsDefault = FALSE;
1251  LRESULT Index;
1252 
1253  if(Resolutions[i] == Resolutions[i+1])
1254  {
1255  if(dpiX == Resolutions[i])
1256  IsDefault = TRUE;
1257  sprintf(buf, "%d dpi", Resolutions[i]);
1258  } else
1259  {
1260  if(dpiX == Resolutions[i] && dpiY == Resolutions[i+1])
1261  IsDefault = TRUE;
1262  sprintf(buf, "%d dpi x %d dpi", Resolutions[i], Resolutions[i+1]);
1263  }
1264 
1265  Index = SendMessageA(hQuality, CB_ADDSTRING, 0, (LPARAM)buf);
1266 
1267  if(IsDefault)
1268  SendMessageA(hQuality, CB_SETCURSEL, Index, 0);
1269 
1270  SendMessageA(hQuality, CB_SETITEMDATA, Index, MAKELONG(dpiX,dpiY));
1271  }
1272  HeapFree(GetProcessHeap(), 0, Resolutions);
1273  }
1274  }
1275  } else { /* PD_PRINTSETUP */
1276  BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1277 
1279  PrintStructures->lpPrinterInfo->pPrinterName,
1280  PrintStructures->lpPrinterInfo->pPortName,
1281  lpdm);
1283  PrintStructures->lpPrinterInfo->pPrinterName,
1284  PrintStructures->lpPrinterInfo->pPortName,
1285  lpdm);
1286  CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1288  (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1289  PrintStructures->hLandscapeIcon));
1290 
1291  }
1292 
1293  /* help button */
1294  if ((lppd->Flags & PD_SHOWHELP)==0) {
1295  /* hide if PD_SHOWHELP not specified */
1297  }
1298  return TRUE;
1299 }
1300 
1302  PRINT_PTRW *PrintStructures)
1303 {
1304  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1305  LPDEVMODEW lpdm = NULL;
1306  LONG dmSize;
1307  DWORD needed;
1308  HANDLE hprn;
1309 
1310  HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1311  HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1312  if(!OpenPrinterW(name, &hprn, NULL)) {
1313  ERR("Can't open printer %s\n", debugstr_w(name));
1314  return FALSE;
1315  }
1316  GetPrinterW(hprn, 2, NULL, 0, &needed);
1317  PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1318  GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1319  &needed);
1320  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
1321  PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1322  if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1323  needed, &needed)) {
1324  ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName));
1325  return FALSE;
1326  }
1327  ClosePrinter(hprn);
1328 
1329  PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo);
1330 
1331  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1332  PrintStructures->lpDevMode = NULL;
1333 
1334  dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
1335  if(dmSize == -1) {
1336  ERR("DocumentProperties fails on %s\n", debugstr_w(name));
1337  return FALSE;
1338  }
1339  PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1340  dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL,
1341  DM_OUT_BUFFER);
1342  if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1343  !lstrcmpW(lpdm->dmDeviceName,
1344  PrintStructures->lpDevMode->dmDeviceName)) {
1345  /* Supplied devicemode matches current printer so try to use it */
1346  DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm,
1348  }
1349  if(lpdm)
1350  GlobalUnlock(lppd->hDevMode);
1351 
1352  lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */
1353 
1354  if(!(lppd->Flags & PD_PRINTSETUP)) {
1355  /* Print range (All/Range/Selection) */
1356  if(lppd->nFromPage != 0xffff)
1357  SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1358  if(lppd->nToPage != 0xffff)
1359  SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1360 
1361  CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */
1362  if (lppd->Flags & PD_NOSELECTION)
1363  EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1364  else
1365  if (lppd->Flags & PD_SELECTION)
1366  CheckRadioButton(hDlg, rad1, rad3, rad2);
1367  if (lppd->Flags & PD_NOPAGENUMS) {
1368  EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1370  EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1372  EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1373  } else {
1374  if (lppd->Flags & PD_PAGENUMS)
1375  CheckRadioButton(hDlg, rad1, rad3, rad3);
1376  }
1377 
1378  /* Collate pages */
1379  if (lppd->Flags & PD_COLLATE) {
1381  (LPARAM)PrintStructures->hCollateIcon);
1382  CheckDlgButton(hDlg, chx2, 1);
1383  } else {
1385  (LPARAM)PrintStructures->hNoCollateIcon);
1386  CheckDlgButton(hDlg, chx2, 0);
1387  }
1388 
1389  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1390  /* if printer doesn't support it: no Collate */
1391  if (!(lpdm->dmFields & DM_COLLATE)) {
1392  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1393  EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1394  }
1395  }
1396 
1397  /* nCopies */
1398  {
1399  INT copies;
1400  if (lppd->hDevMode == 0)
1401  copies = lppd->nCopies;
1402  else
1403  copies = lpdm->u1.s1.dmCopies;
1404  if(copies == 0) copies = 1;
1405  else if(copies < 0) copies = MAX_COPIES;
1406  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1407  }
1408 
1409  if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1410  /* if printer doesn't support it: no nCopies */
1411  if (!(lpdm->dmFields & DM_COPIES)) {
1412  EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1413  EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1414  }
1415  }
1416 
1417  /* print to file */
1418  CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1419  if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1420  EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1421  if (lppd->Flags & PD_HIDEPRINTTOFILE)
1422  ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1423 
1424  } else { /* PD_PRINTSETUP */
1425  BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1426 
1428  PrintStructures->lpPrinterInfo->pPrinterName,
1429  PrintStructures->lpPrinterInfo->pPortName,
1430  lpdm);
1432  PrintStructures->lpPrinterInfo->pPrinterName,
1433  PrintStructures->lpPrinterInfo->pPortName,
1434  lpdm);
1435  CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1437  (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1438  PrintStructures->hLandscapeIcon));
1439 
1440  }
1441 
1442  /* help button */
1443  if ((lppd->Flags & PD_SHOWHELP)==0) {
1444  /* hide if PD_SHOWHELP not specified */
1446  }
1447  return TRUE;
1448 }
1449 
1450  /***********************************************************************
1451  * check_printer_setup [internal]
1452  */
1454 {
1455  DWORD needed,num;
1456  WCHAR resourcestr[256],resultstr[256];
1457 
1458  EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
1459  if(needed == 0)
1460  {
1461  EnumPrintersW(PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &num);
1462  }
1463  if(needed > 0)
1464  return TRUE;
1465  else
1466  {
1468  LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,resourcestr, 255);
1469  MessageBoxW(hDlg, resultstr, resourcestr,MB_OK | MB_ICONWARNING);
1470  return FALSE;
1471  }
1472 }
1473 
1474 /***********************************************************************
1475  * PRINTDLG_WMInitDialog [internal]
1476  */
1478  PRINT_PTRA* PrintStructures)
1479 {
1480  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1481  DEVNAMES *pdn;
1482  DEVMODEA *pdm;
1483  char *name = NULL;
1484  UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1485 
1486  /* load Collate ICONs */
1487  /* We load these with LoadImage because they are not a standard
1488  size and we don't want them rescaled */
1489  PrintStructures->hCollateIcon =
1490  LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0);
1491  PrintStructures->hNoCollateIcon =
1492  LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0);
1493 
1494  /* These can be done with LoadIcon */
1495  PrintStructures->hPortraitIcon =
1496  LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT");
1497  PrintStructures->hLandscapeIcon =
1498  LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE");
1499 
1500  /* display the collate/no_collate icon */
1502  (LPARAM)PrintStructures->hNoCollateIcon);
1503 
1504  if(PrintStructures->hCollateIcon == 0 ||
1505  PrintStructures->hNoCollateIcon == 0 ||
1506  PrintStructures->hPortraitIcon == 0 ||
1507  PrintStructures->hLandscapeIcon == 0) {
1508  ERR("no icon in resource file\n");
1510  EndDialog(hDlg, FALSE);
1511  }
1512 
1513  /*
1514  * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1515  * must be registered and the Help button must be shown.
1516  */
1517  if (lppd->Flags & PD_SHOWHELP) {
1518  if((PrintStructures->HelpMessageID =
1521  return FALSE;
1522  }
1523  } else
1524  PrintStructures->HelpMessageID = 0;
1525 
1526  if(!(lppd->Flags &PD_PRINTSETUP)) {
1527  PrintStructures->hwndUpDown =
1530  UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1532  GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1533  }
1534 
1535  /* FIXME: I allow more freedom than either Win95 or WinNT,
1536  * which do not agree on what errors should be thrown or not
1537  * in case nToPage or nFromPage is out-of-range.
1538  */
1539  if (lppd->nMaxPage < lppd->nMinPage)
1540  lppd->nMaxPage = lppd->nMinPage;
1541  if (lppd->nMinPage == lppd->nMaxPage)
1542  lppd->Flags |= PD_NOPAGENUMS;
1543  if (lppd->nToPage < lppd->nMinPage)
1544  lppd->nToPage = lppd->nMinPage;
1545  if (lppd->nToPage > lppd->nMaxPage)
1546  lppd->nToPage = lppd->nMaxPage;
1547  if (lppd->nFromPage < lppd->nMinPage)
1548  lppd->nFromPage = lppd->nMinPage;
1549  if (lppd->nFromPage > lppd->nMaxPage)
1550  lppd->nFromPage = lppd->nMaxPage;
1551 
1552  /* if we have the combo box, fill it */
1553  if (GetDlgItem(hDlg,comboID)) {
1554  /* Fill Combobox
1555  */
1556  pdn = GlobalLock(lppd->hDevNames);
1557  pdm = GlobalLock(lppd->hDevMode);
1558  if(pdn)
1559  name = (char*)pdn + pdn->wDeviceOffset;
1560  else if(pdm)
1561  name = (char*)pdm->dmDeviceName;
1562  PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name);
1563  if(pdm) GlobalUnlock(lppd->hDevMode);
1564  if(pdn) GlobalUnlock(lppd->hDevNames);
1565 
1566  /* Now find selected printer and update rest of dlg */
1567  name = HeapAlloc(GetProcessHeap(),0,256);
1568  if (GetDlgItemTextA(hDlg, comboID, name, 255))
1569  PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1571  } else {
1572  /* else use default printer */
1573  char name[200];
1576 
1577  if (ret)
1578  PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1579  else
1580  FIXME("No default printer found, expect problems!\n");
1581  }
1582  return TRUE;
1583 }
1584 
1586  PRINT_PTRW* PrintStructures)
1587 {
1588  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1589  DEVNAMES *pdn;
1590  DEVMODEW *pdm;
1591  WCHAR *name = NULL;
1592  UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1593 
1594  /* load Collate ICONs */
1595  /* We load these with LoadImage because they are not a standard
1596  size and we don't want them rescaled */
1597  PrintStructures->hCollateIcon =
1599  PrintStructures->hNoCollateIcon =
1601 
1602  /* These can be done with LoadIcon */
1603  PrintStructures->hPortraitIcon =
1605  PrintStructures->hLandscapeIcon =
1607 
1608  /* display the collate/no_collate icon */
1610  (LPARAM)PrintStructures->hNoCollateIcon);
1611 
1612  if(PrintStructures->hCollateIcon == 0 ||
1613  PrintStructures->hNoCollateIcon == 0 ||
1614  PrintStructures->hPortraitIcon == 0 ||
1615  PrintStructures->hLandscapeIcon == 0) {
1616  ERR("no icon in resource file\n");
1618  EndDialog(hDlg, FALSE);
1619  }
1620 
1621  /*
1622  * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1623  * must be registered and the Help button must be shown.
1624  */
1625  if (lppd->Flags & PD_SHOWHELP) {
1626  if((PrintStructures->HelpMessageID =
1629  return FALSE;
1630  }
1631  } else
1632  PrintStructures->HelpMessageID = 0;
1633 
1634  if(!(lppd->Flags &PD_PRINTSETUP)) {
1635  PrintStructures->hwndUpDown =
1638  UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1640  GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1641  }
1642 
1643  /* FIXME: I allow more freedom than either Win95 or WinNT,
1644  * which do not agree to what errors should be thrown or not
1645  * in case nToPage or nFromPage is out-of-range.
1646  */
1647  if (lppd->nMaxPage < lppd->nMinPage)
1648  lppd->nMaxPage = lppd->nMinPage;
1649  if (lppd->nMinPage == lppd->nMaxPage)
1650  lppd->Flags |= PD_NOPAGENUMS;
1651  if (lppd->nToPage < lppd->nMinPage)
1652  lppd->nToPage = lppd->nMinPage;
1653  if (lppd->nToPage > lppd->nMaxPage)
1654  lppd->nToPage = lppd->nMaxPage;
1655  if (lppd->nFromPage < lppd->nMinPage)
1656  lppd->nFromPage = lppd->nMinPage;
1657  if (lppd->nFromPage > lppd->nMaxPage)
1658  lppd->nFromPage = lppd->nMaxPage;
1659 
1660  /* if we have the combo box, fill it */
1661  if (GetDlgItem(hDlg,comboID)) {
1662  /* Fill Combobox
1663  */
1664  pdn = GlobalLock(lppd->hDevNames);
1665  pdm = GlobalLock(lppd->hDevMode);
1666  if(pdn)
1667  name = (WCHAR*)pdn + pdn->wDeviceOffset;
1668  else if(pdm)
1669  name = pdm->dmDeviceName;
1670  PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name);
1671  if(pdm) GlobalUnlock(lppd->hDevMode);
1672  if(pdn) GlobalUnlock(lppd->hDevNames);
1673 
1674  /* Now find selected printer and update rest of dlg */
1675  /* ansi is ok here */
1676  name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR));
1677  if (GetDlgItemTextW(hDlg, comboID, name, 255))
1678  PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1680  } else {
1681  /* else use default printer */
1682  WCHAR name[200];
1685 
1686  if (ret)
1687  PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1688  else
1689  FIXME("No default printer found, expect problems!\n");
1690  }
1691  return TRUE;
1692 }
1693 
1694 /***********************************************************************
1695  * PRINTDLG_WMCommand [internal]
1696  */
1698  PRINT_PTRA* PrintStructures)
1699 {
1700  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1701  UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1702  LPDEVMODEA lpdm = PrintStructures->lpDevMode;
1703 
1704  switch (LOWORD(wParam)) {
1705  case IDOK:
1706  TRACE(" OK button was hit\n");
1707  if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) {
1708  FIXME("Update printdlg was not successful!\n");
1709  return(FALSE);
1710  }
1711  EndDialog(hDlg, TRUE);
1712  return(TRUE);
1713 
1714  case IDCANCEL:
1715  TRACE(" CANCEL button was hit\n");
1716  EndDialog(hDlg, FALSE);
1717  return(FALSE);
1718 
1719  case pshHelp:
1720  TRACE(" HELP button was hit\n");
1721  SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID,
1722  (WPARAM) hDlg, (LPARAM) lppd);
1723  break;
1724 
1725  case chx2: /* collate pages checkbox */
1726  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1728  (LPARAM)PrintStructures->hCollateIcon);
1729  else
1731  (LPARAM)PrintStructures->hNoCollateIcon);
1732  break;
1733  case edt1: /* from page nr editbox */
1734  case edt2: /* to page nr editbox */
1735  if (HIWORD(wParam)==EN_CHANGE) {
1736  WORD nToPage;
1737  WORD nFromPage;
1738  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1739  nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1740  if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1741  CheckRadioButton(hDlg, rad1, rad3, rad3);
1742  }
1743  break;
1744 
1745  case edt3:
1746  if(HIWORD(wParam) == EN_CHANGE) {
1747  INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1748  if(copies <= 1)
1749  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1750  else
1751  EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1752  }
1753  break;
1754 
1755  case psh2: /* Properties button */
1756  {
1757  HANDLE hPrinter;
1758  char PrinterName[256];
1759 
1760  GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255);
1761  if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) {
1762  FIXME(" Call to OpenPrinter did not succeed!\n");
1763  break;
1764  }
1765  DocumentPropertiesA(hDlg, hPrinter, PrinterName,
1766  PrintStructures->lpDevMode,
1767  PrintStructures->lpDevMode,
1769  ClosePrinter(hPrinter);
1770  break;
1771  }
1772 
1773  case rad1: /* Paperorientation */
1774  if (lppd->Flags & PD_PRINTSETUP)
1775  {
1776  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1778  (LPARAM)(PrintStructures->hPortraitIcon));
1779  }
1780  break;
1781 
1782  case rad2: /* Paperorientation */
1783  if (lppd->Flags & PD_PRINTSETUP)
1784  {
1785  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1787  (LPARAM)(PrintStructures->hLandscapeIcon));
1788  }
1789  break;
1790 
1791  case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT16 */
1792  if (PrinterComboID != LOWORD(wParam)) {
1793  break;
1794  }
1795  /* FALLTHROUGH */
1796  case cmb4: /* Printer combobox */
1797  if (HIWORD(wParam)==CBN_SELCHANGE) {
1798  char *PrinterName;
1801  PrinterName = HeapAlloc(GetProcessHeap(),0,length+1);
1802  SendDlgItemMessageA(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1803  PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures);
1804  HeapFree(GetProcessHeap(),0,PrinterName);
1805  }
1806  break;
1807 
1808  case cmb2: /* Papersize */
1809  {
1810  DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1811  if(Sel != CB_ERR) {
1812  lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2,
1814  Sel, 0);
1815  GetDlgItemTextA(hDlg, cmb2, (char *)lpdm->dmFormName, CCHFORMNAME);
1816  }
1817  }
1818  break;
1819 
1820  case cmb3: /* Bin */
1821  {
1822  DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1823  if(Sel != CB_ERR)
1824  lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3,
1825  CB_GETITEMDATA, Sel,
1826  0);
1827  }
1828  break;
1829  }
1830  if(lppd->Flags & PD_PRINTSETUP) {
1831  switch (LOWORD(wParam)) {
1832  case rad1: /* orientation */
1833  case rad2:
1834  if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1835  if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
1836  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1838  (LPARAM)PrintStructures->hPortraitIcon);
1840  (LPARAM)PrintStructures->hPortraitIcon);
1841  }
1842  } else {
1843  if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
1844  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1846  (LPARAM)PrintStructures->hLandscapeIcon);
1848  (LPARAM)PrintStructures->hLandscapeIcon);
1849  }
1850  }
1851  break;
1852  }
1853  }
1854  return FALSE;
1855 }
1856 
1858  PRINT_PTRW* PrintStructures)
1859 {
1860  LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1861  UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1862  LPDEVMODEW lpdm = PrintStructures->lpDevMode;
1863 
1864  switch (LOWORD(wParam)) {
1865  case IDOK:
1866  TRACE(" OK button was hit\n");
1867  if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) {
1868  FIXME("Update printdlg was not successful!\n");
1869  return(FALSE);
1870  }
1871  EndDialog(hDlg, TRUE);
1872  return(TRUE);
1873 
1874  case IDCANCEL:
1875  TRACE(" CANCEL button was hit\n");
1876  EndDialog(hDlg, FALSE);
1877  return(FALSE);
1878 
1879  case pshHelp:
1880  TRACE(" HELP button was hit\n");
1881  SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID,
1882  (WPARAM) hDlg, (LPARAM) lppd);
1883  break;
1884 
1885  case chx2: /* collate pages checkbox */
1886  if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1888  (LPARAM)PrintStructures->hCollateIcon);
1889  else
1891  (LPARAM)PrintStructures->hNoCollateIcon);
1892  break;
1893  case edt1: /* from page nr editbox */
1894  case edt2: /* to page nr editbox */
1895  if (HIWORD(wParam)==EN_CHANGE) {
1896  WORD nToPage;
1897  WORD nFromPage;
1898  nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1899  nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1900  if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1901  CheckRadioButton(hDlg, rad1, rad3, rad3);
1902  }
1903  break;
1904 
1905  case edt3:
1906  if(HIWORD(wParam) == EN_CHANGE) {
1907  INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1908  if(copies <= 1)
1909  EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1910  else
1911  EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1912  }
1913  break;
1914 
1915  case psh2: /* Properties button */
1916  {
1917  HANDLE hPrinter;
1918  WCHAR PrinterName[256];
1919 
1920  if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break;
1921  if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) {
1922  FIXME(" Call to OpenPrinter did not succeed!\n");
1923  break;
1924  }
1925  DocumentPropertiesW(hDlg, hPrinter, PrinterName,
1926  PrintStructures->lpDevMode,
1927  PrintStructures->lpDevMode,
1929  ClosePrinter(hPrinter);
1930  break;
1931  }
1932 
1933  case rad1: /* Paperorientation */
1934  if (lppd->Flags & PD_PRINTSETUP)
1935  {
1936  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1938  (LPARAM)(PrintStructures->hPortraitIcon));
1939  }
1940  break;
1941 
1942  case rad2: /* Paperorientation */
1943  if (lppd->Flags & PD_PRINTSETUP)
1944  {
1945  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1947  (LPARAM)(PrintStructures->hLandscapeIcon));
1948  }
1949  break;
1950 
1951  case cmb1: /* Printer Combobox in PRINT SETUP */
1952  /* FALLTHROUGH */
1953  case cmb4: /* Printer combobox */
1954  if (HIWORD(wParam)==CBN_SELCHANGE) {
1955  WCHAR *PrinterName;
1958 
1959  PrinterName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
1960  SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1961  PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures);
1962  HeapFree(GetProcessHeap(),0,PrinterName);
1963  }
1964  break;
1965 
1966  case cmb2: /* Papersize */
1967  {
1968  DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1969  if(Sel != CB_ERR) {
1970  lpdm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2,
1972  Sel, 0);
1973  GetDlgItemTextW(hDlg, cmb2, lpdm->dmFormName, CCHFORMNAME);
1974  }
1975  }
1976  break;
1977 
1978  case cmb3: /* Bin */
1979  {
1980  DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1981  if(Sel != CB_ERR)
1982  lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3,
1983  CB_GETITEMDATA, Sel,
1984  0);
1985  }
1986  break;
1987  }
1988  if(lppd->Flags & PD_PRINTSETUP) {
1989  switch (LOWORD(wParam)) {
1990  case rad1: /* orientation */
1991  case rad2:
1992  if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1993  if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
1994  lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1996  (LPARAM)PrintStructures->hPortraitIcon);
1998  (LPARAM)PrintStructures->hPortraitIcon);
1999  }
2000  } else {
2001  if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
2002  lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
2004  (LPARAM)PrintStructures->hLandscapeIcon);
2006  (LPARAM)PrintStructures->hLandscapeIcon);
2007  }
2008  }
2009  break;
2010  }
2011  }
2012  return FALSE;
2013 }
2014 
2015 /***********************************************************************
2016  * PrintDlgProcA [internal]
2017  */
2019  LPARAM lParam)
2020 {
2021  PRINT_PTRA* PrintStructures;
2022  INT_PTR res = FALSE;
2023 
2024  if (uMsg!=WM_INITDIALOG) {
2025  PrintStructures = GetPropW(hDlg, printdlg_prop);
2026  if (!PrintStructures)
2027  return FALSE;
2028  } else {
2029  PrintStructures = (PRINT_PTRA*) lParam;
2030  SetPropW(hDlg, printdlg_prop, PrintStructures);
2031  if(!check_printer_setup(hDlg))
2032  {
2033  EndDialog(hDlg,FALSE);
2034  return FALSE;
2035  }
2036  res = PRINTDLG_WMInitDialog(hDlg, PrintStructures);
2037 
2038  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2039  res = PrintStructures->lpPrintDlg->lpfnPrintHook(
2040  hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg
2041  );
2042  return res;
2043  }
2044 
2045  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2046  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam,
2047  lParam);
2048  if(res) return res;
2049  }
2050 
2051  switch (uMsg) {
2052  case WM_COMMAND:
2053  return PRINTDLG_WMCommandA(hDlg, wParam, PrintStructures);
2054 
2055  case WM_DESTROY:
2056  DestroyIcon(PrintStructures->hCollateIcon);
2057  DestroyIcon(PrintStructures->hNoCollateIcon);
2058  DestroyIcon(PrintStructures->hPortraitIcon);
2059  DestroyIcon(PrintStructures->hLandscapeIcon);
2060  if(PrintStructures->hwndUpDown)
2061  DestroyWindow(PrintStructures->hwndUpDown);
2062  return FALSE;
2063  }
2064  return res;
2065 }
2066 
2068  LPARAM lParam)
2069 {
2070  PRINT_PTRW* PrintStructures;
2071  INT_PTR res = FALSE;
2072 
2073  if (uMsg!=WM_INITDIALOG) {
2074  PrintStructures = GetPropW(hDlg, printdlg_prop);
2075  if (!PrintStructures)
2076  return FALSE;
2077  } else {
2078  PrintStructures = (PRINT_PTRW*) lParam;
2079  SetPropW(hDlg, printdlg_prop, PrintStructures);
2080  if(!check_printer_setup(hDlg))
2081  {
2082  EndDialog(hDlg,FALSE);
2083  return FALSE;
2084  }
2085  res = PRINTDLG_WMInitDialogW(hDlg, PrintStructures);
2086 
2087  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2088  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg);
2089  return res;
2090  }
2091 
2092  if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2093  res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam);
2094  if(res) return res;
2095  }
2096 
2097  switch (uMsg) {
2098  case WM_COMMAND:
2099  return PRINTDLG_WMCommandW(hDlg, wParam, PrintStructures);
2100 
2101  case WM_DESTROY:
2102  DestroyIcon(PrintStructures->hCollateIcon);
2103  DestroyIcon(PrintStructures->hNoCollateIcon);
2104  DestroyIcon(PrintStructures->hPortraitIcon);
2105  DestroyIcon(PrintStructures->hLandscapeIcon);
2106  if(PrintStructures->hwndUpDown)
2107  DestroyWindow(PrintStructures->hwndUpDown);
2108  return FALSE;
2109  }
2110  return res;
2111 }
2112 
2113 /************************************************************
2114  *
2115  * PRINTDLG_GetDlgTemplate
2116  *
2117  */
2119 {
2120  HRSRC hResInfo;
2121  HGLOBAL hDlgTmpl;
2122 
2123  if (lppd->Flags & PD_PRINTSETUP) {
2124  if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2125  hDlgTmpl = lppd->hSetupTemplate;
2126  } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2127  hResInfo = FindResourceA(lppd->hInstance,
2129  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2130  } else {
2131  hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP",
2132  (LPSTR)RT_DIALOG);
2133  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2134  }
2135  } else {
2136  if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2137  hDlgTmpl = lppd->hPrintTemplate;
2138  } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2139  hResInfo = FindResourceA(lppd->hInstance,
2140  lppd->lpPrintTemplateName,
2141  (LPSTR)RT_DIALOG);
2142  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2143  } else {
2144  hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32",
2145  (LPSTR)RT_DIALOG);
2146  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2147  }
2148  }
2149  return hDlgTmpl;
2150 }
2151 
2153 {
2154  HRSRC hResInfo;
2155  HGLOBAL hDlgTmpl;
2156  static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0};
2157  static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0};
2158 
2159  if (lppd->Flags & PD_PRINTSETUP) {
2160  if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2161  hDlgTmpl = lppd->hSetupTemplate;
2162  } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2163  hResInfo = FindResourceW(lppd->hInstance,
2165  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2166  } else {
2167  hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG);
2168  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2169  }
2170  } else {
2171  if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2172  hDlgTmpl = lppd->hPrintTemplate;
2173  } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2174  hResInfo = FindResourceW(lppd->hInstance,
2175  lppd->lpPrintTemplateName,
2176  (LPWSTR)RT_DIALOG);
2177  hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2178  } else {
2179  hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG);
2180  hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2181  }
2182  }
2183  return hDlgTmpl;
2184 }
2185 
2186 /***********************************************************************
2187  *
2188  * PRINTDLG_CreateDC
2189  *
2190  */
2192 {
2193  DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2194  DEVMODEA *pdm = GlobalLock(lppd->hDevMode);
2195 
2196  if(lppd->Flags & PD_RETURNDC) {
2197  lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset,
2198  (char*)pdn + pdn->wDeviceOffset,
2199  (char*)pdn + pdn->wOutputOffset,
2200  pdm );
2201  } else if(lppd->Flags & PD_RETURNIC) {
2202  lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset,
2203  (char*)pdn + pdn->wDeviceOffset,
2204  (char*)pdn + pdn->wOutputOffset,
2205  pdm );
2206  }
2207  GlobalUnlock(lppd->hDevNames);
2208  GlobalUnlock(lppd->hDevMode);
2209  return lppd->hDC != NULL;
2210 }
2211 
2213 {
2214  DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2215  DEVMODEW *pdm = GlobalLock(lppd->hDevMode);
2216 
2217  if(lppd->Flags & PD_RETURNDC) {
2218  lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset,
2219  (WCHAR*)pdn + pdn->wDeviceOffset,
2220  (WCHAR*)pdn + pdn->wOutputOffset,
2221  pdm );
2222  } else if(lppd->Flags & PD_RETURNIC) {
2223  lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset,
2224  (WCHAR*)pdn + pdn->wDeviceOffset,
2225  (WCHAR*)pdn + pdn->wOutputOffset,
2226  pdm );
2227  }
2228  GlobalUnlock(lppd->hDevNames);
2229  GlobalUnlock(lppd->hDevMode);
2230  return lppd->hDC != NULL;
2231 }
2232 
2233 /***********************************************************************
2234  * PrintDlgA (COMDLG32.@)
2235  *
2236  * Displays the PRINT dialog box, which enables the user to specify
2237  * specific properties of the print job.
2238  *
2239  * PARAMS
2240  * lppd [IO] ptr to PRINTDLG32 struct
2241  *
2242  * RETURNS
2243  * nonzero if the user pressed the OK button
2244  * zero if the user cancelled the window or an error occurred
2245  *
2246  * BUGS
2247  * PrintDlg:
2248  * * The Collate Icons do not display, even though they are in the code.
2249  * * The Properties Button(s) should call DocumentPropertiesA().
2250  */
2251 
2253 {
2254  BOOL bRet = FALSE;
2255  LPVOID ptr;
2256  HINSTANCE hInst;
2257 
2258  if (!lppd)
2259  {
2261  return FALSE;
2262  }
2263 
2264  if(TRACE_ON(commdlg)) {
2265  char flagstr[1000] = "";
2266  const struct pd_flags *pflag = pd_flags;
2267  for( ; pflag->name; pflag++) {
2268  if(lppd->Flags & pflag->flag)
2269  strcat(flagstr, pflag->name);
2270  }
2271  TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2272  "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2273  "flags %08x (%s)\n",
2274  lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2275  lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2276  lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2277  }
2278 
2279  if(lppd->lStructSize != sizeof(PRINTDLGA)) {
2280  WARN("structure size failure!!!\n");
2282  return FALSE;
2283  }
2284 
2285  if(lppd->Flags & PD_RETURNDEFAULT) {
2287  DRIVER_INFO_3A *dbuf;
2288  HANDLE hprn;
2289  DWORD needed;
2290 
2291  if(lppd->hDevMode || lppd->hDevNames) {
2292  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2294  return FALSE;
2295  }
2296  if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2297  WARN("Can't find default printer\n");
2299  return FALSE;
2300  }
2301 
2302  GetPrinterA(hprn, 2, NULL, 0, &needed);
2303  pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2304  GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2305 
2306  GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
2307  dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2308  if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2309  ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2310  GetLastError(),pbuf->pPrinterName);
2311  HeapFree(GetProcessHeap(), 0, dbuf);
2312  HeapFree(GetProcessHeap(), 0, pbuf);
2314  return FALSE;
2315  }
2316  ClosePrinter(hprn);
2317 
2319  dbuf->pDriverPath,
2320  pbuf->pPrinterName,
2321  pbuf->pPortName);
2322  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2323  pbuf->pDevMode->dmDriverExtra);
2324  ptr = GlobalLock(lppd->hDevMode);
2325  memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2326  pbuf->pDevMode->dmDriverExtra);
2327  GlobalUnlock(lppd->hDevMode);
2328  HeapFree(GetProcessHeap(), 0, pbuf);
2329  HeapFree(GetProcessHeap(), 0, dbuf);
2330  bRet = TRUE;
2331  } else {
2332  HGLOBAL hDlgTmpl;
2333  PRINT_PTRA *PrintStructures;
2334 
2335  /* load Dialog resources,
2336  * depending on Flags indicates Print32 or Print32_setup dialog
2337  */
2338  hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd);
2339  if (!hDlgTmpl) {
2341  return FALSE;
2342  }
2343  ptr = LockResource( hDlgTmpl );
2344  if (!ptr) {
2346  return FALSE;
2347  }
2348 
2349  PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2350  sizeof(PRINT_PTRA));
2351  PrintStructures->lpPrintDlg = lppd;
2352 
2353  /* and create & process the dialog .
2354  * -1 is failure, 0 is broken hwnd, everything else is ok.
2355  */
2358  bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner,
2359  PrintDlgProcA,
2360  (LPARAM)PrintStructures));
2361 
2362  if(bRet) {
2363  DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2364  PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo;
2365  DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo;
2366 
2367  if (lppd->hDevMode == 0) {
2368  TRACE(" No hDevMode yet... Need to create my own\n");
2370  lpdm->dmSize + lpdm->dmDriverExtra);
2371  } else {
2372  lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2373  lpdm->dmSize + lpdm->dmDriverExtra,
2374  GMEM_MOVEABLE);
2375  }
2376  lpdmReturn = GlobalLock(lppd->hDevMode);
2377  memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2378 
2380  di->pDriverPath,
2381  pi->pPrinterName,
2382  pi->pPortName
2383  );
2384  GlobalUnlock(lppd->hDevMode);
2385  }
2386  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2387  HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2388  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2389  HeapFree(GetProcessHeap(), 0, PrintStructures);
2390  }
2391  if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2392  bRet = PRINTDLG_CreateDCA(lppd);
2393 
2394  TRACE("exit! (%d)\n", bRet);
2395  return bRet;
2396 }
2397 
2398 /***********************************************************************
2399  * PrintDlgW (COMDLG32.@)
2400  *
2401  * See PrintDlgA.
2402  */
2404 {
2405  BOOL bRet = FALSE;
2406  LPVOID ptr;
2407  HINSTANCE hInst;
2408 
2409  if (!lppd)
2410  {
2412  return FALSE;
2413  }
2414 
2415  if(TRACE_ON(commdlg)) {
2416  char flagstr[1000] = "";
2417  const struct pd_flags *pflag = pd_flags;
2418  for( ; pflag->name; pflag++) {
2419  if(lppd->Flags & pflag->flag)
2420  strcat(flagstr, pflag->name);
2421  }
2422  TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2423  "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2424  "flags %08x (%s)\n",
2425  lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2426  lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2427  lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2428  }
2429 
2430  if(lppd->lStructSize != sizeof(PRINTDLGW)) {
2431  WARN("structure size failure!!!\n");
2433  return FALSE;
2434  }
2435 
2436  if(lppd->Flags & PD_RETURNDEFAULT) {
2438  DRIVER_INFO_3W *dbuf;
2439  HANDLE hprn;
2440  DWORD needed;
2441 
2442  if(lppd->hDevMode || lppd->hDevNames) {
2443  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2445  return FALSE;
2446  }
2447  if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2448  WARN("Can't find default printer\n");
2450  return FALSE;
2451  }
2452 
2453  GetPrinterW(hprn, 2, NULL, 0, &needed);
2454  pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2455  GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2456 
2457  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
2458  dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2459  if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2460  ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2461  GetLastError(),debugstr_w(pbuf->pPrinterName));
2462  HeapFree(GetProcessHeap(), 0, dbuf);
2463  HeapFree(GetProcessHeap(), 0, pbuf);
2465  return FALSE;
2466  }
2467  ClosePrinter(hprn);
2468 
2470  dbuf->pDriverPath,
2471  pbuf->pPrinterName,
2472  pbuf->pPortName);
2473  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2474  pbuf->pDevMode->dmDriverExtra);
2475  ptr = GlobalLock(lppd->hDevMode);
2476  memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2477  pbuf->pDevMode->dmDriverExtra);
2478  GlobalUnlock(lppd->hDevMode);
2479  HeapFree(GetProcessHeap(), 0, pbuf);
2480  HeapFree(GetProcessHeap(), 0, dbuf);
2481  bRet = TRUE;
2482  } else {
2483  HGLOBAL hDlgTmpl;
2484  PRINT_PTRW *PrintStructures;
2485 
2486  /* load Dialog resources,
2487  * depending on Flags indicates Print32 or Print32_setup dialog
2488  */
2489  hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd);
2490  if (!hDlgTmpl) {
2492  return FALSE;
2493  }
2494  ptr = LockResource( hDlgTmpl );
2495  if (!ptr) {
2497  return FALSE;
2498  }
2499 
2500  PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2501  sizeof(PRINT_PTRW));
2502  PrintStructures->lpPrintDlg = lppd;
2503 
2504  /* and create & process the dialog .
2505  * -1 is failure, 0 is broken hwnd, everything else is ok.
2506  */
2509  bRet = (0<DialogBoxIndirectParamW(hInst, ptr, lppd->hwndOwner,
2510  PrintDlgProcW,
2511  (LPARAM)PrintStructures));
2512 
2513  if(bRet) {
2514  DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2515  PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo;
2516  DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo;
2517 
2518  if (lppd->hDevMode == 0) {
2519  TRACE(" No hDevMode yet... Need to create my own\n");
2521  lpdm->dmSize + lpdm->dmDriverExtra);
2522  } else {
2523  WORD locks;
2524  if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) {
2525  WARN("hDevMode has %d locks on it. Unlocking it now\n", locks);
2526  while(locks--) {
2527  GlobalUnlock(lppd->hDevMode);
2528  TRACE("Now got %d locks\n", locks);
2529  }
2530  }
2531  lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2532  lpdm->dmSize + lpdm->dmDriverExtra,
2533  GMEM_MOVEABLE);
2534  }
2535  lpdmReturn = GlobalLock(lppd->hDevMode);
2536  memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2537 
2538  if (lppd->hDevNames != 0) {
2539  WORD locks;
2540  if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) {
2541  WARN("hDevNames has %d locks on it. Unlocking it now\n", locks);
2542  while(locks--)
2543  GlobalUnlock(lppd->hDevNames);
2544  }
2545  }
2547  di->pDriverPath,
2548  pi->pPrinterName,
2549  pi->pPortName
2550  );
2551  GlobalUnlock(lppd->hDevMode);
2552  }
2553  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2554  HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2555  HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2556  HeapFree(GetProcessHeap(), 0, PrintStructures);
2557  }
2558  if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2559  bRet = PRINTDLG_CreateDCW(lppd);
2560 
2561  TRACE("exit! (%d)\n", bRet);
2562  return bRet;
2563 }
2564 
2565 /***********************************************************************
2566  *
2567  * PageSetupDlg
2568  * rad1 - portrait
2569  * rad2 - landscape
2570  * cmb1 - printer select (not in standard dialog template)
2571  * cmb2 - paper size
2572  * cmb3 - source (tray?)
2573  * edt4 - border left
2574  * edt5 - border top
2575  * edt6 - border right
2576  * edt7 - border bottom
2577  * psh3 - "Printer..."
2578  */
2579 
2580 typedef struct
2581 {
2583  union
2584  {
2587  } u;
2588  HWND hDlg; /* Page Setup dialog handle */
2589  RECT rtDrawRect; /* Drawing rect for page */
2590 } pagesetup_data;
2591 
2593 {
2594  return data->u.dlgw->Flags;
2595 }
2596 
2597 static inline BOOL is_metric(const pagesetup_data *data)
2598 {
2600 }
2601 
2603 {
2604  if (is_metric(data))
2605  return 10 * size;
2606  else
2607  return 10 * size * 100 / 254;
2608 }
2609 
2611 {
2612  if (is_metric(data))
2613  return size * 254 / 100;
2614  else
2615  return size;
2616 }
2617 
2619 {
2620  static WCHAR sep;
2621 
2622  if(!sep)
2623  {
2624  WCHAR buf[] = {'.', 0};
2626  sep = buf[0];
2627  }
2628  return sep;
2629 }
2630 
2631 static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout)
2632 {
2633  static const WCHAR integer_fmt[] = {'%','d',0};
2634  static const WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0};
2635  static const WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0};
2636 
2637  /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */
2638 
2639  if (is_metric(data))
2640  {
2641  if(size % 100)
2642  wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100);
2643  else
2644  wsprintfW(strout, integer_fmt, size / 100);
2645  }
2646  else
2647  {
2648  if(size % 1000)
2649  wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000);
2650  else
2651  wsprintfW(strout, integer_fmt, size / 1000);
2652 
2653  }
2654 }
2655 
2656 static inline BOOL is_default_metric(void)
2657 {
2658  DWORD system;
2659  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER,
2660  (LPWSTR)&system, sizeof(system));
2661  return system == 0;
2662 }
2663 
2664 /**********************************************
2665  * rotate_rect
2666  * Cyclically permute the four members of rc
2667  * If sense is TRUE l -> t -> r -> b
2668  * otherwise l <- t <- r <- b
2669  */
2670 static inline void rotate_rect(RECT *rc, BOOL sense)
2671 {
2672  INT tmp;
2673  if(sense)
2674  {
2675  tmp = rc->bottom;
2676  rc->bottom = rc->right;
2677  rc->right = rc->top;
2678  rc->top = rc->left;
2679  rc->left = tmp;
2680  }
2681  else
2682  {
2683  tmp = rc->left;
2684  rc->left = rc->top;
2685  rc->top = rc->right;
2686  rc->right = rc->bottom;
2687  rc->bottom = tmp;
2688  }
2689 }
2690 
2692 {
2693  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2694 
2695  assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE);
2696 
2697  if(data->unicode)
2698  dm->u1.s1.dmOrientation = orient;
2699  else
2700  {
2701  DEVMODEA *dmA = (DEVMODEA *)dm;
2702  dmA->u1.s1.dmOrientation = orient;
2703  }
2704  GlobalUnlock(data->u.dlgw->hDevMode);
2705 }
2706 
2708 {
2709  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2710  WORD orient;
2711 
2712  if(data->unicode)
2713  orient = dm->u1.s1.dmOrientation;
2714  else
2715  {
2716  DEVMODEA *dmA = (DEVMODEA *)dm;
2717  orient = dmA->u1.s1.dmOrientation;
2718  }
2719  GlobalUnlock(data->u.dlgw->hDevMode);
2720  return orient;
2721 }
2722 
2724 {
2725  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2726 
2727  if(data->unicode)
2728  dm->u1.s1.dmPaperSize = paper;
2729  else
2730  {
2731  DEVMODEA *dmA = (DEVMODEA *)dm;
2732  dmA->u1.s1.dmPaperSize = paper;
2733  }
2734  GlobalUnlock(data->u.dlgw->hDevMode);
2735 }
2736 
2738 {
2739  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2740  WORD paper;
2741 
2742  if(data->unicode)
2743  paper = dm->u1.s1.dmPaperSize;
2744  else
2745  {
2746  DEVMODEA *dmA = (DEVMODEA *)dm;
2747  paper = dmA->u1.s1.dmPaperSize;
2748  }
2749  GlobalUnlock(data->u.dlgw->hDevMode);
2750  return paper;
2751 }
2752 
2754 {
2755  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2756 
2757  if(data->unicode)
2758  dm->u1.s1.dmDefaultSource = source;
2759  else
2760  {
2761  DEVMODEA *dmA = (DEVMODEA *)dm;
2762  dmA->u1.s1.dmDefaultSource = source;
2763  }
2764  GlobalUnlock(data->u.dlgw->hDevMode);
2765 }
2766 
2767 typedef enum
2768 {
2772 } devnames_name;
2773 
2774 
2776 {
2777  switch(which)
2778  {
2779  case devnames_driver_name: return dn->wDriverOffset;
2780  case devnames_device_name: return dn->wDeviceOffset;
2781  case devnames_output_name: return dn->wOutputOffset;
2782  }
2783  ERR("Shouldn't be here\n");
2784  return 0;
2785 }
2786 
2788 {
2789  DEVNAMES *dn;
2790  WCHAR *name;
2791 
2792  dn = GlobalLock(data->u.dlgw->hDevNames);
2793  if(data->unicode)
2794  name = strdupW((WCHAR *)dn + get_devname_offset(dn, which));
2795  else
2796  {
2797  int len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, NULL, 0);
2798  name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2799  MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, name, len);
2800  }
2801  GlobalUnlock(data->u.dlgw->hDevNames);
2802  return name;
2803 }
2804 
2806 {
2808 }
2809 
2811 {
2813 }
2814 
2816 {
2818 }
2819 
2821 {
2822  HeapFree(GetProcessHeap(), 0, name);
2823 }
2824 
2826 {
2827  DEVNAMES *dn;
2828  WCHAR def[256];
2829  DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len;
2830 
2831  if(data->unicode)
2832  {
2833  drv_len = (lstrlenW(drv) + 1) * sizeof(WCHAR);
2834  dev_len = (lstrlenW(devname) + 1) * sizeof(WCHAR);
2835  port_len = (lstrlenW(port) + 1) * sizeof(WCHAR);
2836  }
2837  else
2838  {
2839  drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL);
2840  dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL);
2841  port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL);
2842  }
2843  len += drv_len + dev_len + port_len;
2844 
2845  if(data->u.dlgw->hDevNames)
2846  data->u.dlgw->hDevNames = GlobalReAlloc(data->u.dlgw->hDevNames, len, GMEM_MOVEABLE);
2847  else
2848  data->u.dlgw->hDevNames = GlobalAlloc(GMEM_MOVEABLE, len);
2849 
2850  dn = GlobalLock(data->u.dlgw->hDevNames);
2851 
2852  if(data->unicode)
2853  {
2854  WCHAR *ptr = (WCHAR *)(dn + 1);
2855  len = sizeof(DEVNAMES) / sizeof(WCHAR);
2856  dn->wDriverOffset = len;
2857  lstrcpyW(ptr, drv);
2858  ptr += drv_len / sizeof(WCHAR);
2859  len += drv_len / sizeof(WCHAR);
2860  dn->wDeviceOffset = len;
2861  lstrcpyW(ptr, devname);
2862  ptr += dev_len / sizeof(WCHAR);
2863  len += dev_len / sizeof(WCHAR);
2864  dn->wOutputOffset = len;
2865  lstrcpyW(ptr, port);
2866  }
2867  else
2868  {
2869  char *ptr = (char *)(dn + 1);
2870  len = sizeof(DEVNAMES);
2871  dn->wDriverOffset = len;
2872  WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL);
2873  ptr += drv_len;
2874  len += drv_len;
2875  dn->wDeviceOffset = len;
2876  WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL);
2877  ptr += dev_len;
2878  len += dev_len;
2879  dn->wOutputOffset = len;
2880  WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL);
2881  }
2882 
2883  dn->wDefault = 0;
2884  len = ARRAY_SIZE(def);
2885  GetDefaultPrinterW(def, &len);
2886  if(!lstrcmpW(def, devname))
2887  dn->wDefault = 1;
2888 
2889  GlobalUnlock(data->u.dlgw->hDevNames);
2890 }
2891 
2893 {
2894  DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2895  DEVMODEW *ret;
2896 
2897  if(data->unicode)
2898  {
2899  /* We make a copy even in the unicode case because the ptr
2900  may get passed back to us in pagesetup_set_devmode. */
2901  ret = HeapAlloc(GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra);
2902  memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra);
2903  }
2904  else
2906 
2907  GlobalUnlock(data->u.dlgw->hDevMode);
2908  return ret;
2909 }
2910 
2912 {
2913  HeapFree(GetProcessHeap(), 0, dm);
2914 }
2915 
2917 {
2918  DEVMODEA *dmA = NULL;
2919  void *src, *dst;
2920  DWORD size;
2921 
2922  if(data->unicode)
2923  {
2924  size = dm->dmSize + dm->dmDriverExtra;
2925  src = dm;
2926  }
2927  else
2928  {
2929  dmA = convert_to_devmodeA(dm);
2930  size = dmA->dmSize + dmA->dmDriverExtra;
2931  src = dmA;
2932  }
2933 
2934  if(data->u.dlgw->hDevMode)
2935  data->u.dlgw->hDevMode = GlobalReAlloc(data->u.dlgw->hDevMode, size,
2936  GMEM_MOVEABLE);
2937  else
2938  data->u.dlgw->hDevMode = GlobalAlloc(GMEM_MOVEABLE, size);
2939 
2940  dst = GlobalLock(data->u.dlgw->hDevMode);
2941  memcpy(dst, src, size);
2942  GlobalUnlock(data->u.dlgw->hDevMode);
2943  HeapFree(GetProcessHeap(), 0, dmA);
2944 }
2945 
2947 {
2948  return &data->u.dlgw->ptPaperSize;
2949 }
2950 
2952 {
2953  return &data->u.dlgw->rtMargin;
2954 }
2955 
2956 typedef enum
2957 {
2960 } hook_type;
2961 
2963 {
2964  switch(which)
2965  {
2966  case page_setup_hook: return data->u.dlgw->lpfnPageSetupHook;
2967  case page_paint_hook: return data->u.dlgw->lpfnPagePaintHook;
2968  }
2969  return NULL;
2970 }
2971 
2972 /* This should only be used in calls to hook procs so we return the ptr
2973  already cast to LPARAM */
2975 {
2976  return (LPARAM)data->u.dlgw;
2977 }
2978 
2979 static inline void swap_point(POINT *pt)
2980 {
2981  LONG tmp = pt->x;
2982  pt->x = pt->y;
2983  pt->y = tmp;
2984 }
2985 
2987 {
2988  DEVMODEW *dm;
2989  LPWSTR devname, portname;
2990  int i, num;
2991  WORD *words = NULL, paperword;
2992  POINT *points = NULL;
2993  BOOL retval = FALSE;
2994 
2996  devname = pagesetup_get_devname(data);
2997  portname = pagesetup_get_portname(data);
2998 
2999  num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm);
3000  if (num <= 0)
3001  {
3002  FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname));
3003  goto end;
3004  }
3005 
3006  words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD));
3007  points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT));
3008 
3009  if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm))
3010  {
3011  FIXME("Number of returned words is not %d\n", num);
3012  goto end;
3013  }
3014 
3015  if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm))
3016  {
3017  FIXME("Number of returned sizes is not %d\n", num);
3018  goto end;
3019  }
3020 
3021  paperword = pagesetup_get_papersize(data);
3022 
3023  for (i = 0; i < num; i++)
3024  if (words[i] == paperword)
3025  break;
3026 
3027  if (i == num)
3028  {
3029  FIXME("Papersize %d not found in list?\n", paperword);
3030  goto end;
3031  }
3032 
3033  /* this is _10ths_ of a millimeter */
3036 
3039 
3040  retval = TRUE;
3041 
3042 end:
3043  HeapFree(GetProcessHeap(), 0, words);
3045  pagesetup_release_a_devname(data, portname);
3048 
3049  return retval;
3050 }
3051 
3052 /**********************************************************************************************
3053  * pagesetup_change_printer
3054  *
3055  * Redefines hDevMode and hDevNames HANDLES and initialises it.
3056  *
3057  */
3059 {
3060  HANDLE hprn;
3061  DWORD needed;
3062  PRINTER_INFO_2W *prn_info = NULL;
3063  DRIVER_INFO_3W *drv_info = NULL;
3064  DEVMODEW *dm = NULL;
3065  BOOL retval = FALSE;
3066 
3067  if(!OpenPrinterW(name, &hprn, NULL))
3068  {
3069  ERR("Can't open printer %s\n", debugstr_w(name));
3070  goto end;
3071  }
3072 
3073  GetPrinterW(hprn, 2, NULL, 0, &needed);
3074  prn_info = HeapAlloc(GetProcessHeap(), 0, needed);
3075  GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed);
3076  GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
3077  drv_info = HeapAlloc(GetProcessHeap(), 0, needed);
3078  if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed))
3079  {
3080  ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName));
3081  goto end;
3082  }
3083  ClosePrinter(hprn);
3084 
3085  needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
3086  if(needed == -1)
3087  {
3088  ERR("DocumentProperties fails on %s\n", debugstr_w(name));
3089  goto end;
3090  }
3091 
3092  dm = HeapAlloc(GetProcessHeap(), 0, needed);
3094 
3096  pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName,
3097  prn_info->pPortName);
3098 
3099  retval = TRUE;
3100 end:
3101  HeapFree(GetProcessHeap(), 0, dm);
3102  HeapFree(GetProcessHeap(), 0, prn_info);
3103  HeapFree(GetProcessHeap(), 0, drv_info);
3104  return retval;
3105 }
3106 
3107 /****************************************************************************************
3108  * pagesetup_init_combos
3109  *
3110  * Fills Printers, Paper and Source combos
3111  *
3112  */
3114 {
3115  DEVMODEW *dm;
3116  LPWSTR devname, portname;
3117 
3119  devname = pagesetup_get_devname(data);
3120  portname = pagesetup_get_portname(data);
3121 
3122  PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname);
3123  PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm);
3124  PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm);
3125 
3126  pagesetup_release_a_devname(data, portname);
3129 }
3130 
3131 
3132 /****************************************************************************************
3133  * pagesetup_change_printer_dialog
3134  *
3135  * Pops up another dialog that lets the user pick another printer.
3136  *
3137  * For now we display the PrintDlg, this should display a striped down version of it.
3138  */
3140 {
3141  PRINTDLGW prnt;
3142  LPWSTR drvname, devname, portname;
3143  DEVMODEW *tmp_dm, *dm;
3144 
3145  memset(&prnt, 0, sizeof(prnt));
3146  prnt.lStructSize = sizeof(prnt);
3147  prnt.Flags = 0;
3148  prnt.hwndOwner = hDlg;
3149 
3150  drvname = pagesetup_get_drvname(data);
3151  devname = pagesetup_get_devname(data);
3152  portname = pagesetup_get_portname(data);
3153  prnt.hDevNames = 0;
3154  PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname);
3155  pagesetup_release_a_devname(data, portname);
3158 
3159  tmp_dm = pagesetup_get_devmode(data);
3160  prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3161  dm = GlobalLock(prnt.hDevMode);
3162  memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3163  GlobalUnlock(prnt.hDevMode);
3165 
3166  if (PrintDlgW(&prnt))
3167  {
3168  DEVMODEW *dm = GlobalLock(prnt.hDevMode);
3169  DEVNAMES *dn = GlobalLock(prnt.hDevNames);
3170 
3172  (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset);
3174  GlobalUnlock(prnt.hDevNames);
3175  GlobalUnlock(prnt.hDevMode);
3176  pagesetup_init_combos(hDlg, data);
3177  }
3178 
3179  GlobalFree(prnt.hDevMode);
3180  GlobalFree(prnt.hDevNames);
3181 
3182 }
3183 
3184 /******************************************************************************************
3185  * pagesetup_change_preview
3186  *
3187  * Changes paper preview size / position
3188  *
3189  */
3191 {
3192  LONG width, height, x, y;
3193  RECT tmp;
3194  const int shadow = 4;
3195 
3197  {
3198  width = data->rtDrawRect.right - data->rtDrawRect.left;
3200  }
3201  else
3202  {
3203  height = data->rtDrawRect.bottom - data->rtDrawRect.top;
3205  }
3206  x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2;
3207  y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2;
3208  TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n",
3209  wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height);
3210 
3211  MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE);
3212  MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE);
3213  MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE);
3214 
3215  tmp = data->rtDrawRect;
3216  tmp.right += shadow;
3217  tmp.bottom += shadow;
3218  InvalidateRect(data->hDlg, &tmp, TRUE);
3219 }
3220 
3221 static inline LONG *element_from_margin_id(RECT *rc, WORD id)
3222 {
3223  switch(id)
3224  {
3225  case edt4: return &rc->left;
3226  case edt5: return &rc->top;
3227  case edt6: return &rc->right;
3228  case edt7: return &rc->bottom;
3229  }
3230  return NULL;
3231 }
3232 
3233 static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id)
3234 {
3235  WCHAR str[100];
3236  WORD idx;
3237 
3238  for(idx = edt4; idx <= edt7; idx++)
3239  {
3240  if(id == 0 || id == idx)
3241  {
3243  SetDlgItemTextW(hDlg, idx, str);
3244  }
3245  }
3246 }
3247 
3249 {
3250  switch (msg)
3251  {
3252  case EN_CHANGE:
3253  {
3254  WCHAR buf[10];
3255  LONG val = 0;
3257 
3258  if (GetDlgItemTextW(hDlg, id, buf, ARRAY_SIZE(buf)) != 0)
3259  {
3260  WCHAR *end;
3261  WCHAR decimal = get_decimal_sep();
3262 
3263  val = wcstol(buf, &end, 10);
3264  if(end != buf || *end == decimal)
3265  {
3266  int mult = is_metric(data) ? 100 : 1000;
3267  val *= mult;
3268  if(*end == decimal)
3269  {
3270  while(mult > 1)
3271  {
3272  end++;
3273  mult /= 10;
3274  if(iswdigit(*end))
3275  val += (*end - '0') * mult;
3276  else
3277  break;
3278  }
3279  }
3280  }
3281  }
3282  *value = val;
3283  return;
3284  }
3285 
3286  case EN_KILLFOCUS:
3287  update_margin_edits(hDlg, data, id);
3288  return;
3289  }
3290 }
3291 
3293 {
3294  WCHAR title[256];
3295 
3297  title, ARRAY_SIZE(title)))
3298  SetDlgItemTextW(hDlg, grp4, title);
3299 }
3300 
3302 {
3304  CheckRadioButton(hDlg, rad1, rad2, rad2);
3305  else
3306  CheckRadioButton(hDlg, rad1, rad2, rad1);
3307 }
3308 
3309 /****************************************************************************************
3310  * pagesetup_printer_properties
3311  *
3312  * Handle invocation of the 'Properties' button (not present in the default template).
3313  */
3315 {
3316  HANDLE hprn;
3317  LPWSTR devname;
3318  DEVMODEW *dm;
3319  LRESULT count;
3320  int i;
3321 
3322  devname = pagesetup_get_devname(data);
3323 
3324  if (!OpenPrinterW(devname, &hprn, NULL))
3325  {
3326  FIXME("Call to OpenPrinter did not succeed!\n");
3328  return;
3329  }
3330 
3332  DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
3336  ClosePrinter(hprn);
3337 
3338  /* Changing paper */
3341 
3342  /* Changing paper preview */
3344 
3345  /* Selecting paper in combo */
3346  count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0);
3347  if(count != CB_ERR)
3348  {
3349  WORD paperword = pagesetup_get_papersize(data);
3350  for(i = 0; i < count; i++)
3351  {
3352  if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) {
3353  SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0);
3354  break;
3355  }
3356  }
3357  }
3358 }
3359 
3360 /********************************************************************************
3361  * pagesetup_wm_command
3362  * process WM_COMMAND message for PageSetupDlg
3363  *
3364  * PARAMS
3365  * hDlg [in] Main dialog HANDLE
3366  * wParam [in] WM_COMMAND wParam
3367  * lParam [in] WM_COMMAND lParam
3368  * pda [in/out] ptr to PageSetupDataA
3369  */
3370 
3372 {
3373  WORD msg = HIWORD(wParam);
3374  WORD id = LOWORD(wParam);
3375 
3376  TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n",
3378  switch (id) {
3379  case IDOK:
3380  EndDialog(hDlg, TRUE);
3381  return TRUE ;
3382 
3383  case IDCANCEL:
3384  EndDialog(hDlg, FALSE);
3385  return FALSE ;
3386 
3387  case psh3: /* Printer... */
3389  return TRUE;
3390 
3391  case rad1: /* Portrait */
3392  case rad2: /* Landscape */
3395  {
3399  update_margin_edits(hDlg, data, 0);
3401  }
3402  break;
3403  case cmb1: /* Printer combo */
3404  if(msg == CBN_SELCHANGE)
3405  {
3406  WCHAR *name;
3407  INT index = SendDlgItemMessageW(hDlg, id, CB_GETCURSEL, 0, 0);
3409  name = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
3412  pagesetup_init_combos(hDlg, data);
3414  }
3415  break;
3416  case cmb2: /* Paper combo */
3417  if(msg == CBN_SELCHANGE)
3418  {
3419  DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA,
3420  SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0);
3421  if (paperword != CB_ERR)
3422  {
3423  pagesetup_set_papersize(data, paperword);
3426  } else
3427  FIXME("could not get dialog text for papersize cmbbox?\n");
3428  }
3429  break;
3430  case cmb3: /* Paper Source */
3431  if(msg == CBN_SELCHANGE)
3432  {
3434  SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0);
3436  }
3437  break;
3438  case psh2: /* Printer Properties button */
3440  break;
3441  case edt4:
3442  case edt5:
3443  case edt6:
3444  case edt7:
3445  margin_edit_notification(hDlg, data, msg, id);
3446  break;
3447  }
3449  return FALSE;
3450 }
3451 
3452 /***********************************************************************
3453  * default_page_paint_hook
3454  * Default hook paint procedure that receives WM_PSD_* messages from the dialog box
3455  * whenever the sample page is redrawn.
3456  */
3458  const pagesetup_data *data)
3459 {
3460  LPRECT lprc = (LPRECT) lParam;
3461  HDC hdc = (HDC) wParam;
3462  HPEN hpen, holdpen;
3463  LOGFONTW lf;
3464  HFONT hfont, holdfont;
3465  INT oldbkmode;
3466  TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER);
3467  /* Call user paint hook if enable */
3469  if (pagesetup_get_hook(data, page_paint_hook)(hwndDlg, uMsg, wParam, lParam))
3470  return TRUE;
3471 
3472  switch (uMsg) {
3473  /* LPPAGESETUPDLG in lParam */
3474  case WM_PSD_PAGESETUPDLG:
3475  /* Inform about the sample page rectangle */
3476  case WM_PSD_FULLPAGERECT:
3477  /* Inform about the margin rectangle */
3478  case WM_PSD_MINMARGINRECT:
3479  return FALSE;
3480 
3481  /* Draw dashed rectangle showing margins */
3482  case WM_PSD_MARGINRECT:
3484  holdpen = SelectObject(hdc, hpen);
3486  DeleteObject(SelectObject(hdc, holdpen));
3487  return TRUE;
3488  /* Draw the fake document */
3489  case WM_PSD_GREEKTEXTRECT:
3490  /* select a nice scalable font, because we want the text really small */
3491  SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
3492  lf.lfHeight = 6; /* value chosen based on visual effect */
3493  hfont = CreateFontIndirectW(&lf);
3494  holdfont = SelectObject(hdc, hfont);
3495 
3496  /* if text not loaded, then do so now */
3497  if (wszFakeDocumentText[0] == '\0')
3502 
3503  oldbkmode = SetBkMode(hdc, TRANSPARENT);
3505  SetBkMode(hdc, oldbkmode);
3506 
3507  DeleteObject(SelectObject(hdc, holdfont));
3508  return TRUE;
3509 
3510  /* Envelope stamp */
3511  case WM_PSD_ENVSTAMPRECT:
3512  /* Return address */
3513  case WM_PSD_YAFULLPAGERECT:
3514  FIXME("envelope/stamp is not implemented\n");
3515  return FALSE;
3516  default:
3517  FIXME("Unknown message %x\n",uMsg);
3518  return FALSE;
3519  }
3520  return TRUE;
3521 }
3522 
3523 /***********************************************************************
3524  * PagePaintProc
3525  * The main paint procedure for the PageSetupDlg function.
3526  * The Page Setup dialog box includes an image of a sample page that shows how
3527  * the user's selections affect the appearance of the printed output.
3528  * The image consists of a rectangle that represents the selected paper
3529  * or envelope type, with a dotted-line rectangle representing
3530  * the current margins, and partial (Greek text) characters
3531  * to show how text looks on the printed page.
3532  *
3533  * The following messages in the order sends to user hook procedure:
3534  * WM_PSD_PAGESETUPDLG Draw the contents of the sample page
3535  * WM_PSD_FULLPAGERECT Inform about the bounding rectangle
3536  * WM_PSD_MINMARGINRECT Inform about the margin rectangle (min margin?)
3537  * WM_PSD_MARGINRECT Draw the margin rectangle
3538  * WM_PSD_GREEKTEXTRECT Draw the Greek text inside the margin rectangle
3539  * If any of first three messages returns TRUE, painting done.
3540  *
3541  * PARAMS:
3542  * hWnd [in] Handle to the Page Setup dialog box
3543  * uMsg [in] Received message
3544  *
3545  * TODO:
3546  * WM_PSD_ENVSTAMPRECT Draw in the envelope-stamp rectangle (for envelopes only)
3547  * WM_PSD_YAFULLPAGERECT Draw the return address portion (for envelopes and other paper sizes)
3548  *
3549  * RETURNS:
3550  * FALSE if all done correctly
3551  *
3552  */
3553 
3554 
3555 static LRESULT CALLBACK
3557 {
3558  PAINTSTRUCT ps;
3559  RECT rcClient, rcMargin;
3560  HPEN hpen, holdpen;
3561  HDC hdc;
3562  HBRUSH hbrush, holdbrush;
3564  int papersize=0, orientation=0; /* FIXME: set these values for the user paint hook */
3565  double scalx, scaly;
3566 
3567  if (uMsg != WM_PAINT)
3569 
3570  /* Processing WM_PAINT message */
3572  if (!data) {
3573  WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3574  return FALSE;
3575  }
3576  if (default_page_paint_hook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation),
3578  return FALSE;
3579 
3580  hdc = BeginPaint(hWnd, &ps);
3581  GetClientRect(hWnd, &rcClient);
3582 
3583  scalx = rcClient.right / (double)pagesetup_get_papersize_pt(data)->x;
3584  scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y;
3585  rcMargin = rcClient;
3586 
3587  rcMargin.left += pagesetup_get_margin_rect(data)->left * scalx;
3588  rcMargin.top += pagesetup_get_margin_rect(data)->top * scaly;
3589  rcMargin.right -= pagesetup_get_margin_rect(data)->right * scalx;
3590  rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly;
3591 
3592  /* if the space is too small then we make sure to not draw anything */
3593  rcMargin.left = min(rcMargin.left, rcMargin.right);
3594  rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3595 
3598  {
3599  /* fill background */
3601  FillRect(hdc, &rcClient, hbrush);
3602  holdbrush = SelectObject(hdc, hbrush);
3603 
3605  holdpen = SelectObject(hdc, hpen);
3606 
3607  /* paint left edge */
3608  MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3609  LineTo(hdc, rcClient.left, rcClient.bottom-1);
3610 
3611  /* paint top edge */
3612  MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3613  LineTo(hdc, rcClient.right, rcClient.top);
3614 
3617 
3618  /* paint right edge */
3619  MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL);
3620  LineTo(hdc, rcClient.right-1, rcClient.bottom);
3621 
3622  /* paint bottom edge */
3623  MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL);
3624  LineTo(hdc, rcClient.right, rcClient.bottom-1);
3625 
3626  DeleteObject(SelectObject(hdc, holdpen));
3627  DeleteObject(SelectObject(hdc, holdbrush));
3628 
3630 
3631  /* give text a bit of a space from the frame */
3632  InflateRect(&rcMargin, -2, -2);
3633 
3634  /* if the space is too small then we make sure to not draw anything */
3635  rcMargin.left = min(rcMargin.left, rcMargin.right);
3636  rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3637 
3639  }
3640 
3641  EndPaint(hWnd, &ps);
3642  return FALSE;
3643 }
3644 
3645 /*******************************************************
3646  * The margin edit controls are subclassed to filter
3647  * anything other than numbers and the decimal separator.
3648  */
3650 {
3651  if (msg == WM_CHAR)
3652  {
3653  WCHAR decimal = get_decimal_sep();
3654  WCHAR wc = (WCHAR)wparam;
3655  if(!iswdigit(wc) && wc != decimal && wc != VK_BACK) return 0;
3656  }
3658 }
3659 
3660 static void subclass_margin_edits(HWND hDlg)
3661 {
3662  int id;
3663  WNDPROC old_proc;
3664 
3665  for(id = edt4; id <= edt7; id++)
3666  {
3668  GWLP_WNDPROC,
3671  }
3672 }
3673 
3674 /***********************************************************************
3675  * pagesetup_dlg_proc
3676  *
3677  * Message handler for PageSetupDlg
3678  */
3680 {
3682  INT_PTR res = FALSE;
3683  HWND hDrawWnd;
3684 
3685  if (uMsg == WM_INITDIALOG) { /*Init dialog*/
3686  data = (pagesetup_data *)lParam;
3687  data->hDlg = hDlg;
3688 
3689  hDrawWnd = GetDlgItem(hDlg, rct1);
3690  TRACE("set property to %p\n", data);
3692  SetPropW(hDrawWnd, pagesetupdlg_prop, data);
3693  GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */
3694  MapWindowPoints( 0, hDlg, (LPPOINT)&data->rtDrawRect, 2 );
3696  hDrawWnd,
3697  GWLP_WNDPROC,
3699 
3700  /* FIXME: Paint hook. Must it be at begin of initialization or at end? */
3701  res = TRUE;
3703  {
3704  if (!pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam,
3706  FIXME("Setup page hook failed?\n");
3707  }
3708 
3709  /* if printer button disabled */
3711  EnableWindow(GetDlgItem(hDlg, psh3), FALSE);
3712  /* if margin edit boxes disabled */
3714  {
3715  EnableWindow(GetDlgItem(hDlg, edt4), FALSE);
3716  EnableWindow(GetDlgItem(hDlg, edt5), FALSE);
3717  EnableWindow(GetDlgItem(hDlg, edt6), FALSE);
3718  EnableWindow(GetDlgItem(hDlg, edt7), FALSE);
3719  }
3720 
3721  /* Set orientation radiobuttons properly */
3723 
3724  /* if orientation disabled */
3726  {
3729  }
3730 
3731  /* We fill them out enabled or not */
3733  {
3734  /* default is 1 inch */
3737  }
3738  update_margin_edits(hDlg, data, 0);
3739  subclass_margin_edits(hDlg);
3741 
3742  /* if paper disabled */
3744  {
3747  }
3748 
3749  /* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */
3750  pagesetup_init_combos(hDlg, data);
3752  pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */
3753 
3754  /* Drawing paper prev */
3756  return TRUE;
3757  } else {
3758  data = GetPropW(hDlg, pagesetupdlg_prop);
3759  if (!data)
3760  {
3761  WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3762  return FALSE;
3763  }
3765  {
3767  if (res) return res;
3768  }
3769  }
3770  switch (uMsg) {
3771  case WM_COMMAND:
3772  return pagesetup_wm_command(hDlg, wParam, lParam, data);
3773  }
3774  return FALSE;
3775 }
3776 
3778 {
3779  WCHAR *name = NULL;
3780  DWORD len = 0;
3781 
3783  if(len)
3784  {
3785  name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3787  }
3788  return name;
3789 }
3790 
3792 {
3793  if(TRACE_ON(commdlg))
3794  {
3795  char flagstr[1000] = "";
3796  const struct pd_flags *pflag = psd_flags;
3797  for( ; pflag->name; pflag++)
3798  {
3799  if(pagesetup_get_flags(data) & pflag->flag)
3800  {
3801  strcat(flagstr, pflag->name);
3802  strcat(flagstr, "|");
3803  }
3804  }
3805  TRACE("%s: (%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
3806  "hinst %p, flags %08x (%s)\n",
3807  data->unicode ? "unicode" : "ansi",
3808  data->u.dlgw, data->u.dlgw->hwndOwner, data->u.dlgw->hDevMode,
3809  data->u.dlgw->hDevNames, data->u.dlgw->hInstance,
3810  pagesetup_get_flags(data), flagstr);
3811  }
3812 }
3813 
3815 {
3816  HRSRC res;
3817  HGLOBAL tmpl_handle;
3818 
3820  {
3821  tmpl_handle = data->u.dlgw->hPageSetupTemplate;
3822  }
3824  {
3825  if(data->unicode)
3826  res = FindResourceW(data->u.dlgw->hInstance,
3827  data->u.dlgw->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG);
3828  else
3829  res = FindResourceA(data->u.dlga->hInstance,
3830  data->u.dlga->lpPageSetupTemplateName, (LPSTR)RT_DIALOG);
3831  tmpl_handle = LoadResource(data->u.dlgw->hInstance, res);
3832  }
3833  else
3834  {
3836  (LPWSTR)RT_DIALOG);
3837  tmpl_handle = LoadResource(COMDLG32_hInstance, res);
3838  }
3839  return LockResource(tmpl_handle);
3840 }
3841 
3843 {
3844  BOOL ret;
3845  void *tmpl;
3846 
3848  {
3850  return FALSE;
3851  }
3852 
3854 
3855  if(data->u.dlgw->lStructSize != sizeof(PAGESETUPDLGW))
3856  {
3858  return FALSE;
3859  }
3860 
3863  {
3865  return FALSE;
3866  }
3867 
3869  data->u.dlgw->Flags |= is_default_metric() ?
3871 
3872  if (!data->u.dlgw->hDevMode || !data->u.dlgw->hDevNames)
3873  {
3874  WCHAR *def = get_default_printer();
3875  if(!def)
3876  {
3878  {
3879  WCHAR errstr[256];
3881  MessageBoxW(data->u.dlgw->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR);
3882  }
3884  return FALSE;
3885  }
3887  HeapFree(GetProcessHeap(), 0, def);
3888  }
3889 
3891  {
3893  return TRUE;
3894  }
3895 
3896  tmpl = pagesetup_get_template(data);
3897 
3898  ret = DialogBoxIndirectParamW(data->u.dlgw->hInstance, tmpl,
3899  data->u.dlgw->hwndOwner,
3901  return ret;
3902 }
3903 
3904 /***********************************************************************
3905  * PageSetupDlgA (COMDLG32.@)
3906  *
3907  * Displays the PAGE SETUP dialog box, which enables the user to specify
3908  * specific properties of a printed page such as
3909  * size, source, orientation and the width of the page margins.
3910  *
3911  * PARAMS
3912  * setupdlg [IO] PAGESETUPDLGA struct
3913  *
3914  * RETURNS
3915  * TRUE if the user pressed the OK button
3916  * FALSE if the user cancelled the window or an error occurred
3917  *
3918  * NOTES
3919  * The values of hDevMode and hDevNames are filled on output and can be
3920  * changed in PAGESETUPDLG when they are passed in PageSetupDlg.
3921  *
3922  */
3924 {
3926 
3927  data.unicode = FALSE;
3928  data.u.dlga = setupdlg;
3929 
3930  return pagesetup_common(&data);
3931 }
3932 
3933 /***********************************************************************
3934  * PageSetupDlgW (COMDLG32.@)
3935  *
3936  * See PageSetupDlgA.
3937  */
3939 {
3941 
3942  data.unicode = TRUE;
3943  data.u.dlgw = setupdlg;
3944 
3945  return pagesetup_common(&data);
3946 }
3947 
3948 static void pdlgex_to_pdlg(const PRINTDLGEXW *pdlgex, PRINTDLGW *pdlg)
3949 {
3950  pdlg->lStructSize = sizeof(*pdlg);
3951  pdlg->hwndOwner = pdlgex->hwndOwner;
3952  pdlg->hDevMode = pdlgex->hDevMode;
3953  pdlg->hDevNames = pdlgex->hDevNames;
3954  pdlg->hDC = pdlgex->hDC;
3955  pdlg->Flags = pdlgex->Flags;
3956  if ((pdlgex->Flags & PD_NOPAGENUMS) || !pdlgex->nPageRanges || !pdlgex->lpPageRanges)
3957  {
3958  pdlg->nFromPage = 0;
3959  pdlg->nToPage = 65534;
3960  }
3961  else
3962  {
3963  pdlg->nFromPage = pdlgex->lpPageRanges[0].nFromPage;
3964  pdlg->nToPage = pdlgex->lpPageRanges[0].nToPage;
3965  }
3966  pdlg->nMinPage = pdlgex->nMinPage;
3967  pdlg->nMaxPage = pdlgex->nMaxPage;
3968  pdlg->nCopies = pdlgex->nCopies;
3969  pdlg->hInstance = pdlgex->hInstance;
3970  pdlg->lCustData = 0;
3971  pdlg->lpfnPrintHook = NULL;
3972  pdlg->lpfnSetupHook = NULL;
3973  pdlg->lpPrintTemplateName = pdlgex->lpPrintTemplateName;
3974  pdlg->lpSetupTemplateName = NULL;
3975  pdlg->hPrintTemplate = NULL;
3976  pdlg->hSetupTemplate = NULL;
3977 }
3978 
3979 /* Only copy fields that are supposed to be changed. */
3980 static void pdlg_to_pdlgex(const PRINTDLGW *pdlg, PRINTDLGEXW *pdlgex)
3981 {
3982  pdlgex->hDevMode = pdlg->hDevMode;
3983  pdlgex->hDevNames = pdlg->hDevNames;
3984  pdlgex->hDC = pdlg->hDC;
3985  if (!(pdlgex->Flags & PD_NOPAGENUMS) && pdlgex->nPageRanges && pdlgex->lpPageRanges)
3986  {
3987  pdlgex->lpPageRanges[0].nFromPage = pdlg->nFromPage;
3988  pdlgex->lpPageRanges[0].nToPage = pdlg->nToPage;
3989  }
3990  pdlgex->nMinPage = pdlg->nMinPage;
3991  pdlgex->nMaxPage = pdlg->nMaxPage;
3992  pdlgex->nCopies = pdlg->nCopies;
3993 }
3994 
3996 {
3997  IPrintDialogCallback *callback;
3999 };
4000 
4002 {
4003  if (msg == WM_INITDIALOG)
4004  {
4005  PRINTDLGW *pd = (PRINTDLGW *)lp;
4006  struct callback_data *cb = (struct callback_data *)pd->lCustData;
4007 
4008  if (cb->callback)
4009  {
4010  cb->callback->lpVtbl->SelectionChange(cb->callback);
4011  cb->callback->lpVtbl->InitDone(cb->callback);
4012  }
4013  }
4014  else
4015  {
4016 /* FIXME: store interface pointer somewhere in window properties and call it
4017  HRESULT hres;
4018  cb->callback->lpVtbl->HandleMessage(cb->callback, hwnd, msg, wp, lp, &hres);
4019 */
4020  }
4021 
4022  return 0;
4023 }
4024 
4025 /***********************************************************************
4026  * PrintDlgExA (COMDLG32.@)
4027  *
4028  * See PrintDlgExW.
4029  *
4030  * BUGS
4031  * Only a Stub
4032  *
4033  */
4034 HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd)
4035 {
4037  DRIVER_INFO_3A *dbuf;
4038  DEVMODEA *dm;
4039  HRESULT hr = S_OK;
4040  HANDLE hprn;
4041 
4042  if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA)))
4043  return E_INVALIDARG;
4044 
4045  if (!IsWindow(lppd->hwndOwner))
4046  return E_HANDLE;
4047 
4048  if (lppd->nStartPage != START_PAGE_GENERAL)
4049  {
4050  if (!lppd->nPropertyPages)
4051  return E_INVALIDARG;
4052 
4053  FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages);
4054  }
4055 
4056  /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */
4057  if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges))
4058  {
4059  return E_INVALIDARG;
4060  }
4061 
4062  if (lppd->Flags & PD_RETURNDEFAULT)
4063  {
4064  if (lppd->hDevMode || lppd->hDevNames)
4065  {
4066  WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
4068  return E_INVALIDARG;
4069  }
4070  if (!PRINTDLG_OpenDefaultPrinter(&hprn))
4071  {
4072  WARN("Can't find default printer\n");
4074  return E_FAIL;
4075  }
4076 
4077  pbuf = get_printer_infoA(hprn);
4078  if (!pbuf)
4079  {
4080  ClosePrinter(hprn);
4081  return E_FAIL;
4082  }
4083 
4084  dbuf = get_driver_infoA(hprn);
4085  if (!dbuf)
4086  {
4087  HeapFree(GetProcessHeap(), 0, pbuf);
4089  ClosePrinter(hprn);
4090  return E_FAIL;
4091  }
4092  dm = pbuf->pDevMode;
4093  }
4094  else
4095  {
4096  PRINTDLGA pdlg;
4097  struct callback_data cb_data = { 0 };
4098 
4099  FIXME("(%p) semi-stub\n", lppd);
4100 
4101  if (lppd->lpCallback)
4102  {
4103  IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback);
4104  IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object);
4105  }
4106 
4107  /*
4108  * PRINTDLGEXA/W and PRINTDLGA/W layout is the same for A and W variants.
4109  */
4110  pdlgex_to_pdlg((const PRINTDLGEXW *)lppd, (PRINTDLGW *)&pdlg);
4111  pdlg.Flags |= PD_ENABLEPRINTHOOK;
4113  pdlg.lCustData = (LPARAM)&cb_data;
4114 
4115  if (PrintDlgA(&pdlg))
4116  {
4117  pdlg_to_pdlgex((const PRINTDLGW *)&pdlg, (PRINTDLGEXW *)lppd);
4118  lppd->dwResultAction = PD_RESULT_PRINT;
4119  }
4120  else
4121  lppd->dwResultAction = PD_RESULT_CANCEL;
4122 
4123  if (cb_data.callback)
4124  cb_data.