Removed MODULE_GetWndProcEntry16().
[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  */
8
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "winbase.h"
13 #include "wine/winbase16.h"
14 #include "wine/winuser16.h"
15 #include "ldt.h"
16 #include "commdlg.h"
17 #include "resource.h"
18 #include "dialog.h"
19 #include "dlgs.h"
20 #include "module.h"
21 #include "debugtools.h"
22 #include "winproc.h"
23 #include "cderr.h"
24 #include "winspool.h"
25
26 DEFAULT_DEBUG_CHANNEL(commdlg)
27
28 #include "cdlg.h"
29
30 /***********************************************************************
31  *           PrintDlg16   (COMMDLG.20)
32  */
33 BOOL16 WINAPI PrintDlg16( SEGPTR printdlg )
34 {
35     HANDLE16 hInst;
36     BOOL16 bRet = FALSE;
37     LPCVOID template;
38     HWND hwndDialog;
39     HANDLE hResInfo, hDlgTmpl;
40     LPSTR rscname;
41     LPPRINTDLG16 lpPrint = (LPPRINTDLG16)PTR_SEG_TO_LIN(printdlg);
42
43     TRACE("(%p) -- Flags=%08lX\n", lpPrint, lpPrint->Flags );
44
45     if (lpPrint->Flags & PD_RETURNDEFAULT)
46         /* FIXME: should fill lpPrint->hDevMode and lpPrint->hDevNames here */
47         return TRUE;
48
49     if (lpPrint->Flags & PD_PRINTSETUP)
50         rscname = "PRINT_SETUP";
51     else
52         rscname = "PRINT";
53
54     if (!(hResInfo = FindResourceA(COMMDLG_hInstance32, rscname, RT_DIALOGA)))
55     {
56         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
57         return FALSE;
58     }
59     if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hResInfo )) ||
60         !(template = LockResource( hDlgTmpl )))
61     {
62         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
63         return FALSE;
64     }
65
66     hInst = GetWindowLongA( lpPrint->hwndOwner, GWL_HINSTANCE );
67     hwndDialog = DIALOG_CreateIndirect( hInst, template, TRUE,
68                                         lpPrint->hwndOwner,
69                                (DLGPROC16)((lpPrint->Flags & PD_PRINTSETUP) ?
70                                 /* FIXME: PrintSetupDlgProc */ PrintDlgProcA :
71                                 PrintDlgProcA ),
72                                 printdlg, WIN_PROC_32A );
73     if (hwndDialog) bRet = DIALOG_DoDialogBox( hwndDialog, lpPrint->hwndOwner);
74     return bRet;
75 }
76
77
78 /* This PRINTDLGA internal structure stores
79  * pointers to several throughout useful structures.
80  * 
81  */
82 typedef struct  
83 {
84   LPPRINTER_INFO_2A lpPrinterInfo;
85   DWORD             NrOfPrinterInfoEntries;
86   LPPRINTDLGA       lpPrintDlg;
87   UINT              HelpMessageID;
88 } PRINT_PTRA;
89
90 /***********************************************************************
91  *           PrintDlgA   (COMDLG32.17)
92  *
93  *  Displays the the PRINT dialog box, which enables the user to specify
94  *  specific properties of the print job.
95  *
96  *  (Note: according to the MS Platform SDK, this call was in the past 
97  *   also used to display some PRINT SETUP dialog. As this is superseded 
98  *   by PageSetupDlg, this now results in an error!)
99  *
100  * RETURNS
101  *  nonzero if the user pressed the OK button
102  *  zero    if the user cancelled the window or an error occurred
103  *
104  * BUGS
105  *  The function is a stub only, returning TRUE to allow more programs
106  *  to function.
107  */
108 BOOL WINAPI PrintDlgA(
109                          LPPRINTDLGA lppd /* ptr to PRINTDLG32 struct */
110                          )
111 {
112 /* My implementing strategy:
113  * 
114  * step 1: display the dialog and implement the layout-flags
115  * step 2: enter valid information in the fields (e.g. real printers)
116  * step 3: fix the RETURN-TRUE-ALWAYS Fixme by checking lppd->Flags for
117  *         PD_RETURNDEFAULT
118  * step 4: implement all other specs
119  * step 5: allow customisation of the dialog box
120  *
121  * current implementation is in step 2, nearly going to 3.
122      */ 
123
124     HWND      hwndDialog;
125     BOOL      bRet = FALSE;
126     LPCVOID   ptr;
127     HANDLE    hResInfo, hDlgTmpl;
128     HINSTANCE hInst = GetWindowLongA( lppd->hwndOwner, GWL_HINSTANCE );
129     DWORD     EnumBytesNeeded;
130     DWORD     CopyOfEnumBytesNeeded;
131     PRINT_PTRA PrintStructures;
132
133     FIXME("KVG (%p): stub\n", lppd);
134     PrintStructures.lpPrintDlg = lppd;
135
136     if (!(hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32", RT_DIALOGA)))
137     {
138         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
139         return FALSE;
140     }
141     if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
142         !(ptr = LockResource( hDlgTmpl )))
143     {
144         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
145         return FALSE;
146     }
147
148     /*
149      * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
150      * must be registered and the Help button must be shown.
151      */
152     if (lppd->Flags & PD_SHOWHELP)
153        {
154         if((PrintStructures.HelpMessageID = RegisterWindowMessageA(HELPMSGSTRING)) 
155                         == 0)
156             {
157              COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
158              return FALSE;
159             }
160        }
161     else
162         PrintStructures.HelpMessageID=0;
163         
164         /*
165          * if lppd->Flags PD_RETURNDEFAULT is specified, the PrintDlg function
166          * does not display the dialog box, but returns with valid entries
167          * for hDevMode and hDevNames .
168          * 
169          * Currently the flag is recognised, but we return empty hDevMode and
170          * and hDevNames. This will be fixed when I am in step 3.
171          */
172         if (lppd->Flags & PD_RETURNDEFAULT)
173            {
174             WARN(": PrintDlg was requested to return printer info only."
175                                           "\n The return value currently does NOT provide these.\n");
176                 COMDLG32_SetCommDlgExtendedError(PDERR_NODEVICES); 
177                                                                         /* return TRUE, thus never checked! */
178             return(TRUE);
179            }
180            
181         if (lppd->Flags & PD_PRINTSETUP)
182                 {
183                  FIXME(": PrintDlg was requested to display PrintSetup box.\n");
184                  COMDLG32_SetCommDlgExtendedError(PDERR_INITFAILURE); 
185                  return(FALSE);
186                 }
187                 
188     /* Use EnumPrinters to obtain a list of PRINTER_INFO_2A's
189      * and store a pointer to this list in our "global structure"
190      * as reference for the rest of the PrintDlg routines
191      */
192     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 
193         0, &EnumBytesNeeded, &PrintStructures.NrOfPrinterInfoEntries);
194     CopyOfEnumBytesNeeded=EnumBytesNeeded+16;
195     PrintStructures.lpPrinterInfo = malloc(CopyOfEnumBytesNeeded*sizeof(char));
196     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, 
197         (LPBYTE)PrintStructures.lpPrinterInfo, 
198         CopyOfEnumBytesNeeded, &EnumBytesNeeded, 
199         &PrintStructures.NrOfPrinterInfoEntries);
200
201     /* Find the default printer.
202      * If not: display a warning message (unless PD_NOWARNING specified)
203      */
204     /* FIXME: Currently Unimplemented */
205     if (lppd->Flags & PD_NOWARNING)     
206            {
207             WARN(": PD_NOWARNING Flag is not yet implemented.\n");
208            }
209         
210     /*
211      * FIXME : Should respond to TEMPLATE and HOOK flags here
212      * For now, only the standard dialog works.
213      */
214     if (lppd->Flags & (PD_ENABLEPRINTHOOK | PD_ENABLEPRINTTEMPLATE |
215                           PD_ENABLEPRINTTEMPLATEHANDLE | PD_ENABLESETUPHOOK | 
216                           PD_ENABLESETUPTEMPLATE|PD_ENABLESETUPTEMPLATEHANDLE)) 
217         FIXME(": unimplemented flag (ignored)\n");     
218         
219                 
220     hwndDialog= DIALOG_CreateIndirect(hInst, ptr, TRUE, lppd->hwndOwner,
221             (DLGPROC16)PrintDlgProcA, (LPARAM)&PrintStructures, WIN_PROC_32A );
222     if (hwndDialog) 
223         bRet = DIALOG_DoDialogBox(hwndDialog, lppd->hwndOwner);  
224         
225     free(PrintStructures.lpPrinterInfo);
226         
227   return bRet;            
228 }
229
230
231
232 /***********************************************************************
233  *           PrintDlg32W   (COMDLG32.18)
234  */
235 BOOL WINAPI PrintDlgW( LPPRINTDLGW printdlg )
236 {
237     FIXME("A really empty stub\n" );
238     return FALSE;
239 }
240
241
242 /***********************************************************************
243  *               PRINTDLG_UpdatePrinterInfoTexts               [internal]
244  */
245 static void PRINTDLG_UpdatePrinterInfoTexts(HWND hDlg, PRINT_PTRA* PrintStructures)
246 {
247         char   PrinterName[256];
248     char   StatusMsg[256];
249     int    i;
250     LPPRINTER_INFO_2A lpPi = NULL;
251         GetDlgItemTextA(hDlg, cmb4, PrinterName, 255);
252              
253     /* look the selected PrinterName up in our array Printer_Info2As*/
254     for (i=0; i < PrintStructures->NrOfPrinterInfoEntries; i++)
255         {
256          lpPi = &PrintStructures->lpPrinterInfo[i];
257          if (strcmp(lpPi->pPrinterName, PrinterName)==0)
258          break;
259         }
260     /* FIXME: the status byte must be converted to user-understandable text...*/
261     sprintf(StatusMsg,"%ld = 0x%08lx", lpPi->Status, lpPi->Status);
262     SendDlgItemMessageA(hDlg, stc12, WM_SETTEXT, 0, (LPARAM)StatusMsg);
263     SendDlgItemMessageA(hDlg, stc11, WM_SETTEXT, 0, (LPARAM)lpPi->pDriverName);
264     if (lpPi->pLocation != NULL && lpPi->pLocation[0]!='\0')
265         SendDlgItemMessageA(hDlg, stc14, WM_SETTEXT, 0,(LPARAM)lpPi->pLocation);
266     else                                        
267         SendDlgItemMessageA(hDlg, stc14, WM_SETTEXT, 0, (LPARAM)lpPi->pPortName);
268     SendDlgItemMessageA(hDlg, stc13, WM_SETTEXT, 0, (LPARAM)lpPi->pComment);
269 }
270
271
272 /***********************************************************************
273  *           PRINTDLG_WMInitDialog                      [internal]
274  */
275 static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam,
276                                      PRINT_PTRA* PrintStructures)
277 {
278  int         i;
279  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
280  LPPRINTER_INFO_2A lppi = PrintStructures->lpPrinterInfo;
281  
282         SetWindowLongA(hDlg, DWL_USER, lParam); 
283         TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
284
285         if (lppd->lStructSize != sizeof(PRINTDLGA))
286         {
287                 FIXME("structure size failure !!!\n");
288 /*              EndDialog (hDlg, 0); 
289                 return FALSE; 
290 */      }
291
292 /* Fill Combobox according to info from PRINTER_INFO2A
293  * structure inside PrintStructures and generate an
294  * update-message to have the rest of the dialog box updated.
295  */ 
296     for (i=0; i < PrintStructures->NrOfPrinterInfoEntries; i++)
297            SendDlgItemMessageA(hDlg, cmb4, CB_ADDSTRING, 0,
298                         (LPARAM)lppi[i].pPrinterName );  
299     PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures);
300
301 /* Flag processing to set the according buttons on/off and
302  * Initialise the various values
303  */
304
305     /* Print range (All/Range/Selection) */
306     /* FIXME: I allow more freedom than either Win95 or WinNT,
307      *        which do not agree to what errors should be thrown or not
308      *        in case nToPage or nFromPage is out-of-range.
309      */
310     if (lppd->nMaxPage < lppd->nMinPage)
311         lppd->nMaxPage = lppd->nMinPage;
312     if (lppd->nMinPage == lppd->nMaxPage) 
313         lppd->Flags |= PD_NOPAGENUMS;        
314     if (lppd->nToPage < lppd->nMinPage)
315         lppd->nToPage = lppd->nMinPage;
316     if (lppd->nToPage > lppd->nMaxPage)
317         lppd->nToPage = lppd->nMaxPage;
318     if (lppd->nFromPage < lppd->nMinPage)
319         lppd->nFromPage = lppd->nMinPage;
320     if (lppd->nFromPage > lppd->nMaxPage)
321         lppd->nFromPage = lppd->nMaxPage;
322     SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
323     SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
324     CheckRadioButton(hDlg, rad1, rad3, rad1);           /* default */
325     if (lppd->Flags & PD_NOSELECTION)
326                 EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
327     else
328                 if (lppd->Flags & PD_SELECTION)
329                 CheckRadioButton(hDlg, rad1, rad3, rad2);
330     if (lppd->Flags & PD_NOPAGENUMS)
331        {
332                 EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
333                 EnableWindow(GetDlgItem(hDlg, stc2),FALSE);
334                 EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
335                 EnableWindow(GetDlgItem(hDlg, stc3),FALSE);
336                 EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
337        }
338     else
339        {
340                 if (lppd->Flags & PD_PAGENUMS)
341                 CheckRadioButton(hDlg, rad1, rad3, rad3);
342        }
343         /* FIXME: in Win95, the radiobutton "All" is displayed as
344          * "Print all xxx pages"... This is not done here (yet?)
345          */
346         
347         /* Collate pages */
348     if (lppd->Flags & PD_COLLATE)
349         FIXME("PD_COLLATE not implemented yet\n");
350         
351     /* print to file */
352         CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
353     if (lppd->Flags & PD_DISABLEPRINTTOFILE)
354                 EnableWindow(GetDlgItem(hDlg, chx1), FALSE);    
355     if (lppd->Flags & PD_HIDEPRINTTOFILE)
356                 ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
357     
358     /* status */
359
360     /* help button */
361         if ((lppd->Flags & PD_SHOWHELP)==0)
362         {       /* hide if PD_SHOWHELP not specified */
363                  ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE);         
364         }
365
366 TRACE("succesful!\n");
367   return TRUE;
368 }
369
370
371 /***********************************************************************
372  *             PRINTDLG_ValidateAndDuplicateSettings          [internal]
373  *
374  *
375  *   updates the PrintDlg structure for returnvalues.
376  * RETURNS
377  *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
378  *   TRUE  if succesful.
379  */
380 static BOOL PRINTDLG_ValidateAndDuplicateSettings(HWND hDlg, 
381                                                   PRINT_PTRA* PrintStructures)
382 {
383  LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
384  
385     /* check whether nFromPage and nToPage are within range defined by
386      * nMinPage and nMaxPage
387      */
388     if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED)
389     {
390         WORD nToPage;
391         WORD nFromPage;
392         nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
393         nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
394         if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
395             nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage)
396         {
397                         char TempBuffer[256];
398             FIXME("This MessageBox is not internationalised.");
399          sprintf(TempBuffer, "This value lies not within Page range\n"
400                              "Please enter a value between %d and %d",
401                              lppd->nMinPage, lppd->nMaxPage);
402          MessageBoxA(hDlg, TempBuffer, "Print", MB_OK | MB_ICONWARNING);
403          return(FALSE);
404         }
405         lppd->nFromPage = nFromPage;
406         lppd->nToPage   = nToPage;
407     }
408      
409     if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED)
410        {
411         lppd->Flags |= PD_PRINTTOFILE;
412         /* FIXME: insert code to set "FILE:" in DEVNAMES structure */
413 }
414
415  return(TRUE);   
416 }
417
418
419 /***********************************************************************
420  *                              PRINTDLG_WMCommand               [internal]
421  */
422 static LRESULT PRINTDLG_WMCommand(HWND hDlg, WPARAM wParam, 
423                         LPARAM lParam, PRINT_PTRA* PrintStructures)
424 {
425     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
426
427     switch (LOWORD(wParam)) 
428     {
429          case IDOK:
430         TRACE(" OK button was hit\n");
431         if (PRINTDLG_ValidateAndDuplicateSettings(hDlg, PrintStructures) != TRUE)
432                 return(FALSE);
433             DestroyWindow(hDlg);
434             return(TRUE);
435          case IDCANCEL:
436         TRACE(" CANCEL button was hit\n");
437         EndDialog(hDlg, FALSE);
438             return(FALSE);
439      case pshHelp:
440         TRACE(" HELP button was hit\n");
441         SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, 
442                                 (WPARAM) hDlg, (LPARAM) lppd);
443         break;
444      case edt1:                                                 /* from page nr editbox */
445      case edt2:                                                 /* to page nr editbox */
446         if (HIWORD(wParam)==EN_CHANGE)
447            {
448             WORD nToPage;
449                 WORD nFromPage;
450                 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
451                 nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
452             if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
453                             CheckRadioButton(hDlg, rad1, rad3, rad3);
454     }
455         break;
456      case psh2:                                                 /* Properties button */
457         {
458          HANDLE hPrinter;
459          char   PrinterName[256];
460          GetDlgItemTextA(hDlg, cmb4, PrinterName, 255);
461          if (OpenPrinterA(PrinterName, &hPrinter, NULL))
462             {
463              PrinterProperties(hDlg, hPrinter);
464              ClosePrinter(hPrinter);
465             }
466          else
467             WARN(" Call to OpenPrinter did not succeed!\n");
468          break;
469         }
470      case cmb4:                                                 /* Printer combobox */
471         if (HIWORD(wParam)==CBN_SELCHANGE)
472                         PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures);
473         break;
474 /*     default:
475         printf("wParam: 0x%x  ",wParam);
476         break;
477 */    }
478     return FALSE;
479 }    
480
481
482
483 /***********************************************************************
484  *           PrintDlgProcA                      [internal]
485  */
486 LRESULT WINAPI PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam,
487                                     LPARAM lParam)
488 {
489   PRINT_PTRA* PrintStructures;
490   LRESULT res=FALSE;
491   if (uMsg!=WM_INITDIALOG)
492   {
493    PrintStructures = (PRINT_PTRA*) GetWindowLongA(hDlg, DWL_USER);   
494    if (!PrintStructures)
495     return FALSE;
496 }
497   else
498   {
499     PrintStructures=(PRINT_PTRA*) lParam;
500     if (!PRINTDLG_WMInitDialog(hDlg, wParam, lParam, PrintStructures)) 
501     {
502       TRACE("PRINTDLG_WMInitDialog returned FALSE\n");
503       return FALSE;
504     }  
505     MessageBoxA(hDlg,"Warning: this dialog has no functionality yet!", 
506                         NULL, MB_OK);
507   }
508   switch (uMsg)
509   {
510         case WM_COMMAND:
511        return PRINTDLG_WMCommand(hDlg, wParam, lParam, PrintStructures);
512     case WM_DESTROY:
513             return FALSE;
514   }
515   
516  return res;
517 }
518
519
520
521
522 /***********************************************************************
523  *           PrintDlgProc16   (COMMDLG.21)
524  */
525 LRESULT WINAPI PrintDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
526                             LPARAM lParam)
527 {
528   switch (wMsg)
529     {
530     case WM_INITDIALOG:
531       TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
532       ShowWindow16(hWnd, SW_SHOWNORMAL);
533       return (TRUE);
534     case WM_COMMAND:
535       switch (wParam)
536         {
537         case IDOK:
538           EndDialog(hWnd, TRUE);
539           return(TRUE);
540         case IDCANCEL:
541           EndDialog(hWnd, FALSE);
542           return(TRUE);
543         }
544       return(FALSE);
545     }
546   return FALSE;
547 }
548
549
550 /***********************************************************************
551  *           PrintSetupDlgProc   (COMMDLG.22)
552  */
553 LRESULT WINAPI PrintSetupDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
554                                  LPARAM lParam)
555 {
556   switch (wMsg)
557     {
558     case WM_INITDIALOG:
559       TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
560       ShowWindow16(hWnd, SW_SHOWNORMAL);
561       return (TRUE);
562     case WM_COMMAND:
563       switch (wParam) {
564       case IDOK:
565         EndDialog(hWnd, TRUE);
566         return(TRUE);
567       case IDCANCEL:
568         EndDialog(hWnd, FALSE);
569         return(TRUE);
570       }
571       return(FALSE);
572     }
573   return FALSE;
574 }
575
576
577
578
579 /***********************************************************************
580  *            PageSetupDlgA  (COMDLG32.15)
581  */
582 BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) {
583         FIXME("(%p), stub!\n",setupdlg);
584         return FALSE;
585 }