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