Implemented _ultow() and export [Nt/Zw]QueryVolumeInformationFile().
[wine] / dlls / commdlg / printdlg.c
1 /*
2  * COMMDLG - Print Dialog
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1996 Albrecht Kleine
6  * Copyright 1999 Klaas van Gend
7  * Copyright 2000 Huw D M Davies
8  */
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include "windef.h"
14 #include "winbase.h"
15 #include "wingdi.h"
16 #include "wine/wingdi16.h"
17 #include "winuser.h"
18 #include "wine/winuser16.h"
19 #include "commdlg.h"
20 #include "dlgs.h"
21 #include "debugtools.h"
22 #include "cderr.h"
23 #include "winspool.h"
24 #include "winerror.h"
25
26 DEFAULT_DEBUG_CHANNEL(commdlg);
27
28 #include "cdlg.h"
29
30
31 /* This PRINTDLGA internal structure stores
32  * pointers to several throughout useful structures.
33  * 
34  */
35 typedef struct  
36 {
37   LPDEVMODEA        lpDevMode;
38   LPPRINTDLGA       lpPrintDlg;
39   LPPRINTER_INFO_2A lpPrinterInfo;
40   UINT              HelpMessageID;
41   HICON             hCollateIcon;    /* PrintDlg only */
42   HICON             hNoCollateIcon;  /* PrintDlg only */
43   HICON             hPortraitIcon;   /* PrintSetupDlg only */
44   HICON             hLandscapeIcon;  /* PrintSetupDlg only */
45 } PRINT_PTRA;
46
47 /* Debugiging info */
48 static struct pd_flags {
49   DWORD flag;
50   LPSTR name;
51 } pd_flags[] = {
52   {PD_SELECTION, "PD_SELECTION "},
53   {PD_PAGENUMS, "PD_PAGENUMS "},
54   {PD_NOSELECTION, "PD_NOSELECTION "},
55   {PD_NOPAGENUMS, "PD_NOPAGENUMS "},
56   {PD_COLLATE, "PD_COLLATE "},
57   {PD_PRINTTOFILE, "PD_PRINTTOFILE "},
58   {PD_PRINTSETUP, "PD_PRINTSETUP "},
59   {PD_NOWARNING, "PD_NOWARNING "},
60   {PD_RETURNDC, "PD_RETURNDC "},
61   {PD_RETURNIC, "PD_RETURNIC "},
62   {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "},
63   {PD_SHOWHELP, "PD_SHOWHELP "},
64   {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "},
65   {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "},
66   {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "},
67   {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "},
68   {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "},
69   {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "},
70   {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "},
71   {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "},
72   {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "},
73   {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "},
74   {-1, NULL}
75 };
76
77
78 /***********************************************************************
79  *    PRINTDLG_GetDefaultPrinterName
80  *
81  * Returns the default printer name in buf.
82  * Even under WinNT/2000 default printer is retrieved via GetProfileString - 
83  * these entries are mapped somewhere in the registry rather than win.ini.
84  *
85  * Returns TRUE on success else FALSE
86  */
87 static BOOL PRINTDLG_GetDefaultPrinterName(LPSTR buf, DWORD len)
88 {
89     char *ptr;
90
91     if(!GetProfileStringA("windows", "device", "", buf, len))
92         return FALSE;
93     if((ptr = strchr(buf, ',')) == NULL)
94         return FALSE;
95     *ptr = '\0';
96     return TRUE;
97 }
98
99 /***********************************************************************
100  *    PRINTDLG_OpenDefaultPrinter
101  *
102  * Returns a winspool printer handle to the default printer in *hprn
103  * Caller must call ClosePrinter on the handle
104  *
105  * Returns TRUE on success else FALSE
106  */
107 static BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn)
108 {
109     char buf[260];
110     if(!PRINTDLG_GetDefaultPrinterName(buf, sizeof(buf)))
111         return FALSE;
112     return OpenPrinterA(buf, hprn, NULL);
113 }
114
115 /***********************************************************************
116  *    PRINTDLG_SetUpPrinterListCombo
117  *
118  * Initializes printer list combox.
119  * hDlg:  HWND of dialog
120  * id:    Control id of combo
121  * name:  Name of printer to select
122  *
123  * Initializes combo with list of available printers.  Selects printer 'name'
124  * If name is NULL or does not exist select the default printer.
125  *
126  * Returns number of printers added to list.
127  */
128 static INT PRINTDLG_SetUpPrinterListCombo(HWND hDlg, UINT id, LPCSTR name)
129 {
130     DWORD needed, num;
131     INT i;
132     LPPRINTER_INFO_2A pi;
133     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
134     pi = HeapAlloc(GetProcessHeap(), 0, needed);
135     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, 
136                   &num);
137
138     for(i = 0; i < num; i++) {
139         SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0,
140                             (LPARAM)pi[i].pPrinterName );
141     }
142     HeapFree(GetProcessHeap(), 0, pi);
143     if(!name ||
144        (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1,
145                                 (LPARAM)name)) == CB_ERR) {
146
147         char buf[260];
148         TRACE("Can't find '%s' in printer list so trying to find default\n",
149               name);
150         if(!PRINTDLG_GetDefaultPrinterName(buf, sizeof(buf)))
151             return num;
152         i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
153         if(i == CB_ERR)
154             TRACE("Can't find default printer in printer list\n");
155     }
156     SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0);
157     return num;
158 }
159
160 /***********************************************************************
161  *             PRINTDLG_CreateDevNames          [internal]
162  *
163  *
164  *   creates a DevNames structure.
165  *
166  *  (NB. when we handle unicode the offsets will be in wchars).
167  */
168 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, char* DeviceDriverName, 
169                                     char* DeviceName, char* OutputPort)
170 {
171     long size;
172     char*   pDevNamesSpace;
173     char*   pTempPtr;
174     LPDEVNAMES lpDevNames;
175     char buf[260];
176
177     size = strlen(DeviceDriverName) + 1
178             + strlen(DeviceName) + 1
179             + strlen(OutputPort) + 1
180             + sizeof(DEVNAMES);
181             
182     if(*hmem)
183         *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
184     else
185         *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
186     if (*hmem == 0)
187         return FALSE;
188
189     pDevNamesSpace = GlobalLock(*hmem);
190     lpDevNames = (LPDEVNAMES) pDevNamesSpace;
191
192     pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
193     strcpy(pTempPtr, DeviceDriverName);
194     lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
195
196     pTempPtr += strlen(DeviceDriverName) + 1;
197     strcpy(pTempPtr, DeviceName);
198     lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
199         
200     pTempPtr += strlen(DeviceName) + 1;
201     strcpy(pTempPtr, OutputPort);
202     lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
203
204     PRINTDLG_GetDefaultPrinterName(buf, sizeof(buf));
205     lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
206     GlobalUnlock(*hmem);
207     return TRUE;
208 }
209
210 /***********************************************************************
211  *             PRINTDLG_UpdatePrintDlg          [internal]
212  *
213  *
214  *   updates the PrintDlg structure for returnvalues.
215  *      
216  * RETURNS
217  *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
218  *   TRUE  if succesful.
219  */
220 static BOOL PRINTDLG_UpdatePrintDlg(HWND hDlg, 
221                                     PRINT_PTRA* PrintStructures)
222 {
223     LPPRINTDLGA       lppd = PrintStructures->lpPrintDlg;
224     PDEVMODEA         lpdm = PrintStructures->lpDevMode;
225     LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
226
227
228     if(!lpdm) return FALSE;
229
230
231     if(!(lppd->Flags & PD_PRINTSETUP)) {
232         /* check whether nFromPage and nToPage are within range defined by
233          * nMinPage and nMaxPage
234          */
235         if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
236             WORD nToPage;
237             WORD nFromPage;
238             nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
239             nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
240             if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
241                 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
242                 char resourcestr[256];
243                 char resultstr[256];
244                 LoadStringA(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, 
245                             resourcestr, 255);
246                 sprintf(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
247                 LoadStringA(COMDLG32_hInstance, PD32_PRINT_TITLE, 
248                             resourcestr, 255);
249                 MessageBoxA(hDlg, resultstr, resourcestr,
250                             MB_OK | MB_ICONWARNING);
251                 return FALSE;
252             }
253             lppd->nFromPage = nFromPage;
254             lppd->nToPage   = nToPage;
255         }
256
257         if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
258             lppd->Flags |= PD_PRINTTOFILE;
259             pi->pPortName = "FILE:";
260         }
261
262         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
263             FIXME("Collate lppd not yet implemented as output\n");
264         }
265
266         /* set PD_Collate and nCopies */
267         if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
268           /*  The application doesn't support multiple copies or collate...
269            */
270             lppd->Flags &= ~PD_COLLATE;
271             lppd->nCopies = 1;
272           /* if the printer driver supports it... store info there
273            * otherwise no collate & multiple copies !
274            */
275             if (lpdm->dmFields & DM_COLLATE)
276                 lpdm->dmCollate = 
277                   (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
278             if (lpdm->dmFields & DM_COPIES)
279                 lpdm->dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
280         } else {
281             if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
282                 lppd->Flags |= PD_COLLATE;
283             else
284                lppd->Flags &= ~PD_COLLATE;
285             lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
286         }
287     }
288     return TRUE;
289 }
290
291
292 /************************************************************************
293  * PRINTDLG_SetUpPaperComboBox
294  *
295  * Initialize either the papersize or inputslot combos of the Printer Setup
296  * dialog.  We store the associated word (eg DMPAPER_A4) as the item data.
297  * We also try to re-select the old selection.
298  */
299 static BOOL PRINTDLG_SetUpPaperComboBox(HWND hDlg,
300                                         int   nIDComboBox,
301                                         char* PrinterName, 
302                                         char* PortName,
303                                         LPDEVMODEA dm)
304 {
305     int     i;
306     DWORD   NrOfEntries;
307     char*   Names;
308     WORD*   Words;
309     DWORD   Sel;
310     WORD    oldWord = 0;
311     int     NamesSize;
312     int     fwCapability_Names;
313     int     fwCapability_Words;
314     
315     TRACE(" Printer: %s, ComboID: %d\n",PrinterName,nIDComboBox);
316     
317     /* query the dialog box for the current selected value */
318     Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
319     if(Sel != CB_ERR) {
320         oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, Sel,
321                                       0);
322     }
323
324     if (nIDComboBox == cmb2) {
325          NamesSize          = 64;
326          fwCapability_Names = DC_PAPERNAMES;
327          fwCapability_Words = DC_PAPERS;
328     } else {
329          nIDComboBox        = cmb3;
330          NamesSize          = 24;
331          fwCapability_Names = DC_BINNAMES;
332          fwCapability_Words = DC_BINS;
333     }
334     
335     /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the 
336      * paper settings. As Wine doesn't allow VXDs, this results in a crash.
337      */
338     WARN(" if your printer driver uses VXDs, expect a crash now!\n");
339     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
340                                       fwCapability_Names, NULL, dm);
341     if (NrOfEntries == 0)
342          WARN("no Name Entries found!\n");
343
344     if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
345        != NrOfEntries) {
346         ERR("Number of caps is different\n");
347         NrOfEntries = 0;
348     }
349
350     Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*NamesSize);
351     Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
352     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
353                                       fwCapability_Names, Names, dm);
354     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
355                                       fwCapability_Words, (LPSTR)Words, dm);
356
357     /* reset any current content in the combobox */
358     SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
359     
360     /* store new content */
361     for (i = 0; i < NrOfEntries; i++) {
362         DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
363                                         (LPARAM)(&Names[i*NamesSize]) );
364         SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos, 
365                             Words[i]);
366     }
367
368     /* Look for old selection - can't do this is previous loop since
369        item order will change as more items are added */
370     Sel = 0;
371     for (i = 0; i < NrOfEntries; i++) {
372         if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
373            oldWord) {
374             Sel = i;
375             break;
376         }
377     }
378     SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
379
380     HeapFree(GetProcessHeap(),0,Words);
381     HeapFree(GetProcessHeap(),0,Names);
382     return TRUE;
383 }
384
385 /***********************************************************************
386  *               PRINTDLG_UpdatePrinterInfoTexts               [internal]
387  */
388 static void PRINTDLG_UpdatePrinterInfoTexts(HWND hDlg, LPPRINTER_INFO_2A pi)
389 {
390     char   StatusMsg[256];
391     char   ResourceString[256];
392     int    i;
393
394     /* Status Message */
395     StatusMsg[0]='\0';
396
397     /* add all status messages */
398     for (i = 0; i < 25; i++) {
399         if (pi->Status & (1<<i)) {
400             LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i, 
401                         ResourceString, 255);
402             strcat(StatusMsg,ResourceString);
403         }
404     }
405     /* append "ready" */
406     /* FIXME: status==ready must only be appended if really so. 
407               but how to detect? */
408     LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY, 
409                 ResourceString, 255);
410     strcat(StatusMsg,ResourceString);
411   
412     SendDlgItemMessageA(hDlg, stc12, WM_SETTEXT, 0, (LPARAM)StatusMsg);
413
414     /* set all other printer info texts */
415     SendDlgItemMessageA(hDlg, stc11, WM_SETTEXT, 0, (LPARAM)pi->pDriverName);
416     if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
417         SendDlgItemMessageA(hDlg, stc14, WM_SETTEXT, 0,(LPARAM)pi->pLocation);
418     else
419         SendDlgItemMessageA(hDlg, stc14, WM_SETTEXT, 0,(LPARAM)pi->pPortName);
420     SendDlgItemMessageA(hDlg, stc13, WM_SETTEXT, 0, (LPARAM)pi->pComment);
421     return;
422 }
423
424
425 /*******************************************************************
426  *
427  *                 PRINTDLG_ChangePrinter
428  *
429  */
430 static BOOL PRINTDLG_ChangePrinter(HWND hDlg, char *name,
431                                    PRINT_PTRA *PrintStructures)
432 {
433     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
434     LPDEVMODEA lpdm = NULL;
435     LONG dmSize;
436     DWORD needed;
437     HANDLE hprn;
438
439     if(PrintStructures->lpPrinterInfo)
440         HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
441     if(!OpenPrinterA(name, &hprn, NULL)) {
442         ERR("Can't open printer %s\n", name);
443         return FALSE;
444     }
445     GetPrinterA(hprn, 2, NULL, 0, &needed);
446     PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
447     GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
448                 &needed);
449     ClosePrinter(hprn);
450
451     PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures->lpPrinterInfo);
452
453     if(PrintStructures->lpDevMode) {
454         HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
455         PrintStructures->lpDevMode = NULL;
456     }
457
458     dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0);
459     if(dmSize == -1) {
460         ERR("DocumentProperties fails on %s\n", debugstr_a(name));
461         return FALSE;
462     }
463     PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
464     dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL,
465                                  DM_OUT_BUFFER);
466     if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
467                           !strcmp(lpdm->dmDeviceName,
468                                   PrintStructures->lpDevMode->dmDeviceName)) {
469       /* Supplied devicemode matches current printer so try to use it */
470         DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm,
471                             DM_OUT_BUFFER | DM_IN_BUFFER);
472     }
473     if(lpdm)
474         GlobalUnlock(lppd->hDevMode);
475
476     lpdm = PrintStructures->lpDevMode;  /* use this as a shortcut */
477
478     if(!(lppd->Flags & PD_PRINTSETUP)) {
479       /* Print range (All/Range/Selection) */
480         SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
481         SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
482         CheckRadioButton(hDlg, rad1, rad3, rad1);               /* default */
483         if (lppd->Flags & PD_NOSELECTION)
484             EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
485         else
486             if (lppd->Flags & PD_SELECTION)
487                 CheckRadioButton(hDlg, rad1, rad3, rad2);
488         if (lppd->Flags & PD_NOPAGENUMS) {
489             EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
490             EnableWindow(GetDlgItem(hDlg, stc2),FALSE);
491             EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
492             EnableWindow(GetDlgItem(hDlg, stc3),FALSE);
493             EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
494         } else {
495             if (lppd->Flags & PD_PAGENUMS)
496                 CheckRadioButton(hDlg, rad1, rad3, rad3);
497         }
498         /* "All xxx pages"... */
499         {
500             char        resourcestr[64];
501             char        result[64];
502             LoadStringA(COMDLG32_hInstance, PD32_PRINT_ALL_X_PAGES, 
503                         resourcestr, 49);
504             sprintf(result,resourcestr,lppd->nMaxPage - lppd->nMinPage + 1);
505             SendDlgItemMessageA(hDlg, rad1, WM_SETTEXT, 0, (LPARAM) result);
506         }
507         
508         /* Collate pages 
509          *
510          * FIXME: The ico3 is not displayed for some reason. I don't know why.
511          */
512         if (lppd->Flags & PD_COLLATE) {
513             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, 
514                                 (LPARAM)PrintStructures->hCollateIcon);
515             CheckDlgButton(hDlg, chx2, 1);
516         } else {
517             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, 
518                                 (LPARAM)PrintStructures->hNoCollateIcon);
519             CheckDlgButton(hDlg, chx2, 0);
520         }
521
522         if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
523           /* if printer doesn't support it: no Collate */
524             if (!(lpdm->dmFields & DM_COLLATE)) {
525                 EnableWindow(GetDlgItem(hDlg, chx2), FALSE);    
526                 EnableWindow(GetDlgItem(hDlg, ico3), FALSE);    
527             }
528         }
529
530         /* nCopies */
531         if (lppd->hDevMode == 0)
532             SetDlgItemInt(hDlg, edt3, lppd->nCopies, FALSE);
533         else
534             SetDlgItemInt(hDlg, edt3, lpdm->dmCopies, FALSE);
535
536         if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
537           /* if printer doesn't support it: no nCopies */
538             if (!(lpdm->dmFields & DM_COPIES)) {
539                 EnableWindow(GetDlgItem(hDlg, edt3), FALSE);    
540                 EnableWindow(GetDlgItem(hDlg, stc5), FALSE);    
541             }
542         }
543
544         /* print to file */
545         CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
546         if (lppd->Flags & PD_DISABLEPRINTTOFILE)
547             EnableWindow(GetDlgItem(hDlg, chx1), FALSE);    
548         if (lppd->Flags & PD_HIDEPRINTTOFILE)
549             ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
550
551     } else { /* PD_PRINTSETUP */
552       PRINTDLG_SetUpPaperComboBox(hDlg, cmb2,
553                                   PrintStructures->lpPrinterInfo->pPrinterName,
554                                   PrintStructures->lpPrinterInfo->pPortName,
555                                   lpdm);
556       PRINTDLG_SetUpPaperComboBox(hDlg, cmb3,
557                                   PrintStructures->lpPrinterInfo->pPrinterName,
558                                   PrintStructures->lpPrinterInfo->pPortName,
559                                   lpdm);
560       CheckRadioButton(hDlg, rad1, rad2,
561                        (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT) ?
562                        rad1: rad2);
563     }
564
565     /* help button */
566     if ((lppd->Flags & PD_SHOWHELP)==0) {
567         /* hide if PD_SHOWHELP not specified */
568         ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE);         
569     }
570
571     return TRUE;
572 }
573
574 /***********************************************************************
575  *           PRINTDLG_WMInitDialog                      [internal]
576  */
577 static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, WPARAM wParam,
578                                      PRINT_PTRA* PrintStructures)
579 {
580     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
581     DEVNAMES *pdn;
582     DEVMODEA *pdm;
583     char *name = NULL;
584     UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
585
586     /* load Collate ICONs */
587     PrintStructures->hCollateIcon =
588       LoadIconA(COMDLG32_hInstance, "PD32_COLLATE");
589     PrintStructures->hNoCollateIcon = 
590       LoadIconA(COMDLG32_hInstance, "PD32_NOCOLLATE");
591     if(PrintStructures->hCollateIcon == 0 ||
592        PrintStructures->hNoCollateIcon == 0) {
593         ERR("no icon in resourcefile\n");
594         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
595         EndDialog(hDlg, FALSE);
596     }
597
598     /* load Paper Orientation ICON */
599     /* FIXME: not implemented yet */
600
601     /*
602      * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
603      * must be registered and the Help button must be shown.
604      */
605     if (lppd->Flags & PD_SHOWHELP) {
606         if((PrintStructures->HelpMessageID = 
607             RegisterWindowMessageA(HELPMSGSTRING)) == 0) {
608             COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
609             return FALSE;
610         }
611     } else
612         PrintStructures->HelpMessageID = 0;
613
614     /* FIXME: I allow more freedom than either Win95 or WinNT,
615      *        which do not agree to what errors should be thrown or not
616      *        in case nToPage or nFromPage is out-of-range.
617      */
618     if (lppd->nMaxPage < lppd->nMinPage)
619         lppd->nMaxPage = lppd->nMinPage;
620     if (lppd->nMinPage == lppd->nMaxPage) 
621         lppd->Flags |= PD_NOPAGENUMS;        
622     if (lppd->nToPage < lppd->nMinPage)
623         lppd->nToPage = lppd->nMinPage;
624     if (lppd->nToPage > lppd->nMaxPage)
625         lppd->nToPage = lppd->nMaxPage;
626     if (lppd->nFromPage < lppd->nMinPage)
627         lppd->nFromPage = lppd->nMinPage;
628     if (lppd->nFromPage > lppd->nMaxPage)
629         lppd->nFromPage = lppd->nMaxPage;
630
631     /* Fill Combobox 
632      */
633     pdn = GlobalLock(lppd->hDevNames);
634     pdm = GlobalLock(lppd->hDevMode);
635     if(pdn)
636         name = (char*)pdn + pdn->wDeviceOffset;
637     else if(pdm)
638         name = pdm->dmDeviceName;
639     PRINTDLG_SetUpPrinterListCombo(hDlg, comboID, name);
640     if(pdm) GlobalUnlock(lppd->hDevMode);
641     if(pdn) GlobalUnlock(lppd->hDevNames);
642
643     /* Now find selected printer and update rest of dlg */
644     name = HeapAlloc(GetProcessHeap(),0,256);
645     GetDlgItemTextA(hDlg, comboID, name, 255);
646     PRINTDLG_ChangePrinter(hDlg, name, PrintStructures);
647     HeapFree(GetProcessHeap(),0,name);
648
649     return TRUE;
650 }
651
652 /***********************************************************************
653  *                              PRINTDLG_WMCommand               [internal]
654  */
655 static LRESULT PRINTDLG_WMCommand(HWND hDlg, WPARAM wParam, 
656                         LPARAM lParam, PRINT_PTRA* PrintStructures)
657 {
658     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
659     UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
660     LPDEVMODEA lpdm = PrintStructures->lpDevMode;
661
662     switch (LOWORD(wParam))  {
663     case IDOK:
664         TRACE(" OK button was hit\n");
665         if (PRINTDLG_UpdatePrintDlg(hDlg, PrintStructures)!=TRUE)
666             return(FALSE);
667         EndDialog(hDlg, TRUE);
668         return(TRUE);
669
670     case IDCANCEL:
671         TRACE(" CANCEL button was hit\n");
672         EndDialog(hDlg, FALSE);
673         return(FALSE);
674
675      case pshHelp:
676         TRACE(" HELP button was hit\n");
677         SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, 
678                                 (WPARAM) hDlg, (LPARAM) lppd);
679         break;
680
681      case chx2:                         /* collate pages checkbox */
682         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
683             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, 
684                                     (LPARAM)PrintStructures->hCollateIcon);
685         else
686             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, 
687                                     (LPARAM)PrintStructures->hNoCollateIcon);
688         break;        
689      case edt1:                         /* from page nr editbox */
690      case edt2:                         /* to page nr editbox */
691         if (HIWORD(wParam)==EN_CHANGE) {
692             WORD nToPage;
693             WORD nFromPage;
694             nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
695             nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
696             if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
697                 CheckRadioButton(hDlg, rad1, rad3, rad3);
698         }
699         break;
700      case psh2:                       /* Properties button */
701        {
702          HANDLE hPrinter;
703          char   PrinterName[256];
704
705          GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255);
706          if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) {
707              WARN(" Call to OpenPrinter did not succeed!\n");
708              break;
709          }
710          DocumentPropertiesA(hDlg, hPrinter, PrinterName, 
711                              PrintStructures->lpDevMode,
712                              PrintStructures->lpDevMode,
713                              DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
714          ClosePrinter(hPrinter);
715          break;
716        }
717
718     case cmb1:
719     case cmb4:                         /* Printer combobox */
720          if (HIWORD(wParam)==CBN_SELCHANGE) {
721              char   PrinterName[256];
722              GetDlgItemTextA(hDlg, LOWORD(wParam), PrinterName, 255);
723              PRINTDLG_ChangePrinter(hDlg, PrinterName, PrintStructures);
724          }
725          break;
726
727     case cmb2: /* Papersize */
728       {
729           DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0);
730           if(Sel != CB_ERR)
731               lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2,
732                                                             CB_GETITEMDATA,
733                                                             Sel, 0);
734       }
735       break;
736
737     case cmb3: /* Bin */
738       {
739           DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0);
740           if(Sel != CB_ERR)
741               lpdm->dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3,
742                                                           CB_GETITEMDATA, Sel,
743                                                           0);
744       }
745       break; 
746     }
747     return FALSE;
748 }    
749
750 /***********************************************************************
751  *           PrintDlgProcA                      [internal]
752  */
753 BOOL WINAPI PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam,
754                           LPARAM lParam)
755 {
756     PRINT_PTRA* PrintStructures;
757     LRESULT res=FALSE;
758
759     if (uMsg!=WM_INITDIALOG) {
760         PrintStructures = (PRINT_PTRA*) GetWindowLongA(hDlg, DWL_USER);   
761         if (!PrintStructures)
762             return FALSE;
763     } else {
764         PrintStructures = (PRINT_PTRA*) lParam;
765         SetWindowLongA(hDlg, DWL_USER, lParam); 
766         res = PRINTDLG_WMInitDialog(hDlg, wParam, PrintStructures);
767
768         if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
769             res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg,
770                                                  wParam,
771                                        (LPARAM)PrintStructures->lpPrintDlg); 
772         }
773         return res;
774     }
775   
776     if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
777         res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam,
778                                                          lParam);
779         if(res) return res;
780     }
781
782     switch (uMsg) {
783     case WM_COMMAND:
784         return PRINTDLG_WMCommand(hDlg, wParam, lParam, PrintStructures);
785
786     case WM_DESTROY:
787         DestroyIcon(PrintStructures->hCollateIcon);
788         DestroyIcon(PrintStructures->hNoCollateIcon);
789     /* FIXME: don't forget to delete the paper orientation icons here! */
790
791         return FALSE;
792     }    
793     return res;
794 }
795
796 /************************************************************
797  *
798  *      PRINTDLG_GetDlgTemplate
799  *
800  */
801 static HGLOBAL PRINTDLG_GetDlgTemplate(PRINTDLGA *lppd)
802 {
803     HGLOBAL hDlgTmpl, hResInfo;
804
805     if (lppd->Flags & PD_PRINTSETUP) {
806         if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
807             hDlgTmpl = lppd->hSetupTemplate;
808         } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {       
809             hResInfo = FindResourceA(lppd->hInstance,
810                                      lppd->lpSetupTemplateName, RT_DIALOGA);
811             hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
812         } else {
813             hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP",
814                                      RT_DIALOGA);
815             hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
816         }
817     } else {
818         if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
819             hDlgTmpl = lppd->hPrintTemplate;
820         } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
821             hResInfo = FindResourceA(lppd->hInstance,
822                                      lppd->lpPrintTemplateName,
823                                      RT_DIALOGA);
824             hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
825         } else {
826             hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32",
827                                      RT_DIALOGA);
828             hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
829         }
830     }
831     return hDlgTmpl;
832 }
833
834 /***********************************************************************
835  *
836  *      PRINTDLG_CreateDC
837  *
838  */
839 static BOOL PRINTDLG_CreateDC(LPPRINTDLGA lppd)
840 {
841     DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
842     DEVMODEA *pdm = GlobalLock(lppd->hDevMode);
843
844     if(lppd->Flags & PD_RETURNDC) {
845         lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset,
846                               (char*)pdn + pdn->wDeviceOffset,
847                               (char*)pdn + pdn->wOutputOffset,
848                               pdm );
849     } else if(lppd->Flags & PD_RETURNIC) {
850         lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset,
851                               (char*)pdn + pdn->wDeviceOffset,
852                               (char*)pdn + pdn->wOutputOffset,
853                               pdm );
854     }
855     GlobalUnlock(lppd->hDevNames);
856     GlobalUnlock(lppd->hDevMode);
857     return lppd->hDC ? TRUE : FALSE;
858 }
859
860 /***********************************************************************
861  *           PrintDlgA   (COMDLG32.17)
862  *
863  *  Displays the the PRINT dialog box, which enables the user to specify
864  *  specific properties of the print job.
865  *
866  * RETURNS
867  *  nonzero if the user pressed the OK button
868  *  zero    if the user cancelled the window or an error occurred
869  *
870  * BUGS
871  *  PrintDlg:
872  *  * The Collate Icons do not display, even though they are in the code.
873  *  * The Properties Button(s) should call DocumentPropertiesA().
874  *  PrintSetupDlg:
875  *  * The Paper Orientation Icons are not implemented yet.
876  *  * The Properties Button(s) should call DocumentPropertiesA().
877  *  * Settings are not yet taken from a provided DevMode or 
878  *    default printer settings.
879  */
880 BOOL WINAPI PrintDlgA(
881                       LPPRINTDLGA lppd /* [in/out] ptr to PRINTDLG32 struct */
882                       )
883 {
884     BOOL      bRet = FALSE;
885     LPVOID   ptr;
886     HINSTANCE hInst = GetWindowLongA( lppd->hwndOwner, GWL_HINSTANCE );
887
888     if(TRACE_ON(commdlg)) {
889         char flagstr[1000] = "";
890         struct pd_flags *pflag = pd_flags;
891         for( ; pflag->name; pflag++) {
892             if(lppd->Flags & pflag->flag)
893                 strcat(flagstr, pflag->name);
894         }
895         TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n"
896               "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n"
897               "flags %08lx (%s)\n",
898               lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
899               lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
900               lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
901     }
902
903     if(lppd->lStructSize != sizeof(PRINTDLGA)) {
904         WARN("structure size failure !!!\n");
905         COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
906         return FALSE; 
907     }
908
909     if(lppd->Flags & PD_RETURNDEFAULT) {
910         PRINTER_INFO_2A *pbuf;
911         HANDLE hprn;
912         DWORD needed;
913
914         if(lppd->hDevMode || lppd->hDevNames) {
915             WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
916             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); 
917             return FALSE;
918         }
919         if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
920             WARN("Can't find default printer\n");
921             COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); 
922             return FALSE;
923         }
924
925         GetPrinterA(hprn, 2, NULL, 0, &needed);
926         pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
927         GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed);
928         ClosePrinter(hprn);
929         PRINTDLG_CreateDevNames(&(lppd->hDevNames), "winspool",
930                                   pbuf->pDevMode->dmDeviceName,
931                                   pbuf->pPortName);
932         lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
933                                      pbuf->pDevMode->dmDriverExtra);
934         ptr = GlobalLock(lppd->hDevMode);
935         memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
936                pbuf->pDevMode->dmDriverExtra);
937         GlobalUnlock(lppd->hDevMode);
938         HeapFree(GetProcessHeap(), 0, pbuf);
939         bRet = TRUE;
940     } else {
941         HGLOBAL hDlgTmpl;
942         PRINT_PTRA *PrintStructures;
943
944     /* load Dialog resources, 
945      * depending on Flags indicates Print32 or Print32_setup dialog 
946      */
947         hDlgTmpl = PRINTDLG_GetDlgTemplate(lppd);
948         if (!(hDlgTmpl) || !(ptr = LockResource( hDlgTmpl ))) {
949             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
950             return FALSE;
951         }
952         PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
953                                     sizeof(PRINT_PTRA));
954         PrintStructures->lpPrintDlg = lppd;
955
956         /* and create & process the dialog .
957          * -1 is failure, 0 is broken hwnd, everything else is ok.
958          */
959         bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner,
960                                        PrintDlgProcA,
961                                        (LPARAM)PrintStructures));
962
963         if(bRet) {
964             DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
965             PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo;
966
967             if (lppd->hDevMode == 0) {
968                 TRACE(" No hDevMode yet... Need to create my own\n");
969                 lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE,
970                                         lpdm->dmSize + lpdm->dmDriverExtra);
971             } else {
972                 WORD locks;
973                 if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) {
974                     WARN("hDevMode has %d locks on it. Unlocking it now\n", locks);
975                     while(locks--) {
976                         GlobalUnlock(lppd->hDevMode);
977                         TRACE("Now got %d locks\n", locks);
978                     }
979                 }
980                 lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
981                                                lpdm->dmSize + lpdm->dmDriverExtra,
982                                                GMEM_MOVEABLE);
983             }
984             lpdmReturn = GlobalLock(lppd->hDevMode);
985             memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
986
987             if (lppd->hDevNames != 0) {
988                 WORD locks;
989                 if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) {
990                     WARN("hDevNames has %d locks on it. Unlocking it now\n", locks);
991                     while(locks--)
992                         GlobalUnlock(lppd->hDevNames);
993                 }
994             }
995             PRINTDLG_CreateDevNames(&(lppd->hDevNames), "winspool",
996                                     lpdmReturn->dmDeviceName, pi->pPortName);
997             GlobalUnlock(lppd->hDevMode);
998         }
999         HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1000         HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
1001         HeapFree(GetProcessHeap(), 0, PrintStructures);
1002     }
1003     if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
1004         bRet = PRINTDLG_CreateDC(lppd);
1005
1006     TRACE("exit! (%d)\n", bRet);        
1007     return bRet;    
1008 }
1009
1010
1011
1012 /***********************************************************************
1013  *           PrintDlgW   (COMDLG32.18)
1014  */
1015 BOOL WINAPI PrintDlgW( LPPRINTDLGW printdlg )
1016 {
1017     FIXME("A really empty stub\n" );
1018     return FALSE;
1019 }
1020
1021 /***********************************************************************
1022  *
1023  *          PageSetupDlg
1024  */
1025
1026 /***********************************************************************
1027  *            PageSetupDlgA  (COMDLG32.15)
1028  */
1029 BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) {
1030         FIXME("(%p), stub!\n",setupdlg);
1031         return FALSE;
1032 }
1033 /***********************************************************************
1034  *            PageSetupDlgW  (COMDLG32.16)
1035  */
1036 BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) {
1037         FIXME("(%p), stub!\n",setupdlg);
1038         return FALSE;
1039 }
1040
1041 /**********************************************************************
1042  *
1043  *      16 bit commdlg
1044  */
1045
1046 /***********************************************************************
1047  *           PrintDlgProc16   (COMMDLG.21)
1048  */
1049 LRESULT WINAPI PrintDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
1050                             LPARAM lParam)
1051 {
1052   switch (wMsg)
1053     {
1054     case WM_INITDIALOG:
1055       TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
1056       ShowWindow(hWnd, SW_SHOWNORMAL);
1057       return (TRUE);
1058     case WM_COMMAND:
1059       switch (wParam)
1060         {
1061         case IDOK:
1062           EndDialog(hWnd, TRUE);
1063           return(TRUE);
1064         case IDCANCEL:
1065           EndDialog(hWnd, FALSE);
1066           return(TRUE);
1067         }
1068       return(FALSE);
1069     }
1070   return FALSE;
1071 }
1072
1073
1074 /***********************************************************************
1075  *           PrintSetupDlgProc16   (COMMDLG.22)
1076  */
1077 LRESULT WINAPI PrintSetupDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
1078                                    LPARAM lParam)
1079 {
1080   switch (wMsg)
1081     {
1082     case WM_INITDIALOG:
1083       TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
1084       ShowWindow(hWnd, SW_SHOWNORMAL);
1085       return (TRUE);
1086     case WM_COMMAND:
1087       switch (wParam) {
1088       case IDOK:
1089         EndDialog(hWnd, TRUE);
1090         return(TRUE);
1091       case IDCANCEL:
1092         EndDialog(hWnd, FALSE);
1093         return(TRUE);
1094       }
1095       return(FALSE);
1096     }
1097   return FALSE;
1098 }
1099
1100
1101 /***********************************************************************
1102  *           PrintDlg16   (COMMDLG.20)
1103  * 
1104  *  Displays the the PRINT dialog box, which enables the user to specify
1105  *  specific properties of the print job.
1106  *
1107  * RETURNS
1108  *  nonzero if the user pressed the OK button
1109  *  zero    if the user cancelled the window or an error occurred
1110  *
1111  * BUGS
1112  *  * calls up to the 32-bit versions of the Dialogs, which look different
1113  *  * Customizing is *not* implemented.
1114  */
1115 BOOL16 WINAPI PrintDlg16( LPPRINTDLG16 lpPrint )
1116 {
1117     PRINTDLGA Print32;
1118     BOOL16 ret;
1119     char *ptr, *ptr16;
1120     DWORD size;
1121
1122     memset(&Print32, 0, sizeof(Print32));
1123     Print32.lStructSize = sizeof(Print32);
1124     Print32.hwndOwner   = lpPrint->hwndOwner;
1125     if(lpPrint->hDevMode) {
1126         size = GlobalSize16(lpPrint->hDevMode);
1127         Print32.hDevMode = GlobalAlloc(GMEM_MOVEABLE, size);
1128         ptr = GlobalLock(Print32.hDevMode);
1129         ptr16 = GlobalLock16(lpPrint->hDevMode);
1130         memcpy(ptr, ptr16, size);
1131         GlobalFree16(lpPrint->hDevMode);
1132         GlobalUnlock(Print32.hDevMode);
1133     } else
1134         Print32.hDevMode = 0;
1135     if(lpPrint->hDevNames) {
1136         size = GlobalSize16(lpPrint->hDevNames);
1137         Print32.hDevNames = GlobalAlloc(GMEM_MOVEABLE, size);
1138         ptr = GlobalLock(Print32.hDevNames);
1139         ptr16 = GlobalLock16(lpPrint->hDevNames);
1140         memcpy(ptr, ptr16, size);
1141         GlobalFree16(lpPrint->hDevNames);
1142         GlobalUnlock(Print32.hDevNames);
1143     } else
1144         Print32.hDevNames = 0;
1145     Print32.Flags       = lpPrint->Flags;
1146     Print32.nFromPage   = lpPrint->nFromPage;
1147     Print32.nToPage     = lpPrint->nToPage;
1148     Print32.nMinPage    = lpPrint->nMinPage;
1149     Print32.nMaxPage    = lpPrint->nMaxPage;
1150     Print32.nCopies     = lpPrint->nCopies;
1151     Print32.hInstance   = lpPrint->hInstance;
1152     Print32.lCustData   = lpPrint->lCustData;
1153     if(lpPrint->lpfnPrintHook) {
1154         FIXME("Need to allocate thunk\n");
1155 /*        Print32.lpfnPrintHook = lpPrint->lpfnPrintHook;*/
1156     }
1157     if(lpPrint->lpfnSetupHook) {
1158         FIXME("Need to allocate thunk\n");
1159 /*      Print32.lpfnSetupHook = lpPrint->lpfnSetupHook;*/
1160     }
1161     Print32.lpPrintTemplateName = MapSL(lpPrint->lpPrintTemplateName);
1162     Print32.lpSetupTemplateName = MapSL(lpPrint->lpSetupTemplateName);
1163     Print32.hPrintTemplate = lpPrint->hPrintTemplate;
1164     Print32.hSetupTemplate = lpPrint->hSetupTemplate;
1165
1166     ret = PrintDlgA(&Print32);
1167
1168     if(Print32.hDevMode) {
1169         size = GlobalSize(Print32.hDevMode);
1170         lpPrint->hDevMode = GlobalAlloc16(GMEM_MOVEABLE, size);
1171         ptr16 = GlobalLock16(lpPrint->hDevMode);
1172         ptr = GlobalLock(Print32.hDevMode);
1173         memcpy(ptr16, ptr, size);
1174         GlobalFree(Print32.hDevMode);
1175         GlobalUnlock16(lpPrint->hDevMode);
1176     } else
1177         lpPrint->hDevMode = 0;
1178     if(Print32.hDevNames) {
1179         size = GlobalSize(Print32.hDevNames);
1180         lpPrint->hDevNames = GlobalAlloc16(GMEM_MOVEABLE, size);
1181         ptr16 = GlobalLock16(lpPrint->hDevNames);
1182         ptr = GlobalLock(Print32.hDevNames);
1183         memcpy(ptr16, ptr, size);
1184         GlobalFree(Print32.hDevNames);
1185         GlobalUnlock16(lpPrint->hDevNames);
1186     } else
1187         lpPrint->hDevNames = 0;
1188     lpPrint->hDC       = Print32.hDC;
1189     lpPrint->Flags     = Print32.Flags;
1190     lpPrint->nFromPage = Print32.nFromPage;
1191     lpPrint->nToPage   = Print32.nToPage;
1192     lpPrint->nCopies   = Print32.nCopies;
1193
1194     return ret;
1195 }
1196
1197 /***********************************************************************
1198  *      PrintDlgExA
1199  */
1200 HRESULT WINAPI PrintDlgExA(LPVOID lpPrintDlgExA) /* [???] FIXME: LPPRINTDLGEXA */
1201 {
1202         FIXME("stub\n");
1203         return E_NOTIMPL;
1204 }
1205 /***********************************************************************
1206  *      PrintDlgExW
1207  */
1208 HRESULT WINAPI PrintDlgExW(LPVOID lpPrintDlgExW) /* [???] FIXME: LPPRINTDLGEXW */
1209 {
1210         FIXME("stub\n");
1211         return E_NOTIMPL;
1212 }