| /* | 
 |  * Copyright (c) 1999-2000 Eric Williams. | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 |  */ | 
 |  | 
 | /* | 
 |  * One might call this a Commdlg test jig.  Its sole function in life | 
 |  * is to call the Commdlg Common Dialogs.  The results of a call to | 
 |  * File Open or File Save are printed in the upper left corner; | 
 |  * Font adjusts the font of the printout, and Color adjusts the color | 
 |  * of the background. | 
 |  */ | 
 |  | 
 | /* | 
 |  * Ideally it would also do event logging and be a bit less stupid | 
 |  * about displaying the results of the various requesters.  But hey, | 
 |  * it's only a first step. :-) | 
 |  */ | 
 |  | 
 | #include <windows.h> | 
 | #include <commdlg.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include "cmdlgtst.h" | 
 |  | 
 | /* | 
 |  * This structure is to set up flag / control associations for the custom | 
 |  * requesters.  The ft_id is the id for the control (usually generated | 
 |  * by the system) and the ft_bit is the flag bit which goes into the | 
 |  * settings longword for the various Commdlg structures.  It is assumed | 
 |  * that all flags fit in an unsigned long and that all bits are in fact | 
 |  * one bit. | 
 |  */ | 
 |  | 
 | /* | 
 |  * The array of entries is terminated by {IDOK, 0}; the assumption is that | 
 |  * IDOK would never be associated with a dialogbox control (since it's | 
 |  * usually the ID of the OK button}. | 
 |  */ | 
 |  | 
 | struct FlagTableEntry { | 
 | 	int ft_id; | 
 | 	unsigned long ft_bit; | 
 | }; | 
 |  | 
 | #define EXPORT | 
 |  | 
 | static char menuName[] = "CmdlgtstMenu"; | 
 | static char className[] = "CmdlgtstClass"; | 
 | static char windowName[] = "Cmdlgtst Window"; | 
 |  | 
 | /* | 
 |  * global hInstance variable.  This makes the code non-threadable, | 
 |  * but wotthehell; this is Win32 anyway!  (Though it does work | 
 |  * under Win16, if one doesn't run more than one copy at a time.) | 
 |  */ | 
 |  | 
 | static HINSTANCE g_hInstance; | 
 |  | 
 | /* | 
 |  * global CommDlg data structures for modals.  These are placed here | 
 |  * so that the custom dialog boxes can get at them. | 
 |  */ | 
 |  | 
 | static PRINTDLG pd; | 
 | static COLORREF cc_cr[16]; | 
 | static CHOOSECOLOR cc; | 
 | static LOGFONT cf_lf; | 
 | static CHOOSEFONT cf; | 
 | static char ofn_filepat[] = "All Files (*.*)\0*.*\0Only Text Files (*.txt)\0*.txt\0"; | 
 | static char ofn_result[1024]; | 
 | static char ofn_titleresult[128]; | 
 | static OPENFILENAME ofn; | 
 |  | 
 | /* Stuff for find and replace.  These are modeless, so I have to put them here. */ | 
 |  | 
 | static HWND findDialogBox = 0; | 
 | static UINT findMessageId = 0; | 
 |  | 
 | static FINDREPLACE frS; | 
 | static char fromstring[1024], tostring[1024]; | 
 |  | 
 | /* Stuff for the drawing of the window(s).  I put them here for convenience. */ | 
 |  | 
 | static COLORREF fgColor = RGB(0, 0, 0); /* not settable */ | 
 | static COLORREF bgColor = RGB(255, 255, 255); /* COLOR dialog */ | 
 | static COLORREF txtColor = RGB(0, 0, 0); /* settable if one enables CF_EFFECTS */ | 
 |  | 
 | /* Utility routines. */ | 
 |  | 
 | void nyi(HWND hWnd) | 
 | { | 
 | 	/* "Hi there!  I'm not yet implemented!" */ | 
 | 	MessageBox(hWnd, "Not yet implemented!", "NYI", MB_ICONEXCLAMATION | MB_OK); | 
 | } | 
 |  | 
 | UINT CALLBACK dummyfnHook(HWND hWnd, UINT msg, UINT wParam, UINT lParam) | 
 | { | 
 | 	/* | 
 | 	 * If the user specifies something that needs an awfully stupid hook function, | 
 | 	 * this is the one to use.  It's a no-op, and says "I didn't do anything." | 
 | 	 */ | 
 |  | 
 | 	(void) hWnd; | 
 | 	(void) msg; | 
 | 	(void) wParam; | 
 | 	(void) lParam; | 
 |  | 
 | 	printf("dummyfnhook\n"); /* visible under Wine, but Windows probably won't see it! */ | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * Initialization code.  This code simply shoves in predefined | 
 |  * data into the COMMDLG data structures; in the future, I might use | 
 |  * a series of loadable resources, or static initializers; of course, | 
 |  * if Microsoft decides to change the field ordering, I'd be screwed. | 
 |  */ | 
 |  | 
 | void mwi_Print(HWND hWnd) | 
 | { | 
 | 	pd.lStructSize = sizeof(PRINTDLG); | 
 | 	pd.hwndOwner = hWnd; | 
 | 	pd.hDevMode = 0; | 
 | 	pd.hDevNames = 0; | 
 | 	pd.hDC = 0; | 
 | 	pd.Flags = 0; | 
 | 	pd.nMinPage = 1; | 
 | 	pd.nMaxPage = 100; | 
 | 	pd.hInstance = g_hInstance; | 
 | 	pd.lCustData = 0; | 
 | 	pd.lpfnPrintHook = 0; | 
 | 	pd.lpfnSetupHook = 0; | 
 | 	pd.lpPrintTemplateName = 0; | 
 | 	pd.lpSetupTemplateName = 0; | 
 | 	pd.hPrintTemplate = 0; | 
 | 	pd.hSetupTemplate = 0; | 
 | } | 
 |  | 
 | void mwi_Color(HWND hWnd) | 
 | { | 
 | 	int i; | 
 |  | 
 | 	/* there's probably an init call for this, somewhere. */ | 
 |  | 
 | 	for(i=0;i<16;i++) | 
 | 		cc_cr[i] = RGB(0,0,0); | 
 |  | 
 | 	cc.lStructSize = sizeof(CHOOSECOLOR); | 
 | 	cc.hwndOwner = hWnd; | 
 | 	cc.hInstance = (HWND)g_hInstance; /* Should be an HINSTANCE but MS made a typo */ | 
 | 	cc.rgbResult = RGB(0,0,0); | 
 | 	cc.lpCustColors = cc_cr; | 
 | 	cc.Flags = 0; | 
 | 	cc.lCustData = 0; | 
 | 	cc.lpfnHook = 0; | 
 | 	cc.lpTemplateName = 0; | 
 | } | 
 |  | 
 | void mwi_Font(HWND hWnd) | 
 | { | 
 | 	cf.lStructSize = sizeof(CHOOSEFONT); | 
 | 	cf.hwndOwner = hWnd; | 
 | 	cf.hDC = 0; | 
 | 	cf.lpLogFont = &cf_lf; | 
 | 	cf.Flags = CF_SCREENFONTS; /* something's needed for display; otherwise it craps out with an error */ | 
 | 	cf.rgbColors = RGB(0,0,0);  /* what is *this* doing here?? */ | 
 | 	cf.lCustData = 0; | 
 | 	cf.lpfnHook = 0; | 
 | 	cf.lpTemplateName = 0; | 
 | 	cf.hInstance = g_hInstance; | 
 | 	cf.lpszStyle = 0; | 
 | 	cf.nFontType = 0; | 
 | 	cf.nSizeMin = 8; | 
 | 	cf.nSizeMax = 72; | 
 |  | 
 | 	cf_lf.lfHeight = -18; /* this can be positive or negative, but negative is usually used. */ | 
 | } | 
 |  | 
 | void mwi_File(HWND hWnd) | 
 | { | 
 | 	ofn.lStructSize = sizeof(OPENFILENAME); | 
 | 	ofn.hwndOwner = hWnd; | 
 | 	ofn.hInstance = g_hInstance; | 
 | 	ofn.lpstrFilter = (LPSTR) ofn_filepat; | 
 | 	ofn.lpstrCustomFilter = 0; | 
 | 	ofn.nMaxCustFilter = 0; | 
 | 	ofn.nFilterIndex = 0; | 
 | 	ofn.lpstrFile = ofn_result; | 
 | 	ofn.nMaxFile = sizeof(ofn_result); | 
 | 	ofn.lpstrFileTitle = ofn_titleresult; | 
 | 	ofn.nMaxFileTitle = sizeof(ofn_titleresult); | 
 | 	ofn.lpstrInitialDir = 0; | 
 | 	ofn.lpstrTitle = "Open File"; | 
 | 	ofn.Flags = 0; | 
 | 	ofn.nFileOffset = 0; | 
 | 	ofn.nFileExtension = 0; | 
 | 	ofn.lpstrDefExt = "*"; | 
 | 	ofn.lCustData = 0; | 
 | 	ofn.lpfnHook = 0; | 
 | 	ofn.lpTemplateName = 0; | 
 |  | 
 | 	ofn_result[0] = '\0'; | 
 | } | 
 |  | 
 | void mwi_FindReplace(HWND hWnd) | 
 | { | 
 | 	frS.lStructSize = sizeof(FINDREPLACE); | 
 | 	frS.hwndOwner = hWnd; | 
 | 	frS.hInstance = g_hInstance; | 
 | 	frS.Flags = FR_DOWN; | 
 | 	frS.lpstrFindWhat = fromstring; | 
 | 	frS.lpstrReplaceWith = tostring; | 
 | 	frS.wFindWhatLen = sizeof(fromstring); | 
 | 	frS.wReplaceWithLen = sizeof(tostring); | 
 | 	frS.lCustData = 0; | 
 | 	frS.lpfnHook = 0; | 
 | 	frS.lpTemplateName = 0; | 
 |  | 
 | 	fromstring[0] = '\0'; | 
 | 	tostring[0] = '\0'; | 
 | 	findMessageId = RegisterWindowMessage(FINDMSGSTRING); | 
 | } | 
 |  | 
 | void mwi_InitAll(HWND hWnd) | 
 | { | 
 | 	mwi_Print(hWnd); | 
 | 	mwi_Font(hWnd); | 
 | 	mwi_Color(hWnd); | 
 | 	mwi_File(hWnd); | 
 | 	mwi_FindReplace(hWnd); | 
 | } | 
 |  | 
 | /* | 
 |  * Various configurations for the window.  Ideally, this | 
 |  * would be stored with the window itself, but then, this | 
 |  * isn't the brightest of apps.  Wouldn't be hard to set up, | 
 |  * though -- one of the neater functions of Windows, but if | 
 |  * someone decides to load the windows themselves from resources, | 
 |  * there might be a problem. | 
 |  */ | 
 |  | 
 | void paintMainWindow(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	PAINTSTRUCT ps; | 
 | 	RECT rect; | 
 | 	HPEN pen; | 
 | 	HFONT font; | 
 | 	HBRUSH brush; | 
 |  | 
 | 	(void) iMessage; | 
 | 	(void) wParam; | 
 | 	(void) lParam; | 
 |  | 
 | 	/* Commence painting! */ | 
 |  | 
 | 	BeginPaint(hWnd, &ps); | 
 | 	GetClientRect(hWnd, (LPRECT) &rect); | 
 |  | 
 | 	pen = (HPEN) SelectObject(ps.hdc, CreatePen(0, 0, fgColor)); | 
 | 	brush = (HBRUSH) SelectObject(ps.hdc, CreateSolidBrush(bgColor)); | 
 | 	font = (HFONT) SelectObject(ps.hdc, CreateFontIndirect(&cf_lf)); | 
 |  | 
 | 	/* | 
 | 	 * Ideally, we'd only need to draw the exposed bit. | 
 | 	 * But something in BeginPaint is screwing up the rectangle. | 
 | 	 * Either that, or Windows is drawing it wrong.  AARGH! | 
 | 	 * Rectangle(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); | 
 |          */ | 
 | 	Rectangle(ps.hdc, rect.left, rect.top, rect.right, rect.bottom); | 
 |  | 
 | 	/* now draw a couple of lines, just for giggles. */ | 
 |  | 
 | 	MoveToEx(ps.hdc, rect.left, rect.top, (POINT *) 0); | 
 | 	LineTo(ps.hdc, rect.right, rect.bottom); | 
 | 	MoveToEx(ps.hdc, rect.left, rect.bottom, (POINT *) 0); | 
 | 	LineTo(ps.hdc, rect.right, rect.top); | 
 |  | 
 | 	/* draw some text */ | 
 |  | 
 | 	SetTextAlign(ps.hdc, TA_CENTER|TA_BASELINE); | 
 | 	SetTextColor(ps.hdc, txtColor); | 
 | 	TextOut(ps.hdc, (rect.left+rect.right)/2, (rect.top+rect.bottom)/2, "Common Dialog Test Page", 23); | 
 |  | 
 | 	SetTextAlign(ps.hdc, TA_LEFT|TA_TOP); | 
 | 	TextOut(ps.hdc, rect.left+10, rect.top+10, ofn_result, strlen(ofn_result)); | 
 | 	TextOut(ps.hdc, rect.left+10, rect.top-cf_lf.lfHeight+10, ofn_titleresult, strlen(ofn_titleresult)); | 
 |  | 
 | 	/* | 
 | 	 * set the HDC back to the old pen and brush, | 
 | 	 * and delete the newly created objects. | 
 | 	 */ | 
 |  | 
 | 	pen = (HPEN) SelectObject(ps.hdc, pen); | 
 | 	DeleteObject(pen); | 
 | 	brush = (HBRUSH) SelectObject(ps.hdc, brush); | 
 | 	DeleteObject(brush); | 
 | 	font = (HFONT) SelectObject(ps.hdc, font); | 
 | 	DeleteObject(font); | 
 |  | 
 | 	EndPaint(hWnd, &ps); | 
 | } | 
 |  | 
 | /* | 
 |  * This function simply returns an error indication.  Naturally, | 
 |  * I do not (yet) see an elegant method by which one can convert | 
 |  * the CDERR_xxx return values into something resembling usable text; | 
 |  * consult cderr.h to see what was returned. | 
 |  */ | 
 |  | 
 | void mw_checkError(HWND hWnd, BOOL explicitcancel) | 
 | { | 
 | 	DWORD errval = CommDlgExtendedError(); | 
 | 	if(errval) { | 
 | 		char errbuf[80]; | 
 |  | 
 | 		sprintf(errbuf, "CommDlgExtendedError(): error code %ld (0x%lx)", errval, errval); | 
 | 		MessageBox(hWnd, errbuf, "Error", MB_ICONEXCLAMATION | MB_OK); | 
 | 	} | 
 | 	else { | 
 | 		if(explicitcancel) MessageBox(hWnd, "Nope, user canceled it.", "No", MB_OK); | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  * The actual dialog function calls.  These merely wrap the Commdlg | 
 |  * calls, and do something (not so) intelligent with the result. | 
 |  * Ideally, the main window would refresh and take into account the | 
 |  * various values specified in the dialog. | 
 |  */ | 
 |  | 
 | void mw_ColorSetup(HWND hWnd) | 
 | { | 
 | 	if(ChooseColor(&cc)) { | 
 | 		RECT rect; | 
 |  | 
 | 		GetClientRect(hWnd, (LPRECT) &rect); | 
 | 		InvalidateRect(hWnd, (LPRECT) &rect, FALSE); | 
 | 		bgColor = cc.rgbResult; | 
 | 	} | 
 | 	else mw_checkError(hWnd, FALSE); | 
 | } | 
 |  | 
 | void mw_FontSetup(HWND hWnd) | 
 | { | 
 | 	if(ChooseFont(&cf)) { | 
 | 		RECT rect; | 
 | 		GetClientRect(hWnd, (LPRECT) &rect); | 
 | 		InvalidateRect(hWnd, (LPRECT) &rect, FALSE); | 
 | 		txtColor = cf.rgbColors; | 
 | 	} | 
 | 	else mw_checkError(hWnd, FALSE); | 
 | } | 
 |  | 
 | void mw_FindSetup(HWND hWnd) | 
 | { | 
 | 	if(findDialogBox == 0) { | 
 | 		findDialogBox = FindText(&frS); | 
 | 		if(findDialogBox==0) mw_checkError(hWnd,TRUE); | 
 | 	} | 
 | } | 
 |  | 
 | void mw_ReplaceSetup(HWND hWnd) | 
 | { | 
 | 	if(findDialogBox == 0) { | 
 | 		findDialogBox = ReplaceText(&frS); | 
 | 		if(findDialogBox==0) mw_checkError(hWnd,TRUE); | 
 | 	} | 
 | } | 
 |  | 
 | void mw_OpenSetup(HWND hWnd) | 
 | { | 
 | 	if(GetOpenFileName(&ofn)) { | 
 | 		RECT rect; | 
 | 		GetClientRect(hWnd, (LPRECT) &rect); | 
 | 		InvalidateRect(hWnd, (LPRECT) &rect, FALSE); | 
 | 	} | 
 | 	else mw_checkError(hWnd,FALSE); | 
 | } | 
 |  | 
 | void mw_SaveSetup(HWND hWnd) | 
 | { | 
 | 	if(GetSaveFileName(&ofn)) { | 
 | 		RECT rect; | 
 | 		GetClientRect(hWnd, (LPRECT) &rect); | 
 | 		InvalidateRect(hWnd, (LPRECT) &rect, FALSE); | 
 | 	} | 
 | 	else mw_checkError(hWnd,FALSE); | 
 | } | 
 |  | 
 | /* | 
 |  * Can't find documentation in Borland for this one.  Does it | 
 |  * exist at all, or is it merely a subdialog of Print? | 
 |  */ | 
 |  | 
 | void mw_PSetupSetup(HWND hWnd) | 
 | { | 
 | 	nyi(hWnd); | 
 | } | 
 |  | 
 | void mw_PrintSetup(HWND hWnd) | 
 | { | 
 | 	if(PrintDlg(&pd)) { | 
 | 		/* | 
 | 		 * the following are suggested in the Borland documentation, | 
 | 		 * but aren't that useful until WinE starts to actually | 
 | 		 * function with respect to printing. | 
 | 		 */ | 
 |  | 
 | #if 0 | 
 | 		Escape(tmp.hDC, STARTDOC, 8, "Test-Doc", NULL); | 
 | #endif | 
 |  | 
 | 	 /* Print text and rectangle */ | 
 |  | 
 | #if 0 | 
 | 		TextOut(tmp.hDC, 50, 50, "Common Dialog Test Page", 23); | 
 |  | 
 | 		Rectangle(tmp.hDC, 50, 90, 625, 105); | 
 | 		Escape(tmp.hDC, NEWFRAME, 0, NULL, NULL); | 
 | 		Escape(tmp.hDC, ENDDOC, 0, NULL, NULL); | 
 | 	 	DeleteDC(tmp.hDC); | 
 | #endif | 
 | 		 if (pd.hDevMode != 0) | 
 | 			 GlobalFree(pd.hDevMode); | 
 | 		 if (pd.hDevNames != 0) | 
 | 			 GlobalFree(pd.hDevNames); | 
 |  | 
 | 		 pd.hDevMode = 0; | 
 | 		 pd.hDevNames = 0; | 
 |  | 
 | 		 MessageBox(hWnd, "Success.", "Yes", MB_OK); | 
 | 	} | 
 | 	else mw_checkError(hWnd,TRUE); | 
 | } | 
 |  | 
 | /* | 
 |  * Some support functions for the custom dialog box handlers. | 
 |  * In particular, we have to set things properly, and get the flags back. | 
 |  */ | 
 |  | 
 | void mwcd_SetFlags(HWND hWnd, struct FlagTableEntry *table, unsigned long flags) | 
 | { | 
 | 	int i; | 
 |  | 
 | 	for(i=0; table[i].ft_id != IDOK; i++) | 
 | 	{ | 
 | 		CheckDlgButton(hWnd, table[i].ft_id,(table[i].ft_bit & flags) ? 1 : 0); | 
 | 	} | 
 | } | 
 |  | 
 | unsigned long mwcd_GetFlags(HWND hWnd, struct FlagTableEntry * table) | 
 | { | 
 | 	int i; | 
 | 	unsigned long l = 0; | 
 |  | 
 | 	for(i=0; table[i].ft_id != IDOK; i++) | 
 | 	{ | 
 | 		if(IsDlgButtonChecked(hWnd, table[i].ft_id) == 1) | 
 | 			l |= table[i].ft_bit; | 
 | 	} | 
 |  | 
 | 	return l; | 
 | } | 
 |  | 
 | /* | 
 |  * These functions are the custom dialog box handlers. | 
 |  * The division of labor may be a tad peculiar; in particular, | 
 |  * the flag tables should probably be in the main functions, | 
 |  * not the handlers.  I'll fix that later; this works as of right now. | 
 |  */ | 
 |  | 
 | BOOL mwcd_Setup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, | 
 | 					 struct FlagTableEntry * table, unsigned long * flags) | 
 | { | 
 | 	(void) lParam; | 
 |  | 
 | 	switch(uMsg) | 
 | 	{ | 
 | 		case WM_INITDIALOG: | 
 | 			/* Set the controls properly. */ | 
 |  | 
 | 			mwcd_SetFlags(hWnd, table, *flags); | 
 |  | 
 | 			return TRUE; /* I would return FALSE if I explicitly called SetFocus(). */ | 
 | 				     /* As usual, Windows is weird. */ | 
 |  | 
 | 		case WM_COMMAND: | 
 | 			switch(wParam) { | 
 | 				case IDOK: | 
 | 					*flags = mwcd_GetFlags(hWnd, table); | 
 | 					EndDialog(hWnd,1); | 
 | 					break; | 
 |  | 
 | 				case IDCANCEL: | 
 | 					EndDialog(hWnd,0); | 
 | 					break; | 
 |  | 
 | 				case CM_R_HELP: | 
 | 					break; /* help?  We don't need no steenkin help! */ | 
 |  | 
 | 				default: | 
 | 					break; /* eat the message */ | 
 | 			} | 
 | 			return TRUE; | 
 |  | 
 | 		default: | 
 | 			return FALSE; /* since I don't process this particular message */ | 
 | 	} | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_ColorSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	static struct FlagTableEntry flagTable[] = { | 
 | 		{I_CC_RGBINIT, CC_RGBINIT}, | 
 | 		{I_CC_SHOWHELP, CC_SHOWHELP}, | 
 | 		{I_CC_PREVENTFULLOPEN, CC_PREVENTFULLOPEN}, | 
 | 		{I_CC_FULLOPEN, CC_FULLOPEN}, | 
 | 		{I_CC_ENABLETEMPLATEHANDLE, CC_ENABLETEMPLATEHANDLE}, | 
 | 		{I_CC_ENABLETEMPLATE, CC_ENABLETEMPLATE}, | 
 | 		{I_CC_ENABLEHOOK, CC_ENABLEHOOK}, | 
 | 		{IDOK, 0}, | 
 | 	}; | 
 |  | 
 | 	return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &cc.Flags); | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_FontSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	static struct FlagTableEntry flagTable[] = { | 
 | 		{I_CF_APPLY, CF_APPLY}, | 
 | 		{I_CF_ANSIONLY, CF_ANSIONLY}, | 
 | 		{I_CF_BOTH, CF_BOTH}, | 
 | 		{I_CF_TTONLY, CF_TTONLY}, | 
 | 		{I_CF_EFFECTS, CF_EFFECTS}, | 
 | 		{I_CF_ENABLEHOOK, CF_ENABLEHOOK}, | 
 | 		{I_CF_ENABLETEMPLATE, CF_ENABLETEMPLATE}, | 
 | 		{I_CF_ENABLETEMPLATEHANDLE, CF_ENABLETEMPLATEHANDLE}, | 
 | 		{I_CF_FIXEDPITCHONLY, CF_FIXEDPITCHONLY}, | 
 | 		{I_CF_INITTOLOGFONTSTRUCT, CF_INITTOLOGFONTSTRUCT}, | 
 | 		{I_CF_LIMITSIZE, CF_LIMITSIZE}, | 
 | 		{I_CF_NOFACESEL, CF_NOFACESEL}, | 
 | 		{I_CF_USESTYLE, CF_USESTYLE}, | 
 | 		{I_CF_WYSIWYG, CF_WYSIWYG}, | 
 | 		{I_CF_SHOWHELP, CF_SHOWHELP}, | 
 | 		{I_CF_SCREENFONTS, CF_SCREENFONTS}, | 
 | 		{I_CF_SCALABLEONLY, CF_SCALABLEONLY}, | 
 | 		{I_CF_PRINTERFONTS, CF_PRINTERFONTS}, | 
 | 		{I_CF_NOVECTORFONTS, CF_NOVECTORFONTS}, | 
 | 		{I_CF_NOSTYLESEL, CF_NOSTYLESEL}, | 
 | 		{I_CF_NOSIZESEL, CF_NOSIZESEL}, | 
 | 		{I_CF_NOOEMFONTS, CF_NOOEMFONTS}, | 
 | 		{IDOK, 0}, | 
 | 	}; | 
 |  | 
 | 	return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &cf.Flags); | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_FindSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 |  | 
 | 	static struct FlagTableEntry flagTable[] = { | 
 | 		{I_FR_DIALOGTERM, FR_DIALOGTERM}, | 
 | 		{I_FR_DOWN, FR_DOWN}, | 
 | 		{I_FR_ENABLEHOOK, FR_ENABLEHOOK}, | 
 | 		{I_FR_ENABLETEMPLATE, FR_ENABLETEMPLATE}, | 
 | 		{I_FR_ENABLETEMPLATEHANDLE, FR_ENABLETEMPLATEHANDLE}, | 
 | 		{I_FR_FINDNEXT, FR_FINDNEXT}, | 
 | 		{I_FR_HIDEMATCHCASE, FR_HIDEMATCHCASE}, | 
 | 		{I_FR_HIDEWHOLEWORD, FR_HIDEWHOLEWORD}, | 
 | 		{I_FR_HIDEUPDOWN, FR_HIDEUPDOWN}, | 
 | 		{I_FR_MATCHCASE, FR_MATCHCASE}, | 
 | 		{I_FR_NOMATCHCASE, FR_NOMATCHCASE}, | 
 | 		{I_FR_NOUPDOWN, FR_NOUPDOWN}, | 
 | 		{I_FR_NOWHOLEWORD, FR_NOWHOLEWORD}, | 
 | 		{I_FR_REPLACE, FR_REPLACE}, | 
 | 		{I_FR_REPLACEALL, FR_REPLACEALL}, | 
 | 		{I_FR_SHOWHELP, FR_SHOWHELP}, | 
 | 		{I_FR_WHOLEWORD, FR_WHOLEWORD}, | 
 | 		{IDOK, 0}, | 
 | 	}; | 
 |  | 
 | 	return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &frS.Flags); | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_PrintSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	static struct FlagTableEntry flagTable[] = { | 
 | 		{I_PD_ALLPAGES, PD_ALLPAGES}, | 
 | 		{I_PD_COLLATE, PD_COLLATE}, | 
 | 		{I_PD_DISABLEPRINTTOFILE, PD_DISABLEPRINTTOFILE}, | 
 | 		{I_PD_ENABLEPRINTHOOK, PD_ENABLEPRINTHOOK}, | 
 | 		{I_PD_ENABLEPRINTTEMPLATE, PD_ENABLEPRINTTEMPLATE}, | 
 | 		{I_PD_ENABLEPRINTTEMPLATEHANDLE, PD_ENABLEPRINTTEMPLATEHANDLE}, | 
 | 		{I_PD_ENABLESETUPHOOK, PD_ENABLESETUPHOOK}, | 
 | 		{I_PD_ENABLESETUPTEMPLATE, PD_ENABLESETUPTEMPLATE}, | 
 | 		{I_PD_ENABLESETUPTEMPLATEHANDLE, PD_ENABLESETUPTEMPLATEHANDLE}, | 
 | 		{I_PD_HIDEPRINTTOFILE, PD_HIDEPRINTTOFILE}, | 
 | 		{I_PD_NOPAGENUMS, PD_NOPAGENUMS}, | 
 | 		{I_PD_NOSELECTION, PD_NOSELECTION}, | 
 | 		{I_PD_NOWARNING, PD_NOWARNING}, | 
 | 		{I_PD_PAGENUMS, PD_PAGENUMS}, | 
 | 		{I_PD_PRINTSETUP, PD_PRINTSETUP}, | 
 | 		{I_PD_PRINTTOFILE, PD_PRINTTOFILE}, | 
 | 		{I_PD_RETURNDC, PD_RETURNDC}, | 
 | 		{I_PD_RETURNDEFAULT, PD_RETURNDEFAULT}, | 
 | 		{I_PD_RETURNIC, PD_RETURNIC}, | 
 | 		{I_PD_SELECTION, PD_SELECTION}, | 
 | 		{I_PD_SHOWHELP, PD_SHOWHELP}, | 
 | 		{I_PD_USEDEVMODECOPIES, PD_USEDEVMODECOPIES}, | 
 | 		{IDOK, 0}, | 
 | 	}; | 
 |  | 
 | 	return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &pd.Flags); | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_FileSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	static struct FlagTableEntry flagTable[] = { | 
 | 		{I_OFN_ALLOWMULTISELECT, OFN_ALLOWMULTISELECT}, | 
 | 		{I_OFN_CREATEPROMPT, OFN_CREATEPROMPT}, | 
 | 		{I_OFN_ENABLEHOOK, OFN_ENABLEHOOK}, | 
 | 		{I_OFN_ENABLETEMPLATE, OFN_ENABLETEMPLATE}, | 
 | 		{I_OFN_ENABLETEMPLATEHANDLE, OFN_ENABLETEMPLATEHANDLE}, | 
 | 		{I_OFN_EXTENSIONDIFFERENT, OFN_EXTENSIONDIFFERENT}, | 
 | 		{I_OFN_FILEMUSTEXIST, OFN_FILEMUSTEXIST}, | 
 | 		{I_OFN_HIDEREADONLY, OFN_HIDEREADONLY}, | 
 | 		{I_OFN_NOCHANGEDIR, OFN_NOCHANGEDIR}, | 
 | 		{I_OFN_NOREADONLYRETURN, OFN_NOREADONLYRETURN}, | 
 | 		{I_OFN_NOTESTFILECREATE, OFN_NOTESTFILECREATE}, | 
 | 		{I_OFN_NOVALIDATE, OFN_NOVALIDATE}, | 
 | 		{I_OFN_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT}, | 
 | 		{I_OFN_PATHMUSTEXIST, OFN_PATHMUSTEXIST}, | 
 | 		{I_OFN_READONLY, OFN_READONLY}, | 
 | 		{I_OFN_SHAREAWARE, OFN_SHAREAWARE}, | 
 | 		{I_OFN_SHOWHELP, OFN_SHOWHELP}, | 
 | 		{IDOK, 0}, | 
 | 	}; | 
 |  | 
 | 	return mwcd_Setup(hWnd, uMsg, wParam, lParam, flagTable, &ofn.Flags); | 
 | } | 
 |  | 
 | BOOL CALLBACK mwcd_About(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 | 	(void) wParam; | 
 | 	(void) lParam; | 
 |  | 
 | 	switch(uMsg) { | 
 | 		case WM_INITDIALOG: return TRUE; /* let WINDOWS set the focus. */ | 
 | 		case WM_COMMAND: EndDialog(hWnd, 0); return TRUE; /* it's our OK button. */ | 
 | 		default: return FALSE; /* it's something else, let Windows worry about it */ | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  * These functions call custom dialog boxes (resource-loaded, if I do this right). | 
 |  * Right now they don't do a heck of a lot, but at some future time | 
 |  * they will muck about with the flags (and be loaded from the flags) of | 
 |  * the CommDlg structures initialized by the mwi_xxx() routines. | 
 |  */ | 
 |  | 
 | void mwc_ColorSetup(HWND hWnd) | 
 | { | 
 | 	int r = DialogBox(g_hInstance, "Color_Flags_Dialog", hWnd, (DLGPROC) mwcd_ColorSetup); | 
 | 	if(r < 0) { MessageBox(hWnd, "Failure opening Color_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); } | 
 | } | 
 |  | 
 | void mwc_FontSetup(HWND hWnd) | 
 | { | 
 | 	int r = DialogBox(g_hInstance, "Font_Flags_Dialog", hWnd, (DLGPROC) mwcd_FontSetup); | 
 | 	if(r < 0) { MessageBox(hWnd, "Failure opening Font_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); } | 
 | } | 
 |  | 
 | void mwc_FindReplaceSetup(HWND hWnd) | 
 | { | 
 | 	int r = DialogBox(g_hInstance, "Find_Flags_Dialog", hWnd, (DLGPROC) mwcd_FindSetup); | 
 | 	if(r < 0) { MessageBox(hWnd, "Failure opening Find_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); } | 
 | } | 
 |  | 
 | void mwc_PrintSetup(HWND hWnd) | 
 | { | 
 | 	int r = DialogBox(g_hInstance, "Print_Flags_Dialog", hWnd, (DLGPROC) mwcd_PrintSetup); | 
 | 	if(r < 0) { MessageBox(hWnd, "Failure opening Print_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); } | 
 | } | 
 |  | 
 | void mwc_FileSetup(HWND hWnd) | 
 | { | 
 | 	int r = DialogBox(g_hInstance, "File_Flags_Dialog", hWnd, (DLGPROC) mwcd_FileSetup); | 
 | 	if(r < 0) { MessageBox(hWnd, "Failure opening File_Flags_Dialog box", "Error", MB_ICONASTERISK|MB_OK); } | 
 | } | 
 |  | 
 | /* | 
 |  * Main window message dispatcher.  Here the messages get chewed up | 
 |  * and spit out.  Note the ugly hack for the modeless Find/Replace box; | 
 |  * this looks like it was bolted on with hexhead screws and is now | 
 |  * dangling from Windows like a loose muffler.  Sigh. | 
 |  */ | 
 |  | 
 | LRESULT CALLBACK EXPORT mainWindowDispatcher( | 
 | 	HWND hWnd, | 
 | 	UINT uMsg, | 
 | 	WPARAM wParam, | 
 | 	LPARAM lParam | 
 | ) | 
 | { | 
 |  | 
 | 	if(uMsg == findMessageId) { | 
 | 		FINDREPLACE * lpfr = (FINDREPLACE *) lParam; | 
 | 		if(lpfr->Flags & FR_DIALOGTERM) { | 
 | 			MessageBox(hWnd, "User closing us down.", "Down", MB_OK); | 
 | 			findDialogBox = 0; | 
 | 		} | 
 | 		else if (lpfr->Flags & FR_FINDNEXT) { | 
 | 			MessageBox(hWnd, "Finding next occurrence.", "Findnext", MB_OK); | 
 | 		} | 
 | 		else if (lpfr->Flags & FR_REPLACE) { | 
 | 			MessageBox(hWnd, "Replacing next occurence.", "Replace", MB_OK); | 
 | 		} | 
 | 		else if (lpfr->Flags & FR_REPLACEALL) { | 
 | 			MessageBox(hWnd, "Replacing all occurrences.", "Replace All", MB_OK); | 
 | 		} | 
 | 		else { | 
 | 			MessageBox(hWnd, "Eh?", "Eh?", MB_OK); | 
 | 		} | 
 | 		return 1; | 
 | 	} | 
 | 	else switch(uMsg) { | 
 | 	case WM_CREATE: | 
 | 			/* | 
 | 			 * this is always the first message...at least as far as | 
 | 			 * we are concerned. | 
 | 			 */ | 
 | 		mwi_InitAll(hWnd); | 
 | 		break; | 
 |  | 
 | 	case WM_PAINT: | 
 | 			/* Well, draw something! */ | 
 | 		paintMainWindow(hWnd, uMsg, wParam, lParam); | 
 | 		break; | 
 |  | 
 | 	case WM_DESTROY: | 
 | 			/* Uh oh.  Eject!  Eject!  Eject! */ | 
 | 		PostQuitMessage(0); | 
 | 		break; | 
 |  | 
 | 	case WM_COMMAND: | 
 | 			/* menu or accelerator pressed; do something. */ | 
 |  | 
 | 		switch(wParam) { | 
 | 		case CM_U_EXIT: | 
 | 				/* Uh oh.  Eject!  Eject!  Eject! */ | 
 | 			PostQuitMessage(0); | 
 | 			break; | 
 |  | 
 | 		/* these actually call the Common Dialogs. */ | 
 |  | 
 | 		case CM_U_COLOR: | 
 | 			mw_ColorSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_FONT: | 
 | 			mw_FontSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_FIND: | 
 | 			mw_FindSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_REPLACE: | 
 | 			mw_ReplaceSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_OPEN: | 
 | 			mw_OpenSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_SAVE: | 
 | 			mw_SaveSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_PSETUP: | 
 | 			mw_PSetupSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_U_PRINT: | 
 | 			mw_PrintSetup(hWnd); return 1; | 
 |  | 
 | 		/* | 
 | 		 * these set up various flags and values in the Common Dialog | 
 | 		 * data structures, which are currently stored in static memory. | 
 | 		 * The control dialogs themselves are resources as well. | 
 | 		 */ | 
 |  | 
 | 		case CM_F_FILE: | 
 | 			mwc_FileSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_F_COLOR: | 
 | 			mwc_ColorSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_F_FONT: | 
 | 			mwc_FontSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_F_FINDREPLACE: | 
 | 			mwc_FindReplaceSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_F_PRINT: | 
 | 			mwc_PrintSetup(hWnd); return 1; | 
 |  | 
 | 		case CM_H_ABOUT: | 
 | 			DialogBox(g_hInstance, "AboutDialog", hWnd, (DLGPROC) mwcd_About); | 
 | 			return 1; | 
 | 		case CM_H_USAGE: | 
 | 			DialogBox(g_hInstance, "UsageDialog", hWnd, (DLGPROC) mwcd_About); | 
 |          	/* return value?  *What* return value? */ | 
 | 			return 1; | 
 |  | 
 | 		default: | 
 | 			nyi(hWnd); return 1; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		return DefWindowProc(hWnd, uMsg, wParam, lParam); | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* Class registration.  One might call this a Windowsism. */ | 
 |  | 
 | int registerMainWindowClass(HINSTANCE hInstance) | 
 | { | 
 | 	WNDCLASS wndClass; | 
 |  | 
 | 	wndClass.style         = CS_HREDRAW|CS_VREDRAW; | 
 | 	wndClass.lpfnWndProc   = mainWindowDispatcher; | 
 | 	wndClass.cbClsExtra    = 0; | 
 | 	wndClass.cbWndExtra    = 0; | 
 | 	wndClass.hInstance     = hInstance; | 
 | #if 0 | 
 | 	wndClass.hIcon         = LoadIcon(hInstance, "whello"); | 
 | 	wndClass.hCursor       = LoadCursor(hInstance, IDC_ARROW); | 
 | #endif | 
 | 	wndClass.hIcon         = 0; | 
 | 	wndClass.hCursor       = 0; | 
 | 	wndClass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); | 
 | 	wndClass.lpszMenuName  = menuName; | 
 | 	wndClass.lpszClassName = className; | 
 |  | 
 | 	return RegisterClass(&wndClass); | 
 | } | 
 |  | 
 | /* | 
 |  * Another Windowsism; this one's not too bad, as it compares | 
 |  * favorably with CreateWindow() in X (mucking about with X Visuals | 
 |  * can get messy; at least here we don't have to worry about that). | 
 |  */ | 
 |  | 
 | HWND createMainWindow(HINSTANCE hInstance, int show) | 
 | { | 
 | 	HWND hWnd; | 
 |  | 
 | 	hWnd = CreateWindow( | 
 | 		className,  /* classname */ | 
 | 		windowName,  /* windowname/title */ | 
 | 		WS_OVERLAPPEDWINDOW, /* dwStyle */ | 
 | 		0, /* x */ | 
 | 		0, /* y */ | 
 | 		CW_USEDEFAULT, /* width */ | 
 | 		CW_USEDEFAULT, /* height */ | 
 | 		0, /* parent window */ | 
 | 		0, /* menu */ | 
 | 		hInstance, /* instance */ | 
 | 		0          /* passthrough for MDI */ | 
 | 	); | 
 |  | 
 | 	if(hWnd==0) return 0; | 
 |  | 
 | 	ShowWindow(hWnd, show); | 
 | 	UpdateWindow(hWnd); | 
 |  | 
 | 	return hWnd; | 
 | } | 
 |  | 
 | int messageLoop(HINSTANCE hInstance, HWND hWnd) | 
 | { | 
 | 	MSG msg; | 
 |  | 
 | 	(void) hInstance; | 
 | 	(void) hWnd; | 
 |  | 
 | 	while(GetMessage(&msg, 0, 0, 0)) { | 
 | 		TranslateMessage(&msg); | 
 | 		DispatchMessage(&msg); | 
 | 	} | 
 |  | 
 | 	return msg.wParam; | 
 | } | 
 |  | 
 | /* | 
 |  * Oh, did we tell you that main() isn't the name of the | 
 |  * thing called in a Win16/Win32 app?  And then there are | 
 |  * the lack of argument lists, the necessity (at least in Win16) | 
 |  * of having to deal with class registration exactly once (as the | 
 |  * app may be run again), and some other bizarre holdovers from | 
 |  * Windows 3.x days.  But hey, Solitaire still works. | 
 |  */ | 
 |  | 
 | int PASCAL WinMain( | 
 | 	HINSTANCE hInstance, HINSTANCE hPrevInstance, | 
 | 	LPSTR lpszCmdLine, int nCmdShow | 
 | ) | 
 | { | 
 | 	HWND hWnd; | 
 |  | 
 | 	(void) lpszCmdLine; | 
 |  | 
 | 	strcpy(ofn_result, "--- not yet set ---"); | 
 |  | 
 | 	if(hPrevInstance==0) { | 
 | 		if(!registerMainWindowClass(hInstance)) | 
 | 			return -1; | 
 | 	} | 
 |  | 
 | 	g_hInstance = hInstance; | 
 |  | 
 | 	hWnd = createMainWindow(hInstance,nCmdShow); | 
 | 	if(hWnd == 0) | 
 | 		return -1; | 
 |  | 
 | 	return messageLoop(hInstance, hWnd); | 
 | } | 
 |  | 
 | /* And now the end of the program.  Enjoy. */ | 
 |  | 
 | /* | 
 |  * (c) 1999-2000 Eric Williams.  Rights as specified under the WINE | 
 |  * License.  Don't hoard code; share it! | 
 |  */ |