Authors: Américo José Melo <mmodem00@netvisao.pt>, Francois Gouget <fgouget@codeweave...
[wine] / programs / cmdlgtst / cmdlgtst.c
1 /*
2  * Copyright (c) 1999-2000 Eric Williams.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 /*
20  * One might call this a Commdlg test jig.  Its sole function in life
21  * is to call the Commdlg Common Dialogs.  The results of a call to
22  * File Open or File Save are printed in the upper left corner;
23  * Font adjusts the font of the printout, and Color adjusts the color
24  * of the background.
25  */
26
27 /*
28  * Ideally it would also do event logging and be a bit less stupid
29  * about displaying the results of the various requesters.  But hey,
30  * it's only a first step. :-)
31  */
32
33 #include <windows.h>
34 #include <commdlg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include "cmdlgtst.h"
38
39 /*
40  * This structure is to set up flag / control associations for the custom
41  * requesters.  The ft_id is the id for the control (usually generated
42  * by the system) and the ft_bit is the flag bit which goes into the
43  * settings longword for the various Commdlg structures.  It is assumed
44  * that all flags fit in an unsigned long and that all bits are in fact
45  * one bit.
46  */
47
48 /*
49  * The array of entries is terminated by {IDOK, 0}; the assumption is that
50  * IDOK would never be associated with a dialogbox control (since it's
51  * usually the ID of the OK button}.
52  */
53
54 struct FlagTableEntry {
55         int ft_id;
56         unsigned long ft_bit;
57 };
58
59 #define EXPORT
60
61 static const char menuName[]   = "CmdlgtstMenu";
62 static const char className[]  = "CmdlgtstClass";
63 static const char windowName[] = "Cmdlgtst Window";
64
65 /*
66  * global hInstance variable.  This makes the code non-threadable,
67  * but wotthehell; this is Win32 anyway!  (Though it does work
68  * under Win16, if one doesn't run more than one copy at a time.)
69  */
70
71 static HINSTANCE g_hInstance;
72
73 /*
74  * global CommDlg data structures for modals.  These are placed here
75  * so that the custom dialog boxes can get at them.
76  */
77
78 static PRINTDLG pd;
79 static COLORREF cc_cr[16];
80 static CHOOSECOLOR cc;
81 static LOGFONT cf_lf;
82 static CHOOSEFONT cf;
83 static const char ofn_filepat[] = "All Files (*.*)\0*.*\0Only Text Files (*.txt)\0*.txt\0";
84 static char ofn_result[1024];
85 static char ofn_titleresult[128];
86 static OPENFILENAME ofn;
87
88 /* Stuff for find and replace.  These are modeless, so I have to put them here. */
89
90 static HWND findDialogBox = 0;
91 static UINT findMessageId = 0;
92
93 static FINDREPLACE frS;
94 static char fromstring[1024], tostring[1024];
95
96 /* Stuff for the drawing of the window(s).  I put them here for convenience. */
97
98 static COLORREF fgColor = RGB(0, 0, 0); /* not settable */
99 static COLORREF bgColor = RGB(255, 255, 255); /* COLOR dialog */
100 static COLORREF txtColor = RGB(0, 0, 0); /* settable if one enables CF_EFFECTS */
101
102 /* Utility routines. */
103
104 void nyi(HWND hWnd)
105 {
106         /* "Hi there!  I'm not yet implemented!" */
107         MessageBox(hWnd, "Not yet implemented!", "NYI", MB_ICONEXCLAMATION | MB_OK);
108 }
109
110 UINT CALLBACK dummyfnHook(HWND hWnd, UINT msg, UINT wParam, UINT lParam)
111 {
112         /*
113          * If the user specifies something that needs an awfully stupid hook function,
114          * this is the one to use.  It's a no-op, and says "I didn't do anything."
115          */
116
117         (void) hWnd;
118         (void) msg;
119         (void) wParam;
120         (void) lParam;
121
122         printf("dummyfnhook\n"); /* visible under Wine, but Windows probably won't see it! */
123
124         return 0;
125 }
126
127 /*
128  * Initialization code.  This code simply shoves in predefined
129  * data into the COMMDLG data structures; in the future, I might use
130  * a series of loadable resources, or static initializers; of course,
131  * if Microsoft decides to change the field ordering, I'd be screwed.
132  */
133
134 void mwi_Print(HWND hWnd)
135 {
136         pd.lStructSize = sizeof(PRINTDLG);
137         pd.hwndOwner = hWnd;
138         pd.hDevMode = 0;
139         pd.hDevNames = 0;
140         pd.hDC = 0;
141         pd.Flags = 0;
142         pd.nMinPage = 1;
143         pd.nMaxPage = 100;
144         pd.hInstance = g_hInstance;
145         pd.lCustData = 0;
146         pd.lpfnPrintHook = 0;
147         pd.lpfnSetupHook = 0;
148         pd.lpPrintTemplateName = 0;
149         pd.lpSetupTemplateName = 0;
150         pd.hPrintTemplate = 0;
151         pd.hSetupTemplate = 0;
152 }
153
154 void mwi_Color(HWND hWnd)
155 {
156         int i;
157
158         /* there's probably an init call for this, somewhere. */
159
160         for(i=0;i<16;i++)
161                 cc_cr[i] = RGB(0,0,0);
162
163         cc.lStructSize = sizeof(CHOOSECOLOR);
164         cc.hwndOwner = hWnd;
165         cc.hInstance = (HWND)g_hInstance; /* Should be an HINSTANCE but MS made a typo */
166         cc.rgbResult = RGB(0,0,0);
167         cc.lpCustColors = cc_cr;
168         cc.Flags = 0;
169         cc.lCustData = 0;
170         cc.lpfnHook = 0;
171         cc.lpTemplateName = 0;
172 }
173
174 void mwi_Font(HWND hWnd)
175 {
176         cf.lStructSize = sizeof(CHOOSEFONT);
177         cf.hwndOwner = hWnd;
178         cf.hDC = 0;
179         cf.lpLogFont = &cf_lf;
180         cf.Flags = CF_SCREENFONTS; /* something's needed for display; otherwise it craps out with an error */
181         cf.rgbColors = RGB(0,0,0);  /* what is *this* doing here?? */
182         cf.lCustData = 0;
183         cf.lpfnHook = 0;
184         cf.lpTemplateName = 0;
185         cf.hInstance = g_hInstance;
186         cf.lpszStyle = 0;
187         cf.nFontType = 0;
188         cf.nSizeMin = 8;
189         cf.nSizeMax = 72;
190
191         cf_lf.lfHeight = -18; /* this can be positive or negative, but negative is usually used. */
192 }
193
194 void mwi_File(HWND hWnd)
195 {
196         ofn.lStructSize = sizeof(OPENFILENAME);
197         ofn.hwndOwner = hWnd;
198         ofn.hInstance = g_hInstance;
199         ofn.lpstrFilter = ofn_filepat;
200         ofn.lpstrCustomFilter = 0;
201         ofn.nMaxCustFilter = 0;
202         ofn.nFilterIndex = 0;
203         ofn.lpstrFile = ofn_result;
204         ofn.nMaxFile = sizeof(ofn_result);
205         ofn.lpstrFileTitle = ofn_titleresult;
206         ofn.nMaxFileTitle = sizeof(ofn_titleresult);
207         ofn.lpstrInitialDir = 0;
208         ofn.lpstrTitle = "Open File";
209         ofn.Flags = 0;
210         ofn.nFileOffset = 0;
211         ofn.nFileExtension = 0;
212         ofn.lpstrDefExt = "*";
213         ofn.lCustData = 0;
214         ofn.lpfnHook = 0;
215         ofn.lpTemplateName = 0;
216
217         ofn_result[0] = '\0';
218 }
219
220 void mwi_FindReplace(HWND hWnd)
221 {
222         frS.lStructSize = sizeof(FINDREPLACE);
223         frS.hwndOwner = hWnd;
224         frS.hInstance = g_hInstance;
225         frS.Flags = FR_DOWN;
226         frS.lpstrFindWhat = fromstring;
227         frS.lpstrReplaceWith = tostring;
228         frS.wFindWhatLen = sizeof(fromstring);
229         frS.wReplaceWithLen = sizeof(tostring);
230         frS.lCustData = 0;
231         frS.lpfnHook = 0;
232         frS.lpTemplateName = 0;
233
234         fromstring[0] = '\0';
235         tostring[0] = '\0';
236         findMessageId = RegisterWindowMessage(FINDMSGSTRING);
237 }
238
239 void mwi_InitAll(HWND hWnd)
240 {
241         mwi_Print(hWnd);
242         mwi_Font(hWnd);
243         mwi_Color(hWnd);
244         mwi_File(hWnd);
245         mwi_FindReplace(hWnd);
246 }
247
248 /*
249  * Various configurations for the window.  Ideally, this
250  * would be stored with the window itself, but then, this
251  * isn't the brightest of apps.  Wouldn't be hard to set up,
252  * though -- one of the neater functions of Windows, but if
253  * someone decides to load the windows themselves from resources,
254  * there might be a problem.
255  */
256
257 void paintMainWindow(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
258 {
259         PAINTSTRUCT ps;
260         RECT rect;
261         HPEN pen;
262         HFONT font;
263         HBRUSH brush;
264
265         (void) iMessage;
266         (void) wParam;
267         (void) lParam;
268
269         /* Commence painting! */
270
271         BeginPaint(hWnd, &ps);
272         GetClientRect(hWnd, (LPRECT) &rect);
273
274         pen = (HPEN) SelectObject(ps.hdc, CreatePen(0, 0, fgColor));
275         brush = (HBRUSH) SelectObject(ps.hdc, CreateSolidBrush(bgColor));
276         font = (HFONT) SelectObject(ps.hdc, CreateFontIndirect(&cf_lf));
277
278         /*
279          * Ideally, we'd only need to draw the exposed bit.
280          * But something in BeginPaint is screwing up the rectangle.
281          * Either that, or Windows is drawing it wrong.  AARGH!
282          * Rectangle(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
283          */
284         Rectangle(ps.hdc, rect.left, rect.top, rect.right, rect.bottom);
285
286         /* now draw a couple of lines, just for giggles. */
287
288         MoveToEx(ps.hdc, rect.left, rect.top, (POINT *) 0);
289         LineTo(ps.hdc, rect.right, rect.bottom);
290         MoveToEx(ps.hdc, rect.left, rect.bottom, (POINT *) 0);
291         LineTo(ps.hdc, rect.right, rect.top);
292
293         /* draw some text */
294
295         SetTextAlign(ps.hdc, TA_CENTER|TA_BASELINE);
296         SetTextColor(ps.hdc, txtColor);
297         TextOut(ps.hdc, (rect.left+rect.right)/2, (rect.top+rect.bottom)/2, "Common Dialog Test Page", 23);
298
299         SetTextAlign(ps.hdc, TA_LEFT|TA_TOP);
300         TextOut(ps.hdc, rect.left+10, rect.top+10, ofn_result, strlen(ofn_result));
301         TextOut(ps.hdc, rect.left+10, rect.top-cf_lf.lfHeight+10, ofn_titleresult, strlen(ofn_titleresult));
302
303         /*
304          * set the HDC back to the old pen and brush,
305          * and delete the newly created objects.
306          */
307
308         pen = (HPEN) SelectObject(ps.hdc, pen);
309         DeleteObject(pen);
310         brush = (HBRUSH) SelectObject(ps.hdc, brush);
311         DeleteObject(brush);
312         font = (HFONT) SelectObject(ps.hdc, font);
313         DeleteObject(font);
314
315         EndPaint(hWnd, &ps);
316 }
317
318 /*
319  * This function simply returns an error indication.  Naturally,
320  * I do not (yet) see an elegant method by which one can convert
321  * the CDERR_xxx return values into something resembling usable text;
322  * consult cderr.h to see what was returned.
323  */
324
325 void mw_checkError(HWND hWnd, BOOL explicitcancel)
326 {
327         DWORD errval = CommDlgExtendedError();
328         if(errval) {
329                 char errbuf[80];
330
331                 sprintf(errbuf, "CommDlgExtendedError(): error code %ld (0x%lx)", errval, errval);
332                 MessageBox(hWnd, errbuf, "Error", MB_ICONEXCLAMATION | MB_OK);
333         }
334         else {
335                 if(explicitcancel) MessageBox(hWnd, "Nope, user canceled it.", "No", MB_OK);
336         }
337 }
338
339 /*
340  * The actual dialog function calls.  These merely wrap the Commdlg
341  * calls, and do something (not so) intelligent with the result.
342  * Ideally, the main window would refresh and take into account the
343  * various values specified in the dialog.
344  */
345
346 void mw_ColorSetup(HWND hWnd)
347 {
348         if(ChooseColor(&cc)) {
349                 RECT rect;
350
351                 GetClientRect(hWnd, (LPRECT) &rect);
352                 InvalidateRect(hWnd, (LPRECT) &rect, FALSE);
353                 bgColor = cc.rgbResult;
354         }
355         else mw_checkError(hWnd, FALSE);
356 }
357
358 void mw_FontSetup(HWND hWnd)
359 {
360         if(ChooseFont(&cf)) {
361                 RECT rect;
362                 GetClientRect(hWnd, (LPRECT) &rect);
363                 InvalidateRect(hWnd, (LPRECT) &rect, FALSE);
364                 txtColor = cf.rgbColors;
365         }
366         else mw_checkError(hWnd, FALSE);
367 }
368
369 void mw_FindSetup(HWND hWnd)
370 {
371         if(findDialogBox == 0) {
372                 findDialogBox = FindText(&frS);
373                 if(findDialogBox==0) mw_checkError(hWnd,TRUE);
374         }
375 }
376
377 void mw_ReplaceSetup(HWND hWnd)
378 {
379         if(findDialogBox == 0) {
380                 findDialogBox = ReplaceText(&frS);
381                 if(findDialogBox==0) mw_checkError(hWnd,TRUE);
382         }
383 }
384
385 void mw_OpenSetup(HWND hWnd)
386 {
387         if(GetOpenFileName(&ofn)) {
388                 RECT rect;
389                 GetClientRect(hWnd, (LPRECT) &rect);
390                 InvalidateRect(hWnd, (LPRECT) &rect, FALSE);
391         }
392         else mw_checkError(hWnd,FALSE);
393 }
394
395 void mw_SaveSetup(HWND hWnd)
396 {
397         if(GetSaveFileName(&ofn)) {
398                 RECT rect;
399                 GetClientRect(hWnd, (LPRECT) &rect);
400                 InvalidateRect(hWnd, (LPRECT) &rect, FALSE);
401         }
402         else mw_checkError(hWnd,FALSE);
403 }
404
405 /*
406  * Can't find documentation in Borland for this one.  Does it
407  * exist at all, or is it merely a subdialog of Print?
408  */
409
410 void mw_PSetupSetup(HWND hWnd)
411 {
412         nyi(hWnd);
413 }
414
415 void mw_PrintSetup(HWND hWnd)
416 {
417         if(PrintDlg(&pd)) {
418                 /*
419                  * the following are suggested in the Borland documentation,
420                  * but aren't that useful until WinE starts to actually
421                  * function with respect to printing.
422                  */
423
424 #if 0
425                 Escape(tmp.hDC, STARTDOC, 8, "Test-Doc", NULL);
426 #endif
427
428          /* Print text and rectangle */
429
430 #if 0
431                 TextOut(tmp.hDC, 50, 50, "Common Dialog Test Page", 23);
432
433                 Rectangle(tmp.hDC, 50, 90, 625, 105);
434                 Escape(tmp.hDC, NEWFRAME, 0, NULL, NULL);
435                 Escape(tmp.hDC, ENDDOC, 0, NULL, NULL);
436                 DeleteDC(tmp.hDC);
437 #endif
438                  if (pd.hDevMode != 0)
439                          GlobalFree(pd.hDevMode);
440                  if (pd.hDevNames != 0)
441                          GlobalFree(pd.hDevNames);
442
443                  pd.hDevMode = 0;
444                  pd.hDevNames = 0;
445
446                  MessageBox(hWnd, "Success.", "Yes", MB_OK);
447         }
448         else mw_checkError(hWnd,TRUE);
449 }
450
451 /*
452  * Some support functions for the custom dialog box handlers.
453  * In particular, we have to set things properly, and get the flags back.
454  */
455
456 void mwcd_SetFlags(HWND hWnd, struct FlagTableEntry *table, unsigned long flags)
457 {
458         int i;
459
460         for(i=0; table[i].ft_id != IDOK; i++)
461         {
462                 CheckDlgButton(hWnd, table[i].ft_id,(table[i].ft_bit & flags) ? 1 : 0);
463         }
464 }
465
466 unsigned long mwcd_GetFlags(HWND hWnd, struct FlagTableEntry * table)
467 {
468         int i;
469         unsigned long l = 0;
470
471         for(i=0; table[i].ft_id != IDOK; i++)
472         {
473                 if(IsDlgButtonChecked(hWnd, table[i].ft_id) == 1)
474                         l |= table[i].ft_bit;
475         }
476
477         return l;
478 }
479
480 /*
481  * These functions are the custom dialog box handlers.
482  * The division of labor may be a tad peculiar; in particular,
483  * the flag tables should probably be in the main functions,
484  * not the handlers.  I'll fix that later; this works as of right now.
485  */
486
487 BOOL mwcd_Setup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
488                                          struct FlagTableEntry * table, unsigned long * flags)
489 {
490         (void) lParam;
491
492         switch(uMsg)
493         {
494                 case WM_INITDIALOG:
495                         /* Set the controls properly. */
496
497                         mwcd_SetFlags(hWnd, table, *flags);
498
499                         return TRUE; /* I would return FALSE if I explicitly called SetFocus(). */
500                                      /* As usual, Windows is weird. */
501
502                 case WM_COMMAND:
503                         switch(wParam) {
504                                 case IDOK:
505                                         *flags = mwcd_GetFlags(hWnd, table);
506                                         EndDialog(hWnd,1);
507                                         break;
508
509                                 case IDCANCEL:
510                                         EndDialog(hWnd,0);
511                                         break;
512
513                                 case CM_R_HELP:
514                                         break; /* help?  We don't need no steenkin help! */
515
516                                 default:
517                                         break; /* eat the message */
518                         }
519                         return TRUE;
520
521                 default:
522                         return FALSE; /* since I don't process this particular message */
523         }
524 }
525
526 BOOL CALLBACK mwcd_ColorSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
527 {
528         static struct FlagTableEntry flagTable[] = {
529                 {I_CC_RGBINIT, CC_RGBINIT},
530                 {I_CC_SHOWHELP, CC_SHOWHELP},
531                 {I_CC_PREVENTFULLOPEN, CC_PREVENTFULLOPEN},
532                 {I_CC_FULLOPEN, CC_FULLOPEN},
533                 {I_CC_ENABLETEMPLATEHANDLE, CC_ENABLETEMPLATEHANDLE},
534                 {I_CC_ENABLETEMPLATE, CC_ENABLETEMPLATE},
535                 {I_CC_ENABLEHOOK, CC_ENABLEHOOK},
536                 {IDOK, 0},
537         };
538
539         return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &cc.Flags);
540 }
541
542 BOOL CALLBACK mwcd_FontSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
543 {
544         static struct FlagTableEntry flagTable[] = {
545                 {I_CF_APPLY, CF_APPLY},
546                 {I_CF_ANSIONLY, CF_ANSIONLY},
547                 {I_CF_BOTH, CF_BOTH},
548                 {I_CF_TTONLY, CF_TTONLY},
549                 {I_CF_EFFECTS, CF_EFFECTS},
550                 {I_CF_ENABLEHOOK, CF_ENABLEHOOK},
551                 {I_CF_ENABLETEMPLATE, CF_ENABLETEMPLATE},
552                 {I_CF_ENABLETEMPLATEHANDLE, CF_ENABLETEMPLATEHANDLE},
553                 {I_CF_FIXEDPITCHONLY, CF_FIXEDPITCHONLY},
554                 {I_CF_INITTOLOGFONTSTRUCT, CF_INITTOLOGFONTSTRUCT},
555                 {I_CF_LIMITSIZE, CF_LIMITSIZE},
556                 {I_CF_NOFACESEL, CF_NOFACESEL},
557                 {I_CF_USESTYLE, CF_USESTYLE},
558                 {I_CF_WYSIWYG, CF_WYSIWYG},
559                 {I_CF_SHOWHELP, CF_SHOWHELP},
560                 {I_CF_SCREENFONTS, CF_SCREENFONTS},
561                 {I_CF_SCALABLEONLY, CF_SCALABLEONLY},
562                 {I_CF_PRINTERFONTS, CF_PRINTERFONTS},
563                 {I_CF_NOVECTORFONTS, CF_NOVECTORFONTS},
564                 {I_CF_NOSTYLESEL, CF_NOSTYLESEL},
565                 {I_CF_NOSIZESEL, CF_NOSIZESEL},
566                 {I_CF_NOOEMFONTS, CF_NOOEMFONTS},
567                 {IDOK, 0},
568         };
569
570         return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &cf.Flags);
571 }
572
573 BOOL CALLBACK mwcd_FindSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
574 {
575
576         static struct FlagTableEntry flagTable[] = {
577                 {I_FR_DIALOGTERM, FR_DIALOGTERM},
578                 {I_FR_DOWN, FR_DOWN},
579                 {I_FR_ENABLEHOOK, FR_ENABLEHOOK},
580                 {I_FR_ENABLETEMPLATE, FR_ENABLETEMPLATE},
581                 {I_FR_ENABLETEMPLATEHANDLE, FR_ENABLETEMPLATEHANDLE},
582                 {I_FR_FINDNEXT, FR_FINDNEXT},
583                 {I_FR_HIDEMATCHCASE, FR_HIDEMATCHCASE},
584                 {I_FR_HIDEWHOLEWORD, FR_HIDEWHOLEWORD},
585                 {I_FR_HIDEUPDOWN, FR_HIDEUPDOWN},
586                 {I_FR_MATCHCASE, FR_MATCHCASE},
587                 {I_FR_NOMATCHCASE, FR_NOMATCHCASE},
588                 {I_FR_NOUPDOWN, FR_NOUPDOWN},
589                 {I_FR_NOWHOLEWORD, FR_NOWHOLEWORD},
590                 {I_FR_REPLACE, FR_REPLACE},
591                 {I_FR_REPLACEALL, FR_REPLACEALL},
592                 {I_FR_SHOWHELP, FR_SHOWHELP},
593                 {I_FR_WHOLEWORD, FR_WHOLEWORD},
594                 {IDOK, 0},
595         };
596
597         return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &frS.Flags);
598 }
599
600 BOOL CALLBACK mwcd_PrintSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
601 {
602         static struct FlagTableEntry flagTable[] = {
603                 {I_PD_ALLPAGES, PD_ALLPAGES},
604                 {I_PD_COLLATE, PD_COLLATE},
605                 {I_PD_DISABLEPRINTTOFILE, PD_DISABLEPRINTTOFILE},
606                 {I_PD_ENABLEPRINTHOOK, PD_ENABLEPRINTHOOK},
607                 {I_PD_ENABLEPRINTTEMPLATE, PD_ENABLEPRINTTEMPLATE},
608                 {I_PD_ENABLEPRINTTEMPLATEHANDLE, PD_ENABLEPRINTTEMPLATEHANDLE},
609                 {I_PD_ENABLESETUPHOOK, PD_ENABLESETUPHOOK},
610                 {I_PD_ENABLESETUPTEMPLATE, PD_ENABLESETUPTEMPLATE},
611                 {I_PD_ENABLESETUPTEMPLATEHANDLE, PD_ENABLESETUPTEMPLATEHANDLE},
612                 {I_PD_HIDEPRINTTOFILE, PD_HIDEPRINTTOFILE},
613                 {I_PD_NOPAGENUMS, PD_NOPAGENUMS},
614                 {I_PD_NOSELECTION, PD_NOSELECTION},
615                 {I_PD_NOWARNING, PD_NOWARNING},
616                 {I_PD_PAGENUMS, PD_PAGENUMS},
617                 {I_PD_PRINTSETUP, PD_PRINTSETUP},
618                 {I_PD_PRINTTOFILE, PD_PRINTTOFILE},
619                 {I_PD_RETURNDC, PD_RETURNDC},
620                 {I_PD_RETURNDEFAULT, PD_RETURNDEFAULT},
621                 {I_PD_RETURNIC, PD_RETURNIC},
622                 {I_PD_SELECTION, PD_SELECTION},
623                 {I_PD_SHOWHELP, PD_SHOWHELP},
624                 {I_PD_USEDEVMODECOPIES, PD_USEDEVMODECOPIES},
625                 {IDOK, 0},
626         };
627
628         return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &pd.Flags);
629 }
630
631 BOOL CALLBACK mwcd_FileSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
632 {
633         static struct FlagTableEntry flagTable[] = {
634                 {I_OFN_ALLOWMULTISELECT, OFN_ALLOWMULTISELECT},
635                 {I_OFN_CREATEPROMPT, OFN_CREATEPROMPT},
636                 {I_OFN_ENABLEHOOK, OFN_ENABLEHOOK},
637                 {I_OFN_ENABLETEMPLATE, OFN_ENABLETEMPLATE},
638                 {I_OFN_ENABLETEMPLATEHANDLE, OFN_ENABLETEMPLATEHANDLE},
639                 {I_OFN_EXTENSIONDIFFERENT, OFN_EXTENSIONDIFFERENT},
640                 {I_OFN_FILEMUSTEXIST, OFN_FILEMUSTEXIST},
641                 {I_OFN_HIDEREADONLY, OFN_HIDEREADONLY},
642                 {I_OFN_NOCHANGEDIR, OFN_NOCHANGEDIR},
643                 {I_OFN_NOREADONLYRETURN, OFN_NOREADONLYRETURN},
644                 {I_OFN_NOTESTFILECREATE, OFN_NOTESTFILECREATE},
645                 {I_OFN_NOVALIDATE, OFN_NOVALIDATE},
646                 {I_OFN_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT},
647                 {I_OFN_PATHMUSTEXIST, OFN_PATHMUSTEXIST},
648                 {I_OFN_READONLY, OFN_READONLY},
649                 {I_OFN_SHAREAWARE, OFN_SHAREAWARE},
650                 {I_OFN_SHOWHELP, OFN_SHOWHELP},
651                 {IDOK, 0},
652         };
653
654         return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &ofn.Flags);
655 }
656
657 BOOL CALLBACK mwcd_About(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
658 {
659         (void) wParam;
660         (void) lParam;
661
662         switch(uMsg) {
663                 case WM_INITDIALOG: return TRUE; /* let WINDOWS set the focus. */
664                 case WM_COMMAND: EndDialog(hWnd, 0); return TRUE; /* it's our OK button. */
665                 default: return FALSE; /* it's something else, let Windows worry about it */
666         }
667 }
668
669 /*
670  * These functions call custom dialog boxes (resource-loaded, if I do this right).
671  * Right now they don't do a heck of a lot, but at some future time
672  * they will muck about with the flags (and be loaded from the flags) of
673  * the CommDlg structures initialized by the mwi_xxx() routines.
674  */
675
676 void mwc_ColorSetup(HWND hWnd)
677 {
678         int r = DialogBox(g_hInstance, "Color_Flags_Dialog", hWnd, (DLGPROC) mwcd_ColorSetup);
679         if(r < 0) { MessageBox(hWnd, "Failure opening Color_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); }
680 }
681
682 void mwc_FontSetup(HWND hWnd)
683 {
684         int r = DialogBox(g_hInstance, "Font_Flags_Dialog", hWnd, (DLGPROC) mwcd_FontSetup);
685         if(r < 0) { MessageBox(hWnd, "Failure opening Font_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); }
686 }
687
688 void mwc_FindReplaceSetup(HWND hWnd)
689 {
690         int r = DialogBox(g_hInstance, "Find_Flags_Dialog", hWnd, (DLGPROC) mwcd_FindSetup);
691         if(r < 0) { MessageBox(hWnd, "Failure opening Find_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); }
692 }
693
694 void mwc_PrintSetup(HWND hWnd)
695 {
696         int r = DialogBox(g_hInstance, "Print_Flags_Dialog", hWnd, (DLGPROC) mwcd_PrintSetup);
697         if(r < 0) { MessageBox(hWnd, "Failure opening Print_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); }
698 }
699
700 void mwc_FileSetup(HWND hWnd)
701 {
702         int r = DialogBox(g_hInstance, "File_Flags_Dialog", hWnd, (DLGPROC) mwcd_FileSetup);
703         if(r < 0) { MessageBox(hWnd, "Failure opening File_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); }
704 }
705
706 /*
707  * Main window message dispatcher.  Here the messages get chewed up
708  * and spit out.  Note the ugly hack for the modeless Find/Replace box;
709  * this looks like it was bolted on with hexhead screws and is now
710  * dangling from Windows like a loose muffler.  Sigh.
711  */
712
713 LRESULT CALLBACK EXPORT mainWindowDispatcher(
714         HWND hWnd,
715         UINT uMsg,
716         WPARAM wParam,
717         LPARAM lParam
718 )
719 {
720
721         if(uMsg == findMessageId) {
722                 FINDREPLACE * lpfr = (FINDREPLACE *) lParam;
723                 if(lpfr->Flags & FR_DIALOGTERM) {
724                         MessageBox(hWnd, "User closing us down.", "Down", MB_OK);
725                         findDialogBox = 0;
726                 }
727                 else if (lpfr->Flags & FR_FINDNEXT) {
728                         MessageBox(hWnd, "Finding next occurrence.", "Findnext", MB_OK);
729                 }
730                 else if (lpfr->Flags & FR_REPLACE) {
731                         MessageBox(hWnd, "Replacing next occurence.", "Replace", MB_OK);
732                 }
733                 else if (lpfr->Flags & FR_REPLACEALL) {
734                         MessageBox(hWnd, "Replacing all occurrences.", "Replace All", MB_OK);
735                 }
736                 else {
737                         MessageBox(hWnd, "Eh?", "Eh?", MB_OK);
738                 }
739                 return 1;
740         }
741         else switch(uMsg) {
742         case WM_CREATE:
743                         /*
744                          * this is always the first message...at least as far as
745                          * we are concerned.
746                          */
747                 mwi_InitAll(hWnd);
748                 break;
749
750         case WM_PAINT:
751                         /* Well, draw something! */
752                 paintMainWindow(hWnd, uMsg, wParam, lParam);
753                 break;
754
755         case WM_DESTROY:
756                         /* Uh oh.  Eject!  Eject!  Eject! */
757                 PostQuitMessage(0);
758                 break;
759
760         case WM_COMMAND:
761                         /* menu or accelerator pressed; do something. */
762
763                 switch(wParam) {
764                 case CM_U_EXIT:
765                                 /* Uh oh.  Eject!  Eject!  Eject! */
766                         PostQuitMessage(0);
767                         break;
768
769                 /* these actually call the Common Dialogs. */
770
771                 case CM_U_COLOR:
772                         mw_ColorSetup(hWnd); return 1;
773
774                 case CM_U_FONT:
775                         mw_FontSetup(hWnd); return 1;
776
777                 case CM_U_FIND:
778                         mw_FindSetup(hWnd); return 1;
779
780                 case CM_U_REPLACE:
781                         mw_ReplaceSetup(hWnd); return 1;
782
783                 case CM_U_OPEN:
784                         mw_OpenSetup(hWnd); return 1;
785
786                 case CM_U_SAVE:
787                         mw_SaveSetup(hWnd); return 1;
788
789                 case CM_U_PSETUP:
790                         mw_PSetupSetup(hWnd); return 1;
791
792                 case CM_U_PRINT:
793                         mw_PrintSetup(hWnd); return 1;
794
795                 /*
796                  * these set up various flags and values in the Common Dialog
797                  * data structures, which are currently stored in static memory.
798                  * The control dialogs themselves are resources as well.
799                  */
800
801                 case CM_F_FILE:
802                         mwc_FileSetup(hWnd); return 1;
803
804                 case CM_F_COLOR:
805                         mwc_ColorSetup(hWnd); return 1;
806
807                 case CM_F_FONT:
808                         mwc_FontSetup(hWnd); return 1;
809
810                 case CM_F_FINDREPLACE:
811                         mwc_FindReplaceSetup(hWnd); return 1;
812
813                 case CM_F_PRINT:
814                         mwc_PrintSetup(hWnd); return 1;
815
816                 case CM_H_ABOUT:
817                         DialogBox(g_hInstance, "AboutDialog", hWnd, (DLGPROC) mwcd_About);
818                         return 1;
819                 case CM_H_USAGE:
820                         DialogBox(g_hInstance, "UsageDialog", hWnd, (DLGPROC) mwcd_About);
821                 /* return value?  *What* return value? */
822                         return 1;
823
824                 default:
825                         nyi(hWnd); return 1;
826                 }
827                 break;
828
829         default:
830                 return DefWindowProc(hWnd, uMsg, wParam, lParam);
831         }
832         return 0;
833 }
834
835 /* Class registration.  One might call this a Windowsism. */
836
837 int registerMainWindowClass(HINSTANCE hInstance)
838 {
839         WNDCLASS wndClass;
840
841         wndClass.style         = CS_HREDRAW|CS_VREDRAW;
842         wndClass.lpfnWndProc   = mainWindowDispatcher;
843         wndClass.cbClsExtra    = 0;
844         wndClass.cbWndExtra    = 0;
845         wndClass.hInstance     = hInstance;
846 #if 0
847         wndClass.hIcon         = LoadIcon(hInstance, "whello");
848         wndClass.hCursor       = LoadCursor(hInstance, IDC_ARROW);
849 #endif
850         wndClass.hIcon         = 0;
851         wndClass.hCursor       = 0;
852         wndClass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
853         wndClass.lpszMenuName  = menuName;
854         wndClass.lpszClassName = className;
855
856         return RegisterClass(&wndClass);
857 }
858
859 /*
860  * Another Windowsism; this one's not too bad, as it compares
861  * favorably with CreateWindow() in X (mucking about with X Visuals
862  * can get messy; at least here we don't have to worry about that).
863  */
864
865 HWND createMainWindow(HINSTANCE hInstance, int show)
866 {
867         HWND hWnd;
868
869         hWnd = CreateWindow(
870                 className,  /* classname */
871                 windowName,  /* windowname/title */
872                 WS_OVERLAPPEDWINDOW, /* dwStyle */
873                 0, /* x */
874                 0, /* y */
875                 CW_USEDEFAULT, /* width */
876                 CW_USEDEFAULT, /* height */
877                 0, /* parent window */
878                 0, /* menu */
879                 hInstance, /* instance */
880                 0          /* passthrough for MDI */
881         );
882
883         if(hWnd==0) return 0;
884
885         ShowWindow(hWnd, show);
886         UpdateWindow(hWnd);
887
888         return hWnd;
889 }
890
891 int messageLoop(HINSTANCE hInstance, HWND hWnd)
892 {
893         MSG msg;
894
895         (void) hInstance;
896         (void) hWnd;
897
898         while(GetMessage(&msg, 0, 0, 0)) {
899                 TranslateMessage(&msg);
900                 DispatchMessage(&msg);
901         }
902
903         return msg.wParam;
904 }
905
906 /*
907  * Oh, did we tell you that main() isn't the name of the
908  * thing called in a Win16/Win32 app?  And then there are
909  * the lack of argument lists, the necessity (at least in Win16)
910  * of having to deal with class registration exactly once (as the
911  * app may be run again), and some other bizarre holdovers from
912  * Windows 3.x days.  But hey, Solitaire still works.
913  */
914
915 int PASCAL WinMain(
916         HINSTANCE hInstance, HINSTANCE hPrevInstance,
917         LPSTR lpszCmdLine, int nCmdShow
918 )
919 {
920         HWND hWnd;
921
922         (void) lpszCmdLine;
923
924         strcpy(ofn_result, "--- not yet set ---");
925
926         if(hPrevInstance==0) {
927                 if(!registerMainWindowClass(hInstance))
928                         return -1;
929         }
930
931         g_hInstance = hInstance;
932
933         hWnd = createMainWindow(hInstance,nCmdShow);
934         if(hWnd == 0)
935                 return -1;
936
937         return messageLoop(hInstance, hWnd);
938 }
939
940 /* And now the end of the program.  Enjoy. */
941
942 /*
943  * (c) 1999-2000 Eric Williams.  Rights as specified under the WINE
944  * License.  Don't hoard code; share it!
945  */