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