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