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