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